在同一个 JTree 中使用两个不同的对象时,JTree 和 CellEditor 无法正常工作

JTree and CellEditor not working correctly when using two different objects in the same JTree

我目前在使用 JTree 的单元格编辑器时遇到问题。我的 JTree 中有两个不同的对象,Users 和 Books。

所以用户是Bianca,书籍是节点。这些节点内的标签(眼睛、油漆标签和垃圾桶)也是可点击的。但是,当我设置我的单元格编辑器时,它给了我一个空异常。我认为这是因为我正在处理两个不同的对象,所以我无法正确设置单元格编辑器。这是我认为有问题的具体方法:

public Component getTreeCellEditorComponent(JTree tree, Object value, boolean isSelected, boolean expanded,
        boolean leaf, int row) {
    Component returnValue = null;
    System.out.println("loo");
    if ((value != null) && (value instanceof DefaultMutableTreeNode)) {
        Object userObject = ((DefaultMutableTreeNode) value)
                .getUserObject();
        System.out.println("b");
        if(userObject instanceof Book){
            Book feature = (Book) userObject;
            title.setText(feature.getTitulo());
            renderer.setEnabled(tree.isEnabled());
            returnValue = renderer;
            System.out.println("hi!!");
        }
    }
    if (returnValue == null) {
        System.out.println("hi1");
        returnValue = defaultEditor.getTreeCellEditorComponent(tree, value, isSelected, expanded, leaf, row);
        System.out.println(defaultEditor);

    } 
    return returnValue;
}

当节点类型不是 Book 时,我不知道如何 return DefaultCellEditor。

如果有人想重现这个问题,下面是我的完整代码:

Class 书:

public class Book {
    String titulo;

    public String getTitulo() {
        return titulo;
    }

    public void setTitulo(String titulo) {
        this.titulo = titulo;
    }
    public Book(String titulo){
        this.titulo = titulo;
    }
}

Class 用户

public class User {
    String nomeUser;

    public String getNomeUser() {
        return nomeUser;
    }

    public void setNomeUser(String nomeUser) {
        this.nomeUser = nomeUser;
    }
    public User(String nome){
        this.nomeUser = nome;
    }
}

Class Render(用于设置JTree的cell editor和cell render)

import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.IOException;
import java.io.InputStream;

import javax.imageio.ImageIO;
import javax.swing.AbstractCellEditor;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.TreeCellEditor;
import javax.swing.tree.TreeCellRenderer;


public class Render{
public static class NodeCellRenderer implements TreeCellRenderer{
        private JLabel nomeRadar;
        private JPanel renderer;
        private JLabel btnVisible;
        private JLabel btnPaint;
        private JLabel btnTrash;

