2013-07-05 61 views
2

当我将ActionListeners与Drag'n'Drop组合时,会遇到意外的行为。意外操作在拖动后执行

运行下面的例子,请尝试以下操作:

  1. 拖动按钮一个的地方,并释放mousebutton
  2. 不要将鼠标移动到按钮A再次
  3. 点击按钮
  4. 在System.out上,您将看到actionPerformed将针对按钮Ab的

我不想打电话的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());

+0

是否要发生鼠标拖动事件而不是执行操作? – zari

+0

拖动事件按预期发生。先前拖动的按钮的额外操作使我困扰。 – MyPasswordIsLasercats

+0

因此,您可以将鼠标拖动事件侦听器添加到您的表单中,而不是您的按钮。 – zari

回答

3

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

不足之处在于按钮点击并非意味着拖动,而是触发拖动,因为用户稍微移动鼠标,不会导致按钮点击。另一方面,对于可拖动的按钮,用户的意图在这种情况下是相当不清楚的。

+1

谢谢!这有帮助!我不认为这是一个缺点,“返回”的拖动不触发actionPerformed。我会称之为功能:-) – MyPasswordIsLasercats