Swing won't cause mouseEntered / mouseExited correctly after mouse wheel events?

I have a problem where Swing (in Java 1.6, Windows) does not seem to trigger the mouseEntered and mouseExited events the way I want it. I have an application in which I want several JPanels to be positioned vertically in the JScrollPane, and to have them highlighted in a different color when the mouse is above them. Quite a simple problem, but whenever I scroll the mouse wheel, it doesn’t quite behave.

I made an example application to illustrate my problem (code below). The images below are from that, not the "real" application.

When I hold the mouse cursor over the edge of the panel, it is highlighted correctly. Now, when I use the mouse wheel to scroll down, I expect the cursor to be above field B and the corresponding mouseEntered / mouseExited events will be raised, so that A will turn white and B will turn red.

alt text
(source: perp.se )

alt text
(source: perp.se )

However, this does not happen.

Now B is highlighted if I fire another mouse event, whether it’s “move 1 pixel”, “press a button” or “scroll another step”. Knowing this, I could solve it in a hacker way, but I would prefer if there wasn’t the right solution.

In general, I wonder if this is considered a mistake in Swing, or am I just doing something wrong?

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); } }); } } 
+6
java swing mouse mousewheel mouseevent
source share
2 answers

This is similar to a similar problem described in tooltips and scrolling . That is, mouse events are not generated, because the mouse itself does not move, moving the viewport. I'm not sure what the exact solution is using the AdjustmentListener to track the component at the location of the mouse. Each time you change, you can fire the mouseExited event on the previous panel and the mouseEntered event on a new panel.

+5
source share

I can make your code reproduce this reliably, but only when I don’t quite finish scrolling. At least there is a kind of “catch” on my mouse when the mouse wheel has finished scrolling. If I scroll very slowly, I can make it move, but it does not change the selection until the mouse wheel reaches the “catch”.

When I do this, the mouse message is entered in the previous panel (the same behavior you see).

Looking at this, I scroll the mouse, and actually it does not accept the displayed / entered events, unless I scroll enough to “grab” the mouse wheel. It is possible that Windows does not send a message in Java until a catch occurs ... from my testing, this is what it looks like.

You might want to explore the MouseWheelListener interface and the MouseInfo class. I think you could detect the movement of the wheel, and then find out where you are with MouseInfo.getPointerInfo (). GetLocation (), then find out which component you finished and change the selection.

+3
source share

All Articles