        DefaultTreeCellRenderer defaultRenderer = new DefaultTreeCellRenderer();
        public NodeCellRenderer() throws IOException{
            renderer = new JPanel(new FlowLayout(5, 5,5));
            nomeRadar = new JLabel();
            renderer.add(nomeRadar);
            btnVisible = new JLabel();
            btnPaint = new JLabel();
            btnTrash = new JLabel();
            InputStream visible = getClass().getResourceAsStream("/eye_visible-16.png");
            InputStream invisible = getClass().getResourceAsStream("/eye_invisible-16.png");
            InputStream paint = getClass().getResourceAsStream("/paint-16.png");
            InputStream trash = getClass().getResourceAsStream("/trash-16.png");
            btnVisible.setIcon(new ImageIcon(ImageIO.read(visible)));
            btnPaint.setIcon(new ImageIcon(ImageIO.read(paint)));
            btnTrash.setIcon(new ImageIcon(ImageIO.read(trash)));
            nomeRadar.addMouseListener(new MouseAdapter(){

                public void mouseClicked(MouseEvent e){
                    System.out.println("clicou no nome");
                }
            });
            btnVisible.addMouseListener(new MouseAdapter(){
                public void mouseClicked(MouseEvent e){
                    System.out.println("clicou no olho");
                }
            });
            btnPaint.addMouseListener(new MouseAdapter(){
                public void mouseClicked(MouseEvent e){
                    System.out.println("clicou no paint");
                }
            });
            btnTrash.addMouseListener(new MouseAdapter(){
                public void mouseClicked(MouseEvent e){
                    System.out.println("clicou no trash");
                }
            });
            renderer.add(nomeRadar);
            renderer.add(btnVisible);
            renderer.add(btnPaint);
            renderer.add(btnTrash);

        }
        @Override
        public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf,
                int row, boolean hasFocus) {
            Component returnValue = null;
            // TODO Auto-generated method stub
            if ((value != null) && (value instanceof DefaultMutableTreeNode)) {
                Object userObject = ((DefaultMutableTreeNode) value)
                        .getUserObject();
                if(userObject instanceof Book){
                    Book feature = (Book) userObject;
                    nomeRadar.setText(feature.getTitulo());
                    renderer.setEnabled(tree.isEnabled());
                    returnValue = renderer;
                }
            }
            if (returnValue == null) {
                returnValue = defaultRenderer.getTreeCellRendererComponent(tree,
                        value, selected, expanded, leaf, row, hasFocus);
            }
            return returnValue;
        }

    }
    public static class ButtonCellEditor extends AbstractCellEditor implements TreeCellEditor, ActionListener, MouseListener
    {
        /**
         * 
         */
        private static final long serialVersionUID = 1L;
        TreeCellEditor defaultEditor = JTreeOfObjects.currentStyle;
        JLabel title;
        JPanel renderer;
        JLabel btnVisible;
        JLabel btnPaint;
        JLabel btnTrash;
        private Object value;

        public ButtonCellEditor() throws IOException{
            renderer = new JPanel(new FlowLayout(5, 5,5));
            System.out.println("ulo");
            title = new JLabel();
            renderer.add(title);
            btnVisible = new JLabel();
            btnPaint = new JLabel();
            btnTrash = new JLabel(); 
            InputStream visible = getClass().getResourceAsStream("/eye_visible-16.png");
            InputStream invisible = getClass().getResourceAsStream("/eye_invisible-16.png");
            InputStream paint = getClass().getResourceAsStream("/paint-16.png");
            InputStream trash = getClass().getResourceAsStream("/trash-16.png");
            btnVisible.setIcon(new ImageIcon(ImageIO.read(visible)));
            btnPaint.setIcon(new ImageIcon(ImageIO.read(paint)));
            btnTrash.setIcon(new ImageIcon(ImageIO.read(trash)));
            System.out.println("nossa 1");
            title.addMouseListener(new MouseAdapter(){

                public void mouseClicked(MouseEvent e){
                    System.out.println("clicou no nome");
                    stopCellEditing();
                }
            });
            btnVisible.addMouseListener(new MouseAdapter(){
                public void mouseClicked(MouseEvent e){
                    System.out.println("clicou no olho");
                    stopCellEditing();
                }
            });
            btnPaint.addMouseListener(new MouseAdapter(){
                public void mouseClicked(MouseEvent e){
                    System.out.println("clicou no paint");
                    stopCellEditing();
                }
            });
            btnTrash.addMouseListener(new MouseAdapter(){
                public void mouseClicked(MouseEvent e){
                    System.out.println("clicou no trash");
                    stopCellEditing();
                }
            });
            renderer.add(title);
            renderer.add(btnVisible);
            renderer.add(btnPaint);
            renderer.add(btnTrash); 
        }


        @Override
        public Object getCellEditorValue() {
            // TODO Auto-generated method stub
            //return value.toString();
            return null;
        }


        @Override
        public void mouseClicked(MouseEvent e) {
            // TODO Auto-generated method stub
            System.out.println("clicou no b");
            stopCellEditing();
        }


        @Override
        public void mouseEntered(MouseEvent e) {
            // TODO Auto-generated method stub

        }


        @Override
        public void mouseExited(MouseEvent e) {
            // TODO Auto-generated method stub

        }


        @Override
        public void mousePressed(MouseEvent e) {
            // TODO Auto-generated method stub
            System.out.println("clicou no d");
            stopCellEditing();
        }


        @Override
        public void mouseReleased(MouseEvent e) {
            // TODO Auto-generated method stub

        }


        @Override
        public void actionPerformed(ActionEvent e) {
            // TODO Auto-generated method stub
            System.out.println("clicou no a");
            stopCellEditing();

        }


        @Override
        public Component getTreeCellEditorComponent(JTree tree, Object value, boolean isSelected, boolean expanded,
                boolean leaf, int row) {
            Component returnValue = null;
            System.out.println("loo");
            if ((value != null) && (value instanceof DefaultMutableTreeNode)) {
                Object userObject = ((DefaultMutableTreeNode) value)
                        .getUserObject();
                System.out.println("b");
                if(userObject instanceof Book){
                    Book feature = (Book) userObject;
                    title.setText(feature.getTitulo());
                    renderer.setEnabled(tree.isEnabled());
                    returnValue = renderer;
                    System.out.println("hi!!");
                }
            }
            if (returnValue == null) {
                System.out.println("hi1");
                returnValue = defaultEditor.getTreeCellEditorComponent(tree, value, isSelected, expanded, leaf, row);
                System.out.println(defaultEditor);

            } 
            return returnValue;
        }


    }
}

