Узел Java JTree представляет собой интерактивную URL-ссылку.

Я пытаюсь сделать node интерактивным URL-адресом, но я просто не могу понять, как это сделать.

Я искал высоко и низко, и я не могу найти решение.

Это мой код:

public class NyttigeLinks {

    private static JFrame nyttigeLinks;

    public static void main(String[] args) {

                    initialize();
            }

    public NyttigeLinks() {

    }

    private static void initialize() {
        nyttigeLinks = new JFrame();
        nyttigeLinks.setBounds(new Rectangle(0, 0, 350, 650));
        nyttigeLinks.getContentPane().setBounds(new Rectangle(0, 0, 350, 650));
        nyttigeLinks.getContentPane().setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);
        nyttigeLinks.getContentPane().setLayout(null);

        JLabel logoLabel = new JLabel("");
        logoLabel.setIcon(new ImageIcon(NyttigeLinks.class.getResource("/images/ssiLogo.jpg")));
        logoLabel.setBounds(0, 0, 350, 60);

        JTree tree = new JTree();

        nyttigeLinks.getContentPane().add(logoLabel);

        JScrollPane scrollPane = new JScrollPane(tree);
        scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
        scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
        scrollPane.setBounds(10, 71, 324, 508);
        nyttigeLinks.getContentPane().add(scrollPane);

        tree.setModel(new DefaultTreeModel(
            new DefaultMutableTreeNode("Nyttige Links\t") {
                {
                    DefaultMutableTreeNode node_1;
                    node_1 = new DefaultMutableTreeNode("Projekt Wiki");
                        node_1.add(new DefaultMutableTreeNode("AO"));
                        node_1.add(new DefaultMutableTreeNode("Attends"));
                        node_1.add(new DefaultMutableTreeNode("Carlsberg"));
                        node_1.add(new DefaultMutableTreeNode("COOP"));
                        node_1.add(new DefaultMutableTreeNode("Dafgaard"));
                        node_1.add(new DefaultMutableTreeNode("Jysk DK"));
                        node_1.add(new DefaultMutableTreeNode("Jysk SE"));
                        node_1.add(new DefaultMutableTreeNode("Kvadrat"));
                        node_1.add(new DefaultMutableTreeNode("Solar"));
                        node_1.add(new DefaultMutableTreeNode("Stockmann"));
                        node_1.add(new DefaultMutableTreeNode("Tine"));
                        node_1.add(new DefaultMutableTreeNode("Unicef"));
                        node_1.add(new DefaultMutableTreeNode("Vectura"));
                    add(node_1);
                    node_1 = new DefaultMutableTreeNode("Helpdesk Norcic");
                        node_1.add(new DefaultMutableTreeNode("Test"));
                    add(node_1);
                    node_1 = new DefaultMutableTreeNode("Test");
                        node_1.add(new DefaultMutableTreeNode("AO"));
                        node_1.add(new DefaultMutableTreeNode("Attends"));
                        node_1.add(new DefaultMutableTreeNode("Carlsberg"));
                        node_1.add(new DefaultMutableTreeNode("COOP"));
                        node_1.add(new DefaultMutableTreeNode("Dafgaard"));
                        node_1.add(new DefaultMutableTreeNode("Jysk DK"));
                        node_1.add(new DefaultMutableTreeNode("Jysk SE"));
                        node_1.add(new DefaultMutableTreeNode("Kvadrat"));
                        node_1.add(new DefaultMutableTreeNode("Solar"));
                        node_1.add(new DefaultMutableTreeNode("Stockmann"));
                        node_1.add(new DefaultMutableTreeNode("Tine"));
                        node_1.add(new DefaultMutableTreeNode("Unicef"));
                        node_1.add(new DefaultMutableTreeNode("VecturaAO"));
                        node_1.add(new DefaultMutableTreeNode("Attends"));
                        node_1.add(new DefaultMutableTreeNode("Carlsberg"));
                        node_1.add(new DefaultMutableTreeNode("COOP"));
                        node_1.add(new DefaultMutableTreeNode("Dafgaard"));
                        node_1.add(new DefaultMutableTreeNode("Jysk DK"));
                        node_1.add(new DefaultMutableTreeNode("Jysk SE"));
                        node_1.add(new DefaultMutableTreeNode("Kvadrat"));
                        node_1.add(new DefaultMutableTreeNode("Solar"));
                        node_1.add(new DefaultMutableTreeNode("Stockmann"));
                        node_1.add(new DefaultMutableTreeNode("Tine"));
                        node_1.add(new DefaultMutableTreeNode("Unicef"));
                        node_1.add(new DefaultMutableTreeNode("VecturaAO"));
                        node_1.add(new DefaultMutableTreeNode("Attends"));
                        node_1.add(new DefaultMutableTreeNode("Carlsberg"));
                        node_1.add(new DefaultMutableTreeNode("COOP"));
                        node_1.add(new DefaultMutableTreeNode("Dafgaard"));
                        node_1.add(new DefaultMutableTreeNode("Jysk DK"));
                        node_1.add(new DefaultMutableTreeNode("Jysk SE"));
                        node_1.add(new DefaultMutableTreeNode("Kvadrat"));
                        node_1.add(new DefaultMutableTreeNode("Solar"));
                        node_1.add(new DefaultMutableTreeNode("Stockmann"));
                        node_1.add(new DefaultMutableTreeNode("Tine"));
                        node_1.add(new DefaultMutableTreeNode("Unicef"));
                        node_1.add(new DefaultMutableTreeNode("Vectura"));
                    add(node_1);
                }
            }
        ));
        tree.setBounds(10, 71, 324, 540);
        tree.setRootVisible(false);

