JCheckBoxTree初始状态问题

问题描述 投票:0回答:1

我正在使用实现拖放的自定义JTree,并且单元格渲染器是Jcheckbox

问题是我的复选框状态不同于我的jtree选择状态,因为我正在更新单元格渲染器中的复选框选择状态

@Override
public TreeCellRenderer getCellRenderer() {
    return (tree, value, selected, expanded, leaf, row, hasFocus) -> {

        selected = GridManager.getInstance().getDisplayableSources().containsKey(value+"");
        final String key = value + "";
        final JCheckBoxMenuItem jCheckBoxMenuItem = new JCheckBoxMenuItem(key);
        jCheckBoxMenuItem.setSelected(selected);
        return jCheckBoxMenuItem;
    };
}

我很清楚,点击事件触发了(触发)某种内部选择状态,这种状态由selected lambda参数反映出来,解释了我的拖放未遂行为

所以如何更新JTree选择,这样我就可以像这样盲目使用渲染器

@Override
public TreeCellRenderer getCellRenderer() {
    return (tree, value, selected, expanded, leaf, row, hasFocus) -> {
        final String key = value + "";
        final JCheckBoxMenuItem jCheckBoxMenuItem = new JCheckBoxMenuItem(key);
        jCheckBoxMenuItem.setSelected(selected);
        return jCheckBoxMenuItem;
    };
}

这是我的完整实现

import java.util.HashMap;

import javax.swing.DropMode;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JTree;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeCellRenderer;
import javax.swing.tree.TreePath;

import com.wanasis.vlc.control.GridManager;
import com.wanasis.vlc.domain.SourceNode;

public class JCheckBoxDragableTree extends JTree {

    /**
     * 
     */
    private static final long serialVersionUID = -7768978192373533316L;
    private HashMap<String, SourceNode> configurableSources;
    private static HashMap<String, String> displaySources = new HashMap<>();

    public JCheckBoxDragableTree(HashMap<String, SourceNode> configurableSources,
            HashMap<String, String> displaySources) {

        this.configurableSources = configurableSources;
        this.displaySources = displaySources;
        final DefaultTreeModel dtm = new DefaultTreeModel(new DefaultMutableTreeNode());

        final DefaultMutableTreeNode root = (DefaultMutableTreeNode) dtm.getRoot();
        configurableSources.values().stream().filter(s -> {
            return s.getParent().isEmpty();
        }).forEachOrdered(child -> {
            dtm.insertNodeInto(new DefaultMutableTreeNode(child.getId()), root, root.getChildCount());
        });
        setModel(dtm);

        setDragEnabled(true);
        setDropMode(DropMode.ON);
        setTransferHandler(new TreeTransferHandler());
        setSelectionModel(new SomativeSelectionModel());
        addTreeSelectionListener(new TreeSelectionListener() {

            @Override
            public void valueChanged(TreeSelectionEvent e) {



                String key = ""+e.getPath().getLastPathComponent();
                DefaultMutableTreeNode dmtn = (DefaultMutableTreeNode) e.getPath().getLastPathComponent();
                System.out.println(dmtn.getUserObject());
                System.out.println(key);
                GridManager gm = GridManager.getInstance();
                boolean isDisplayed = gm.getDisplayableSources().containsKey(key);
                if (isDisplayed) {
                    System.out.println("hiding selected element");
                    gm.getDisplayableSources().remove(key);
                    System.out.println(gm.getDisplayableSources().keySet());
                } else {
                    System.out.println("showing selected element");
                    gm.getDisplayableSources().put(key, gm.getConfigurableSources().get(key).getSource());

                    System.out.println(gm.getDisplayableSources().keySet());
                }
                gm.prepareDisplay();

            }
        });

    }

    @Override
    public void setSelectionPath(TreePath path) {

        addSelectionPath(path);

        return;
    }

    @Override
    public void setSelectionPaths(TreePath[] paths) {

        addSelectionPaths(paths);

        return;
    }

    @Override
    public void setSelectionRow(int row) {

        addSelectionRow(row);

        return;
    }

    @Override
    public void setSelectionRows(int[] rows) {

        addSelectionRows(rows);

        return;
    }

