我有一个问题,Swing(在Java 1.6,Windows中)似乎没有按照我想要的方式触发mouseEntered和mouseExited事件。我有一个应用程序,我希望在JScrollPane中有多个垂直堆叠的JPanels,并且当鼠标悬停在它们上面时,它们应该以不同的颜色突出显示。足够简单的问题,但每当我使用鼠标滚轮滚动时,它都不会表现得很好。
我已经制作了一个示例应用程序来说明我的问题(下面的代码)。下面的图片来自那个,而不是“真正的”应用程序。
当我将鼠标光标悬停在面板边缘时,它会正确突出显示。现在,当我使用鼠标滚轮向下滚动时,我希望光标在框B上方,并且触发正确的mouseEntered / mouseExited事件,以便A变为白色,B变为红色。
(来源:perp.se)
(来源:perp.se)
然而,这似乎并未发生。
现在,如果我触发另一个鼠标事件,B将变为高亮显示,无论是“移动1个像素”,“单击按钮”还是“滚动另一个步骤”。知道了这一点,我也许可以用一种骇人的方式来解决它,但如果有合适的解决方案,我宁愿不解决。
基本上我想知道的是,如果将此视为Swing中的错误,还是我只是做错了?
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
public class ScrollTest extends JFrame {
public static class LetterPanel extends JPanel {
private static final Font BIG_FONT = new Font(Font.MONOSPACED, Font.BOLD, 24);
public LetterPanel(String text) {
setBackground(Color.WHITE);
setBorder(BorderFactory.createLineBorder(Color.BLACK));
addMouseListener(new MouseAdapter() {
@Override
public void mouseEntered(MouseEvent e) {
setBackground(Color.RED);
}
@Override
public void mouseExited(MouseEvent e) {
setBackground(Color.WHITE);
}
});
setLayout(new GridLayout(1, 1));
setPreferredSize(new Dimension(-1, 50));
JLabel label = new JLabel(text, SwingConstants.CENTER);
label.setFont(BIG_FONT);
add(label);
}
}
public ScrollTest() {
setLayout(new GridLayout(1, 1));
setSize(400, 400);
JPanel base = new JPanel();
JScrollPane jsp = new JScrollPane(base);
jsp.getVerticalScrollBar().setUnitIncrement(16);
add(jsp);
base.setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.gridheight = 1;
gbc.gridwidth = 1;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.insets = new Insets(0, 0, 10, 0);
gbc.weightx = 1.0;
for (char c = 'A'; c <= 'Z'; c++) {
base.add(new LetterPanel(String.valueOf(c)), gbc);
gbc.gridy++;
}
}
public static void main(String[] args) {
final JFrame f = new ScrollTest();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
f.setVisible(true);
}
});
}
}
答案 0 :(得分:5)
这似乎与Tooltips and Scrollpanes中描述的问题类似。也就是说,不会生成鼠标事件,因为鼠标本身不移动,视口移动。我不确定其他使用AdjustmentListener跟踪鼠标位置组件的确切解决方案。每次更改都可以将mouseExited事件发送到上一个面板,将mouseEntered事件发送到新面板。
答案 1 :(得分:3)
我可以让你的代码可靠地重现这个,但只有当我还没有完成滚动时。在我的鼠标上,至少在鼠标滚轮完成滚动时有一种“捕获”。如果我滚动得非常慢,我可以让它移动,但它不会改变高光,直到鼠标滚轮到达“捕获”。
当我这样做时,在前一个面板上收到鼠标输入消息(您看到的行为相同)。
看着它我滚动鼠标它实际上并没有收到退出/输入的事件,除非我滚动到足以使鼠标滚轮“捕获”。在发生“捕获”之前,Windows可能不会将消息发送到Java ...从我的测试看起来就是这样。
您可能希望查看MouseWheelListener接口和MouseInfo类。我想你可能能够检测到车轮运动,然后用MouseInfo.getPointerInfo()。getLocation()找出你的位置,然后找出你所在的组件并更改突出显示。