JTree cell editor receives mouse clicks differently depending on OS

前端 未结 3 1786
伪装坚强ぢ
伪装坚强ぢ 2021-01-22 02:08

I\'ve created a tree cell renderer/editor framework that is admittedly a little bit hacky, but it works perfectly on Windows and Linux. The image below illustrates a sample set

3条回答
  •  囚心锁ツ
    2021-01-22 02:33

    A quick outline of how to implement complex cellEditors. The assumption is that all interactive elements of the editor do indeed edit a property of the node's userObject - as is the case in the OP's full code.

    The collaborators

    • a mock Data object with several properties
    • a renderer with several children, each bound to one property of the data object
    • an editor which uses an "live" instance of the rendering component, that is adds listeners to comply to editor's contract as needed

    Some code (obviously not usable for real-world usage, just to get the idea :)

    public static class ViewProvider extends AbstractCellEditor 
        implements TreeCellEditor, TreeCellRenderer {
    
        private JCheckBox firstBox;
        private JButton colorButton;
        private JComponent nodePanel;
        private JButton nameButton;
    
        private Data data;
        private boolean ignore;
    
        public ViewProvider(boolean asEditor) {
            initComponents();
            if (asEditor)
              installListeners();
        }
    
        protected void initComponents() {
            nodePanel = new JPanel();
            nodePanel.setOpaque(false);
            firstBox = new JCheckBox();
            colorButton = new JButton();
            // if we need something clickable use something ... clickable :-)
            nameButton = new JButton();
            nameButton.setContentAreaFilled(false);
            nameButton.setOpaque(true);
            nameButton.setBorderPainted(false);
            nameButton.setMargin(new Insets(0, 0, 0, 0));
            nodePanel.add(firstBox);
            nodePanel.add(colorButton);
            nodePanel.add(nameButton);
        }
    
        protected void installListeners() {
            ActionListener cancel = new ActionListener() {
    
                @Override
                public void actionPerformed(ActionEvent e) {
                    cancelCellEditing();
                }
    
            };
            nameButton.addActionListener(cancel);
            ActionListener stop = new ActionListener() {
    
                @Override
                public void actionPerformed(ActionEvent e) {
                    stopCellEditing();
                }
    
            };
            firstBox.addActionListener(stop);
            // Note: code for using a button to trigger opening a dialog
            // is in the tutorial, should replace this
            colorButton.addActionListener(stop);
        }
    
        @Override
        public Component getTreeCellRendererComponent(JTree tree, Object value,
                boolean selected, boolean expanded, boolean leaf, int row,
                boolean hasFocus) {
            Data data = (Data) ((DefaultMutableTreeNode) value).getUserObject();
            firstBox.setSelected(data.isVisible);
            colorButton.setBackground(data.color);
            nameButton.setText(data.name);
            nameButton.setBackground(selected ? Color.YELLOW : tree.getBackground());
            nameButton.setFont(tree.getFont());
            return nodePanel;
        }
    
        @Override
        public Component getTreeCellEditorComponent(JTree tree, Object value,
                boolean isSelected, boolean expanded, boolean leaf, int row) {
            // copy to not fiddle with the original
            data = new Data((Data) ((DefaultMutableTreeNode) value).getUserObject());
            ignore = true;
            getTreeCellRendererComponent(tree, value, isSelected, expanded, leaf, row, false);
            ignore = false;
            return nodePanel;
        }
    
        @Override
        public Object getCellEditorValue() {
            return data;
        }
    
        @Override
        public boolean shouldSelectCell(EventObject anEvent) {
            // at this point the editing component is added to the tree
            // and the mouse coordinates still in tree coordinates
            if (anEvent instanceof MouseEvent) {
                MouseEvent me = (MouseEvent) anEvent;
                Point loc = SwingUtilities.convertPoint(me.getComponent(), 
                        me.getPoint(), nodePanel);
                return loc.x >= nameButton.getX();
            }
            return false;
        }
    
        @Override
        public boolean stopCellEditing() {
            if (ignore) return false;
            // real-world data will have setters
            data.isVisible = firstBox.isSelected();
            return super.stopCellEditing();
        }
    
        @Override
        public void cancelCellEditing() {
            if (ignore) return;
            data = null;
            super.cancelCellEditing();
        }
    
    }
    
    // simple Data - obviously not for production 
    public static class Data {
        boolean isVisible;
        Color color;
        String name;
    
        public Data(boolean isVisible, Color color,
                String name) {
            this.isVisible = isVisible;
            this.color = color;
            this.name = name;
        }
    
        /**
         * A copy constructor to allow editors to manipulate its
         * properties without changing the original.
         * 
         * @param original
         */
        public Data(Data original) {
            this.isVisible = original.isVisible;
            this.color = original.color;
            this.name = original.name;
        }
    }
    
    // usage:
    DefaultMutableTreeNode root = new DefaultMutableTreeNode(
        new Data(true, Color.RED, "someName"));
    root.add(new DefaultMutableTreeNode(new Data(true, Color.GREEN, "other")));
    root.add(new DefaultMutableTreeNode(new Data(false, Color.BLUE, "whatagain")));
    root.add(new DefaultMutableTreeNode(new Data(false, Color.YELLOW, "dummy")));
    
    JTree tree = new JTree(root);
    tree.setCellRenderer(new ViewProvider(false));
    tree.setCellEditor(new ViewProvider(true));
    tree.setEditable(true);
    

提交回复
热议问题