Class JTreeOfObjects

public class JTreeOfObjects {


    public static TreeCellRenderer renderer;
    private JFrame frame;
    public static JTree tree;
    private DefaultTreeModel model;
    private DefaultMutableTreeNode parent;
    JLabel nomeRadar;
    JLabel btnVisible;
    JLabel btnPaint;
    JLabel btnTrash;
    public static TreeCellEditor currentStyle;
    public void initialize() throws IOException{
        frame = new JFrame("Árvore de Navegação");
        parent = new DefaultMutableTreeNode("Library",true);
        //DefaultMutableTreeNode undefined = new DefaultMutableTreeNode("Indefinida");
        //undefined.add(new DefaultMutableTreeNode("!"));
        System.out.println(parent.getUserObject());

        //parent.add(undefined);
        tree = new JTree(parent);
        System.out.println("Current"+tree.getCellEditor());
        //currentStyle = tree.getCellEditor();
        renderer  = new Render.NodeCellRenderer();
        model = (DefaultTreeModel) tree.getModel();

        tree.setEditable(true);
        tree.setCellRenderer(renderer);
        tree.setCellEditor(new Render.ButtonCellEditor());
        //frame.getContentPane().add(tree);
        nomeRadar = new JLabel();
        btnVisible = new JLabel();
        btnPaint = new JLabel();
        btnTrash = new JLabel(); 
        InputStream visible = getClass().getResourceAsStream("/eye_visible-16.png");
        InputStream invisible = getClass().getResourceAsStream("/eye_invisible-16.png");
        InputStream paint = getClass().getResourceAsStream("/paint-16.png");
        InputStream trash = getClass().getResourceAsStream("/trash-16.png");
        btnVisible.setIcon(new ImageIcon(ImageIO.read(visible)));
        btnPaint.setIcon(new ImageIcon(ImageIO.read(paint)));
        btnTrash.setIcon(new ImageIcon(ImageIO.read(trash)));
        frame.getContentPane().add(btnPaint);
        frame.getContentPane().add(btnVisible);
        frame.getContentPane().add(btnTrash);
        frame.getContentPane().add(tree);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setUndecorated(true);
        frame.getRootPane().setWindowDecorationStyle(JRootPane.PLAIN_DIALOG);
        frame.setSize(200, 200);
        frame.setVisible(true);

    }
    public void adicionarNoCamada(String nomePessoa){
        //DefaultTreeModel model = (DefaultTreeModel)tree.getModel();

        DefaultMutableTreeNode noCamada = new DefaultMutableTreeNode(nomePessoa);
        parent.add(noCamada);


    }
    public void adicionarLivro(String nomeCamada,Book feature) throws IOException{
        //tree.get
        DefaultMutableTreeNode node = null;
        Enumeration e = parent.breadthFirstEnumeration();
        while(e.hasMoreElements()){
            node = (DefaultMutableTreeNode) e.nextElement();
            if(nomeCamada.equals(node.getUserObject().toString())){
                node.add(new DefaultMutableTreeNode(feature));
                break;
            }
            else{

            }
        }
        tree.setCellEditor(new Render.ButtonCellEditor());
    }

}

Class 主应用程序