    @Override
    public TreeCellRenderer getCellRenderer() {
        return (tree, value, selected, expanded, leaf, row, hasFocus) -> {

            selected = GridManager.getInstance().getDisplayableSources().containsKey(value+"");
            final String key = value + "";
            final JCheckBoxMenuItem jCheckBoxMenuItem = new JCheckBoxMenuItem(key);
            jCheckBoxMenuItem.setSelected(selected);
            return jCheckBoxMenuItem;
        };
    }
}
java swing drag-and-drop jtree jcheckbox
1个回答
0
投票

就我而言,我更新了所有代码,下面的jtree是带有复选框作为单元格渲染器的拖放操作

我还在D&D和复选框选择事件上附加了一些事件逻辑,您要做的就是根据需要对其进行更新

希望这会有所帮助

import java.awt.Color;
import java.awt.Component;
import java.awt.Font;
import java.awt.Insets;
import java.awt.Point;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DragGestureEvent;
import java.awt.dnd.DragGestureListener;
import java.awt.dnd.DragGestureRecognizer;
import java.awt.dnd.DragSource;
import java.awt.dnd.DragSourceDragEvent;
import java.awt.dnd.DragSourceDropEvent;
import java.awt.dnd.DragSourceEvent;
import java.awt.dnd.DragSourceListener;
import java.awt.dnd.DropTarget;
import java.awt.dnd.DropTargetContext;
import java.awt.dnd.DropTargetDragEvent;
import java.awt.dnd.DropTargetDropEvent;
import java.awt.dnd.DropTargetEvent;
import java.awt.dnd.DropTargetListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.MouseEvent;
import java.io.IOException;
import java.util.EventObject;
import java.util.HashMap;

import javax.swing.AbstractCellEditor;
import javax.swing.Icon;
import javax.swing.JCheckBox;
import javax.swing.JTree;
import javax.swing.UIManager;
import javax.swing.border.LineBorder;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeCellEditor;
import javax.swing.tree.TreeCellRenderer;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;

import com.wanasis.vlc.control.GridManager;
import com.wanasis.vlc.domain.SourceNode;

public class JCheckBoxDragableTree extends JTree {

    /**
     * 
     */
    private static final long serialVersionUID = -776897819237333316L;
    private HashMap<String, SourceNode> configurableSources;
    private static HashMap<String, String> displaySources = new HashMap<>();

    private static DefaultMutableTreeNode root = new DefaultMutableTreeNode("wanaDVR");

    TreeDragSource ds;

    TreeDropTarget dt;

    public JCheckBoxDragableTree(HashMap<String, SourceNode> configurableSources, HashMap<String, String> displaySources) {
        super(root);
        System.out.println("JCheckBoxDragableTree");
        setupTreeElements(configurableSources);

        this.configurableSources = configurableSources;
        this.displaySources = displaySources;

        setCellRenderer(new CheckBoxTreeNodeRenderer());
        setCellEditor(new CheckBoxTreeNodeEditor(this));
        setEditable(true);
        ds = new TreeDragSource(this, DnDConstants.ACTION_COPY_OR_MOVE);
        dt = new TreeDropTarget(this);

        addTreeSelectionListener(new TreeSelectionListener() {

            @Override
            public void valueChanged(TreeSelectionEvent e) {

                GridManager gm = GridManager.getInstance();
                String key = "" + e.getPath().getLastPathComponent();
                DefaultMutableTreeNode dmtn = (DefaultMutableTreeNode) e.getPath().getLastPathComponent();
                System.out.println(dmtn.getUserObject());
                System.out.println(key);


            }
        });
    }

