Java JTextArea-设置TransferHandler后维护剪贴板功能

Java JTextArea-设置TransferHandler后维护剪贴板功能,java,swing,drag-and-drop,jtextarea,Java,Swing,Drag And Drop,Jtextarea,下面的示例创建了一个JTextArea,我可以在它上面放置一个对象并执行一些操作。那很好。我的问题是,在使用textArea.setTransferHandler(myTransferHandler)设置TransferHandler后,默认情况下可用的剪贴板操作(剪切、复制和粘贴文本)不再有效 有没有办法在我的JTextArea上设置一个自定义TransferHandler来启用拖动对象,但不干扰JTextArea的默认剪贴板功能?如果没有,修改TransferHandler以允许常规剪贴板操

下面的示例创建了一个JTextArea,我可以在它上面放置一个对象并执行一些操作。那很好。我的问题是,在使用textArea.setTransferHandler(myTransferHandler)设置TransferHandler后,默认情况下可用的剪贴板操作(剪切、复制和粘贴文本)不再有效

有没有办法在我的JTextArea上设置一个自定义TransferHandler来启用拖动对象,但不干扰JTextArea的默认剪贴板功能?如果没有,修改TransferHandler以允许常规剪贴板操作继续正常运行的最简单方法是什么

更新:这里有一个例子说明了这个问题。我可以从树拖放到文本区域,但是文本区域的剪贴板功能被破坏

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

import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTree;
import javax.swing.TransferHandler;
import javax.swing.text.JTextComponent;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeSelectionModel;

public class DnDTest
{
    public DnDTest()
    {
        DefaultMutableTreeNode root = new DefaultMutableTreeNode(new NodeObject("root"));
        root.add(new DefaultMutableTreeNode(new NodeObject("child1")));
        root.add(new DefaultMutableTreeNode(new NodeObject("child2")));

        JTree tree = new JTree(new DefaultTreeModel(root));
        tree.setDragEnabled(true);
        tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);

        JTextArea textArea = new JTextArea();
        textArea.setDragEnabled(true);
        textArea.setLineWrap(true);
        textArea.setWrapStyleWord(true);

        NodeObjectTransferHandler transferHandler = new NodeObjectTransferHandler();
        tree.setTransferHandler(transferHandler);
        textArea.setTransferHandler(transferHandler);

        JFrame f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setLayout(new GridLayout(1,0));
        f.add(new JScrollPane(tree));
        f.add(new JScrollPane(textArea));
        f.setSize(500,400);
        f.setLocation(200,200);
        f.setVisible(true);
    }

    public static void main(String[] args)
    {
        new DnDTest();
    }
}

class NodeObject {
    public String str;

    public NodeObject(String str) { this.str = str; }
    @Override
    public String toString() { return str; }
}

class NodeObjectTransferHandler extends TransferHandler {
    private static final long serialVersionUID = 1L;

    private static final DataFlavor nodeObjectFlavor = new DataFlavor(NodeObject.class, "NodeObject");

    @Override
    public boolean importData(JComponent c, Transferable t)
    {
        if (!canImport(c, t.getTransferDataFlavors())) {
            return false;
        }

        if (!(c instanceof JTextComponent)) {
            return false;
        }

        try {
            NodeObject nodeObject = (NodeObject) t.getTransferData(nodeObjectFlavor);
            ((JTextComponent) c).setText(nodeObject.str);
            return true;
        } catch (UnsupportedFlavorException e) {
        } catch (IOException e) {
        }

        return false;
    }

    @Override
    public Transferable createTransferable(JComponent c)
    {
        if (!(c instanceof JTree)) {
            return null;
        }

        JTree tree = (JTree) c;
        DefaultMutableTreeNode lastPathComponent = (DefaultMutableTreeNode) tree.getSelectionPath().getLastPathComponent();
        return new NodeObjectTransferable((NodeObject) lastPathComponent.getUserObject());
    }

    @Override
    public int getSourceActions(JComponent c)
    {
        return COPY;
    }

    @Override
    public boolean canImport(JComponent c, DataFlavor[] flavors)
    {
        for (DataFlavor flavor : flavors) {
            if (flavor.match(nodeObjectFlavor)) {
                return true;
            }
        }
        return false;
    }
}

class NodeObjectTransferable implements Transferable {
    private static final DataFlavor nodeObjectFlavor = new DataFlavor(NodeObject.class, "NodeObject");
    private NodeObject nodeObject;

    public NodeObjectTransferable(NodeObject nodeObject) {
        this.nodeObject = nodeObject;
    }

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

        return nodeObject;
    }

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

    @Override
    public boolean isDataFlavorSupported(DataFlavor flavor)
    {
        return flavor.match(nodeObjectFlavor);
    }
};

不确定这是否适合您的场景。您可以将textArea注册为DropTarget,而不是textArea.setTransferHandler()。然后在DropTargetListener.drop()方法中处理所有导入逻辑。这样就不会干扰JTextArea使用的TextTransferHandler。谢谢Max。我不知道这个功能。这听起来似乎对我所做的更有意义。要更快地获得更好的帮助,请发布一条。@Max-hmm。。。好奇:有竞争性的dnd处理程序是如何工作的?因为dnd机制是天生的单子,会有很多麻烦吗?所以我要做的(实际上是)是实现一个委托transferHandler。不幸的是,TransferHandler(createTransferable受保护)的一个设计缺陷阻碍了这一点,该缺陷要求core对相应代码进行一些c&p…@kleopatra,我实际上是想将textArea的容器作为DropTarget,我在描述中犯了错误。不确定这是否适合您的场景。您可以将textArea注册为DropTarget,而不是textArea.setTransferHandler()。然后在DropTargetListener.drop()方法中处理所有导入逻辑。这样就不会干扰JTextArea使用的TextTransferHandler。谢谢Max。我不知道这个功能。这听起来似乎对我所做的更有意义。要更快地获得更好的帮助,请发布一条。@Max-hmm。。。好奇:有竞争性的dnd处理程序是如何工作的?因为dnd机制是天生的单子,会有很多麻烦吗?所以我要做的(实际上是)是实现一个委托transferHandler。不幸的是,TransferHandler(createTransferable受保护)的一个设计缺陷阻碍了这一过程,该缺陷要求core对相应的代码进行一些c&p…@kleopatra,我实际上是想将textArea的容器作为DropTarget,这是我描述中的错误。