public class MainApp {

    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        Book b1 = new Book("The Book of Life");
        Book b2 = new Book ("The Book of Death");
        User u1 = new User("Bianca");
        JTreeOfObjects object = new JTreeOfObjects();
        object.initialize();
        object.adicionarNoCamada(u1.getNomeUser());
        object.adicionarLivro(u1.getNomeUser(), b1);
        object.adicionarLivro(u1.getNomeUser(), b2);

    }

}

如有任何帮助,我们将不胜感激。它不是重复的,因为我知道如何修复 NullPointer 异常(必须实例化对象)。我只是不知道在 TreeCellEditor 的情况下 return 是什么,如何 return 它的默认值。

您可能需要覆盖 CellEditor#isCellEditable(...)CellEditor#getCellEditorValue(),但我不确定这是否能满足您的需求。

  @Override public boolean isCellEditable(EventObject e) {
    Object source = e.getSource();
    if (!(source instanceof JTree) || !(e instanceof MouseEvent)) {
      return false;
    }
    JTree tree = (JTree) source;
    Point p = ((MouseEvent) e).getPoint();
    Object node = tree.getPathForLocation(p.x, p.y).getLastPathComponent();
    if (!(node instanceof DefaultMutableTreeNode)) {
      return false;
    }
    Object userObject = ((DefaultMutableTreeNode) node).getUserObject();
    if (!(userObject instanceof Book)) {
      return false;
    }
    return super.isCellEditable(e);
  }

  @Override
  public Object getCellEditorValue() {
    return new Book(renderer.nomeRadar.getText());
  }

这是一个简单的例子:

import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.tree.*;

public class MainApp2 {
  public JComponent makeUI() {
    JTree tree = new JTree(makeModel());
    tree.setEditable(true);
    tree.setCellRenderer(new NodeCellRenderer());
    tree.setCellEditor(new ButtonCellEditor());

    JPanel p = new JPanel(new BorderLayout());
    p.add(new JScrollPane(tree));
    return p;
  }
  private static DefaultMutableTreeNode makeModel() {
    Book b1 = new Book("The Book of Life");
    Book b2 = new Book("The Book of Death");
    User u1 = new User("Bianca");

    DefaultMutableTreeNode noCamada = new DefaultMutableTreeNode(u1);
    noCamada.add(new DefaultMutableTreeNode(b1));
    noCamada.add(new DefaultMutableTreeNode(b2));

    DefaultMutableTreeNode root = new DefaultMutableTreeNode("Library", true);
    root.add(noCamada);
    return root;
  }
  public static void main(String[] args) {
    EventQueue.invokeLater(() -> {
      JFrame f = new JFrame("Arvore de Navegacao");
      f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
      f.getContentPane().add(new MainApp2().makeUI());
      f.setSize(320, 240);
      f.setLocationRelativeTo(null);
      f.setVisible(true);
    });
  }
}

class NodePanel extends JPanel {
  public final JLabel nomeRadar = new JLabel();
  public final JLabel btnVisible = new JLabel(new ColorIcon(Color.RED));
  public final JLabel btnPaint = new JLabel(new ColorIcon(Color.GREEN));
  public final JLabel btnTrash = new JLabel(new ColorIcon(Color.BLUE));
  protected NodePanel() {
    super(new FlowLayout(FlowLayout.LEADING, 5, 5));
    add(nomeRadar);
    add(btnVisible);
    add(btnPaint);
    add(btnTrash);
  }
}

class NodeCellRenderer implements TreeCellRenderer {
  private final DefaultTreeCellRenderer defaultRenderer = new DefaultTreeCellRenderer();
  private final NodePanel renderer = new NodePanel();

  @Override public Component getTreeCellRendererComponent(
      JTree tree, Object value, boolean selected, boolean expanded,
      boolean leaf, int row, boolean hasFocus) {
    Component returnValue = null;
    if (value instanceof DefaultMutableTreeNode) {
      Object userObject = ((DefaultMutableTreeNode) value).getUserObject();
      if (userObject instanceof Book) {
        Book feature = (Book) userObject;
        renderer.nomeRadar.setText(feature.getTitulo());
        returnValue = renderer;
      }
    }
    if (returnValue == null) {
      returnValue = defaultRenderer.getTreeCellRendererComponent(
          tree, value, selected, expanded, leaf, row, hasFocus);
    }
    return returnValue;
  }
}