    public void setupTreeElements(HashMap<String, SourceNode> configurableSources) {
        final HashMap<String, DefaultMutableTreeNode> parents = new HashMap<>();
        final HashMap<String, SourceNode> reste = new HashMap<>();

        configurableSources.values().stream().filter(s -> {
            return s.getParent().isEmpty()||s.getParent().trim().toLowerCase().equals("wanadvr");
        }).forEachOrdered(child -> {
            String key = child.getId();
            DefaultMutableTreeNode newChild = new DefaultMutableTreeNode(key);
            parents.put(key, newChild);
            root.add(newChild);
        });
        configurableSources.values().stream().filter(s -> {
            return !s.getParent().isEmpty() && !s.getParent().trim().toLowerCase().equals("wanadvr");
        }).forEachOrdered(child -> {
            String parentKey = child.getParent();
            String key = child.getId();
            DefaultMutableTreeNode newChild = new DefaultMutableTreeNode(key);
            if (parents.keySet().contains(parentKey)) {
                parents.get(parentKey).add(newChild);
                parents.put(key, newChild);
            } else {
                reste.put(key, child);
            }
        });
        while (reste.size() > 0) {
            reste.values().stream().forEachOrdered(child -> {
                String parentKey = child.getParent();
                String key = child.getId();
                DefaultMutableTreeNode newChild = new DefaultMutableTreeNode(key);
                if (parents.keySet().contains(parentKey)) {
                    parents.get(parentKey).add(newChild);
                    parents.put(key, newChild);
                    reste.remove(key);
                }
            });
        }
    }
}

class TreeNodeCheckBox extends JCheckBox {

    public TreeNodeCheckBox() {
        this("", false);
    }

    public TreeNodeCheckBox(final String text, final boolean selected) {
        this(text, null, selected);
    }

    public TreeNodeCheckBox(final String text, final Icon icon, final boolean selected) {
        super(text, icon, selected);
        setMargin(new Insets(1, 1, 1, 1));

        System.out.println(text);
        System.out.println(isSelected());
        GridManager instance = GridManager.getInstance();
        if (isSelected()) {
            instance.getDisplayableSources().put(text, instance.getConfigurableSources().get(text).getSource());

        }else {
            instance.getDisplayableSources().remove(text);
        }
        instance.prepareDisplay();
    }
}

class CheckBoxTreeNodeRenderer implements TreeCellRenderer {
    Color selectionBorderColor, selectionForeground, selectionBackground, textForeground, textBackground;
    private TreeNodeCheckBox treeNodeCheckBox = new TreeNodeCheckBox();
    private DefaultTreeCellRenderer defaultRenderer = new DefaultTreeCellRenderer();

    public CheckBoxTreeNodeRenderer() {
        Font fontValue;
        fontValue = UIManager.getFont("Tree.font");
        if (fontValue != null) {
            treeNodeCheckBox.setFont(fontValue);
        }
        Boolean booleanValue = (Boolean) UIManager.get("Tree.drawsFocusBorderAroundIcon");
        treeNodeCheckBox.setFocusPainted((booleanValue != null) && (booleanValue.booleanValue()));

        selectionBorderColor = UIManager.getColor("Tree.selectionBorderColor");
        selectionForeground = UIManager.getColor("Tree.selectionForeground");
        selectionBackground = UIManager.getColor("Tree.selectionBackground");
        textForeground = UIManager.getColor("Tree.textForeground");
        textBackground = UIManager.getColor("Tree.textBackground");
    }

    protected TreeNodeCheckBox getCheckBoxRenderer() {
        return treeNodeCheckBox;
    }

    public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded,
            boolean leaf, int row, boolean hasFocus) {
        Component component;
        if (leaf) {         
            String stringValue = tree.convertValueToText(value, selected, expanded, leaf, row, false);

            treeNodeCheckBox.setText(stringValue);
            treeNodeCheckBox.setSelected(GridManager.getInstance().getDisplayableSources().keySet().contains(stringValue));
            treeNodeCheckBox.setEnabled(tree.isEnabled());
            if (selected) {
                treeNodeCheckBox.setBorder(new LineBorder(selectionBorderColor));
                treeNodeCheckBox.setForeground(selectionForeground);
                treeNodeCheckBox.setBackground(selectionBackground);
            } else {
                treeNodeCheckBox.setBorder(null);
                treeNodeCheckBox.setForeground(textForeground);
                treeNodeCheckBox.setBackground(textBackground);
            }
            if ((value != null) && (value instanceof DefaultMutableTreeNode)) {
                Object userObject = ((DefaultMutableTreeNode) value).getUserObject();
                if (userObject instanceof TreeNodeCheckBox) {
                    TreeNodeCheckBox node = (TreeNodeCheckBox) userObject;
                    treeNodeCheckBox.setText(node.getText());
                    treeNodeCheckBox.setSelected(node.isSelected());
                }
            }
            component = treeNodeCheckBox;
        } else {
            component = defaultRenderer.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row,
                    hasFocus);
        }
        return component;
    }
}

