2016-12-04 55 views
1

对于我一直在努力的项目,我必须创建一个JTree,每行有JToggleButton,实际上每行有两个。因此,为了实现这一目标,正如您将在MCVE中看到的那样,我编写了自定义DefaultTreeCellRenderer和自定义AbstractCellEditor在JToggleButton中保存选择

但是,在编辑JToggleBox是否被选中时出现问题。最初,当您选择要更改的第一个值时,它工作正常。如果你留在JTree的那一行上,并且不要点击其他任何地方,但是在JToggleButton上,它可以正常工作。如果您在其他地方点击,您设置的值将丢失。

当点击其他地方时,JToggleButton的设置值如何保留?

MCVE

import java.awt.Color; 
import java.awt.Component; 
import java.awt.EventQueue; 
import java.awt.GridBagConstraints; 
import java.awt.GridBagLayout; 
import java.awt.GridLayout; 
import java.awt.Insets; 
import java.awt.event.ItemEvent; 
import java.awt.event.ItemListener; 
import java.awt.event.MouseEvent; 
import java.util.EventObject; 

import javax.swing.AbstractCellEditor; 
import javax.swing.JComponent; 
import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.JPanel; 
import javax.swing.JScrollPane; 
import javax.swing.JToggleButton; 
import javax.swing.JTree; 
import javax.swing.event.ChangeEvent; 
import javax.swing.plaf.metal.MetalToggleButtonUI; 
import javax.swing.tree.DefaultMutableTreeNode; 
import javax.swing.tree.DefaultTreeCellRenderer; 
import javax.swing.tree.TreeCellEditor; 
import javax.swing.tree.TreePath; 

@SuppressWarnings("serial") 
public class DirectoryExplorer extends JFrame { 
    private DirectoryExplorer() { 
     super("Directory Explorer"); 
     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     setLayout(new GridLayout(1, 1)); 
     createPanel(); 
     setSize(800,600); 
     setVisible(true); 
    } 

    private void createPanel() { 
     DefaultMutableTreeNode colors = new DefaultMutableTreeNode("Colours"); 
     colors.add(new DefaultMutableTreeNode("Red")); 
     colors.add(new DefaultMutableTreeNode("Green")); 
     colors.add(new DefaultMutableTreeNode("Blue")); 

     DefaultMutableTreeNode falvors = new DefaultMutableTreeNode("Flavours"); 
     falvors.add(new DefaultMutableTreeNode("Toffee")); 
     falvors.add(new DefaultMutableTreeNode("Fudge")); 
     falvors.add(new DefaultMutableTreeNode("Chocolate")); 

     DefaultMutableTreeNode root = new DefaultMutableTreeNode("root"); 
     root.add(colors); 
     root.add(falvors); 
     root.add(new DefaultMutableTreeNode("Leafy")); 

     JPanel panel = new JPanel(new GridLayout(1, 1)); 
     JTree tree = new JTree(root); 

     FileNameRenderer fileRender = new FileNameRenderer(); 
     tree.setCellRenderer(fileRender); 

     tree.setCellEditor(new CheckBoxNodeEditor(tree)); 
     tree.setEditable(true); 

     tree.setShowsRootHandles(true); 

     panel.add(new JScrollPane(tree)); 
     getContentPane().add(panel); 
    } 

    public static void main(String[] args) { 
     EventQueue.invokeLater(() -> new DirectoryExplorer()); 
    } 

    private class FileNameRenderer extends DefaultTreeCellRenderer { 
     @Override 
     public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) { 
      JComponent c = (JComponent) super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus); 

      return new Holder((JLabel) c); 
     } 
    } 

    private class CheckBoxNodeEditor extends AbstractCellEditor implements TreeCellEditor { 
     FileNameRenderer renderer = new FileNameRenderer(); 
     ChangeEvent changeEvent = null; 
     JTree t; 
     TreePath path; 

     public CheckBoxNodeEditor(JTree tree) { 
      t = tree; 
     } 

     public Object getCellEditorValue() { 
      Holder checkBoxNode = new Holder(new JLabel((((DefaultMutableTreeNode) path.getLastPathComponent()).getUserObject().toString()))); 
      return checkBoxNode; 
     } 

     public boolean isCellEditable(EventObject event) { 
      if(event instanceof MouseEvent) { 
       MouseEvent mouseEvent = (MouseEvent) event; 
       path = t.getPathForLocation(mouseEvent.getX(), mouseEvent.getY()); 
       if (path != null) { 
        Object node = path.getLastPathComponent(); 
        if ((node != null) && (node instanceof DefaultMutableTreeNode)) { 
         DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode) node; 
         Object userObject = treeNode.getUserObject(); 
         return (userObject instanceof String); 
        } 
       } 
      } 
      return false; 
     } 

     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); 
      ItemListener itemListener = new ItemListener() { 
       public void itemStateChanged(ItemEvent itemEvent) { 
        if (stopCellEditing()) 
         fireEditingStopped(); 
       } 
      }; 

      if (editor instanceof JToggleButton) { 
       ((JToggleButton) editor).addItemListener(itemListener); 
      } 

      return editor; 
     } 
    } 

    private class Holder extends JPanel { 
     public Holder(Component c) { 
      setLayout(new GridBagLayout()); 
      setBackground(Color.BLACK); 
      setOpaque(false); 
      addComponents(c); 
     } 

     private void addComponents(Component c) { 
      GridBagConstraints gBC = new GridBagConstraints(); 

      gBC.insets = new Insets(0, 0, 0, 5); 
      add(c, gBC); 

      gBC.insets = new Insets(0, 0, 0, 0); 
      add(new DefaultChkBx(), gBC); 
      add(new FavouriteChkBx(), gBC); 
     } 
    } 

    private class DefaultChkBx extends JToggleButton { 
     public DefaultChkBx() { 
      setUI(new MetalToggleButtonUI() { 
       @Override 
       protected Color getSelectColor() { 
        return new Color(242, 0, 255); 
       } 
      }); 
      setBorder(null); 
      setForeground(Color.GRAY); 
      setText("Default"); 
      setFocusPainted(false); 
     } 
    } 

    private class FavouriteChkBx extends JToggleButton { 
     public FavouriteChkBx() { 
      setUI(new MetalToggleButtonUI() { 
       @Override 
       protected Color getSelectColor() { 
        return Color.RED; 
       } 
      }); 
      setBorder(null); 
      setForeground(Color.GRAY); 
      setText("Favourite"); 
      setFocusPainted(false); 
     } 
    } 
} 

回答

3

在我看来,你的问题是你的“模式”:您正在使用普通的香草DefaultMutableTreeNode对象为您的节点,一类是无法保存的最重要数据 - 按钮的状态。

而是考虑

  1. 使用一个类从DefaultMutableTreeNode延伸,一个有两个布尔值,将由渲染器用来告诉按钮什么状态下显示的值。
  2. 或者使用DefaultMutableTreeNode作为“包装器”,方法是将DefaultMutableTreeNode传递给保存文本的对象以及JToggleButton用来显示其状态的两个布尔字段。
+0

感谢您的回答,我采取了您列出的第一种方法,以使其工作 – Dan