使用自己的对象从 JTree 拖放到 JList
Drag and Drop from JTree to JList with own objects
我有一个 JTree 和 DefaultMutableTreeNodes。在某些层面上,这些节点是用 我自己的可序列化对象 初始化的。总共有两种不同类型的对象(称为“Step”和“Order”)。我希望能够仅删除使用这两个对象中的任何一个初始化的节点。任何其他只是字符串的节点都不应该是可删除的。一个“Order”可以包含多个“Steps”。如果它们被插入 JList,我希望能够将它们拖到 JPanel 上。如果删除了“Order”,则应该插入所有“Steps”,如果只有“Step" 只删除了应该插入的特定 "Step"。
SSCCE以下!
JTree:
tree = new JTree();
tree.setShowsRootHandles(true);
tree.setRootVisible(false);
tree.setDragEnabled(true);
tree.setModel(treeModel);
tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
J面板:
public class TablePanel extends JPanel
{
private static final long serialVersionUID = 3216206960422611905L;
public TablePanel()
{
super();
setLayout(new MigLayout("", "[grow]", "[][grow]"));
JProgressBar progressBar = new JProgressBar();
progressBar.setMaximum(28800); // 8 hours in seconds
progressBar.setStringPainted(true);
add(progressBar, "cell 0 0,growx");
DefaultListModel<Step> listModel = new DefaultListModel<Step>();
JList<Step> list = new JList<Step>();
list.setModel(listModel);
setDropTarget(new DropTarget(this, TransferHandler.COPY, new DropTargetAdapter()
{
private int index = 0;
private int amount = 0;
@Override
public void drop(DropTargetDropEvent dtde)
{
amount = 0;
index = 0;
}
@Override
public void dragExit(DropTargetEvent dte)
{
if (listModel.size() > 0)
{
if (amount == 1)
{
listModel.remove(index);
}
else
{
for (int i = 0; i < amount; i++)
{
listModel.remove(index + i);
}
}
amount = 0;
}
}
@Override
public void dragEnter(DropTargetDragEvent dtde)
{
try
{
Transferable tr = dtde.getTransferable();
if (dtde.isDataFlavorSupported(Order.auftragFlavor))
{
Order a = (Order) tr.getTransferData(Order.auftragFlavor); // Wrong, how do I get this?
dtde.acceptDrag(DnDConstants.ACTION_COPY);
amount = a.getSteps().size();
}
else if (dtde.isDataFlavorSupported(Step.arbeitsgangFlavor))
{
Step ag = (Step) tr.getTransferData(Step.arbeitsgangFlavor);
dtde.acceptDrag(DnDConstants.ACTION_COPY);
amount = 1;
}
else
{
dtde.rejectDrag();
}
}
catch (Exception e)
{
e.printStackTrace();
dtde.rejectDrag();
}
}
@Override
public void dragOver(DropTargetDragEvent dtde)
{
try
{
Transferable tr = dtde.getTransferable();
if (dtde.isDataFlavorSupported(Order.auftragFlavor))
{
Order a = (Order) tr.getTransferData(Order.auftragFlavor); // Wrong, how do I get this?
dtde.acceptDrag(DnDConstants.ACTION_COPY);
amount = a.getSteps().size();
}
else if (dtde.isDataFlavorSupported(Step.arbeitsgangFlavor))
{
Step ag = (Step) tr.getTransferData(Step.arbeitsgangFlavor);
dtde.acceptDrag(DnDConstants.ACTION_COPY);
amount = 1;
}
else dtde.rejectDrag();
}
catch (Exception e)
{
e.printStackTrace();
dtde.rejectDrag();
}
}
}, true, null));
add(list, "cell 0 1,grow");
}
}
当您在 JList 上拖动时,应将数据插入到列表中以提供用户反馈以及将其放入列表中的可能性。没掉的话应该再删。
如何将我的对象拖放到 JPanel 上,而不是只是字符串的节点?
编辑:
使用 (String) tr.getTransferData(DataFlavor.stringFlavor)
我可以获得节点的标签,但这并不是很有帮助,因为我不知道它是否是 Order、Step 或者只是一个字符串节点。
EDIT2 SSCCE:
public class Test extends JFrame
{
private static final long serialVersionUID = 1L;
private JPanel contentPane;
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
try
{
Test window = new Test();
window.setVisible(true);
}
catch (Exception e)
{
e.printStackTrace();
}
}
});
}
public Test()
{
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 300);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
contentPane.setLayout(new BorderLayout(0, 0));
setContentPane(contentPane);
DefaultMutableTreeNode root = new DefaultMutableTreeNode("root");
DefaultMutableTreeNode string1 = new DefaultMutableTreeNode("String 1");
DefaultMutableTreeNode order1 = new DefaultMutableTreeNode(new ParentObject());
order1.add(new DefaultMutableTreeNode(new ChildObject()));
order1.add(new DefaultMutableTreeNode(new ChildObject()));
string1.add(order1);
root.add(string1);
DefaultTreeModel model = new DefaultTreeModel(root);
JTree tree = new JTree(model);
tree.setShowsRootHandles(true);
tree.setRootVisible(false);
tree.setDragEnabled(true);
tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
contentPane.add(tree, BorderLayout.WEST);
CustPanel panel = new CustPanel();
contentPane.add(panel, BorderLayout.CENTER);
}
}
class CustPanel extends JPanel
{
private static final long serialVersionUID = 1L;
public CustPanel()
{
super();
setLayout(new MigLayout("", "[grow]", "[][grow]"));
JProgressBar progressBar = new JProgressBar();
add(progressBar, "cell 0 0,growx");
DefaultListModel<ChildObject> listModel = new DefaultListModel<ChildObject>();
JList<ChildObject> list = new JList<ChildObject>();
list.setModel(listModel);
setDropTarget(new DropTarget(this, TransferHandler.COPY, new DropTargetAdapter()
{
@Override
public void drop(DropTargetDropEvent dtde)
{
Transferable tr = dtde.getTransferable();
if (dtde.isDataFlavorSupported(DataFlavor.stringFlavor))
{
try
{
System.out.println((String) tr.getTransferData(DataFlavor.stringFlavor)); // I want the actual object
}
catch (UnsupportedFlavorException | IOException e)
{
e.printStackTrace();
}
}
}
@Override
public void dragExit(DropTargetEvent dte)
{
}
@Override
public void dragEnter(DropTargetDragEvent dtde)
{
Transferable tr = dtde.getTransferable();
if (dtde.isDataFlavorSupported(DataFlavor.stringFlavor))
{
try
{
System.out.println((String) tr.getTransferData(DataFlavor.stringFlavor)); // I want the actual object
}
catch (UnsupportedFlavorException | IOException e)
{
e.printStackTrace();
}
}
}
@Override
public void dragOver(DropTargetDragEvent dtde)
{
Transferable tr = dtde.getTransferable();
if (dtde.isDataFlavorSupported(DataFlavor.stringFlavor))
{
try
{
System.out.println((String) tr.getTransferData(DataFlavor.stringFlavor)); // I want the actual object
}
catch (UnsupportedFlavorException | IOException e)
{
e.printStackTrace();
}
}
}
}, true, null));
add(list, "cell 0 1,grow");
}
}
class ParentObject implements Serializable
{
private static final long serialVersionUID = 1279985471254050120L;
public ArrayList<ChildObject> getChildren()
{
return new ArrayList<ChildObject>();
}
@Override
public String toString()
{
return "ParentObject";
}
}
class ChildObject implements Serializable
{
private static final long serialVersionUID = -5833860202973614790L;
@Override
public String toString()
{
return "ChildObject";
}
}
but not nodes which are just Strings?
您也许可以使用 TransferHandler#createTransferable(...)
方法来获取 DefaultMutableTreeNode
。
- TransferHandler#createTransferable(JComponent) (Java Platform SE 8 )
- Demo - DropDemo (The Java™ Tutorials > Creating a GUI With JFC/Swing > Drag and Drop and Data Transfer)
import java.awt.*;
import java.awt.datatransfer.*;
import java.awt.dnd.*;
import java.io.*;
import java.util.*;
import javax.activation.*;
import javax.swing.*;
import javax.swing.tree.*;
public class Test2 {
public JComponent makeUI() {
DefaultMutableTreeNode root = new DefaultMutableTreeNode("root");
DefaultMutableTreeNode string1 = new DefaultMutableTreeNode("String 1");
DefaultMutableTreeNode order1 = new DefaultMutableTreeNode(new ParentObject());
order1.add(new DefaultMutableTreeNode(new ChildObject()));
order1.add(new DefaultMutableTreeNode(new ChildObject()));
string1.add(order1);
root.add(string1);
DefaultTreeModel model = new DefaultTreeModel(root);
JTree tree = new JTree(model);
tree.setShowsRootHandles(true);
tree.setRootVisible(false);
tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
tree.setTransferHandler(new TreeTransferHandler());
tree.setDragEnabled(true);
DefaultListModel<ChildObject> listModel = new DefaultListModel<ChildObject>();
JList<ChildObject> list = new JList<ChildObject>();
list.setModel(listModel);
list.setDropTarget(new DropTarget(list, TransferHandler.COPY, new DropTargetAdapter() {
private void print(Transferable tr) {
try {
Object node = tr.getTransferData(TreeTransferHandler.FLAVOR);
System.out.println(node); // I want the actual object
} catch (UnsupportedFlavorException | IOException ex) {
ex.printStackTrace();
}
}
@Override
public void drop(DropTargetDropEvent dtde) {
if (dtde.isDataFlavorSupported(TreeTransferHandler.FLAVOR)) {
print(dtde.getTransferable());
}
}
@Override public void dragExit(DropTargetEvent dte) {}
@Override public void dragEnter(DropTargetDragEvent dtde) {}
@Override public void dragOver(DropTargetDragEvent dtde) {}
}, true, null));
JPanel contentPane = new JPanel(new GridLayout(1, 2));
contentPane.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
contentPane.add(new JScrollPane(tree), BorderLayout.WEST);
contentPane.add(new JScrollPane(list), BorderLayout.CENTER);
return contentPane;
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override public void run() {
try {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().add(new Test2().makeUI());
f.setBounds(100, 100, 450, 300);
f.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
class ParentObject implements Serializable {
public ArrayList<ChildObject> getChildren() {
return new ArrayList<ChildObject>();
}
@Override
public String toString() {
return "ParentObject";
}
}
class ChildObject implements Serializable {
@Override
public String toString() {
return "ChildObject";
}
}
class TreeTransferHandler extends TransferHandler {
public static final DataFlavor FLAVOR = new ActivationDataFlavor(
DefaultMutableTreeNode[].class,
DataFlavor.javaJVMLocalObjectMimeType,
"Array of DefaultMutableTreeNode");
@Override protected Transferable createTransferable(JComponent c) {
JTree source = (JTree) c;
TreePath[] paths = source.getSelectionPaths();
DefaultMutableTreeNode[] nodes = new DefaultMutableTreeNode[paths.length];
for (int i = 0; i < paths.length; i++) {
nodes[i] = (DefaultMutableTreeNode) paths[i].getLastPathComponent();
}
return new DataHandler(nodes, FLAVOR.getMimeType());
}
@Override public int getSourceActions(JComponent c) {
return TransferHandler.COPY;
}
}
我有一个 JTree 和 DefaultMutableTreeNodes。在某些层面上,这些节点是用 我自己的可序列化对象 初始化的。总共有两种不同类型的对象(称为“Step”和“Order”)。我希望能够仅删除使用这两个对象中的任何一个初始化的节点。任何其他只是字符串的节点都不应该是可删除的。一个“Order”可以包含多个“Steps”。如果它们被插入 JList,我希望能够将它们拖到 JPanel 上。如果删除了“Order”,则应该插入所有“Steps”,如果只有“Step" 只删除了应该插入的特定 "Step"。
SSCCE以下!
JTree:
tree = new JTree();
tree.setShowsRootHandles(true);
tree.setRootVisible(false);
tree.setDragEnabled(true);
tree.setModel(treeModel);
tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
J面板:
public class TablePanel extends JPanel
{
private static final long serialVersionUID = 3216206960422611905L;
public TablePanel()
{
super();
setLayout(new MigLayout("", "[grow]", "[][grow]"));
JProgressBar progressBar = new JProgressBar();
progressBar.setMaximum(28800); // 8 hours in seconds
progressBar.setStringPainted(true);
add(progressBar, "cell 0 0,growx");
DefaultListModel<Step> listModel = new DefaultListModel<Step>();
JList<Step> list = new JList<Step>();
list.setModel(listModel);
setDropTarget(new DropTarget(this, TransferHandler.COPY, new DropTargetAdapter()
{
private int index = 0;
private int amount = 0;
@Override
public void drop(DropTargetDropEvent dtde)
{
amount = 0;
index = 0;
}
@Override
public void dragExit(DropTargetEvent dte)
{
if (listModel.size() > 0)
{
if (amount == 1)
{
listModel.remove(index);
}
else
{
for (int i = 0; i < amount; i++)
{
listModel.remove(index + i);
}
}
amount = 0;
}
}
@Override
public void dragEnter(DropTargetDragEvent dtde)
{
try
{
Transferable tr = dtde.getTransferable();
if (dtde.isDataFlavorSupported(Order.auftragFlavor))
{
Order a = (Order) tr.getTransferData(Order.auftragFlavor); // Wrong, how do I get this?
dtde.acceptDrag(DnDConstants.ACTION_COPY);
amount = a.getSteps().size();
}
else if (dtde.isDataFlavorSupported(Step.arbeitsgangFlavor))
{
Step ag = (Step) tr.getTransferData(Step.arbeitsgangFlavor);
dtde.acceptDrag(DnDConstants.ACTION_COPY);
amount = 1;
}
else
{
dtde.rejectDrag();
}
}
catch (Exception e)
{
e.printStackTrace();
dtde.rejectDrag();
}
}
@Override
public void dragOver(DropTargetDragEvent dtde)
{
try
{
Transferable tr = dtde.getTransferable();
if (dtde.isDataFlavorSupported(Order.auftragFlavor))
{
Order a = (Order) tr.getTransferData(Order.auftragFlavor); // Wrong, how do I get this?
dtde.acceptDrag(DnDConstants.ACTION_COPY);
amount = a.getSteps().size();
}
else if (dtde.isDataFlavorSupported(Step.arbeitsgangFlavor))
{
Step ag = (Step) tr.getTransferData(Step.arbeitsgangFlavor);
dtde.acceptDrag(DnDConstants.ACTION_COPY);
amount = 1;
}
else dtde.rejectDrag();
}
catch (Exception e)
{
e.printStackTrace();
dtde.rejectDrag();
}
}
}, true, null));
add(list, "cell 0 1,grow");
}
}
当您在 JList 上拖动时,应将数据插入到列表中以提供用户反馈以及将其放入列表中的可能性。没掉的话应该再删。
如何将我的对象拖放到 JPanel 上,而不是只是字符串的节点?
编辑:
使用 (String) tr.getTransferData(DataFlavor.stringFlavor)
我可以获得节点的标签,但这并不是很有帮助,因为我不知道它是否是 Order、Step 或者只是一个字符串节点。
EDIT2 SSCCE:
public class Test extends JFrame
{
private static final long serialVersionUID = 1L;
private JPanel contentPane;
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
try
{
Test window = new Test();
window.setVisible(true);
}
catch (Exception e)
{
e.printStackTrace();
}
}
});
}
public Test()
{
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 300);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
contentPane.setLayout(new BorderLayout(0, 0));
setContentPane(contentPane);
DefaultMutableTreeNode root = new DefaultMutableTreeNode("root");
DefaultMutableTreeNode string1 = new DefaultMutableTreeNode("String 1");
DefaultMutableTreeNode order1 = new DefaultMutableTreeNode(new ParentObject());
order1.add(new DefaultMutableTreeNode(new ChildObject()));
order1.add(new DefaultMutableTreeNode(new ChildObject()));
string1.add(order1);
root.add(string1);
DefaultTreeModel model = new DefaultTreeModel(root);
JTree tree = new JTree(model);
tree.setShowsRootHandles(true);
tree.setRootVisible(false);
tree.setDragEnabled(true);
tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
contentPane.add(tree, BorderLayout.WEST);
CustPanel panel = new CustPanel();
contentPane.add(panel, BorderLayout.CENTER);
}
}
class CustPanel extends JPanel
{
private static final long serialVersionUID = 1L;
public CustPanel()
{
super();
setLayout(new MigLayout("", "[grow]", "[][grow]"));
JProgressBar progressBar = new JProgressBar();
add(progressBar, "cell 0 0,growx");
DefaultListModel<ChildObject> listModel = new DefaultListModel<ChildObject>();
JList<ChildObject> list = new JList<ChildObject>();
list.setModel(listModel);
setDropTarget(new DropTarget(this, TransferHandler.COPY, new DropTargetAdapter()
{
@Override
public void drop(DropTargetDropEvent dtde)
{
Transferable tr = dtde.getTransferable();
if (dtde.isDataFlavorSupported(DataFlavor.stringFlavor))
{
try
{
System.out.println((String) tr.getTransferData(DataFlavor.stringFlavor)); // I want the actual object
}
catch (UnsupportedFlavorException | IOException e)
{
e.printStackTrace();
}
}
}
@Override
public void dragExit(DropTargetEvent dte)
{
}
@Override
public void dragEnter(DropTargetDragEvent dtde)
{
Transferable tr = dtde.getTransferable();
if (dtde.isDataFlavorSupported(DataFlavor.stringFlavor))
{
try
{
System.out.println((String) tr.getTransferData(DataFlavor.stringFlavor)); // I want the actual object
}
catch (UnsupportedFlavorException | IOException e)
{
e.printStackTrace();
}
}
}
@Override
public void dragOver(DropTargetDragEvent dtde)
{
Transferable tr = dtde.getTransferable();
if (dtde.isDataFlavorSupported(DataFlavor.stringFlavor))
{
try
{
System.out.println((String) tr.getTransferData(DataFlavor.stringFlavor)); // I want the actual object
}
catch (UnsupportedFlavorException | IOException e)
{
e.printStackTrace();
}
}
}
}, true, null));
add(list, "cell 0 1,grow");
}
}
class ParentObject implements Serializable
{
private static final long serialVersionUID = 1279985471254050120L;
public ArrayList<ChildObject> getChildren()
{
return new ArrayList<ChildObject>();
}
@Override
public String toString()
{
return "ParentObject";
}
}
class ChildObject implements Serializable
{
private static final long serialVersionUID = -5833860202973614790L;
@Override
public String toString()
{
return "ChildObject";
}
}
but not nodes which are just Strings?
您也许可以使用 TransferHandler#createTransferable(...)
方法来获取 DefaultMutableTreeNode
。
- TransferHandler#createTransferable(JComponent) (Java Platform SE 8 )
- Demo - DropDemo (The Java™ Tutorials > Creating a GUI With JFC/Swing > Drag and Drop and Data Transfer)
import java.awt.*;
import java.awt.datatransfer.*;
import java.awt.dnd.*;
import java.io.*;
import java.util.*;
import javax.activation.*;
import javax.swing.*;
import javax.swing.tree.*;
public class Test2 {
public JComponent makeUI() {
DefaultMutableTreeNode root = new DefaultMutableTreeNode("root");
DefaultMutableTreeNode string1 = new DefaultMutableTreeNode("String 1");
DefaultMutableTreeNode order1 = new DefaultMutableTreeNode(new ParentObject());
order1.add(new DefaultMutableTreeNode(new ChildObject()));
order1.add(new DefaultMutableTreeNode(new ChildObject()));
string1.add(order1);
root.add(string1);
DefaultTreeModel model = new DefaultTreeModel(root);
JTree tree = new JTree(model);
tree.setShowsRootHandles(true);
tree.setRootVisible(false);
tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
tree.setTransferHandler(new TreeTransferHandler());
tree.setDragEnabled(true);
DefaultListModel<ChildObject> listModel = new DefaultListModel<ChildObject>();
JList<ChildObject> list = new JList<ChildObject>();
list.setModel(listModel);
list.setDropTarget(new DropTarget(list, TransferHandler.COPY, new DropTargetAdapter() {
private void print(Transferable tr) {
try {
Object node = tr.getTransferData(TreeTransferHandler.FLAVOR);
System.out.println(node); // I want the actual object
} catch (UnsupportedFlavorException | IOException ex) {
ex.printStackTrace();
}
}
@Override
public void drop(DropTargetDropEvent dtde) {
if (dtde.isDataFlavorSupported(TreeTransferHandler.FLAVOR)) {
print(dtde.getTransferable());
}
}
@Override public void dragExit(DropTargetEvent dte) {}
@Override public void dragEnter(DropTargetDragEvent dtde) {}
@Override public void dragOver(DropTargetDragEvent dtde) {}
}, true, null));
JPanel contentPane = new JPanel(new GridLayout(1, 2));
contentPane.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
contentPane.add(new JScrollPane(tree), BorderLayout.WEST);
contentPane.add(new JScrollPane(list), BorderLayout.CENTER);
return contentPane;
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override public void run() {
try {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().add(new Test2().makeUI());
f.setBounds(100, 100, 450, 300);
f.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
class ParentObject implements Serializable {
public ArrayList<ChildObject> getChildren() {
return new ArrayList<ChildObject>();
}
@Override
public String toString() {
return "ParentObject";
}
}
class ChildObject implements Serializable {
@Override
public String toString() {
return "ChildObject";
}
}
class TreeTransferHandler extends TransferHandler {
public static final DataFlavor FLAVOR = new ActivationDataFlavor(
DefaultMutableTreeNode[].class,
DataFlavor.javaJVMLocalObjectMimeType,
"Array of DefaultMutableTreeNode");
@Override protected Transferable createTransferable(JComponent c) {
JTree source = (JTree) c;
TreePath[] paths = source.getSelectionPaths();
DefaultMutableTreeNode[] nodes = new DefaultMutableTreeNode[paths.length];
for (int i = 0; i < paths.length; i++) {
nodes[i] = (DefaultMutableTreeNode) paths[i].getLastPathComponent();
}
return new DataHandler(nodes, FLAVOR.getMimeType());
}
@Override public int getSourceActions(JComponent c) {
return TransferHandler.COPY;
}
}