class CheckBoxTreeNodeEditor extends AbstractCellEditor implements TreeCellEditor {
    CheckBoxTreeNodeRenderer renderer = new CheckBoxTreeNodeRenderer();
    JTree tree;

    public CheckBoxTreeNodeEditor(JTree tree) {
        this.tree = tree;
    }

    public Object getCellEditorValue() {
        TreeNodeCheckBox checkBox = renderer.getCheckBoxRenderer();
        TreeNodeCheckBox checkBoxNode = new TreeNodeCheckBox(checkBox.getText(), checkBox.isSelected());
        return checkBoxNode;
    }

    public boolean isCellEditable(EventObject event) {
        boolean editable = false;
        if (event instanceof MouseEvent) {
            MouseEvent mouseEvent = (MouseEvent) event;
            TreePath path = tree.getPathForLocation(mouseEvent.getX(), mouseEvent.getY());
            if (path != null) {
                Object node = path.getLastPathComponent();
                if ((node != null) && (node instanceof DefaultMutableTreeNode)) {
                    DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode) node;
                    editable = treeNode.isLeaf();
                }
            }
        }
        return editable;
    }

    public Component getTreeCellEditorComponent(JTree tree, Object value, boolean selected, boolean expanded,
            boolean leaf, int row) {
        Component editor = renderer.getTreeCellRendererComponent(tree, value, true, expanded, leaf, row, true);
        if (editor instanceof TreeNodeCheckBox) {
            ((TreeNodeCheckBox) editor).addItemListener(new ItemListener() {
                public void itemStateChanged(ItemEvent itemEvent) {
                    if (stopCellEditing()) {
                        fireEditingStopped();
                    }
                }
            });
        }
        return editor;
    }

}

class TreeDragSource implements DragSourceListener, DragGestureListener {

    DragSource source;

    DragGestureRecognizer recognizer;

    TransferableTreeNode transferable;

    DefaultMutableTreeNode oldNode;

    JTree sourceTree;

    public TreeDragSource(JTree tree, int actions) {
        sourceTree = tree;
        source = new DragSource();
        recognizer = source.createDefaultDragGestureRecognizer(sourceTree, actions, this);
    }

    /*
     * Drag Gesture Handler
     */
    public void dragGestureRecognized(DragGestureEvent dge) {
        TreePath path = sourceTree.getSelectionPath();
        if ((path == null) || (path.getPathCount() <= 1)) {
            // We can't move the root node or an empty selection
            return;
        }
        oldNode = (DefaultMutableTreeNode) path.getLastPathComponent();
        transferable = new TransferableTreeNode(path);
        // source.startDrag(dge, DragSource.DefaultMoveNoDrop, transferable, this);

        // If you support dropping the node anywhere, you should probably
        // start with a valid move cursor:
        source.startDrag(dge, DragSource.DefaultMoveDrop, transferable, this);
    }

    /*
     * Drag Event Handlers
     */
    public void dragEnter(DragSourceDragEvent dsde) {
    }

    public void dragExit(DragSourceEvent dse) {
    }

    public void dragOver(DragSourceDragEvent dsde) {
    }

    public void dropActionChanged(DragSourceDragEvent dsde) {
        System.out.println("Action: " + dsde.getDropAction());
        System.out.println("Target Action: " + dsde.getTargetActions());
        System.out.println("User Action: " + dsde.getUserAction());
    }

    public void dragDropEnd(DragSourceDropEvent dsde) {
        /*
         * to support move or copy, we have to check which occurred:
         */
        System.out.println("Drop Action: " + dsde.getDropAction());
        if (dsde.getDropSuccess() && (dsde.getDropAction() == DnDConstants.ACTION_MOVE)) {
            ((DefaultTreeModel) sourceTree.getModel()).removeNodeFromParent(oldNode);
        }

        /*
         * to support move only... if (dsde.getDropSuccess()) {
         * ((DefaultTreeModel)sourceTree.getModel()).removeNodeFromParent(oldNode); }
         */
    }
}

// TreeDropTarget.java
// A quick DropTarget that's looking for drops from draggable JTrees.
//

class TreeDropTarget implements DropTargetListener {

    DropTarget target;

    JTree targetTree;

