Предотвращение перемещения JInternalFrame из JDesktopPane
когда у меня есть 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 ответов
сотрудник, который отвечает за перемещение/изменение размера, является 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, что может быть сделано путем реализации wrapper 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;
это относительно текущего положения мыши, хотя.
полный кредит Клеопатре за то, что указал мне в правильном направлении.
Я думаю, что я решил проблему невосприимчивости и делюсь своим решением здесь. После ответа Клеопатры, если точка мыши находится за пределами панели, внутренняя рамка находится на краю панели. Кроме того, это продолжает следовать за мышью - т. е. если вы переместите мышь с нижней части панели, а затем вокруг в правую сторону панели, рамка будет следовать вдоль нижней части панели, и затем вверх по правому песку.
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;
}
}
попробуйте установить FlowLayout
JFrame и использовать add()
метод добавления JDesktopPane.
frame.setLayout(new FlowLayout());
tableDisplay.setPreferredSize(new Dimension(100,100));
frame.add(tableDisplay);
важно, чтобы верхняя часть JInternalFrame не была скрыта, так как именно там расположены кнопки захвата и управления. Итак, в качестве последнего шага перед установкой границ убедитесь, что ваше значение y не является отрицательным: например, с помощью оператора y = Math.max(0, y).