【问题标题】:Java, drag and drop to change the order of panelsJava,拖放改变面板的顺序
【发布时间】:2014-12-02 08:51:01
【问题描述】:

好的,我的设置如下。我有一个使用 javax.swing 作为 ui 的 java 1.7 项目。这是我在以下教程之外的第一个项目,对于那些熟悉桌面的人来说,它是一个主动跟踪器。我有一个扩展 JPanel(并实现 Comparable)的类,因此我可以动态添加它并为每个类记录不同的数据。

面板被添加到布局中,其 y 位置取决于已有面板的数量。它们也被添加到 ArrayList 以按顺序对其进行排序。 该列表可以按类的属性之一进行排序。

我现在遇到的是,我希望能够手动拖放它们以更改布局和 ArrayList 中的顺序。加上一个注释,我不能只删除并重新添加一个,因为我会丢失保存在类中的值。

为此,我制作了一个需要执行以下操作的 JButton:

  • 只要在按钮上按下鼠标,就需要用鼠标拖动它所属的面板。
  • 释放鼠标后,它需要检查其位置,并在必要时前往该位置。

So for example

我尝试了一些拖放教程,但似乎找不到可以调整为我想要的内容。

Edit1:这是我尝试过的。

MouseListener listener = new DragMouseAdapter();
dragButton.addMouseListener(listener);
dragButton.setTransferHandler(new TransferHandler("text"));

然后

class DragMouseAdapter extends MouseAdapter {
    public void mousePressed(MouseEvent e) {
        JComponent c = (JComponent) e.getSource();
        TransferHandler handler = c.getTransferHandler();
        handler.exportAsDrag(c, e, TransferHandler.COPY);
        // TODO make it a swap location drag and drop
    }
}

这是来自一个教程,它成功地改变了文本,但这根本不是我想要的,我不知道如何改变它来做我想要的。

Edit2: This tutorial 描述了我想要做什么,但它不起作用。它给出了以下错误:

    Step 1 of 7: Mouse pressed. Going to export our RandomDragAndDropPanel so that it is draggable.
Step 2 of 7: Returning the acceptable TransferHandler action. Our RandomDragAndDropPanel accepts Copy only.
Step 3 of 7: Casting the RandomDragAndDropPanel as Transferable. The Transferable RandomDragAndDropPanel will be queried for acceptable DataFlavors as it enters drop targets, as well as eventually present the target with the Object it transfers.
Step 4 of 7: Querying for acceptable DataFlavors to determine what is available. Our example only supports our custom RandomDragAndDropPanel DataFlavor.
Problem lazy loading: RandomDragAndDropPanel
java.lang.ClassNotFoundException: RandomDragAndDropPanel
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Unknown Source)
    at java.awt.datatransfer.DataFlavor.tryToLoadClass(Unknown Source)
    at java.awt.datatransfer.DataFlavor.initialize(Unknown Source)
    at java.awt.datatransfer.DataFlavor.<init>(Unknown Source)
    at DnD.DragAndDropPanelsDemo.getDragAndDropPanelDataFlavor(DragAndDropPanelsDemo.java:197)
    at DnD.RandomDragAndDropPanel.getTransferDataFlavors(DragAndDropPanelsDemo.java:392)
    at sun.awt.datatransfer.DataTransferer.getFormatsForTransferable(Unknown Source)
    at sun.awt.dnd.SunDragSourceContextPeer.startDrag(Unknown Source)
    at java.awt.dnd.DragSource.startDrag(Unknown Source)
    at java.awt.dnd.DragSource.startDrag(Unknown Source)
    at java.awt.dnd.DragGestureEvent.startDrag(Unknown Source)
    at javax.swing.TransferHandler$DragHandler.dragGestureRecognized(Unknown Source)
    at java.awt.dnd.DragGestureRecognizer.fireDragGestureRecognized(Unknown Source)
    at javax.swing.TransferHandler$SwingDragGestureRecognizer.gestured(Unknown Source)
    at javax.swing.TransferHandler.exportAsDrag(Unknown Source)
    at DnD.DraggableMouseListener.mousePressed(DragAndDropPanelsDemo.java:456)
    at java.awt.Component.processMouseEvent(Unknown Source)
    at javax.swing.JComponent.processMouseEvent(Unknown Source)
    at java.awt.Component.processEvent(Unknown Source)
    at java.awt.Container.processEvent(Unknown Source)
    at java.awt.Component.dispatchEventImpl(Unknown Source)
    at java.awt.Container.dispatchEventImpl(Unknown Source)
    at java.awt.Component.dispatchEvent(Unknown Source)
    at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
    at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
    at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
    at java.awt.Container.dispatchEventImpl(Unknown Source)
    at java.awt.Window.dispatchEventImpl(Unknown Source)
    at java.awt.Component.dispatchEvent(Unknown Source)
    at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
    at java.awt.EventQueue.access$200(Unknown Source)
    at java.awt.EventQueue$3.run(Unknown Source)
    at java.awt.EventQueue$3.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
    at java.awt.EventQueue$4.run(Unknown Source)
    at java.awt.EventQueue$4.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
    at java.awt.EventQueue.dispatchEvent(Unknown Source)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
    at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.run(Unknown Source)

【问题讨论】:

  • 拜托,您能否发布您的尝试,以便我们帮助您找出问题所在?
  • 我会编辑它,但问题主要不是我的代码不起作用,而是我不知道代码应该是什么。

标签: java swing drag-and-drop


【解决方案1】:

