javaswingjinternalframejdesktoppane

Preventing JInternalFrame from being moved out of a JDesktopPane


When I have a JInternalFrame in a JDesktopPane, the JInternalFrame is movable (which is good). However, it's possible to move it outside of the visible scope of the JDesktopPane (which I'm not so fond of)

To see for yourself, here's some sample code:

public static void main(String[] args) {

  JFrame frame = new JFrame("JDesktopPane");
  JDesktopPane tableDisplay = new JDesktopPane();

  JInternalFrame internalFrame = new JInternalFrame("JInternalFrame",true,true,true,true);
  internalFrame.setContentPane(new JLabel("Content"));
  internalFrame.pack();
  internalFrame.setVisible(true);
  tableDisplay.add(internalFrame, JDesktopPane.POPUP_LAYER);

  frame.setContentPane(tableDisplay);
  frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  frame.setMinimumSize(new Dimension(400, 300));
  frame.setVisible(true);
}

Is it possible to set either the JInternalFrame or JDesktopPane so that they won't allow this?


Solution

  • The collaborator which is responsible for doing the move/resize is the DesktopPaneManager. So I would try to limit the movement to within the pane. Here's a quick & dirty proof of concept:

        JDesktopPane background = new JDesktopPane();
        JInternalFrame internalFrame = new JInternalFrame("Internal Frame",
                true, true, true, true);
        DesktopManager manager = new DefaultDesktopManager() {
            /** This moves the <code>JComponent</code> and repaints the damaged areas. */
            @Override
            public void setBoundsForFrame(JComponent f, int newX, int newY, int newWidth, int newHeight) {
                boolean didResize = (f.getWidth() != newWidth || f.getHeight() != newHeight);
                if (!inBounds((JInternalFrame) f, newX, newY, newWidth, newHeight)) return;
                f.setBounds(newX, newY, newWidth, newHeight);
                if(didResize) {
                    f.validate();
                } 
            }
    
            protected boolean inBounds(JInternalFrame f, int newX, int newY, int newWidth, int newHeight) {
                if (newX < 0 || newY < 0) return false;
                if (newX + newWidth > f.getDesktopPane().getWidth()) return false;
                if (newY + newHeight > f.getDesktopPane().getHeight()) return false;
                return true;
            }
    
        };
        background.setDesktopManager(manager);
    

    There are some issues to solve, obviously :-) F.i.

    Edit

    just to clarify: with "unresponsive" I mean that the user has to release and press/drag again (once the internal frame has hit the desktop bounds) to further move the. That's not overly surprising, as the BorderListener (that's the mouseListener installed by BasicInternalFrame) keeps some state related to the initial press and then requests re-locates relative to that initial location. Dragging the mouse with the frame stuck somewhere confuses that internal state.

    Interestingly, looking at the code, it seems like there had been intentions to limit the movement to not push it to the outside,

        // Make sure we stay in-bounds
        if(newX + i.left <= -__x)
            newX = -__x - i.left + 1;
        if(newY + i.top <= -__y)
            newY = -__y - i.top + 1;
        if(newX + __x + i.right >= pWidth)
            newX = pWidth - __x - i.right - 1;
        if(newY + __y + i.bottom >= pHeight)
            newY =  pHeight - __y - i.bottom - 1;
    

    that's relative to the current mouse location, though.