JPanelの並び順をドラッグ&ドロップで入れ替える
Total: 6774
, Today: 1
, Yesterday: 2
Posted by aterai at
Last-modified:
概要
JPanel
に配置した子コンポーネントの並び順を、マウスのドラッグ&ドロップによる入れ替えで変更します。
Screenshot
Advertisement
サンプルコード
class RearrangingHandler extends MouseAdapter {
private static final Rectangle R1 = new Rectangle();
private static final Rectangle R2 = new Rectangle();
private final Rectangle prevRect = new Rectangle();
private final int gestureMotionThreshold = DragSource.getDragThreshold();
private final JWindow window = new JWindow();
private final Point startPt = new Point();
private int index = -1;
private Component draggingComponent;
private Component gap;
private final Point dragOffset = new Point();
public RearrangingHandler() {
super();
window.setBackground(new Color(0x0, true));
}
@Override public void mousePressed(MouseEvent e) {
if (((JComponent) e.getComponent()).getComponentCount() <= 1) {
startPt.setLocation(0, 0);
} else {
startPt.setLocation(e.getPoint());
}
}
private void startDragging(JComponent parent, Point pt) {
Component c = parent.getComponentAt(pt);
index = parent.getComponentZOrder(c);
if (Objects.equals(c, parent) || index < 0) {
return;
}
draggingComponent = c;
Dimension d = draggingComponent.getSize();
Point dp = draggingComponent.getLocation();
dragOffset.setLocation(pt.x - dp.x, pt.y - dp.y);
gap = Box.createRigidArea(d);
swapComponentLocation(parent, c, gap, index);
window.add(draggingComponent);
// window.setSize(d);
window.pack();
updateWindowLocation(pt, parent);
window.setVisible(true);
}
private void updateWindowLocation(Point pt, JComponent parent) {
if (window.isVisible() && Objects.nonNull(draggingComponent)) {
Point p = new Point(pt.x - dragOffset.x, pt.y - dragOffset.y);
SwingUtilities.convertPointToScreen(p, parent);
window.setLocation(p);
}
}
private int getTargetIndex(Rectangle r, Point pt, int i) {
int ht2 = (int) (.5 + r.height * .5);
R1.setBounds(r.x, r.y, r.width, ht2);
R2.setBounds(r.x, r.y + ht2, r.width, ht2);
if (R1.contains(pt)) {
prevRect.setBounds(R1);
return i - 1 > 0 ? i : 0;
} else if (R2.contains(pt)) {
prevRect.setBounds(R2);
return i;
}
return -1;
}
private static void swapComponentLocation(
Container parent, Component remove, Component add, int idx) {
parent.remove(remove);
parent.add(add, idx);
parent.revalidate();
parent.repaint();
}
@Override public void mouseDragged(MouseEvent e) {
Point pt = e.getPoint();
JComponent parent = (JComponent) e.getComponent();
if (Objects.isNull(draggingComponent)) {
if (startPt.distance(pt) > gestureMotionThreshold) {
startDragging(parent, pt);
}
return;
}
updateWindowLocation(pt, parent);
if (prevRect.contains(pt)) {
return;
}
for (int i = 0; i < parent.getComponentCount(); i++) {
Component c = parent.getComponent(i);
Rectangle r = c.getBounds();
if (Objects.equals(c, gap) && r.contains(pt)) {
return;
}
int tgt = getTargetIndex(r, pt, i);
if (tgt >= 0) {
swapComponentLocation(parent, gap, gap, tgt);
return;
}
}
// System.out.println("outer");
parent.remove(gap);
parent.revalidate();
}
@Override public void mouseReleased(MouseEvent e) {
startPt.setLocation(0, 0);
dragOffset.setLocation(0, 0);
prevRect.setBounds(0, 0, 0, 0);
window.setVisible(false);
Point pt = e.getPoint();
JComponent parent = (JComponent) e.getComponent();
Component cmp = draggingComponent;
draggingComponent = null;
for (int i = 0; i < parent.getComponentCount(); i++) {
Component c = parent.getComponent(i);
if (Objects.equals(c, gap)) {
swapComponentLocation(parent, gap, cmp, i);
return;
}
int tgt = getTargetIndex(c.getBounds(), pt, i);
if (tgt >= 0) {
swapComponentLocation(parent, gap, cmp, tgt);
return;
}
}
if (parent.getParent().getBounds().contains(pt)) {
swapComponentLocation(parent, gap, cmp, parent.getComponentCount());
} else {
swapComponentLocation(parent, gap, cmp, index);
}
}
}
View in GitHub: Java, Kotlin解説
上記のサンプルでは、親のJPanel
にMouseListener
とMouseMotionListener
を継承するハンドラを追加し、子のJPanel
をマウスドラッグで任意の位置に差し替えることが出来ます。移動中の子JPanel
は、ドラッグ・イメージとして別JWindow
でカーソル位置に表示されます。
- 使用しているハンドラは、以下の
2
点を除いてJToolBarに配置したアイコンをドラッグして並べ替えるで使用しているものとほぼ同一- 水平ではなく垂直方向に入れ替えを行うように変更
- サイズ(高さ)の異なるパネルの入れ替えに対応
参考リンク
- JToolBarに配置したアイコンをドラッグして並べ替える
- swing - Java, drag and drop to change the order of panels - Stack Overflow
- JLayerを使用してコンポーネントの並べ替えを行う
JTable
の列入れ替え風に親パネルの範囲内のみ子コンポーネントをドラッグ可能にして入れ替えるサンプル