【问题标题】:Why is canImport() not called anymore after setDropTarget()?为什么在 setDropTarget() 之后不再调用 canImport()?
【发布时间】:2013-11-28 10:07:45
【问题描述】:

我正在 Java SE 7 中试验 JList 的拖放功能。问题是,一旦我为 JList 设置了 DropTarget,我的 TransferHandler 实现中的 canImport() 方法就会停止调用。这是演示该问题的简化代码:

主类:

import javax.swing.ListSelectionModel;

public class TestDragDrop extends javax.swing.JFrame {

    public TestDragDrop() {
        initComponents();
        lstTest.setDragEnabled(true);
        lstTest.setTransferHandler(new MyTransferHandler());
        // try to comment and uncomment the following line:
        lstTest.setDropTarget(new MyDropTarget());
        // - commented => canImport() is called during drag gesture
        // - uncommented => canImport() is not called during drag gesture
        lstTest.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    }

    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">                          
    private void initComponents() {

        scroll1 = new javax.swing.JScrollPane();
        lstTest = new javax.swing.JList();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        lstTest.setModel(new javax.swing.AbstractListModel() {
            String[] strings = { "Item 1", "Item 2", "Item 3", "Item 4", "Item 5" };
            public int getSize() { return strings.length; }
            public Object getElementAt(int i) { return strings[i]; }
        });
        scroll1.setViewportView(lstTest);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(scroll1, javax.swing.GroupLayout.DEFAULT_SIZE, 249, Short.MAX_VALUE)
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(scroll1, javax.swing.GroupLayout.DEFAULT_SIZE, 174, Short.MAX_VALUE)
                .addContainerGap())
        );

        pack();
    }// </editor-fold>                        

    public static void main(String args[]) {
        new TestDragDrop().setVisible(true);
    }

    // Variables declaration - do not modify                     
    private javax.swing.JList lstTest;
    private javax.swing.JScrollPane scroll1;
    // End of variables declaration                   
}

我的传输处理程序实现:

import java.awt.datatransfer.Transferable;
import javax.swing.JComponent;
import javax.swing.JList;
import javax.swing.TransferHandler;

public class MyTransferHandler extends TransferHandler {

    @Override
    public int getSourceActions(JComponent component) {
        return COPY_OR_MOVE;
    }

    @Override
    protected Transferable createTransferable(JComponent component) {
        if(component instanceof JList) {
            return new MyTransferable(new String("TestObject"));
        }
        return null;
    }

    @Override
    public boolean canImport(TransferHandler.TransferSupport support) {
        System.out.println("canImport()");
        return true;
    }

    @Override
    public boolean importData(TransferHandler.TransferSupport support) {
        System.out.println("importData()");
        return true;
    }

}

我的可转移实现:

import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.IOException;

public class MyTransferable implements Transferable {

    private final Object object;

    public MyTransferable(Object object) {
        this.object = object;
    }

    @Override
    public DataFlavor[] getTransferDataFlavors() {
        return new DataFlavor[] { DataFlavor.javaFileListFlavor };
    }

    @Override
    public boolean isDataFlavorSupported(DataFlavor flavor) {
        return flavor.equals(DataFlavor.javaFileListFlavor);
    }

    @Override
    public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
        if(!isDataFlavorSupported(flavor)) {
            throw new UnsupportedFlavorException(flavor);
        }
        return object;
    }

}

我的放置目标实现:

import java.awt.dnd.DropTarget;
import java.awt.dnd.DropTargetDropEvent;

public class MyDropTarget extends DropTarget {

    @Override
    public synchronized void drop(DropTargetDropEvent evt) {
        evt.acceptDrop(evt.getDropAction());
        if(evt.isLocalTransfer()) {
            System.out.println("local transfer");
        } else {
            System.out.println("extern transfer");
        }
        evt.dropComplete(true);
    }

}

如果主类中的 lstTest.setDropTarget(new MyDropTarget()); 行被关闭/注释,则在拖动手势期间调用 MyTransferHandler 中的 canImport() 方法正如预期的那样。但是一旦我取消注释这一行,canImport() 方法就不会在拖动过程中被调用...

有人知道为什么不再调用 canImport() 吗?

非常感谢任何帮助!非常感谢。

【问题讨论】:

    标签: java drag-and-drop


    【解决方案1】:

    setTransferHandler 安装一个新的DropTarget(如果不存在)并将其设置为使用指定的TransferHandler。之后用另一个替换这个DropTarget 将破坏这个设置。将自定义 DropTarget 与以 Swing 方式工作的 TransferHandler 组合起来相当棘手。以下将完成这项工作:

    jComponent.setTransferHandler(new MyTransferHandler());
    DropTarget original = jComponent.getDropTarget();// the Swing DropTarget
    MyDropTarget myDropTarget = new MyDropTarget();
    myDropTarget.addDropTargetListener(original);// delegate for original behavior
    jComponent.setDropTarget(myDropTarget);
    

    【讨论】:

    • 嗨,霍尔格。感谢您的回答。我尝试更改方法调用 setTransferHandler() 和 setDropTarget() 的顺序,但没有成功。子系统仍未调用函数 canImport()。还有什么建议吗?
    • 是的,我刚刚发现 setTransferHandler 如果存在自定义 DropTarget 则什么都不做。我确定了答案。
    • 太好了,现在它可以按预期工作了。非常感谢霍尔格!
    猜你喜欢
    • 2013-11-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-25
    • 2016-05-14
    • 2018-12-03
    相关资源
    最近更新 更多