【问题标题】:JCheckBoxTree initial state issueJCheckBoxTree 初始状态问题
【发布时间】:2020-03-27 20:15:13
【问题描述】:

我在使用一个自定义的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】:

    在我的例子中,我更新了我的所有代码,下面的 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 事件在成功放入 drop 处理程序 TreeDropTarget 方法 drop 后附加,因为 D&D 使用的是复制 Jtree 模式,因此您可以注入您的构造函数中的事件逻辑。最后,这个 JTree 在一个小的上下文中表现得像我需要的那样,这对于大数据集来说不是一个好主意(很多事件总是在重绘树)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-07-17
      • 1970-01-01
      • 2019-05-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-20
      相关资源
      最近更新 更多