        JLabel bottomLabelTop = new JLabel("                   Nyttige Links Version 1.0");
        bottomLabelTop.setBounds(0, 590, 230, 14);
        nyttigeLinks.getContentPane().add(bottomLabelTop);

        JLabel bottomLabelBot = new JLabel("                              Made by xxx");
        bottomLabelBot.setBounds(0, 605, 230, 15);
        nyttigeLinks.getContentPane().add(bottomLabelBot);

        JButton btnNewButton = new JButton("Admin");
        btnNewButton.setIcon(new ImageIcon(NyttigeLinks.class.getResource("/images/appIcon.ico")));
        btnNewButton.setBounds(240, 590, 80, 20);
        nyttigeLinks.getContentPane().add(btnNewButton);
        nyttigeLinks.setPreferredSize(new Dimension(350, 650));
        nyttigeLinks.setSize(new Dimension(350, 650));
        nyttigeLinks.setResizable(false);
        nyttigeLinks.setTitle("Nyttige Links");
        nyttigeLinks.setIconImage(Toolkit.getDefaultToolkit().getImage(NyttigeLinks.class.getResource("/images/appIcon.ico")));
        nyttigeLinks.setBackground(Color.YELLOW);
        nyttigeLinks.setBounds(100, 100, 350, 650);
        nyttigeLinks.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        nyttigeLinks.setVisible(true);
    }
}

Прошу прощения за то, что я немного нуб, но ведь надо же с чего-то начинать, верно?

Если кто-то может указать мне в правильном направлении, я был бы очень признателен! Всем спокойной ночи!


person TheGreyNight    schedule 30.05.2017    source источник


Ответы (2)


Я не верю, что есть способ сделать сам узел URL-адресом. Однако вы можете сделать то же самое, используя прослушиватели для открытия браузера при щелчке узла. Чтобы открыть браузер, вы можете использовать Desktop#browse(URI).

Что касается щелчка, я бы рекомендовал не открывать URL-адрес при однократном щелчке узла. Для пользователя это было бы очень раздражающим (IMO). Вместо этого я бы рекомендовал использовать двойной щелчок. Этот ответ дает хороший способ различить одиночный и двойной щелчок и как добавить его в файл Tree.


[...] но ведь надо же с чего-то начинать, верно?

Точно! Позвольте мне рассказать здесь немного больше подробностей, которые, я надеюсь, помогут вам узнать немного больше.

Одна из проблем, с которой вы столкнетесь, заключается в том, как узнать, какой URL открыть для данного узла. В настоящее время вы знаете только отображаемый String, и я думаю, что это безопасное предположение, что вы не хотите отображать полный URL-адрес для каждого узла. Вместо создания объектов DefaultMutableTreeNode с параметром String я бы рекомендовал вместо этого создать объект для передачи конструктору DefaultMutableTreeNode. Этот объект также может иметь атрибут URI, чтобы он знал, какой URL открывать.

Например:

public class LeafNodeObject {
    private final URI uri;

    public LeafNodeObject(final String display, final URI uri) {
        this.display = display;
        this.uri = uri;
    }

    /**
     * Override so that we control what is display on the Node
     */
    @Override
    public String toString() {
        return display;
    }

    public void onDoubleClick() {
        try {
            Desktop.getDesktop().browse(uri);
        } catch (final IOException e) {
            e.printStackTrace();
        }
    }

}

Узлы могут быть добавлены следующим образом:

node_1.add(new DefaultMutableTreeNode(new LeafNodeObject("Test", new URI("www.eclipse.org"))));

И в нашем слушателе (слегка измененном по ссылке выше):

final MouseListener ml = new MouseAdapter() {
    public void mousePressed(final MouseEvent e) {
        final int selRow = tree.getRowForLocation(e.getX(), e.getY());
        final TreePath selPath = tree.getPathForLocation(e.getX(), e.getY());
        if (selRow != -1) {
            final DefaultMutableTreeNode node = (DefaultMutableTreeNode) selPath.getLastPathComponent();
            if (e.getClickCount() == 1) {
                // Single click
            } else if (e.getClickCount() == 2) {
                // Double click
                ((LeafNodeObject) node.getUserObject()).onDoubleClick();
            }
        }
    }
};

Теперь, когда происходит двойной щелчок, мы вызываем метод onDoubleClick() для созданного нами LeafNodeObject.

Это выглядит великолепно, за исключением того, что мы столкнемся с проблемами приведения классов с узлами, которые не являются конечными узлами! Чтобы исправить это, мы можем создать аналогичный класс для этих узлов (например, ParentNodeObject). В интересах хорошего ООП мы должны признать общее поведение этих двух классов (onDoubleClick(), а также onSingleClick()) и создать интерфейс для общих возможностей.

Например:

public interface NodeObject {
    public void onSingleClick();
    public void onDoubleClick();
}

Теперь мы можем реализовать этот интерфейс в наших двух классах:

public class ParentNodeObject implements NodeObject {
    private final String display;

    public ParentNodeObject(final String display) {
        this.display = display;
    }

    /**
     * Override so that we control what is display on the Node
     */
    @Override
    public String toString() {
        return display;
    }

    @Override
    public void onSingleClick() {
        // Do nothing
    }

    @Override
    public void onDoubleClick() {
        // Do nothing
    }
}

public class LeafNodeObject implements NodeObject {
    private final URI uri;

    public LeafNodeObject(final String display, final URI uri) {
        this.display = display;
        this.uri = uri;
    }

    /**
     * Override so that we control what is display on the Node
     */
    @Override
    public String toString() {
        return display;
    }

    @Override
    public void onSingleClick() {
        // Do nothing
    }

    @Override
    public void onDoubleClick() {
        try {
            Desktop.getDesktop().browse(uri);
        } catch (final IOException e) {
            e.printStackTrace();
        }
    }

}

В результате в нашем слушателе нам больше не нужно знать (и больше не заботиться), является ли узел родительским или конечным узлом. Мы можем просто вызвать либо onSingleClick(), либо onDoubleClick(), а реализация сделает все остальное!

if (e.getClickCount() == 1) {
    // Single click
    ((NodeObject) node.getUserObject()).onSingleClick();
} else if (e.getClickCount() == 2) {
    // Double click
    ((NodeObject) node.getUserObject()).onDoubleClick();
}

Вернувшись в код, родительские и дочерние узлы можно добавить следующим образом:

node_1 = new DefaultMutableTreeNode(new ParentNodeObject("Helpdesk Norcic"));
node_1.add(new DefaultMutableTreeNode(new LeafNodeObject("Test", new URI("www.eclipse.org"))));

Теперь при одиночном или двойном щелчке по любому узлу также будут вызываться методы onSingleClick() или onDoubleClick(). В этом случае нас интересует только то, что происходит при двойном щелчке по листовым узлам, поэтому нам нужно заполнить только этот метод.

person avojak    schedule 30.05.2017
comment
Это восхитительно! Спасибо большое за вашу помощь. Я посмотрю это завтра утром, когда я не работаю. У меня больше нет времени сегодня вечером. Большое спасибо, я обязательно обновлю эту тему, чтобы узнать, как все идет. - person TheGreyNight; 30.05.2017
comment
@TheGreyNight Добро пожаловать! Дайте мне знать, если есть что-то, что не имеет полного смысла или может использовать лучшее объяснение. - person avojak; 30.05.2017

Хотя я не проверял вышеупомянутый код, вот как я обошел проблему, пока ждал ответа в этой теме:

class SelectionListener implements TreeSelectionListener {

    public void valueChanged(TreeSelectionEvent se) {
        JTree tree = (JTree) se.getSource();
        DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
        String selectedNodeName = selectedNode.toString();
        if (selectedNode.isLeaf()) {
            if (selectedNodeName == "Unicef") {
                try {
                    java.awt.Desktop.getDesktop().browse(java.net.URI.create("http://www.eb.dk"));
                } catch (IOException e1) {
                    // make a error pop up appear here
                    JOptionPane.showMessageDialog(null, "Something went wrong, please report this to the developer!", "Something went wrong", 0);
                    e1.printStackTrace();

                }
            }

            if (selectedNodeName == "Vectura") {
                try {
                    java.awt.Desktop.getDesktop().browse(java.net.URI.create("http://www.google.com"));
                } catch (IOException e1) {
                    // make a error pop up appear here
                    JOptionPane.showMessageDialog(null, "Something went wrong, please report this to the developer!", "Something went wrong", 0);
                    e1.printStackTrace();

                }
            }

        }

    }
}

Это определенно нехороший способ сделать это, так как это приведет к МНОЖЕСТВУ операторов if, но это было достаточно просто, чтобы я мог понять сам.

person TheGreyNight    schedule 30.05.2017