Предотвращение перемещения JInternalFrame из JDesktopPane - PullRequest
8 голосов
/ 15 ноября 2011

Когда у меня есть JInternalFrame в JDesktopPane, 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, чтобы они этого не допустили?

Ответы [ 4 ]

8 голосов
/ 15 ноября 2011

Соавтором, который отвечает за перемещение / изменение размера, является 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);

Очевидно, что есть некоторые проблемы, которые необходимо решить :-) Fi

  • использовать менеджера в соответствии с требованиями LAF, что можетсделать это путем реализации обертки DesktopManager, которая делегирует все остальное установленной LAF
  • проверка на побочные эффекты (перетаскивание кажется не отвечающим после удара о стену, могут быть другие вещи, необходимые)

Редактировать

просто чтобы уточнить: под "безразличным" я имею в виду, что пользователь должен отпустить и снова нажать / перетащить (как только внутренняя рамка достигнет границ рабочего стола), чтобыдальше двигайся.Это не слишком удивительно, так как BorderListener (это mouseListener, установленный BasicInternalFrame) сохраняет некоторое состояние, относящееся к начальному нажатию, а затем запрашивает повторное расположение относительно этого исходного местоположения.Перетаскивание мыши с застрявшей рамкой вводит в заблуждение это внутреннее состояние.

Интересно, что, глядя на код, кажется, что были намерения ограничить движение, чтобы не толкать его наружу,

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

относительно текущего местоположения мыши, хотя,

8 голосов
/ 16 ноября 2011

Полная заслуга Клеопатры за то, что она указала мне правильное направление.

Я думаю, что решил проблему с неотзывчивостью и делюсь своим решением здесь. После ответа Клеопатры, если точка мыши находится за пределами панели, внутренняя рамка находится на краю панели. Кроме того, это продолжает следовать за мышью - то есть, если вы переместите мышь за нижнюю часть панели, а затем поверните ее к правой стороне панели, рамка будет следовать вдоль нижней части панели, а затем вверх по правой песок панели.

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;
  }
}
0 голосов
/ 26 августа 2015

Важно, чтобы верх JInternalFrame не скрывался, поскольку именно там расположены его панель захвата и кнопки управления. Итак, в качестве последнего шага перед установкой границ, убедитесь, что ваше значение y не является отрицательным: например, с помощью такого выражения, как y = Math.max (0, y).

0 голосов
/ 15 ноября 2011

Попробуйте установить FlowLayout JFrame и используйте метод add() для добавления JDesktopPane.

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