TheFreddy1404 TheFreddy1404 - 2 months ago 6
Java Question

Drag and Drop from JTree to JList with own objects

I have a JTree with DefaultMutableTreeNodes. On some levels these nodes were initialized with my own serializable objects. In total there are two different types of objects (called "Step" and "Order"). I want to be able to drop only nodes which were initialized with either of these two objects. Any other nodes which are just Strings shouldn't be droppable. One "Order" can contain many "Steps". I want to be able to drag them onto a JPanel were they get inserted into a JList. If a "Order" was dropped all of the "Steps" are supposed to be inserted, if only a "Step" was dropped only that particular "Step" is supposed to be inserted.

SSCCE below!

JTree:

tree = new JTree();
tree.setShowsRootHandles(true);
tree.setRootVisible(false);
tree.setDragEnabled(true);
tree.setModel(treeModel);
tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);


JPanel:

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");
}
}


When you are dragging over the JList, then the data should be inserted into the list to give the user feedback and the possibility to place it in the list. If not dropped, it should be removed again.

How can drag and drop my objects onto the JPanel, but not nodes which are just Strings?

EDIT:
With
(String) tr.getTransferData(DataFlavor.stringFlavor)
I am able to get the label of the node, but this is not really helpfull, because I don't know if it was a Order, Step or just a string node.

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";
}
}

Answer

but not nodes which are just Strings?

You might be able to use a TransferHandler#createTransferable(...) method to get the DefaultMutableTreeNode.

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;
  }
}