Monday, May 7, 2012

Listen to JFrame resize events as the user drags their mouse?


When a user clicks on the corner of a JFrame to resize and drags the mouse around, the JFrame redraws based on the current position of the mouse as the user drags. How can you listen to these events?



Below is the what I have currently tried:




public final class TestFrame extends JFrame {
public TestFrame() {
this.addComponentListener(new ComponentAdapter() {
public void componentResized(ComponentEvent e) {
// This is only called when the user releases the mouse button.
System.out.println("componentResized");
}
});
}

// These methods do not appear to be called at all when a JFrame
// is being resized.
@Override
public void setSize(int width, int height) {
System.out.println("setSize");
}

@Override
public void setBounds(Rectangle r) {
System.out.println("setBounds A");
}

@Override
public void setBounds(int x, int y, int width, int height) {
System.out.println("setBounds B");
}
}



How can I determine and constrain how the user resizes a window (based on the current aspect ratio of the window) as they are dragging around the mouse around?


Source: Tips4all

4 comments:

  1. You probably need to override something like validate (don't forget to call the super). Of course, that still may not work if you are using a windowing system to configured to drag outlines.

    ReplyDelete
  2. You can add a component listener and implement the componentResized function like that:

    JFrame component = new JFrame("My Frame");

    component.addComponentListener(new ComponentListener()
    {
    public void componentResized(ComponentEvent evt) {
    Component c = (Component)evt.getSource();
    //........
    }
    });


    EDIT: Apparently, for JFrame, the componentResized event is hooked to the mouseReleased event. That's why the method is invoked when the mouse button is released.

    One way to achieve what you want, is to add a JPanel that will cover the whole area of your JFrame. Then add the componentListener to the JPanel (componentResized for JPanel is called even while your mouse is still dragging). When your frame is resized, your panel will also be resized too.

    I know, this isn't the most elegant solution, but it works!

    ReplyDelete
  3. Another workaround (which is very similar to Alex's but a little more straightforward) is to listen to the events from the JFrame's root pane instead:

    public final class TestFrame extends JFrame {
    public TestFrame() {
    this.getRootPane().addComponentListener(new ComponentAdapter() {
    public void componentResized(ComponentEvent e) {
    // This is only called when the user releases the mouse button.
    System.out.println("componentResized");
    }
    });
    }
    }


    Depending on other implementation details, it's possible that the root pane might be changed. If that's a possibility then you could override setRootPane() and deal with that. Since setRootPane() is protected and only called from the constructor though, it's unlikely you'll need to do that.

    ReplyDelete
  4. public class MouseDrag extends Component implements MouseListener,
    MouseMotionListener {
    /** The Image we are to paint */
    Image curImage;

    /** Kludge for showStatus */
    static Label status;

    /** true if we are in drag */
    boolean inDrag = false;

    /** starting location of a drag */
    int startX = -1, startY = -1;

    /** current location of a drag */
    int curX = -1, curY = -1;

    // "main" method
    public static void main(String[] av) {
    JFrame f = new JFrame("Mouse Dragger");
    Container cp = f.getContentPane();

    if (av.length < 1) {
    System.err.println("Usage: MouseDrag imagefile");
    System.exit(1);
    }
    Image im = Toolkit.getDefaultToolkit().getImage(av[0]);

    // create a MouseDrag object
    MouseDrag j = new MouseDrag(im);

    cp.setLayout(new BorderLayout());
    cp.add(BorderLayout.NORTH, new Label(
    "Hello, and welcome to the world of Java"));
    cp.add(BorderLayout.CENTER, j);
    cp.add(BorderLayout.SOUTH, status = new Label());
    status.setSize(f.getSize().width, status.getSize().height);
    f.pack();
    f.setVisible(true);
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    // "Constructor" - creates the object
    public MouseDrag(Image i) {
    super();
    curImage = i;
    setSize(300, 200);
    addMouseListener(this);
    addMouseMotionListener(this);
    }

    public void showStatus(String s) {
    status.setText(s);
    }

    // Five methods from MouseListener:
    /** Called when the mouse has been clicked on a component. */
    public void mouseClicked(MouseEvent e) {
    }

    /** Called when the mouse enters a component. */
    public void mouseEntered(MouseEvent e) {
    }

    /** Called when the mouse exits a component. */
    public void mouseExited(MouseEvent e) {
    }


    // And two methods from MouseMotionListener:
    public void mouseDragged(MouseEvent e) {
    Point p = e.getPoint();
    // System.err.println("mouse drag to " + p);
    showStatus("mouse Dragged to " + p);
    curX = p.x;
    curY = p.y;
    if (inDrag) {
    repaint();
    }
    }

    public void paint(Graphics g) {
    int w = curX - startX, h = curY - startY;
    Dimension d = getSize();
    g.drawImage(curImage, 0, 0, d.width, d.height, this);
    if (startX < 0 || startY < 0)
    return;
    System.err.println("paint:drawRect @[" + startX + "," + startY
    + "] size " + w + "x" + h);
    g.setColor(Color.red);
    g.fillRect(startX, startY, w, h);
    }

    }

    ReplyDelete