java 动态更改 JTree 的节点图像

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2199987/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 20:01:02  来源:igfitidea点击:

Changing the Node image of a JTree dynamically

javaswingjtree

提问by mogli

I am using a CustomCellRenderer to display nodes of a JTree to display image with a node as shown below :-

我正在使用 CustomCellRenderer 来显示 JTree 的节点以显示带有节点的图像,如下所示:-

class CustomTreeCellRenderer extends DefaultTreeCellRenderer{

    public Component getTreeCellRendererComponent(JTree tree,
        Object value, boolean selected, boolean expanded,
        boolean leaf, int row, boolean hasFocus){

        super.getTreeCellRendererComponent(tree, value,
        selected, expanded, leaf, row, hasFocus);

        JLabel label = (JLabel) this ;

        label.setIcon( new ImageIcon("white.png") ) ;

        return this;
    }
}

My requirement is to change image of the node on some external action. I am trying to reload the model of JTree, but it's not working as shown below :-

我的要求是在某些外部操作上更改节点的图像。我正在尝试重新加载 JTree 的模型,但它无法正常工作,如下所示:-

public void actionPerformed(ActionEvent ae) {

        DefaultTreeModel model = (DefaultTreeModel) tree.getModel() ;

        JLabel label = (JLabel) tree.getCellRenderer() ;
        System.out.println(label.getIcon()); //displaying white.png

        label.setIcon( new ImageIcon("black.gif") ) ;


        model.reload() ;
    }

Where I am doing wrong??????

我哪里做错了??????

回答by Laurent K

Add your Icon to your renderer class as a field.

将您的图标作为字段添加到您的渲染器类中。

Change the value of this field and repaint the JTree.

更改此字段的值并重新绘制 JTree。

class CustomTreeCellRenderer extends DefaultTreeCellRenderer{


    ImageIcon rendererIcon;


    public void setRendererIcon(ImageIcon myIcon){
         this.rendererIcon = myIcon;
    };


    public Component getTreeCellRendererComponent(JTree tree,
        Object value, boolean selected, boolean expanded,
        boolean leaf, int row, boolean hasFocus){

        super.getTreeCellRendererComponent(tree, value,
        selected, expanded, leaf, row, hasFocus);

        JLabel label = (JLabel) this ;

        label.setIcon( rendererIcon ) ;

        return this;
    }
}

Edit: explanations

编辑:解释

In your case, it is useless to change the model. The icon used to display each of the nodes is a part of the renderer.

在你的情况下,改变模型是没有用的。用于显示每个节点的图标是渲染器的一部分。

The renderer object of the JTree is not forced to be a JComponent. It has to be an object providing a JComponentwhen the code calls getTreeCellRendererComponent.

JTree 的渲染器对象没有被强制为JComponent. 它必须是一个JComponent在代码调用时提供 a 的对象getTreeCellRendererComponent

In your case, the cast of getCellRenderer() into a JLabel is just plain luck, because the default implementation of the DefaultTreeCellRendereris an extension of JLabel.

在您的情况下,将 getCellRenderer() 转换为 JLabel 只是运气好,因为 的默认实现DefaultTreeCellRendererJLabel.

And, in fact, as your renderer did call setIcon on itself, it's normal that your getIcon methods gives you the last icon you did put into the renderer.

而且,事实上,由于您的渲染器确实在自身上调用了 setIcon,因此您的 getIcon 方法为您提供了您放入渲染器的最后一个图标是正常的。

Full code working :

完整代码工作:

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTree;
import javax.swing.SwingUtilities;
import javax.swing.tree.DefaultTreeCellRenderer;

public class TestJTree {

    private static ImageIcon iconWhite = new ImageIcon("white.jpg");

    private static ImageIcon iconBlack = new ImageIcon("black.jpg");;

    public static void main(String[] args) {
        TestJTree me = new TestJTree();
        me.process();
    }

    private void process() {
        SwingUtilities.invokeLater(new Runnable() {

            public void run() {
                initGui();

            }

        });

    }

    protected void initGui() {
        JFrame frame = new JFrame("Test JTree");
        frame.setContentPane(new JPanel(new BorderLayout()));

        final JTree tree = new JTree();
        frame.getContentPane().add(tree);

        final CustomTreeCellRenderer renderer = new CustomTreeCellRenderer();
        renderer.setRendererIcon(iconWhite);
        tree.setCellRenderer(renderer);

        JPanel panelButtons = new JPanel();

        JButton buttonWhite = new JButton("");
        buttonWhite.setIcon(iconWhite);
        JButton buttonBlack = new JButton("");
        buttonBlack.setIcon(iconBlack);

        buttonBlack.addActionListener(new ActionListener(){

            public void actionPerformed(ActionEvent e) {
                renderer.setRendererIcon(iconBlack);
                tree.repaint();
            }

        });

        panelButtons.add(buttonBlack);
        panelButtons.add(buttonWhite);
        frame.getContentPane().add(panelButtons,BorderLayout.SOUTH);

        frame.setLocationRelativeTo(null);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(500,500);
        frame.setVisible(true);


    }

    @SuppressWarnings("serial")
    private static class CustomTreeCellRenderer extends DefaultTreeCellRenderer{


        ImageIcon rendererIcon;


        public void setRendererIcon(ImageIcon myIcon){
             this.rendererIcon = myIcon;
        };


        public Component getTreeCellRendererComponent(JTree tree,
            Object value, boolean selected, boolean expanded,
            boolean leaf, int row, boolean hasFocus){

            Component ret = super.getTreeCellRendererComponent(tree, value,
            selected, expanded, leaf, row, hasFocus);

            JLabel label = (JLabel) ret ;

            label.setIcon( rendererIcon ) ;

            return ret;
        }
    }
}

回答by akf

a couple points:

几点:

  1. grabbing the renderer from the table in a method like actionPerformedand modifying it is not common practice. You should note that the renderer is shared, so you will be affecting all cells in the column that use that renderer
  2. even though you set the Iconon your renderer instance during actionPerformed, the renderer is always accessed for painting via the getTreeCellRendererComponentmethod, and in that you are always setting the icon to "white.png", so you will never get the "black.gif" to display.
  1. 以类似的方法从表格中抓取渲染器actionPerformed并对其进行修改并不常见。您应该注意渲染器是共享的,因此您将影响列中使用该渲染器的所有单元格
  2. 即使您Icon在 期间actionPerformed在渲染器实例上设置了,渲染器始终可以通过该getTreeCellRendererComponent方法访问以进行绘画,并且您始终将图标设置为“white.png”,因此您永远不会将“black.gif”设置为展示。

An option you have is to set state on the Model in your actionPerformedmethod, and then from within the getTreeCellRendererComponentyou can query your model for the icon to be displayed.

您可以选择在您的actionPerformed方法中在模型上设置状态,然后getTreeCellRendererComponent您可以从模型中查询要显示的图标。

for example:

例如:

public void actionPerformed(ActionEvent ae) {

    MyCustomTreeModel model = (MyCustomTreeModel) tree.getModel() ;
    ...
    model.setMyState(state); //set the state based on the action
}

in the renderer:

在渲染器中:

public Component getTreeCellRendererComponent(JTree tree,
    Object value, boolean selected, boolean expanded,
    boolean leaf, int row, boolean hasFocus)
{
     MyCustomTreeModel model = (MyCustomTreeModel) tree.getModel();
     ....
     setIcon(model.getMyIconBasedOnTheStateISetInActionPerformed());
     return this;    
}