class ButtonCellEditor extends AbstractCellEditor implements TreeCellEditor {
  private final DefaultTreeCellRenderer defaultRenderer = new DefaultTreeCellRenderer();
  private final NodePanel renderer = new NodePanel();

  public ButtonCellEditor() {
    renderer.setBackground(Color.ORANGE);
    renderer.nomeRadar.addMouseListener(new MouseAdapter() {
      @Override public void mousePressed(MouseEvent e) {
        System.out.println("clicou no nome");
        stopCellEditing();
      }
    });
    renderer.btnVisible.addMouseListener(new MouseAdapter() {
      @Override public void mousePressed(MouseEvent e) {
        System.out.println("clicou no olho");
        stopCellEditing();
      }
    });
    renderer.btnPaint.addMouseListener(new MouseAdapter() {
      public void mousePressed(MouseEvent e) {
        System.out.println("clicou no paint");
        stopCellEditing();
      }
    });
    renderer.btnTrash.addMouseListener(new MouseAdapter() {
      public void mousePressed(MouseEvent e) {
        System.out.println("clicou no trash");
        stopCellEditing();
      }
    });
    renderer.addMouseListener(new MouseAdapter() {
      public void mousePressed(MouseEvent e) {
        System.out.println("renderer");
        stopCellEditing();
      }
    });
  }

  @Override public boolean isCellEditable(EventObject e) {
    Object source = e.getSource();
    if (!(source instanceof JTree) || !(e instanceof MouseEvent)) {
      return false;
    }
    JTree tree = (JTree) source;
    Point p = ((MouseEvent) e).getPoint();
    TreePath path = tree.getPathForLocation(p.x, p.y);
    if (Objects.isNull(path)) {
      return false;
    }
    Object node = path.getLastPathComponent();
    if (!(node instanceof DefaultMutableTreeNode)) {
      return false;
    }
    Object userObject = ((DefaultMutableTreeNode) node).getUserObject();
    if (!(userObject instanceof Book)) {
      return false;
    }
    return super.isCellEditable(e);
  }

  @Override
  public Object getCellEditorValue() {
    return new Book(renderer.nomeRadar.getText());
  }

  @Override
  public Component getTreeCellEditorComponent(
      JTree tree, Object value, boolean isSelected, boolean expanded,
      boolean leaf, int row) {
    Component returnValue = null;
    if (value instanceof DefaultMutableTreeNode) {
      Object userObject = ((DefaultMutableTreeNode) value).getUserObject();
      if (userObject instanceof Book) {
        Book feature = (Book) userObject;
        renderer.nomeRadar.setText(feature.getTitulo());
        returnValue = renderer;
      }
    }
    if (returnValue == null) {
      returnValue = defaultRenderer.getTreeCellRendererComponent(
          tree, value, isSelected, expanded, leaf, row, true);
    }
    return returnValue;
  }
}

class Book {
  String titulo;
  public String getTitulo() {
    return titulo;
  }
  public void setTitulo(String titulo) {
    this.titulo = titulo;
  }
  public Book(String titulo) {
    this.titulo = titulo;
  }
}

class User {
  String nomeUser;
  public String getNomeUser() {
    return nomeUser;
  }
  public void setNomeUser(String nomeUser) {
    this.nomeUser = nomeUser;
  }
  public User(String nome) {
    this.nomeUser = nome;
  }
  @Override public String toString() {
    return nomeUser;
  }
}

class ColorIcon implements Icon {
  private final Color color;
  protected ColorIcon(Color color) {
    this.color = color;
  }
  @Override public void paintIcon(Component c, Graphics g, int x, int y) {
    Graphics2D g2 = (Graphics2D) g.create();
    g2.translate(x, y);
    g2.setPaint(color);
    g2.fillRect(0, 0, getIconWidth(), getIconHeight());
    g2.dispose();
  }
  @Override public int getIconWidth() {
    return 16;
  }
  @Override public int getIconHeight() {
    return 16;
  }
}