2013-07-05 59 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