tags:

views:

327

answers:

2

Hello!

I need to restrict movement of a component (JInternalFrame) inside a JPanel.
More exact: a component should only move along one axis when dragged by the user.

I tried to do it by adding a component listener and reset the position of one axis everytime the component moves. But it "vibrates" (moves rapidly during dragging).

I even wrote a custom layout manager, it didn't help a little!

I guess, the problem is: Both the layout manager and the listener handle the movement-event after the component is actually moved, right?

Any suggestions?

Should (can I) intercept some event, and modify it, before it's delivered?

+1  A: 

you might want to subclass your InternalFrameUI. I see in BasicInteralFrameUI.BorderListener.mouseDragged(event)(line 885 in version 1.129) a call to getDesktopManager().dragFrame(frame, newX, newY);

You could extend BasicInternalFrameUI to return a custom DesktopManager (extension of DefaultDesktopManager), where in dragFrame() you test the identity of your frame and adjust the axis.

edit:

thinking about it, you are right - it is too complex. as the UI for the internal frame defers to the DesktopManager of the JDesktopPane, you can set it there. here is a poc:

public Demo() {
        JFrame frame = new JFrame();
        frame.setSize(300,300);
        JDesktopPane df = new JDesktopPane();
        DesktopManager dm = df.getDesktopManager();
        df.setDesktopManager(new DefaultDesktopManager(){
            public void dragFrame(JComponent f, int newX, int newY) {
               super.dragFrame(f, newX, 5);
            }

        });
        JInternalFrame jif = new JInternalFrame("test ");
        jif.setLocation(5, 5);
        jif.setSize(150,100);
        jif.setVisible(true);
        df.add(jif);
        frame.setContentPane(df);
        frame.setVisible(true);
}
akf
Works perfectly !!!
ivan_ivanovich_ivanoff
+2  A: 

There is no "event" you need to intercept. Once Swing processes the mouse event, it tells the component to move - and that's where you can tweak the movement values.

move, setLocation and resize are all just wrappers to setBounds. Extend JInternalFrame, override the setBounds() method and ignore the new value of x (or y if you want horizontal movement) before calling super.setBounds().

import javax.swing.JInternalFrame;
public class VerticalOnlyFrame extends JInternalFrame {

    public void setBounds(int x, int y, int width, int height) {
            super.setBounds(getBounds().x, y, width, height);
    }

}

That should solve your example, although looking at the JRE code setBounds() is actually a wrapper to the deprecated reshape() method so if you're feeling brave override reshape() instead.

Spyder
Thank you. This sounds good. The reason I was thinking about intercepting events, is the ability to do the intended alignment for any component.
ivan_ivanovich_ivanoff
Unfortunately events are for notification, so a component move event is only fired after the component has moved and repainted. To avoid jitter you need to do your work before the event.The only alternative is some kind of mouseDragged listener as akf suggested :)
Spyder