代码之家  ›  专栏  ›  技术社区  ›  LaPalme

如何在同一个窗口中获取多棵树的所有复选框?

  •  4
  • LaPalme  · 技术社区  · 7 年前

    我要处理的是:

    我想做的是:

    我有三棵树,我想把每棵树的所有选中元素放在一个单独的元素中,一个数组或一个ArrayList。因此,我可以只读取这些数组或ArrayList来处理选定的元素。当然,如果我取消选中一个框,则必须从数组中删除元素。

    我已经尝试过的:

    我不得不承认我没有很多想法。我试图准确地理解当我选中一个复选框时会发生什么,在许多函数中都有日志,并且我可以观察到当我选中树中的一个元素时,我的日志被写入了三次以上(例如getTreeCellRenderer中的一个日志)。

    我的代码:

    class CheckBoxNode extends DefaultMutableTreeNode {
    
        /**
         * 
         */
        private static final long serialVersionUID = 1155080395876568819L;
        private String _title;
        private boolean _selectedStatus;
    
        public CheckBoxNode(String name, boolean isSelected) {
            this._title = name;
            this._selectedStatus = isSelected;
        }
    
        //GETTERS
    
        public String getTitle() {
            return this._title;
        }
    
        public boolean isSelected() {
            return this._selectedStatus;
        }
    
        //SETTERS
    
        public void setTitle(String newTitle) {
            this._title = newTitle;
        }
    
        public void setSelected(boolean isSelected) {
            this._selectedStatus = isSelected;
        }
    
        public String toString() {
            return _title;
        }
    }
    

    CheckBoxNodeEditor

    class CheckBoxNodeEditor extends AbstractCellEditor implements TreeCellEditor {
    
        /**
         * 
         */
        private static final long serialVersionUID = 2616799535763664121L;
        private CheckBoxNodeRenderer renderer = new CheckBoxNodeRenderer();
    
        //CONSTRUCTOR 
    
        public CheckBoxNodeEditor() {}
    
        //METHODS
    
        public Object getCellEditorValue() {
            JCheckBox checkBox = renderer.getNodeRenderer();
            CheckBoxNode checkBoxNode = new CheckBoxNode(checkBox.getText(), checkBox.isSelected());
            return checkBoxNode;
        }
    
        public Component getTreeCellEditorComponent(JTree tree, Object value,
                boolean isSelected, boolean expanded, boolean leaf, int row) {
            Component editor = renderer.getTreeCellRendererComponent(tree, value,
                    true, expanded, leaf, row, true);
            // editor always selected / focused
            ItemListener itemListener = new ItemListener() {
                public void itemStateChanged(ItemEvent itemEvent) {
                    if (stopCellEditing()) {
                        fireEditingStopped();
                    }
                }
            };
    
            if (editor instanceof JCheckBox) {
                ((JCheckBox) editor).addItemListener(itemListener);
            }
            return editor;
        }
    }
    

    CheckBoxNodeRenderer

    class CheckBoxNodeRenderer implements TreeCellRenderer {
    
        private JCheckBox nodeRenderer = new JCheckBox();
        private Color selectionForeground, selectionBackground, textForeground, textBackground;
    
        //CONSTRUCTOR
    
        public CheckBoxNodeRenderer() {
            Font fontValue;
            fontValue = UIManager.getFont("Tree.font");
            if (fontValue != null) {
                nodeRenderer.setFont(fontValue);
            }
            Boolean booleanValue = (Boolean) UIManager.get("Tree.drawsFocusBorderAroundIcon");
            nodeRenderer.setFocusPainted((booleanValue != null)&& (booleanValue.booleanValue()));
            selectionForeground = UIManager.getColor("Tree.selectionForeground");
            selectionBackground = UIManager.getColor("Tree.selectionBackground");
            textForeground = UIManager.getColor("Tree.textForeground");
            textBackground = UIManager.getColor("Tree.textBackground");
        }
    
        //METHODS
    
        protected JCheckBox getNodeRenderer() {
            return nodeRenderer;
        }
    
        public Component getTreeCellRendererComponent(JTree tree, Object value,
                boolean selected, boolean expanded, boolean leaf, int row,
                boolean hasFocus) {
            Component returnValue;
            String stringValue = tree.convertValueToText(value, selected, expanded,
                    leaf, row, false);
            nodeRenderer.setText(stringValue);
            nodeRenderer.setSelected(false);
            nodeRenderer.setEnabled(tree.isEnabled());
            if (selected) {
                nodeRenderer.setForeground(selectionForeground);
                nodeRenderer.setBackground(selectionBackground);
            } else {
                nodeRenderer.setForeground(textForeground);
                nodeRenderer.setBackground(textBackground);
            }
            if ((value != null) && (value instanceof DefaultMutableTreeNode)) {
                Object userObject = ((DefaultMutableTreeNode) value)
                        .getUserObject();
                if (userObject instanceof CheckBoxNode) {
                    CheckBoxNode node = (CheckBoxNode) userObject;
                    nodeRenderer.setText(node.getTitle());
                    nodeRenderer.setSelected(node.isSelected());
                }
            }
            returnValue = nodeRenderer;
            return returnValue;
        }
    }
    

    构建窗口和树:包括从数据库中提取数据,构建复选框树以及包含树和其他面板的应用程序的主窗口

    public class WindowBuilding extends JFrame {
    
        /**
         * 
         */
        private static final long serialVersionUID = -634017858375515775L;
        private Parser _parser;
    
        // CONSTRUCTOR
    
        public WindowBuilding() {
            this._parser = new Parser();                        //parser to extract data from the database containining all the informations
            getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.X_AXIS));  //gridlayout to have all the elements in the same window
    
        }
    
        // METHODS
    
        public void buildTrees() throws SQLException {
            _parser.extractData();
            _parser.sortModels();
            _parser.sortCustomers();
            _parser.sortGroups();
    
            System.out.println(_parser.getNumberOfCustomers());
            System.out.println(_parser.getNumberOfGroups());
    
            // Families, Types and Models arrays
            CheckBoxNode[] myFamilies = new CheckBoxNode[_parser.getNumberOfFamilies()];
            CheckBoxNode[] myTypes = new CheckBoxNode[_parser.getNumberOfTypes()];
            CheckBoxNode[] myModels = new CheckBoxNode[_parser.getNumberOfModels()];
    
            // Root
            CheckBoxNode root = new CheckBoxNode("All", false);
    
            // Complete the arrays
            for (int i = 0; i < _parser.getNumberOfFamilies(); i++) {
                myFamilies[i] = new CheckBoxNode(_parser.getFamily(i), false);
            }
            for (int i = 0; i < _parser.getNumberOfTypes(); i++) {
                myTypes[i] = new CheckBoxNode(_parser.getType(i), false);
            }
            for (int i = 0; i < _parser.getNumberOfModels(); i++) {
                myModels[i] = new CheckBoxNode(_parser.getModel(i), false);
            }
    
            // Add Models to Types
            for (int i = 0; i < myModels.length; i++) {
                if (myModels[i].toString().startsWith("T119")) {
                    myTypes[1].add(myModels[i]);
                }
                if (myModels[i].toString().startsWith("T120")) {
                    myTypes[2].add(myModels[i]);
                }
                if (myModels[i].toString().startsWith("T121")) {
                    myTypes[3].add(myModels[i]);
                }
                if (myModels[i].toString().startsWith("T130")) {
                    myTypes[4].add(myModels[i]);
                }
                if (myModels[i].toString().startsWith("T150")) {
                    myTypes[7].add(myModels[i]);
                }
            }
    
            // Add Types to Families
            for (int i = 0; i < myTypes.length; i++) {
                if (myTypes[i].toString().startsWith("T119") || myTypes[i].toString().startsWith("T12")) {
                    myFamilies[0].add(myTypes[i]);
                }
                if (myTypes[i].toString().startsWith("T13")) {
                    myFamilies[1].add(myTypes[i]);
                }
                if (myTypes[i].toString().startsWith("T15")) {
                    myFamilies[3].add(myTypes[i]);
                }
            }
    
            // Add Families to Root
            for (int i = 0; i < _parser.getNumberOfFamilies(); i++) {
                if (i != 2) {
                    root.add(myFamilies[i]);
                }
            }
    
            // Customers and Groups arrays
            CheckBoxNode[] myCustomers = new CheckBoxNode[_parser.getNumberOfCompanies()];
            CheckBoxNode[] myGroups = new CheckBoxNode[_parser.getNumberOfFleets()];
    
            // Root for Groups
            CheckBoxNode rootGroups = new CheckBoxNode("All", false);
    
            // Complete the arrays
            for (int i = 0; i < _parser.getNumberOfCustomers(); i++) {
                myCustomers[i] = new CheckBoxNode(_parser.getCustomer(i), false);
            }
            for (int i = 0; i < _parser.getNumberOfGroups(); i++) {
                myGroups[i] = new CheckBoxNode(_parser.getGroup(i), false);
            }
    
            // Add Groups to Customers
            for (int i = 0; i < myCustomers.length; i++) {
                for (int j = 0; j < Groups.length; j++) {
                    if (myFleets[j].getTitle()
                            .startsWith(myCustomers[i].getTitle())) {
                        myCustomers[i].add(myGroups[j]);
                    }
                }
            }
    
            // Add Companies to Root
            for (int i = 0; i < myCustomers.length; i++) {
                rootGroups.add(myCustomers[i]);
            }
    
            // Test Types array
            CheckBoxNode[] myTests = new CheckBoxNode[8];
    
            // Root
            CheckBoxNode rootTests = new CheckBoxNode("All", false);
    
            // Complete the arrays
            myTests[0] = new CheckBoxNode("FIRST TEST", false);
            myTests[1] = new CheckBoxNode("SECOND TEST", false);
            myTests[2] = new CheckBoxNode("CHECK TEST", false);
            myTests[3] = new CheckBoxNode("RUN TEST", false);
            myTests[4] = new CheckBoxNode("STATIC", false);
            myTests[5] = new CheckBoxNode("TYPICAL TEST", false);
            myTests[6] = new CheckBoxNode("SIMU VALIDATION", false);
            myTests[7] = new CheckBoxNode("OTHER", false);
    
            // Add Test Types to root
            for(int i=0; i<8; i++) {
                rootTests.add(myTests[i]);
            }
    
            // TPP Array
            CheckBoxNode[] myTpp = new CheckBoxNode[30];
    
            // Root 
            CheckBoxNode rootTpp = new CheckBoxNode("All", false);
    
            // Complete the arrays
            for(int i=0; i<30; i++) {
                myTpp[i] = new CheckBoxNode("TPP "+(i+1), false);
            }
    
            // Add Tpp to root
            for(int i=0; i<myTpp.length; i++) {
                rootTpp.add(myTpp[i]);
            }
    
    
            // Create objects JTree
            JTree treeProducts = new JTree(root);
            JTree treeGroups = new JTree(rootGroups);
            JTree treeTests = new JTree(rootTests);
            JTree treeTpp = new JTree(rootTpp);
    
            // Trees renderer
            CheckBoxNodeRenderer renderer = new CheckBoxNodeRenderer();
    
            // Products tree parameters
            treeProducts.setCellRenderer(renderer);
            treeProducts.setCellEditor(new CheckBoxNodeEditor());
            treeProducts.setEditable(true);
    
            // Groups tree parameters
            treeGroups.setCellRenderer(renderer);
            treeGroups.setCellEditor(new CheckBoxNodeEditor());
            treeGroups.setEditable(true);
    
            // Test Types tree parameters
            treeTests.setCellRenderer(renderer);
            treeTests.setCellEditor(new CheckBoxNodeEditor());
            treeTests.setEditable(true);
    
            // Tpp tree parameters
            treeTpp.setCellRenderer(renderer);
            treeTpp.setCellEditor(new CheckBoxNodeEditor());
            treeTpp.setEditable(true);
    
            // Building panels
            JPanel mainPanel = new JPanel();
            JPanel titlePanel = new JPanel();
            JPanel dataPropPanel = new JPanel();
            JPanel topPanel = new JPanel();
            JPanel bottomPanel = new JPanel();
            JPanel spinnersPanel = new JPanel();
            JPanel msnPanel = new JPanel();
            JPanel datePanel = new JPanel();
            JPanel selectTppPanel = new JPanel();
            JPanel tppPanel = new JPanel();
            JPanel descPanel = new JPanel();
            JPanel labelsPanel= new JPanel();
            JPanel fieldsPanel = new JPanel();
            mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
            spinnersPanel.setLayout(new BoxLayout(spinnersPanel, BoxLayout.Y_AXIS));
            labelsPanel.setLayout(new BoxLayout(labelsPanel, BoxLayout.Y_AXIS));
            fieldsPanel.setLayout(new BoxLayout(fieldsPanel, BoxLayout.Y_AXIS));
            descPanel.setLayout(new BoxLayout(descPanel, BoxLayout.Y_AXIS));
            topPanel.setLayout(new BoxLayout(topPanel, BoxLayout.X_AXIS));
            bottomPanel.setLayout(new BoxLayout(bottomPanel, BoxLayout.X_AXIS));
            tppPanel.setLayout(new BoxLayout(tppPanel, BoxLayout.X_AXIS));
            msnPanel.setLayout(new BoxLayout(msnPanel, BoxLayout.X_AXIS));
            datePanel.setLayout(new BoxLayout(datePanel, BoxLayout.X_AXIS));
            titlePanel.setLayout(new FlowLayout(FlowLayout.LEFT));
            dataPropPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
            selectTppPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
    
            // Dimensions
            Dimension dimLabel = new Dimension(300,35);
    
            // JScrollPane for trees
            JScrollPane prodPane = new JScrollPane(treeProducts);           // ScrollPane products
            prodPane.setMaximumSize(new Dimension(250,300));
            JScrollPane groupPane = new JScrollPane(treeGroups);            // ScrollPane groups
            groupPpane.setMaximumSize(new Dimension(250,300));
            JScrollPane tePane = new JScrollPane(treeTests);
            tePane.setMaximumSize(new Dimension(250,300));
            JScrollPane tppPane = new JScrollPane(treeTpp);
            tppPane.setMaximumSize(new Dimension(600,300));
    
            // Labels for main panel
            JLabel title = new JLabel("Generate Test Points");
            titlePanel.add(title);
            JLabel topLabel = new JLabel("Data properties");
            dataPropPanel.add(topLabel);
            JLabel bottomLabel = new JLabel("Select TPP");
            selectTppPanel.add(bottomLabel);
    
            // MSN Panel
            SpinnerModel model1 = new SpinnerNumberModel(0,0,10000,1);
            SpinnerModel model2 = new SpinnerNumberModel(0,0,10000,1);
            JSpinner spinner1 = new JSpinner(model1);
            JSpinner spinner2 = new JSpinner(model2);
            msnPanel.add(spinner1);
            msnPanel.add(new JLabel("   to   "));
            msnPanel.add(spinner2);
            msnPanel.setMaximumSize(dimLabel);
    
            // Date Panel
            SpinnerModel date1 = new SpinnerDateModel();
            SpinnerModel date2 = new SpinnerDateModel();
            JSpinner dateSpinner1 = new JSpinner(date1);
            JSpinner dateSpinner2 = new JSpinner(date2);
            datePanel.add(dateSpinner1);
            datePanel.add(new JLabel("   to   "));
            datePanel.add(dateSpinner2);
            datePanel.setMaximumSize(dimLabel);
    
            // Spinners Panel
            JLabel msnRangeLabel = new JLabel("MSN Range");
            spinnersPanel.add(msnRangeLabel);
            spinnersPanel.add(msnPanel);
            spinnersPanel.add(new JLabel("Test Date Range"));
            spinnersPanel.add(datePanel);
    
            // Top Panel
            JLabel acPropertiesLabel = new JLabel("Product properties");
            topPanel.add(prodPropertiesLabel);
            topPanel.add(prodPane);
            topPanel.add(new JLabel("Groups"));
            topPanel.add(groupPane);
            topPanel.add(new JLabel("Test properties"));
            topPanel.add(tePane);
            topPanel.add(spinnersPanel);
    
            // Labels Panel
            JLabel tppName = new JLabel("TPP Name");
            tppName.setMaximumSize(new Dimension(100,35));
            labelsPanel.add(tppName);
            labelsPanel.add(new JLabel("TPP List"));
    
            // Fields Panel
            JTextField textField = new JTextField();
            textField.setMaximumSize(new Dimension(600,35));
            fieldsPanel.add(textField);
            fieldsPanel.add(tppane);
    
            // TPP Panel
            tppPanel.add(labelsPanel);
            tppPanel.add(fieldsPanel);
    
            // Desc Panel
            descPanel.add(new JLabel("label for description"));
            descPanel.add(new JLabel("label for description"));
            descPanel.add(new JLabel("label for description"));
            descPanel.add(new JLabel("label for description"));
            descPanel.add(new JLabel("label for description"));
    
            // Bottom Panel
            bottomPanel.add(tppPanel);
            bottomPanel.add(descPanel);
    
            // Main Panel
            mainPanel.add(titlePanel);
            mainPanel.add(dataPropPanel);
            mainPanel.add(topPanel);
            mainPanel.add(selectTppPanel);
            mainPanel.add(bottomPanel);
            this.getContentPane().add(mainPanel);
    
            // Window parameters
            ((JComponent) this.getContentPane()).setBorder(BorderFactory.createEmptyBorder(5,5,5,5));   //add a border to the window
            this.setSize(1600,900);
            this.setTitle("Generate Test Points");
            this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            this.setVisible(true);
    
        }
    }
    

    主要类别

    public class TestPointGeneration {
    
        /**
         * @param args
         * @throws ParserConfigurationException 
         * @throws SAXException 
         * @throws IOException 
         * @throws SQLException 
         */
        public static void main(String[] args) throws SQLException {
            WindowBuilding window = new WindowBuilding();
            window.buildTrees();
            window.setVisible(true);
    
        }
    }
    

    1 回复  |  直到 7 年前
        1
  •  1
  •   sirandy    7 年前

    我根据这个答案修改了解决方案: How to get all the checked boxes of several trees in a same window?

    我认为您的类CheckBoxNode缺少功能,基本上是状态的repo信息,但在CheckBoxNodeEditor类中,您只添加了一个JCheckBox,在我看来,它必须是一个数组或列表,并且CheckBoxNode必须处理要检查的事件,如果它们被选中或未选中。

    import java.awt.BorderLayout;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.tree.TreePath;
    
    public class Main extends JFrame {
    
        private static final long serialVersionUID = 4648172894076113183L;
    
        public Main() {
            super();
            setSize(500, 500);
            this.getContentPane().setLayout(new BorderLayout());
            final JCheckBoxTree cbt = new JCheckBoxTree();
            final JButton button = new JButton("get checked");
            JPanel panel = new JPanel();
            panel.add(cbt);
            panel.add(button);
            this.getContentPane().add(panel);
    
            button.addActionListener(new ActionListener() {
    
                @Override
                public void actionPerformed(ActionEvent arg0) {
                    printChecked(cbt);
                }
            });
    
            cbt.addCheckChangeEventListener(new JCheckBoxTree.CheckChangeEventListener() {
                public void checkStateChanged(JCheckBoxTree.CheckChangeEvent event) {
                    printChecked(cbt);
                }
            });         
            this.setDefaultCloseOperation(EXIT_ON_CLOSE);
        }
    
        public void printChecked(final JCheckBoxTree cbt) {
            System.out.println("Select items");
            TreePath[] paths = cbt.getCheckedPaths();
            for (TreePath tp : paths) {
                for (Object pathPart : tp.getPath()) {
                    System.out.print(pathPart + ",");
                }                   
                System.out.println();
            }
        }
    
        public static void main(String args[]) {
            Main m = new Main();
            m.setVisible(true);
        }
    }
    

    JTree类

    package com.stackoverflow.checkedboxes;
    import java.awt.BorderLayout;
    import java.awt.Component;
    import java.awt.event.MouseEvent;
    import java.awt.event.MouseListener;
    import java.util.EventListener;
    import java.util.EventObject;
    import java.util.HashMap;
    import java.util.HashSet;
    
    import javax.swing.JCheckBox;
    import javax.swing.JPanel;
    import javax.swing.JTree;
    import javax.swing.event.EventListenerList;
    import javax.swing.tree.DefaultMutableTreeNode;
    import javax.swing.tree.DefaultTreeSelectionModel;
    import javax.swing.tree.TreeCellRenderer;
    import javax.swing.tree.TreeModel;
    import javax.swing.tree.TreeNode;
    import javax.swing.tree.TreePath;
    
    public class JCheckBoxTree extends JTree {
    
        private static final long serialVersionUID = -4194122328392241790L;
    
        JCheckBoxTree selfPointer = this;
    
    
    
        // Defining data structure that will enable to fast check-indicate the state of each node
        // It totally replaces the "selection" mechanism of the JTree
        private class CheckedNode {
            boolean isSelected;
            boolean hasChildren;
            boolean allChildrenSelected;
    
            public CheckedNode(boolean isSelected_, boolean hasChildren_, boolean allChildrenSelected_) {
                isSelected = isSelected_;
                hasChildren = hasChildren_;
                allChildrenSelected = allChildrenSelected_;
            }
        }
        HashMap<TreePath, CheckedNode> nodesCheckingState;
        HashSet<TreePath> checkedPaths = new HashSet<TreePath>();
    
        // Defining a new event type for the checking mechanism and preparing event-handling mechanism
        protected EventListenerList listenerList = new EventListenerList();
    
        public class CheckChangeEvent extends EventObject {     
            private static final long serialVersionUID = -8100230309044193368L;
    
            public CheckChangeEvent(Object source) {
                super(source);          
            }       
        }   
    
        public interface CheckChangeEventListener extends EventListener {
            public void checkStateChanged(CheckChangeEvent event);
        }
    
        public void addCheckChangeEventListener(CheckChangeEventListener listener) {
            listenerList.add(CheckChangeEventListener.class, listener);
        }
        public void removeCheckChangeEventListener(CheckChangeEventListener listener) {
            listenerList.remove(CheckChangeEventListener.class, listener);
        }
    
        void fireCheckChangeEvent(CheckChangeEvent evt) {
            Object[] listeners = listenerList.getListenerList();
            for (int i = 0; i < listeners.length; i++) {
                if (listeners[i] == CheckChangeEventListener.class) {
                    ((CheckChangeEventListener) listeners[i + 1]).checkStateChanged(evt);
                }
            }
        }
    
        // Override
        public void setModel(TreeModel newModel) {
            super.setModel(newModel);
            resetCheckingState();
        }
    
        // New method that returns only the checked paths (totally ignores original "selection" mechanism)
        public TreePath[] getCheckedPaths() {
            return checkedPaths.toArray(new TreePath[checkedPaths.size()]);
        }
    
        // Returns true in case that the node is selected, has children but not all of them are selected
        public boolean isSelectedPartially(TreePath path) {
            CheckedNode cn = nodesCheckingState.get(path);
            return cn.isSelected && cn.hasChildren && !cn.allChildrenSelected;
        }
    
        private void resetCheckingState() { 
            nodesCheckingState = new HashMap<TreePath, CheckedNode>();
            checkedPaths = new HashSet<TreePath>();
            DefaultMutableTreeNode node = (DefaultMutableTreeNode)getModel().getRoot();
            if (node == null) {
                return;
            }
            addSubtreeToCheckingStateTracking(node);
        }
    
        // Creating data structure of the current model for the checking mechanism
        private void addSubtreeToCheckingStateTracking(DefaultMutableTreeNode node) {
            TreeNode[] path = node.getPath();   
            TreePath tp = new TreePath(path);
            CheckedNode cn = new CheckedNode(false, node.getChildCount() > 0, false);
            nodesCheckingState.put(tp, cn);
            for (int i = 0 ; i < node.getChildCount() ; i++) {              
                addSubtreeToCheckingStateTracking((DefaultMutableTreeNode) tp.pathByAddingChild(node.getChildAt(i)).getLastPathComponent());
            }
        }
    
        // Overriding cell renderer by a class that ignores the original "selection" mechanism
        // It decides how to show the nodes due to the checking-mechanism
        private class CheckBoxCellRenderer extends JPanel implements TreeCellRenderer {     
            private static final long serialVersionUID = -7341833835878991719L;     
            JCheckBox checkBox;     
            public CheckBoxCellRenderer() {
                super();
                this.setLayout(new BorderLayout());
                checkBox = new JCheckBox();
                add(checkBox, BorderLayout.CENTER);
                setOpaque(false);
            }
    
            @Override
            public Component getTreeCellRendererComponent(JTree tree, Object value,
                    boolean selected, boolean expanded, boolean leaf, int row,
                    boolean hasFocus) {
                DefaultMutableTreeNode node = (DefaultMutableTreeNode)value;
                Object obj = node.getUserObject();          
                TreePath tp = new TreePath(node.getPath());
                CheckedNode cn = nodesCheckingState.get(tp);
                if (cn == null) {
                    return this;
                }
                checkBox.setSelected(cn.isSelected);
                checkBox.setText(obj.toString());
                checkBox.setOpaque(cn.isSelected && cn.hasChildren && ! cn.allChildrenSelected);
                return this;
            }       
        }
    
        public JCheckBoxTree() {
            super();
            // Disabling toggling by double-click
            this.setToggleClickCount(0);
            // Overriding cell renderer by new one defined above
            CheckBoxCellRenderer cellRenderer = new CheckBoxCellRenderer();
            this.setCellRenderer(cellRenderer);
    
            // Overriding selection model by an empty one
            DefaultTreeSelectionModel dtsm = new DefaultTreeSelectionModel() {      
                private static final long serialVersionUID = -8190634240451667286L;
                // Totally disabling the selection mechanism
                public void setSelectionPath(TreePath path) {
                }           
                public void addSelectionPath(TreePath path) {                       
                }           
                public void removeSelectionPath(TreePath path) {
                }
                public void setSelectionPaths(TreePath[] pPaths) {
                }
            };
            // Calling checking mechanism on mouse click
            this.addMouseListener(new MouseListener() {
                public void mouseClicked(MouseEvent arg0) {
                    TreePath tp = selfPointer.getPathForLocation(arg0.getX(), arg0.getY());
                    if (tp == null) {
                        return;
                    }
                    boolean checkMode = ! nodesCheckingState.get(tp).isSelected;
                    checkSubTree(tp, checkMode);
                    updatePredecessorsWithCheckMode(tp, checkMode);
                    // Firing the check change event
                    fireCheckChangeEvent(new CheckChangeEvent(new Object()));
                    // Repainting tree after the data structures were updated
                    selfPointer.repaint();                          
                }           
                public void mouseEntered(MouseEvent arg0) {         
                }           
                public void mouseExited(MouseEvent arg0) {              
                }
                public void mousePressed(MouseEvent arg0) {             
                }
                public void mouseReleased(MouseEvent arg0) {
                }           
            });
            this.setSelectionModel(dtsm);
        }
    
        // When a node is checked/unchecked, updating the states of the predecessors
        protected void updatePredecessorsWithCheckMode(TreePath tp, boolean check) {
            TreePath parentPath = tp.getParentPath();
            // If it is the root, stop the recursive calls and return
            if (parentPath == null) {
                return;
            }       
            CheckedNode parentCheckedNode = nodesCheckingState.get(parentPath);
            DefaultMutableTreeNode parentNode = (DefaultMutableTreeNode) parentPath.getLastPathComponent();     
            parentCheckedNode.allChildrenSelected = true;
            parentCheckedNode.isSelected = false;
            for (int i = 0 ; i < parentNode.getChildCount() ; i++) {                
                TreePath childPath = parentPath.pathByAddingChild(parentNode.getChildAt(i));
                CheckedNode childCheckedNode = nodesCheckingState.get(childPath);           
                // It is enough that even one subtree is not fully selected
                // to determine that the parent is not fully selected
                if (! childCheckedNode.allChildrenSelected) {
                    parentCheckedNode.allChildrenSelected = false;      
                }
                // If at least one child is selected, selecting also the parent
                if (childCheckedNode.isSelected) {
                    parentCheckedNode.isSelected = true;
                }
            }
            if (parentCheckedNode.isSelected) {
                checkedPaths.add(parentPath);
            } else {
                checkedPaths.remove(parentPath);
            }
            // Go to upper predecessor
            updatePredecessorsWithCheckMode(parentPath, check);
        }
    
        // Recursively checks/unchecks a subtree
        protected void checkSubTree(TreePath tp, boolean check) {
            CheckedNode cn = nodesCheckingState.get(tp);
            cn.isSelected = check;
            DefaultMutableTreeNode node = (DefaultMutableTreeNode) tp.getLastPathComponent();
            for (int i = 0 ; i < node.getChildCount() ; i++) {              
                checkSubTree(tp.pathByAddingChild(node.getChildAt(i)), check);
            }
            cn.allChildrenSelected = check;
            if (check) {
                checkedPaths.add(tp);
            } else {
                checkedPaths.remove(tp);
            }
        }
    
    }
    

    enter image description here 输出: 选择项目 JTree,颜色, JTree,颜色,黄色,