MouseListener на кнопке, отображаемой в строке JTree в Java

Я заблокирован с проблемой о Java и использовании JTree:

Я хочу создать JTree с, узел за узлом, некоторыми компонентами JButtons (или изображениями, я не возражаю), как на следующем рисунке. Это будет 3 или 4 кнопки в одном ряду. Мне это удается.

введите здесь описание изображения

Но где я заблокирован, так это когда я хочу добавить прослушиватель мыши на каждую из этих кнопок, чтобы управлять их всплывающей подсказкой или действием над ними. На самом деле компонент JTree большую часть времени используется для управления действиями на полном узле, а не на его внутренних компонентах.

Я сделал короткий код, по сравнению с действительно большим кодом, с которым мне приходится работать, чтобы быстро проверить то, что я говорю:

import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.tree.*;

import java.awt.event.*;
import java.awt.*;
import java.io.IOException;
import java.net.URL;

public class TreeWithPopup extends JPanel {

    DefaultMutableTreeNode root, node1, node2, node3;

    public TreeWithPopup() {
        MyJTree tree;
        root = new DefaultMutableTreeNode("root", true);
        node1 = new DefaultMutableTreeNode("node 1", true);
        node2 = new DefaultMutableTreeNode("node 2", true);
        node3 = new DefaultMutableTreeNode("node 3", true);
        root.add(node1);
        node1.add(node2);
        root.add(node3);
        setLayout(new BorderLayout());
        tree = new MyJTree(root);
        tree.setCellRenderer(new PCellRenderer());
        add(new JScrollPane((JTree) tree), "Center");
    }

    public Dimension getPreferredSize() {
        return new Dimension(300, 300);
    }

    public static void main(String s[]) {
        JFrame frame = new JFrame("Tree with button");
        TreeWithPopup panel = new TreeWithPopup();
        frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
        frame.setForeground(Color.black);
        frame.setBackground(Color.lightGray);
        frame.getContentPane().add(panel, "Center");
        frame.setSize(panel.getPreferredSize());
        frame.setVisible(true);
        frame.addWindowListener(new WindowCloser());
    }
}

class WindowCloser extends WindowAdapter {
    public void windowClosing(WindowEvent e) {
        Window win = e.getWindow();
        win.setVisible(false);
        System.exit(0);
    }
}

class MyJTree extends JTree implements ActionListener {

    MyJTree(DefaultMutableTreeNode dmtn) {
        super(dmtn);
        addMouseListener(new MouseListener() {
            public void mouseClicked(MouseEvent arg0) {
                System.out.println("JTree.MouseListener");
            }

            public void mouseEntered(MouseEvent arg0) {
                System.out.println("JTree.MouseListener");
            }

            public void mouseExited(MouseEvent arg0) {
                System.out.println("JTree.MouseListener");
            }

            public void mousePressed(MouseEvent arg0) {
                System.out.println("JTree.MouseListener");
            }

            public void mouseReleased(MouseEvent arg0) {
                System.out.println("JTree.MouseListener");
            }
        });

    }

    public void actionPerformed(ActionEvent ae) {
        System.out.println("MyJTree.ActionPerformed");
    }

}

class PCellRenderer extends DefaultTreeCellRenderer {
    public Component getTreeCellRendererComponent(JTree ptree, Object pvalue, boolean psel, boolean pexpanded, boolean pleaf, int prow,
            boolean phasFocus) {
        Box myPanel = new Box(BoxLayout.X_AXIS);

        JButton myButton = new JButton("test");
        Image imgToUse = null;
        Image imgRollOver = null;
        try {
            URL urlIcon = new URL("file:///C:/1.jpg"); // <===== change their the path to icons
            imgToUse = ImageIO.read(urlIcon);
            urlIcon = new URL("file:///C:/2.jpg"); // <===== change their the path to icons
            imgRollOver = ImageIO.read(urlIcon);
        } catch (IOException e) {
            e.printStackTrace();
        }
        myButton.setRolloverIcon(new ImageIcon(imgRollOver));
        myButton.setIcon(new ImageIcon(imgToUse));
        myButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                System.out.println(" detected on ");
            }
        });

        myButton.addMouseListener(new MouseListener() {
            public void mouseClicked(MouseEvent arg0) {
                System.out.println("myButton.MouseListener");
            }

            public void mouseEntered(MouseEvent arg0) {
                System.out.println("myButton.MouseListener");
            }

            public void mouseExited(MouseEvent arg0) {
                System.out.println("myButton.MouseListener");
            }

            public void mousePressed(MouseEvent arg0) {
                System.out.println("myButton.MouseListener");
            }

            public void mouseReleased(MouseEvent arg0) {
                System.out.println("myButton.MouseListener");
            }
        });
        myPanel.add(myButton);

        return myPanel;
    }
}

