Swing/ReorderingLayer のバックアップ(No.4)
- バックアップ一覧
- 差分 を表示
- 現在との差分 を表示
- 現在との差分 - Visual を表示
- ソース を表示
- Swing/ReorderingLayer へ行く。
- 1 (2015-05-28 (木) 17:37:42)
- 2 (2015-12-17 (木) 14:37:49)
- 3 (2016-05-16 (月) 11:46:47)
- 4 (2016-05-25 (水) 12:58:51)
- 5 (2016-11-18 (金) 14:50:51)
- 6 (2017-11-24 (金) 14:48:57)
- 7 (2019-07-20 (土) 16:50:42)
- 8 (2019-09-17 (火) 19:16:51)
- 9 (2019-12-17 (火) 02:35:20)
- 10 (2021-06-15 (火) 11:48:31)
- 11 (2024-02-16 (金) 08:26:03)
- title: JLayerを使用してコンポーネントの並べ替えを行う tags: [JLayer, DragAndDrop, BoxLayout] author: aterai pubdate: 2015-04-06T00:00:32+09:00 description: JPanel内に配置したコンポーネントの並べ替えで、ドラッグ中のコンポーネントをJLayerで描画します。
概要
JPanel
内に配置したコンポーネントの並べ替えで、ドラッグ中のコンポーネントをJLayer
で描画します。
Screenshot
Advertisement
サンプルコード
class ReorderingLayerUI extends LayerUI<JComponent> {
private static final Rectangle R1 = new Rectangle();
private static final Rectangle R2 = new Rectangle();
private static final Rectangle R3 = new Rectangle();
private final Rectangle prevRect = new Rectangle();
private final Rectangle draggingRect = new Rectangle();
private final Point startPt = new Point(-100, -100);
private final Point dragOffset = new Point();
private final JComponent rubberStamp = new JPanel();
private final int gestureMotionThreshold = DragSource.getDragThreshold();
private Component draggingComonent;
private Component gap;
private int index = -1;
@Override public void paint(Graphics g, JComponent c) {
super.paint(g, c);
if (c instanceof JLayer && Objects.nonNull(draggingComonent)) {
SwingUtilities.paintComponent(g, draggingComonent, rubberStamp, draggingRect);
}
}
@Override public void installUI(JComponent c) {
super.installUI(c);
if (c instanceof JLayer) {
((JLayer) c).setLayerEventMask(
AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK);
}
}
@Override public void uninstallUI(JComponent c) {
if (c instanceof JLayer) {
((JLayer) c).setLayerEventMask(0);
}
super.uninstallUI(c);
}
@Override protected void processMouseEvent(
MouseEvent e, JLayer<? extends JComponent> l) {
JComponent parent = l.getView();
switch (e.getID()) {
case MouseEvent.MOUSE_PRESSED:
if (parent.getComponentCount() <= 1) {
return;
}
startPt.setLocation(e.getPoint());
l.repaint();
break;
case MouseEvent.MOUSE_RELEASED:
if (Objects.isNull(draggingComonent)) {
return;
}
Point pt = e.getPoint();
Component cmp = draggingComonent;
draggingComonent = null;
//swap the dragging panel and the dummy filler
for (int i = 0; i < parent.getComponentCount(); i++) {
Component c = parent.getComponent(i);
if (Objects.equals(c, gap)) {
replaceComponent(parent, gap, cmp, i);
return;
}
int tgt = getTargetIndex(c.getBounds(), pt, i);
if (tgt >= 0) {
replaceComponent(parent, gap, cmp, tgt);
return;
}
}
if (parent.getParent().getBounds().contains(pt)) {
replaceComponent(parent, gap, cmp, parent.getComponentCount());
} else {
replaceComponent(parent, gap, cmp, index);
}
l.repaint();
break;
default:
break;
}
}
@Override protected void processMouseMotionEvent(
MouseEvent e, JLayer<? extends JComponent> l) {
if (e.getID() == MouseEvent.MOUSE_DRAGGED) {
Point pt = e.getPoint();
JComponent parent = l.getView();
if (Objects.isNull(draggingComonent)) {
//MotionThreshold
if (startPt.distance(pt) > gestureMotionThreshold) {
startDragging(parent, pt);
}
return;
}
//update the cursor window location
updateWindowLocation(pt, parent);
l.repaint();
if (prevRect.contains(pt)) {
return;
}
//change the dummy filler location
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) {
replaceComponent(parent, gap, gap, tgt);
return;
}
}
parent.revalidate();
l.repaint();
}
}
private void startDragging(JComponent parent, Point pt) {
Component c = parent.getComponentAt(pt);
index = parent.getComponentZOrder(c);
if (Objects.equals(c, parent) || index < 0) {
return;
}
draggingComonent = c;
Rectangle r = draggingComonent.getBounds();
draggingRect.setBounds(r); //save draggingComonent size
dragOffset.setLocation(pt.x - r.x, pt.y - r.y);
gap = Box.createRigidArea(r.getSize());
replaceComponent(parent, c, gap, index);
updateWindowLocation(pt, parent);
}
private void updateWindowLocation(Point pt, JComponent parent) {
Insets i = parent.getInsets();
Rectangle r = SwingUtilities.calculateInnerArea(parent, R3);
int x = r.x;
int y = pt.y - dragOffset.y;
int h = draggingRect.height;
int yy = y < i.top ? i.top : r.contains(x, y + h) ? y : r.height + i.top - h;
draggingRect.setLocation(x, yy);
}
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 replaceComponent(
Container parent, Component remove, Component insert, int idx) {
parent.remove(remove);
parent.add(insert, idx);
parent.revalidate();
parent.repaint();
}
}
View in GitHub: Java, Kotlin解説
並べ替えの処理などは、JPanelの並び順をドラッグ&ドロップで入れ替えると同じものを使用していますが、こちらはドラッグ中のコンポーネントの描画を親のJPanel内でのみに制限しているので、JWindow
ではなくJLayer
を使用しています。
- ドラッグ中のコンポーネントの位置・サイズ
- 位置: 親の
JPanel
から内部余白を除いた部分をドラッグ可能な領域(SwingUtilities.calculateInnerArea(...)
で取得)に設定し、その範囲内に位置を制限 - サイズ:
LayerUI#paint(...)
内でのドラッグ中のコンポーネントの描画には、SwingUtilities.paintComponent(...)
を使用しているが、この時ドラッグ中のコンポーネントは親のJPanel
の子ではなくなっているため、getSize()
で大きさを取得できない- そのため、ドラッグ開始前にそのサイズを別途記憶しておく必要がある
- 位置: 親の