这是我之前question.
的后续问题我有两个JPanels
,每个JLabels
个JLabels
。当我将鼠标移动到其中一个import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.PointerInfo;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.*;
@SuppressWarnings("serial")
public class KeybindExample extends JPanel {
public KeybindExample() {
setLayout(new BorderLayout());
add(firstRow(), BorderLayout.NORTH);
add(secondRow(),BorderLayout.SOUTH);
int condition = JComponent.WHEN_IN_FOCUSED_WINDOW;
InputMap inputMap = getInputMap(condition);
ActionMap actionMap = getActionMap();
KeyStroke delKeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0);
String delete = "delete";
inputMap.put(delKeyStroke, delete);
actionMap.put(delete, new DeleteAction());
}
private class DeleteAction extends AbstractAction {
@Override
public void actionPerformed(ActionEvent evt) {
PointerInfo pInfo = MouseInfo.getPointerInfo();
Point ptOnScrn = pInfo.getLocation();
int xPanel = getLocationOnScreen().x;
int yPanel = getLocationOnScreen().y;
int x = ptOnScrn.x - xPanel;
int y = ptOnScrn.y - yPanel;
Component component = getComponentAt(x, y);
if (component != null) {
JLabel selectedLabel = (JLabel) component;
System.out.println("Selected Label: " + selectedLabel.getText());
}
}
}
private static JPanel firstRow(){
JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEFT));
String [] x = {"1","2","3","4","5"};
for(int i = 0; i < 5; i++){
JLabel label = new JLabel(x[i]);
label.setPreferredSize(new Dimension(50,50));
panel.add(label);
}
return panel;
}
private static JPanel secondRow(){
JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEFT));
String [] x = {"6","7","8","9","10"};
for(int i = 0; i < 5; i++){
JLabel label = new JLabel(x[i]);
label.setPreferredSize(new Dimension(50,50));
panel.add(label);
}
return panel;
}
private static void createAndShowGui() {
KeybindExample mainPanel = new KeybindExample();
JFrame frame = new JFrame("Key Bindings Example");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
并按下删除键时,我想打印标签的文本。这是我尝试过的:
Exception in thread "AWT-EventQueue-0" java.lang.ClassCastException: javax.swing.JPanel cannot be cast to javax.swing.JLabel
我收到以下错误:
JPanel
如果我理解正确,我的JPanels
(KeybindExample)包含两个JPanels
,这两个JLabels
中的每一个都包含JPanel
。因此,当我执行getComponentAt(x,y)时,我得到的组件是另一个JLabel
,这导致了类型转换的问题。
我认为我需要做的是获得Component At(x,y)的组件,它是 Component component = getComponentAt(x, y);
if (component != null) {
JPanel selectPanel = (JPanel) component;
Component comp = selectPanel.getComponentAt(x,y);
if(comp != null){
JLabel selectLabel = (JLabel) comp;
System.out.println("Selected Label: " + selectLabel.getText());
}
}
}
。换句话说,我需要更进一步。我尝试了以下方法,但它只适用于顶部面板,有时仍会返回相同的错误。
{{1}}
}
我如何拥有多个包含多个JLabel的JPanel,但是能够拥有鼠标悬停在文本上的JLabel。
答案 0 :(得分:3)
关键问题是 - 如何在某个时间点将引用送到所需的JLabel,这时按下删除键。您当前的解决方案(我之前提出的解决方案)无法正常工作,因为代码会找到相对于KeybindExample JPanel的当前组件,因为这是您调用getComponentAt()
方法的组件。一种可能的解决方案是在实际持有JLabel的JPanel上调用getComponentAt()
。另一种可能的解决方案是计算相对于每个JLabel的鼠标位置,并使用contains(...)
方法查看鼠标是否超过其中一个JLabel。要做到这一点,您需要访问所有JLabel,可能需要将它们放在List<JLabel>
中。例如......
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.PointerInfo;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
@SuppressWarnings("serial")
public class KeybindExample extends JPanel {
private List<JLabel> labelList = new ArrayList<>();
public KeybindExample() {
setLayout(new BorderLayout());
add(firstRow(), BorderLayout.NORTH);
add(secondRow(), BorderLayout.SOUTH);
int condition = JComponent.WHEN_IN_FOCUSED_WINDOW;
InputMap inputMap = getInputMap(condition);
ActionMap actionMap = getActionMap();
KeyStroke delKeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0);
String delete = "delete";
inputMap.put(delKeyStroke, delete);
actionMap.put(delete, new DeleteAction());
}
private class DeleteAction extends AbstractAction {
@Override
public void actionPerformed(ActionEvent evt) {
PointerInfo pInfo = MouseInfo.getPointerInfo();
Point ptOnScrn = pInfo.getLocation();
for (JLabel label : labelList) {
int x = ptOnScrn.x - label.getLocationOnScreen().x;
int y = ptOnScrn.y - label.getLocationOnScreen().y;
if (label.contains(x, y)) {
System.out.println("Selected Label: " + label.getText());
}
}
// int xPanel = getLocationOnScreen().x;
// int yPanel = getLocationOnScreen().y;
// int x = ptOnScrn.x - xPanel;
// int y = ptOnScrn.y - yPanel;
//
// Component component = getComponentAt(x, y);
// if (component != null) {
// JLabel selectedLabel = (JLabel) component;
// System.out.println("Selected Label: " + selectedLabel.getText());
// }
}
}
private JPanel firstRow() {
JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEFT));
String[] x = { "1", "2", "3", "4", "5" };
for (int i = 0; i < 5; i++) {
JLabel label = new JLabel(x[i]);
labelList.add(label);
label.setPreferredSize(new Dimension(50, 50));
panel.add(label);
}
return panel;
}
private JPanel secondRow() {
JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEFT));
String[] x = { "6", "7", "8", "9", "10" };
for (int i = 0; i < 5; i++) {
JLabel label = new JLabel(x[i]);
labelList.add(label);
label.setPreferredSize(new Dimension(50, 50));
panel.add(label);
}
return panel;
}
private static void createAndShowGui() {
KeybindExample mainPanel = new KeybindExample();
JFrame frame = new JFrame("Key Bindings Example");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
答案 1 :(得分:3)
尽管this answer中描述的方法确实很好,但很快就会因为Component#getComponentAt(int x, int y)有其局限性而陷入困境:
确定此组件或其直接子组件之一 包含
(x, y)
位置,如果是,则返回包含的位置 零件。 此方法只有一个级别。如果点(x, y)
在一个子组件内部,它本身有子组件,它不会去 向下看子组件树。
注意: 备注是我的。
恕我直言,你应该遵循KISS(当然没有最后的S)原则,并采用this other answer中描述的更简单,更强大和可扩展的方法。简而言之:
保留JLabel
班级成员(比方说hoveredLabel
)
仅使用MouseListener实施一个mouseEntered()来更新getSource()上的此类成员,并将其设置为mouseExited()上的null
。
将此鼠标侦听器附加到所有标签。
仅在hoveredLabel
hoveredLabel != null