拖动后执行意外操作

时间:2013-07-05 08:54:34

标签: java swing drag-and-drop actionlistener

当我将ActionListeners与Drag'n'Drop结合使用时,我会遇到意外行为。

运行以下示例并尝试以下操作:

  1. 在某处拖动按钮 A 并释放鼠标按钮
  2. 不要再将鼠标移到按钮A上
  3. 点击按钮 B
  4. 在System.out上,您将看到将为 A B
  5. 这两个按钮调用actionPerformed

    我不想为按钮 A 调用actionPerformed。我究竟做错了什么?

    以下是完整示例:

    import java.awt.*;
    import java.awt.datatransfer.*;
    import java.awt.dnd.*;
    import java.awt.event.*;
    import java.io.IOException;
    import javax.swing.*;
    
    public class DragDropTest{
    
    private static Color slightlyRed = new Color(255, 220, 220);
    private static Color slightlyGreen = new Color(220, 255, 220);
    
    private static class DragDropButton extends JButton implements DragSourceListener, DragGestureListener, Transferable, ActionListener{
        private DragSource dragSource;
    
        public DragDropButton(String string) {
            super(string);
            addActionListener(this);
            dragSource = new DragSource();
            dragSource.createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_COPY, this);
        }
    
        // Interface DragSourceListener
        @Override public void dragEnter(DragSourceDragEvent dsde) {}
        @Override public void dragOver(DragSourceDragEvent dsde) {}
        @Override public void dropActionChanged(DragSourceDragEvent dsde) {}
        @Override public void dragExit(DragSourceEvent dse) {}
        @Override public void dragDropEnd(DragSourceDropEvent dsde) {
            System.out.println("Dragging of [" + getText() + "] ended");
        }
        // Interface DragGestureListener
        @Override public void dragGestureRecognized(DragGestureEvent dge) {
            dragSource.startDrag(dge, DragSource.DefaultMoveDrop, this, this);
        }
        // Interface Transferable
        @Override public DataFlavor[] getTransferDataFlavors() {return null;}
        @Override public boolean isDataFlavorSupported(DataFlavor flavor) {return false;}
        @Override public Object getTransferData(DataFlavor flavor)
                throws UnsupportedFlavorException, IOException {return null;}
        // Interface ActionListener
        @Override public void actionPerformed(ActionEvent e) {
            System.out.println("Action on [" + getText() + "]");
        }
    }
    
    private static class DropPanel extends JPanel implements DropTargetListener{
    
        public DropPanel(){
            setBorder(BorderFactory.createLineBorder(Color.BLACK));
            setPreferredSize(new Dimension(300, 300));
            setBackground(slightlyGreen);
    
            new DropTarget(this, this);
        }
    
        @Override public void dragEnter(DropTargetDragEvent dtde) {}
        @Override public void dragOver(DropTargetDragEvent dtde) {}
        @Override public void dropActionChanged(DropTargetDragEvent dtde) {}
        @Override public void dragExit(DropTargetEvent dte) {}
        @Override public void drop(DropTargetDropEvent dtde) {
            System.out.println("Drop complete");
            dtde.dropComplete(true);
        }
    
    }
    
    
    
    // Create Panels
    
    private static JPanel leftSide(){
        JPanel leftPanel = new JPanel();
        leftPanel.setPreferredSize(new Dimension(300, 300));
        leftPanel.setBackground(slightlyRed);
        leftPanel.add(new DragDropButton("A"));
        leftPanel.add(new DragDropButton("B"));
        return leftPanel;
    }
    private static JPanel rightSide(){
        JPanel leftPanel = new DropPanel();
        return leftPanel;
    }
    
    // Create Window
    
    private static JFrame boringFrame(String text){
    
        JFrame boringFrame = new JFrame(text);
        boringFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        boringFrame.getContentPane().setLayout(new FlowLayout(FlowLayout.CENTER));
    
        boringFrame.setVisible(true);
        return boringFrame;
    }
    
    public static void main(String[] args){
    
        JFrame boringFrame = boringFrame("boring");
    
        boringFrame.add(leftSide());
        boringFrame.add(rightSide());   // try to comment out this line!
        boringFrame.pack();
    
    
    }
    
    }
    

    我的项目还有一些问题,但我不会打扰你,因为这似乎是我问题的主要来源,但这是我做的另一个观察:

    如果没有DropTargetListener(例如我的 DropPanel ),问题就会消失。请尝试注释掉以下行:

    boringFrame.add(rightSide());

1 个答案:

答案 0 :(得分:3)

问题是按钮单击和拖动处理的鼠标释放处理之间的冲突。您可以致电getModel().setArmed(false)中的dragGestureRecognized()来解决此问题。这告诉按钮下次将被按下的属性设置为false时不会触发该动作。

缺点是按钮点击不是拖动,而是触发拖动,因为用户稍微移动鼠标,不会导致按钮点击。另一方面,对于可拖动按钮,无论如何,用户的意图在这种情况下还不太清楚。