如何将鼠标侦听器添加到多个 JLabel[]
How to add a mouse listener to multiple JLabel[]
我正在制作一个有主菜单的游戏。我想从数组中加载菜单项,以便更有效地向菜单添加新项。我想让 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.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.access0(Unknown Source)
at java.awt.EventQueue.run(Unknown Source)
at java.awt.EventQueue.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.run(Unknown Source)
at java.awt.EventQueue.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)
在你的匿名 class 中,你有这个方法:
public void mouseEntered(MouseEvent entered) {
item[i].setText(item_hover_left + " " + items[i] + " " + item_hover_right);
sound.playSound("menu_hover");
}
在其中,您正在使用 i
,我可以说它是一个 class 成员变量,因为它只能是那个或 final
局部变量,但是 i
是循环中的增量,所以它只能是一个 class 成员。
问题是 i
随 for 循环而改变,当您完成创建标签时,i = items.length
因为 for (i = 0; i < items.length; i++) {
。当事件发生时,item[i]
将指向数组外部,解释异常。
首先,不要为 i
使用 class 成员,保留该值没有意义,会给您带来问题(例如这个)。
我知道你这样做是因为它没有编译,因为你可以在你正在实现的监听器的方法中使用它,但是你可以在循环中使用 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
,因为这是一个不能在其他地方使用的匿名 class。
public void mouseEntered(MouseEvent entered) {
JLabel label = (JLabel)entered.getSource();
label.setText(item_hover_left + " " + label + " " + item_hover_right);
sound.playSound("menu_hover");
}
我建议您为 MouseListener
创建一个单独的 class,比如一个内部的,而不是您正在使用的匿名的。
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");
}
// ...
}
然后在循环中使用这个 class
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
成员,因为您可以使用事件的目标将文本设置为。
这是我使用的解决方案。
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]);
}
}
我正在制作一个有主菜单的游戏。我想从数组中加载菜单项,以便更有效地向菜单添加新项。我想让 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.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.access0(Unknown Source) at java.awt.EventQueue.run(Unknown Source) at java.awt.EventQueue.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.run(Unknown Source) at java.awt.EventQueue.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)
在你的匿名 class 中,你有这个方法:
public void mouseEntered(MouseEvent entered) {
item[i].setText(item_hover_left + " " + items[i] + " " + item_hover_right);
sound.playSound("menu_hover");
}
在其中,您正在使用 i
,我可以说它是一个 class 成员变量,因为它只能是那个或 final
局部变量,但是 i
是循环中的增量,所以它只能是一个 class 成员。
问题是 i
随 for 循环而改变,当您完成创建标签时,i = items.length
因为 for (i = 0; i < items.length; i++) {
。当事件发生时,item[i]
将指向数组外部,解释异常。
首先,不要为 i
使用 class 成员,保留该值没有意义,会给您带来问题(例如这个)。
我知道你这样做是因为它没有编译,因为你可以在你正在实现的监听器的方法中使用它,但是你可以在循环中使用 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
,因为这是一个不能在其他地方使用的匿名 class。
public void mouseEntered(MouseEvent entered) {
JLabel label = (JLabel)entered.getSource();
label.setText(item_hover_left + " " + label + " " + item_hover_right);
sound.playSound("menu_hover");
}
我建议您为 MouseListener
创建一个单独的 class,比如一个内部的,而不是您正在使用的匿名的。
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");
}
// ...
}
然后在循环中使用这个 class
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
成员,因为您可以使用事件的目标将文本设置为。
这是我使用的解决方案。
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]);
}
}