这里是一个拖放改变面板顺序的例子(不支持排序)。

  1. DragMouseAdapter#mouseDragged(...):搜索拖拽面板,移除表单父面板并打开光标窗口。
  2. DragMouseAdapter#mouseReleased(...):搜索放置位置,插入拖拽面板,关闭光标窗口。
import java.awt.*;
import java.awt.dnd.*;
import java.awt.event.*;
import java.net.*;
import java.util.*;
import javax.swing.*;

public class RearrangeOrderOfPanelsTest2 {
  public JComponent makeUI() {
    Box box = Box.createVerticalBox();
    DragMouseAdapter dh = new DragMouseAdapter();
    box.addMouseListener(dh);
    box.addMouseMotionListener(dh);

    int idx = 0;
    for (JComponent c : Arrays.asList(
           new JLabel("<html>111<br>11<br>11"),
           new JButton("2"), new JCheckBox("3"), new JTextField(14))) {
      box.add(createToolbarButton(idx++, c));
    }
    JPanel p = new JPanel(new BorderLayout());
    p.add(box, BorderLayout.NORTH);
    return p;
  }

  private static JComponent createToolbarButton(int i, JComponent c) {
    JLabel l = new JLabel(String.format(" %04d ", i));
    l.setOpaque(true);
    l.setBackground(Color.RED);
    JPanel p = new JPanel(new BorderLayout());
    p.setBorder(BorderFactory.createCompoundBorder(
                  BorderFactory.createEmptyBorder(5, 5, 5, 5),
                  BorderFactory.createLineBorder(Color.BLUE, 2)));
    p.add(l, BorderLayout.WEST);
    p.add(c);
    p.setOpaque(false);
    return p;
  }

  public static void main(String... args) {
    EventQueue.invokeLater(new Runnable() {
      @Override public void run() {
        createAndShowGUI();
      }
    });
  }

  public static void createAndShowGUI() {
    JFrame f = new JFrame();
    f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    f.getContentPane().add(new RearrangeOrderOfPanelsTest2().makeUI());
    f.setSize(320, 240);
    f.setLocationRelativeTo(null);
    f.setVisible(true);
  }
}

class DragMouseAdapter extends MouseAdapter {
  private static final int xoffset = 16;
  private static final Rectangle R1 = new Rectangle();
  private static final Rectangle R2 = new Rectangle();
  private static Rectangle prevRect;
  private final JWindow window = new JWindow();
  private Component draggingComonent;
  private int index = -1;
  private Component gap;
  private Point startPt;
  private Point dragOffset;
  private final int gestureMotionThreshold = DragSource.getDragThreshold();

  public DragMouseAdapter() {
    super();
    window.setBackground(new Color(0, true));
  }

  @Override public void mousePressed(MouseEvent e) {
    JComponent parent = (JComponent) e.getComponent();
    if (parent.getComponentCount() <= 1) {
      startPt = null;
      return;
    }
    startPt = e.getPoint();
  }

  private void startDragging(JComponent parent, Point pt) {
    //get a dragging panel
    Component c = parent.getComponentAt(pt);
    index = parent.getComponentZOrder(c);
    if (Objects.equals(c, parent) || index < 0) {
      return;
    }
    draggingComonent = c;
    Dimension d = draggingComonent.getSize();

    Point dp = draggingComonent.getLocation();
    dragOffset = new Point(pt.x - dp.x, pt.y - dp.y);

    //make a dummy filler
    gap = Box.createRigidArea(d);
    swapComponentLocation(parent, c, gap, index);

    //make a cursor window
    window.add(draggingComonent);
    window.pack();

    updateWindowLocation(pt, parent);
    window.setVisible(true);
  }

  private void updateWindowLocation(Point pt, JComponent parent) {
    Point p = new Point(pt.x - dragOffset.x, pt.y - dragOffset.y);
    SwingUtilities.convertPointToScreen(p, parent);
    window.setLocation(p);
  }

  private static 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 = R1;
      return i - 1 > 0 ? i : 0;
    } else if (R2.contains(pt)) {
      prevRect = 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();

    //MotionThreshold
    double a = Math.pow(pt.x - startPt.x, 2);
    double b = Math.pow(pt.y - startPt.y, 2);
    if (draggingComonent == null &&
        Math.sqrt(a + b) > gestureMotionThreshold) {
      startDragging(parent, pt);
      return;
    }
    if (!window.isVisible() || draggingComonent == null) {
      return;
    }

    //update the cursor window location
    updateWindowLocation(pt, parent);
    if (prevRect != null && 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) {
        swapComponentLocation(parent, gap, gap, tgt);
        return;
      }
    }
    parent.remove(gap);
    parent.revalidate();
  }

  @Override public void mouseReleased(MouseEvent e) {
    startPt = null;
    if (!window.isVisible() || draggingComonent == null) {
      return;
    }
    Point pt = e.getPoint();
    JComponent parent = (JComponent) e.getComponent();

    //close the cursor window
    Component cmp = draggingComonent;
    draggingComonent = null;
    prevRect = null;
    startPt = null;
    dragOffset = null;
    window.setVisible(false);

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

【讨论】:

  • 这确实是我想要的,它不支持排序没什么大不了的,我以后可能会在自己身上添加它。但问题是我不明白代码的哪一部分做了什么,它几乎没有解释什么做什么或为什么使用某些东西。你能详细说明一下吗?
  • 在源码中添加一些cmets来解释DragMouseAdapter
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-17
  • 1970-01-01
  • 1970-01-01
  • 2019-02-06
  • 2013-03-27
相关资源
最近更新 更多