复合JTree节点允许事件传递到下面的对象 [英] Compound JTree Node allowing events to pass through to objects underneath

查看:131
本文介绍了复合JTree节点允许事件传递到下面的对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试创建一个JTree,其中一些节点是包含JLabel和JButton的复合对象。 Node表示JLabel显示的服务器和端口,JButton将使用Desktop API打开默认浏览器并转到URL。

I'm trying to create a JTree in which some nodes are compound objects containing a JLabel and a JButton. The Node is representing a server and port shown by the JLabel, the JButton will use the Desktop API to open the default browser and go to the URL.

我已阅读过已经跟随他们,并尽可能地密切关注他们。节点显示我想要的方式(主要是 - 我可以处理以后更好)但当我尝试点击按钮时,JTree正在响应事件,而不是按钮。

I have read the following already and have followed them as closely as I can. The Node is displayed how I want it (mostly - I can deal with making it nicer later) but when I try to click on the button the JTree is responding to the events, not the button.

java swing:添加自定义图形按钮JTree项目

http://www.java2s.com/Code/Java/Swing-JFC/TreeCellRenderer.htm

https://stackoverflow.com/a/3769158/1344282

我需要知道如何允许事件通过JTree,以便它们由下面的对象(JButton或JLabel)处理。

I need to know how to allow the events to pass through the JTree so that they are handled by the object(s) underneath - the JButton or JLabel.

这是我的TreeCellEditor:

Here is my TreeCellEditor:

public class UrlValidationCellEditor extends DefaultTreeCellEditor
{
    public UrlValidationCellEditor(JTree tree, DefaultTreeCellRenderer renderer)
    {
        super(tree, renderer);
    }

    @Override
    public Component getTreeCellEditorComponent(JTree tree, Object value,
            boolean isSelected, boolean expanded, boolean leaf, int row)
    {
        return renderer.getTreeCellRendererComponent(tree, value, true, expanded, leaf, row, true);
    }

    @Override
    public boolean isCellEditable(EventObject anEvent)
    {
        return true; // Or make this conditional depending on the node
    }
}

这里是TreeCellRenderer:

Here is the TreeCellRenderer:

public class UrlValidationRenderer extends DefaultTreeCellRenderer implements TreeCellRenderer
{
    JLabel titleLabel;
    UrlGoButton goButton;

    JPanel renderer;

    DefaultTreeCellRenderer defaultRenderer = new DefaultTreeCellRenderer();

    public UrlValidationRenderer()
    {
        renderer = new JPanel(new GridLayout(1, 2));
        titleLabel = new JLabel(" ");
        titleLabel.setForeground(Color.blue);
        renderer.add(titleLabel);
        goButton = new UrlGoButton();
        renderer.add(goButton);
        renderer.setBorder(BorderFactory.createLineBorder(Color.black));
        backgroundSelectionColor = defaultRenderer
            .getBackgroundSelectionColor();
        backgroundNonSelectionColor = defaultRenderer
            .getBackgroundNonSelectionColor();
    }

    @Override
    public Component getTreeCellRendererComponent(JTree tree, Object value,
      boolean selected, boolean expanded, boolean leaf, int row,
      boolean hasFocus)
    {
        Component returnValue = null;
        if ((value != null) && (value instanceof DefaultMutableTreeNode))
        {
          Object userObject = ((DefaultMutableTreeNode) value)
              .getUserObject();
          if (userObject instanceof UrlValidation)
          {
                UrlValidation validationResult = (UrlValidation) userObject;
                titleLabel.setText(validationResult.getServer()+":"+validationResult.getPort());
                goButton.setUrl(validationResult.getUrl());

                if (selected) {
                  renderer.setBackground(backgroundSelectionColor);
                } else {
                  renderer.setBackground(backgroundNonSelectionColor);
                }
                renderer.setEnabled(tree.isEnabled());
                returnValue = renderer;
          }
        }
        if (returnValue == null)
        {
          returnValue = defaultRenderer.getTreeCellRendererComponent(tree,
              value, selected, expanded, leaf, row, hasFocus);
        }
        return returnValue;
    }

}

我将不胜感激任何见解或建议。谢谢!

I would appreciate any insight or suggestions. Thanks!

推荐答案

渲染器不能这样工作。它们被用作橡皮图章,这意味着在绘制JList时,实际上只有一个渲染器实例被绘制在整个地方。所以它无法处理鼠标输入,因为对象实际上并不存在 - 它们只是被绘制。

The renderers do not work this way. They are used as rubber stamps, which means that there is really only one instance of renderer that is painted all over the place as the JList is painted. So it cannot handle mouse inputs, as the objects are not really there - they are just painted.

为了将鼠标事件传递给下面的对象,你需要实现一个细胞编辑器。有时,编辑器看起来与渲染器不同(String渲染器是标签,编辑器是文本字段,例如)。遵循这个逻辑,编辑器必须使用组件的另一个实例来实现。

In order to pass mouse events to objects underneath, you need to implement a cell editor. Sometimes, the editor looks different than the renderer (String renderers are labels, editors are textfields, for example). Following this logic, the editor must be implemented using another instance of a component.

现在你要渲染按钮并使用它们进行操作(即编辑)。然后编辑器必须是JButton的另一个实例,与渲染器不同。将按钮实现为渲染器很容易,但棘手的部分是作为编辑器实现。您需要扩展AbstractCellEditor并实现TreeCellEditor 和ActionListener 。然后该按钮是编辑器类的一个字段。在编辑器类的构造函数中,您初始化按钮并添加 this 作为按钮的新动作侦听器。在getTreeCellEditorComponent方法中,您只需返回按钮。在actionPerformed中,您可以在按下按钮时调用您需要执行的任何代码,然后调用stopCellEditing()

Now you are going to render buttons and use them for manipulating (ie. editing). The editor then must be another instance of JButton, distinctive from the renderer. Implementing button as renderer is easy, but the tricky part is to implement is as an editor. You need to extend AbstractCellEditor and implement TreeCellEditor and ActionListener. The button is then a field of the editor class. In the constructor of the editor class, you initialize the button and add this as a new action listener for the button. In the getTreeCellEditorComponent method, you just return the button. In the actionPerformed, you call whatever code you need to do on button press and then call stopCellEditing().

这种方式对我有用。

我制作了一个SSCCE来演示String Tree上的用法

I made a SSCCE that demonstrates the usage on a String Tree

public class Start
{
    public static class ButtonCellEditor extends AbstractCellEditor implements TreeCellEditor, ActionListener, MouseListener
    {
        private JButton button;
        private JLabel label;
        private JPanel panel;
        private Object value;

        public ButtonCellEditor(){
            panel = new JPanel(new BorderLayout());
            button = new JButton("Press me!");
            button.addActionListener(this);
            label = new JLabel();
            label.addMouseListener(this);
            panel.add(button, BorderLayout.EAST);
            panel.add(label);
        }

        @Override public Object getCellEditorValue(){
            return value.toString();
        }

        @Override public void actionPerformed(ActionEvent e){
            String val = value.toString();
            System.out.println("Pressed: " + val);
            stopCellEditing();
        }

        @Override public Component getTreeCellEditorComponent(JTree tree, Object value, boolean isSelected, boolean expanded, boolean leaf, int row){
            this.value = value;
            label.setText(value.toString());
            return panel;
        }

        @Override public void mouseClicked(MouseEvent e){
        }

        @Override public void mousePressed(MouseEvent e){
            String val = value.toString();
            System.out.println("Clicked: " + val);
            stopCellEditing();
        }

        @Override public void mouseReleased(MouseEvent e){
        }

        @Override public void mouseEntered(MouseEvent e){
        }

        @Override public void mouseExited(MouseEvent e){
        }

    }

    public static class ButtonCellRenderer extends JPanel implements TreeCellRenderer
    {
        JButton button;
        JLabel label;

        ButtonCellRenderer(){
            super(new BorderLayout());
            button = new JButton("Press me!");
            label = new JLabel();
            add(button, BorderLayout.EAST);
            add(label);
        }

        @Override public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus){
            label.setText(value.toString());
            return this;
        }

    }

    public static void main(String[] args){
        JTree tree = new JTree();
        tree.setEditable(true);
        tree.setCellRenderer(new ButtonCellRenderer());
        tree.setCellEditor(new ButtonCellEditor());

        JFrame test = new JFrame();
        test.add(new JScrollPane(tree));
        test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        test.setSize(500, 500);
        test.setLocationRelativeTo(null);
        test.setVisible(true);
    }
}

这篇关于复合JTree节点允许事件传递到下面的对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