【问题标题】:Preventing JInternalFrame from being moved out of a JDesktopPane防止 JInternalFrame 被移出 JDesktopPane
【发布时间】:2011-12-29 12:47:02
【问题描述】:

当我在 JDesktopPane 中有 JInternalFrame 时,JInternalFrame 是可移动的(这很好)。但是,可以将它移到 JDesktopPane 的可见范围之外(我不太喜欢)

为了自己看,这里有一些示例代码:

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);
}

是否可以将 JInternalFrame 或 JDesktopPane 设置为不允许这样做?

【问题讨论】:

    标签: java swing jinternalframe jdesktoppane


    【解决方案1】:

    负责移动/调整大小的协作者是 DesktopPaneManager。所以我会尝试将移动限制在窗格内。这是一个快速而肮脏的概念证明:

        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);
    

    显然有一些问题需要解决 :-) F.i.

    • 为 LAF 使用适当的管理器,这可以通过实现一个包装器 DesktopManager 来完成,该包装器将其他所有内容委托给安装的 LAF
    • 检查副作用(拖拽在撞墙后出现无响应,可能需要其他操作)

    编辑

    只是为了澄清:“无响应”是指用户必须释放并再次按下/拖动(一旦内部框架触及桌面边界)以进一步移动。这并不奇怪,因为 BorderListener(即由 BasicInternalFrame 安装的 mouseListener)保持与初始按下相关的一些状态,然后请求相对于该初始位置重新定位。在框架卡在某处的情况下拖动鼠标会混淆该内部状态。

    有趣的是,看代码,似乎有人打算限制运动不将其推到外面,

        // 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;
    

    不过,这是相对于当前鼠标位置的。

    【讨论】:

    • +1 - 一个破解的答案,谢谢。我想我已经解决了无响应问题(我将单独发布我的解决方案)。
    • +1 寻求帮助,因为我遇到了同样的问题。非常感谢您的帖子。
    • 如果我使用这个技巧然后尝试最小化 JInternalFrames 然后我得到一个 NPR,null Window w。
    【解决方案2】:

    感谢 kleopatra 为我指明了正确的方向。

    我想我已经解决了无响应问题,并在这里分享我的解决方案。按照 kleopatra 的回答,如果鼠标点在窗格之外,则内部框架位于窗格的边缘。此外,这将继续跟随鼠标 - 即,如果您将鼠标移出窗格底部,然后向窗格的右侧移动,则框架将沿着窗格底部跟随,然后向右上方窗格的沙子。

    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;
      }
    }
    

    【讨论】:

      【解决方案3】:

      尝试设置JFrame的FlowLayout,使用add()方法添加JDesktopPane。

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

      【讨论】:

      • 首先,这似乎不起作用 - 即它不能解决 JDesktopPane 问题之外的移动问题。其次,我正在寻找 JDesktopPane 或 JInternalFrame 级别的解决方案,而不是 JFrame 级别。 (我想将这些组件用作更大 GUI 的一部分。)
      【解决方案4】:

      重要的是不要隐藏 JInternalFrame 的顶部,因为那里是它的抓取栏和控制按钮所在的位置。因此,作为设置边界之前的最后一步,请确保您的 y 值不是负数:例如,使用 y = Math.max(0, y) 之类的语句。

      【讨论】:

        猜你喜欢
        • 2013-08-28
        • 2011-06-03
        • 2014-12-14
        • 2011-10-15
        • 2011-11-23
        • 2012-11-29
        • 2011-11-21
        • 2018-02-16
        • 1970-01-01
        相关资源
        最近更新 更多