Вам просто нужно изменить путь к значку или поместить два следующих значка в «c:/»

введите здесь описание изображения

введите здесь описание изображения

Я также пытался использовать положение x/y события строки, но мне не удалось найти положение моей кнопки после рендеринга.

Если у кого-то есть идея, как это сделать, он может быть очень полезным.

Спасибо, хотя бы за то, что прочитали этот вопрос ;-)


person user954156    schedule 30.05.2013    source источник
comment
Поддержка всплывающих подсказок будет предоставляться непосредственно средством визуализации. Установите текст всплывающей подсказки компонента, который использовался для рендеринга ячейки дерева напрямую.   -  person MadProgrammer    schedule 30.05.2013


Ответы (1)


Поддержка всплывающих подсказок на самом деле обеспечивается TableCellRenderer напрямую. Ваш TableCellRenderer немного запутался. Он расширяется от DefaultTreeCellRenderer, но не использует ни одну из его функций, вместо этого создает новые Box, JButton и загружает значки каждый раз, когда ячейка визуализируется...

Это увеличит использование памяти, замедляя работу вашего приложения...

Вместо этого попробуйте что-то вроде...

class PCellRenderer extends Box implements TreeCellRenderer {

    private Image imgToUse = null;
    private Image imgRollOver = null;

    public PCellRenderer() {
        super(BoxLayout.X_AXIS);

        JButton myButton = new JButton("test");
        try {
            URL urlIcon = new URL("file:///C:/1.jpg"); // <===== change their the path to icons
            imgToUse = ImageIO.read(urlIcon);
            urlIcon = new URL("file:///C:/2.jpg"); // <===== change their the path to icons
            imgRollOver = ImageIO.read(urlIcon);
        } catch (IOException e) {
            e.printStackTrace();
        }
        myButton.setRolloverIcon(new ImageIcon(imgRollOver));
        myButton.setIcon(new ImageIcon(imgToUse));

        add(myButton);
    }

    public Component getTreeCellRendererComponent(JTree ptree, Object pvalue, boolean psel, boolean pexpanded, boolean pleaf, int prow,
            boolean phasFocus) {
        // set the tooltip text here...
        // Maybe change the icon...
        return this;
    }
}

Теперь, действительно, что-то делать...

Рендереры — это резиновые штампы. На самом деле это не компоненты жизни. Думайте о них, как о фотографиях. Вы можете сделать снимок своих друзей, но вы не можете взаимодействовать с ними... то же самое и здесь...

Ваша идея MouseListener на JTree верна, на самом деле JavaDocs действительно демонстрирует это...

public void mousePressed(MouseEvent e) {
    int selRow = tree.getRowForLocation(e.getX(), e.getY());
    TreePath selPath = tree.getPathForLocation(e.getX(), e.getY());
    if(selRow != -1) {
        if(e.getClickCount() == 1) {
            mySingleClick(selRow, selPath);
        }
        else if(e.getClickCount() == 2) {
            myDoubleClick(selRow, selPath);
        }
    }
}
person MadProgrammer    schedule 30.05.2013
comment
Спасибо за ответ, но: класс, который вы предлагаете изменить для реализации TableCellRenderer, похоже, используется JTable, мой JTree отказывается его использовать (компилятор). Кроме того, пример, полученный из JavaDocs, полезен, если я не ошибаюсь, чтобы узнать, нажали ли вы на строку/узел или на пробел. На самом деле я не могу поместить этот код на свою кнопку, потому что действие вообще не запускается, и в этом проблема. - person user954156; 30.05.2013
comment
Мой плохой обновленный пример. Проблема в том, что ваша кнопка никогда не сработает. Лучшее, что вы можете сделать, это определить, когда щелкнули строку, а затем определить, заполняет ли щелчок границы средства визуализации ячеек. - person MadProgrammer; 30.05.2013