简体   繁体   English

防止JInternalFrame移出JDesktopPane

[英]Preventing JInternalFrame from being moved out of a JDesktopPane

When I have a JInternalFrame in a JDesktopPane, the JInternalFrame is movable (which is good). 当我在JDesktopPane中有一个JInternalFrame时,JInternalFrame是可移动的(这很好)。 However, it's possible to move it outside of the visible scope of the JDesktopPane (which I'm not so fond of) 但是,可以将它移到JDesktopPane的可见范围之外(我不是很喜欢)

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? 是否可以设置JInternalFrame或JDesktopPane,以便它们不允许这样做?

The collaborator which is responsible for doing the move/resize is the DesktopPaneManager. 负责移动/调整大小的协作者是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 :-) Fi 有一些问题需要解决,显然:-) Fi

  • use the manager as appropriate for the LAF, which could be done by implementing a wrapper DesktopManager which delegates everything else to the LAF installed 使用适用于LAF的管理器,这可以通过实现一个包装器DesktopManager来完成,该程序包将所有其他内容委托给安装的LAF
  • check for side-effects (the drag appears a unresponsive after having hit a wall, there might be other things needed) 检查副作用(在撞墙后阻力似乎没有反应,可能还需要其他东西)

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. 这并不奇怪,因为BorderListener(它是由BasicInternalFrame安装的mouseListener)保持一些与初始按下相关的状态,然后请求相对于该初始位置重新定位。 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. 但这与当前鼠标位置有关。

Full credit to kleopatra for pointing me in the right direction. 完全归功于kleopatra让我指向正确的方向。

I think I've solved the unresponsiveness issue, and am sharing my solution here. 我想我已经解决了无反应问题,并且在这里分享我的解决方案。 Following kleopatra's answer, if the mouse point is outside of the pane, the internal frame is at the edge of the pane. 按照kleopatra的回答,如果鼠标点位于窗格之外,则内部框架位于窗格的边缘。 Also, this continues to follow the mouse - ie if you move the mouse off the bottom of the pane, and then round to the right hand side of the pane, the frame will follow along the bottom of the pane, and then up the right sand of the pane. 此外,这继续跟随鼠标 - 即如果您将鼠标移离窗格底部,然后向窗口的右侧移动,则框架将沿着窗格的底部,然后向右移动窗格的沙子。

public class BoundedDesktopManager extends DefaultDesktopManager {

  @Override
  public void beginDraggingFrame(JComponent f) {
    // Don't do anything. Needed to prevent the DefaultDesktopManager setting the dragMode
  }

  @Override
  public void beginResizingFrame(JComponent f, int direction) {
    // Don't do anything. Needed to prevent the DefaultDesktopManager setting the dragMode
  }

  @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)) {
      Container parent = f.getParent();
      Dimension parentSize = parent.getSize();
      int boundedX = (int) Math.min(Math.max(0, newX), parentSize.getWidth() - newWidth);
      int boundedY = (int) Math.min(Math.max(0, newY), parentSize.getHeight() - newHeight);
      f.setBounds(boundedX, boundedY, newWidth, newHeight);
    } else {
      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;
  }
}

It is important that the top of the JInternalFrame not get hidden, since that is where its grab bar and control buttons are located. 重要的是JInternalFrame的顶部不会被隐藏,因为这是它的抓杆和控制按钮所在的位置。 So, as a last step before setting bounds, make sure that your y value is not negative: for example, with a statement like y = Math.max(0, y). 因此,作为设置边界之前的最后一步,请确保您的y值不是负值:例如,使用y = Math.max(0,y)之类的语句。

Try to set FlowLayout of JFrame and use add() method to add JDesktopPane. 尝试设置JFrame的FlowLayout并使用add()方法添加JDesktopPane。

frame.setLayout(new FlowLayout());
tableDisplay.setPreferredSize(new Dimension(100,100));
frame.add(tableDisplay);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM