如何将鼠标监听器添加到多个JLabel []

时间:2018-06-15 06:38:50

标签: java arrays for-loop mouselistener

我正在制作一个主菜单。我想从数组中加载菜单项,这样可以更有效地将新项添加到菜单中。我想让for循环创建的每个JLabel都有一个活动的鼠标监听器,这样我就可以检查鼠标是否悬停在它上面并查看它何时被单击。我将如何实现这一目标?

这里是我目前正在使用的代码,虽然鼠标监听器不起作用,但它可以创建JLabel。

private String[] items = { "Exit", "Mods", "Settings", "New Game", "Play Game" };

private String item_hover_left = "[";
private String item_hover_right = "]";

    private void createItems() {

        GameSound sound = new GameSound();

        int initialY = 951;

        JLabel[] item = new JLabel[items.length];

        for (i = 0; i < items.length; i++) {

            int y = initialY - (101 * i);

            item[i] = new JLabel();
            item[i].setText(items[i]);
            item[i].setForeground(ui_colour);
            item[i].setFont(new Font("Overseer", Font.PLAIN, 50));
            item[i].setHorizontalAlignment(SwingConstants.CENTER);
            item[i].setBounds(1582, y, 328, 99);
            add(item[i]);
            repaint();
            item[i].addMouseListener(new MouseAdapter() {

                public void mousePressed(MouseEvent pressed) {

                    if (pressed.getButton() == MouseEvent.BUTTON1) {

                        sound.playSound("menu_ok");

                    }

                }

                public void mouseEntered(MouseEvent entered) {

                    item[i].setText(item_hover_left + " " + items[i] + " " + item_hover_right);
                    sound.playSound("menu_hover");

                }

                public void mouseExited(MouseEvent exited) {

                    item[i].setText(items[i]);

                }

            });
        }
    }
Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 5
  at net.fallout.menu.MainMenu$1.mouseEntered(MainMenu.java:87)
  at java.awt.Component.processMouseEvent(Unknown Source)
  at javax.swing.JComponent.processMouseEvent(Unknown Source)
  at java.awt.Component.processEvent(Unknown Source)
  at java.awt.Container.processEvent(Unknown Source)
  at java.awt.Component.dispatchEventImpl(Unknown Source)
  at java.awt.Container.dispatchEventImpl(Unknown Source)
  at java.awt.Component.dispatchEvent(Unknown Source)
  at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
  at java.awt.LightweightDispatcher.retargetMouseEnterExit(Unknown Source)
  at java.awt.LightweightDispatcher.trackMouseEnterExit(Unknown Source)
  at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
  at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
  at java.awt.Container.dispatchEventImpl(Unknown Source)
  at java.awt.Window.dispatchEventImpl(Unknown Source)
  at java.awt.Component.dispatchEvent(Unknown Source)
  at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
  at java.awt.EventQueue.access$500(Unknown Source)
  at java.awt.EventQueue$3.run(Unknown Source)
  at java.awt.EventQueue$3.run(Unknown Source)
  at java.security.AccessController.doPrivileged(Native Method)
  at > java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
  at  java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
  at java.awt.EventQueue$4.run(Unknown Source)
  at java.awt.EventQueue$4.run(Unknown Source)
  at java.security.AccessController.doPrivileged(Native Method)
  at > java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
  at java.awt.EventQueue.dispatchEvent(Unknown Source)
  at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
  at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
  at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
  at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
  at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
  at java.awt.EventDispatchThread.run(Unknown Source)

3 个答案:

答案 0 :(得分:1)

在您的匿名课程中,您有以下方法:

public void mouseEntered(MouseEvent entered) {
    item[i].setText(item_hover_left + " " + items[i] + " " + item_hover_right);
    sound.playSound("menu_hover");
}

在其中,您正在使用i,我可以说它是一个类成员变量,因为它只能是那个或final局部变量,但i在循环中递增,所以它只能是一个班级成员。

问题在于i随着for循环的变化以及由于i = items.length而创建标签后for (i = 0; i < items.length; i++) {。当事件发生时,item[i]将指向数组之外,解释异常。

首先,不要为i使用类成员,保留该值并且会给您带来问题(如此)是没有意义的。
我知道你这样做是因为它没有编译,因为你可以在你正在实现的监听器的方法中使用它,但你可以在循环中使用final变量来解决这个问题:

//declare `i` here
for (int i = 0; i < items.length; i++) {
    //declare `index` final and assign `i`, each MouseAdapter instance will use the correct `index`
    final int index = i;

    item[i].addMouseListener(new MouseAdapter() {
        public void mouseEntered(MouseEvent entered) {
            item[index].setText(item_hover_left + " " + items[index] + " " + item_hover_right);
            sound.playSound("menu_hover");
        }
    }

daniu 提出的备选方案,因为我过分关注索引问题,而是将标签声明为final。

for (int i = 0; i < items.length; i++) {
    final JLabel label = new JLabel();
    item[i] = label;

    label.addMouseListener(new MouseAdapter() {
        public void mouseEntered(MouseEvent entered) {
            label.setText(item_hover_left + " " + label + " " + item_hover_right);
            sound.playSound("menu_hover");
        }
    }
}

当然还有另外一种方法,您可以使用EventObject.getSource获取活动的来源。您知道它将是JLabel,因为这是一个无法在其他地方使用的匿名类。

public void mouseEntered(MouseEvent entered) {
    JLabel label = (JLabel)entered.getSource();
    label.setText(item_hover_left + " " + label + " " + item_hover_right);
    sound.playSound("menu_hover");
}

答案 1 :(得分:1)

我建议你为MouseListener创建一个单独的类,比如说一个内部类,而不是你正在使用的匿名类。

class YourMouseListener extends MouseAdapter {
    JLabel label;
    String text;
    YourMouseListener(JLabel label, String text) {
        this.label = label;
        this.text = text;
    }
    // ...
    // use this.label instead of item[i], like this
    public void mouseEntered(MouseEvent entered) {

        label.setText(item_hover_left + " " + text + " " + item_hover_right);
        sound.playSound("menu_hover");

    }
    // ...
}

然后在循环中使用此类

JLabel[] item = new JLabel[items.length];

for (i = 0; i < items.length; i++) {


    item[i] = new JLabel(items[i]);
    // ...
    add(item[i]);
    item[i].addMouseListener(new YourMouseListener(item[i], items[i]));
    repaint();
}

您可能甚至不需要label成员,因为您可以使用事件的目标将文本设置为。

答案 2 :(得分:0)

这是我使用的解决方案。

private void createItems(){

        int initialY = 951;

        JLabel[] item = new JLabel[items.length];

        for (int i = 0; i < item.length; i++) {

            final int selected = i;

            int y = initialY - (101 * selected);

            item[selected] = new JLabel();
            item[selected].setText(items[selected]);
            item[selected].setForeground(ui_colour);
            item[selected].setFont(new Font("Overseer", Font.PLAIN, 50));
            item[selected].setHorizontalAlignment(SwingConstants.CENTER);
            item[selected].setBounds(1582, y, 328, 99);
            add(item[selected]);
            item[i].addMouseListener(new ItemListener(item[i], selected));
            repaint();

        }
    }

class ItemListener extends MouseAdapter {
                GameSound sound = new GameSound();
                JLabel item_label;
        Integer item_index;

        ItemListener(JLabel label, int index) {
            this.item_label = label;
            this.item_index = index;
        }

        public void mousePressed(MouseEvent pressed) {

            if (pressed.getButton() == MouseEvent.BUTTON1) {

                sound.playSound("menu_ok");
                item_selected = item_index;
                checkItem();

            }

        }

        public void mouseEntered(MouseEvent entered) {

            item_label.setText(item_hover_left + " " + items[item_index] + " "
+ item_hover_right);            sound.playSound("menu_hover");

        }

        public void mouseExited(MouseEvent exited) {

            item_label.setText(items[item_index]);

        }

    }