2

ActionListeners と Drag'n'Drop を組み合わせると、予期しない動作が発生します。

以下の例を実行して、次のことを試してください。

  1. ボタンAをどこかにドラッグし、マウスボタンを放します
  2. 二度とマウスをボタン A の上に移動しないでください
  3. ボタンBをクリック
  4. System.out では、actionPerformed がボタンABの両方に対して呼び出されることがわかります。

ボタン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());

4

1 に答える 1

3

問題は、ボタン クリックのマウス リリース処理とドラッグ処理の間の競合です。を呼び出すことで回避できgetModel().setArmed(false)ますdragGestureRecognized()。これは、次に押されたプロパティが false に設定されたときにアクションを起動しないようにボタンに指示します。

欠点は、ドラッグを意味するものではなく、ユーザーがマウスを少し動かしたためにドラッグをトリガーするボタン クリックがボタン クリックにならないことです。一方、ドラッグ可能なボタンの場合、とにかくそのような状況ではユーザーの意図がかなり不明確です。

于 2013-07-05T09:54:27.480 に答える