    public TreeDropTarget(JTree tree) {
        targetTree = tree;
        target = new DropTarget(targetTree, this);
    }

    /*
     * Drop Event Handlers
     */
    private TreeNode getNodeForEvent(DropTargetDragEvent dtde) {
        Point p = dtde.getLocation();
        DropTargetContext dtc = dtde.getDropTargetContext();
        JTree tree = (JTree) dtc.getComponent();
        TreePath path = tree.getClosestPathForLocation(p.x, p.y);
        return (TreeNode) path.getLastPathComponent();
    }

    public void dragEnter(DropTargetDragEvent dtde) {
        TreeNode node = getNodeForEvent(dtde);
        if (node.isLeaf()) {
            dtde.rejectDrag();
        } else {
            // start by supporting move operations
            // dtde.acceptDrag(DnDConstants.ACTION_MOVE);
            dtde.acceptDrag(dtde.getDropAction());
        }
    }

    public void dragOver(DropTargetDragEvent dtde) {
        TreeNode node = getNodeForEvent(dtde);
        if (node.isLeaf()) {
            dtde.rejectDrag();
        } else {
            // start by supporting move operations
            // dtde.acceptDrag(DnDConstants.ACTION_MOVE);
            dtde.acceptDrag(dtde.getDropAction());
        }
    }

    public void dragExit(DropTargetEvent dte) {
    }

    public void dropActionChanged(DropTargetDragEvent dtde) {
    }

    public void drop(DropTargetDropEvent dtde) {
        Point pt = dtde.getLocation();
        DropTargetContext dtc = dtde.getDropTargetContext();
        JTree tree = (JTree) dtc.getComponent();
        TreePath parentpath = tree.getClosestPathForLocation(pt.x, pt.y);
        DefaultMutableTreeNode parent = (DefaultMutableTreeNode) parentpath.getLastPathComponent();


        if (parent.isLeaf()) {
            dtde.rejectDrop();
            return;
        }

        try {
            Transferable tr = dtde.getTransferable();
            DataFlavor[] flavors = tr.getTransferDataFlavors();
            for (int i = 0; i < flavors.length; i++) {
                if (tr.isDataFlavorSupported(flavors[i])) {
                    dtde.acceptDrop(dtde.getDropAction());
                    TreePath p = (TreePath) tr.getTransferData(flavors[i]);
                    DefaultMutableTreeNode node = (DefaultMutableTreeNode) p.getLastPathComponent();
                    DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
                    model.insertNodeInto(node, parent, 0);
                    dtde.dropComplete(true);
                    System.out.println("dragged node : "+node);
                    System.out.println("dropped in parent : "+parent);
                    GridManager.getInstance().getConfigurableSources().get(""+node).setParent(""+parent);
                    System.out.println(GridManager.getInstance().getConfigurableSources().values());

                    return;
                }
            }
            dtde.rejectDrop();
        } catch (Exception e) {
            e.printStackTrace();
            dtde.rejectDrop();
        }
    }
}

// TransferableTreeNode.java
// A Transferable TreePath to be used with Drag & Drop applications.
//

class TransferableTreeNode implements Transferable {

    public static DataFlavor TREE_PATH_FLAVOR = new DataFlavor(TreePath.class, "Tree Path");

    DataFlavor flavors[] = { TREE_PATH_FLAVOR };

    TreePath path;

    public TransferableTreeNode(TreePath tp) {
        path = tp;
    }

    public synchronized DataFlavor[] getTransferDataFlavors() {
        return flavors;
    }

    public boolean isDataFlavorSupported(DataFlavor flavor) {
        return (flavor.getRepresentationClass() == TreePath.class);
    }

    public synchronized Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
        if (isDataFlavorSupported(flavor)) {
            return (Object) path;
        } else {
            throw new UnsupportedFlavorException(flavor);
        }
    }
}

NB我的D&D事件在成功拖放到拖放处理程序TreeDropTarget方法drop中后被附加,对于复选框,因为D&D使用复制Jtree模式,因此您可以将事件逻辑注入到构造函数。最终,这个JTree在较小的上下文中表现出了我的需求,这对于大型数据集来说不是一个好主意(很多事件总是在重绘树)]

© www.soinside.com 2019 - 2024. All rights reserved.