Simply; I have a JPanel
inside a JScrollPane
;
As expected; JScrollPane
by default listens to MouseWheelEvent
so that scrolling is working well for when the wheel is rotating and while the cursor is hovering over the JPanel
.
But After that; I just updated JPanel
so that it implements MouseWheelListener
, and I added this mouse wheel listener for the JPanel
itself.
@Override
public void mouseWheelMoved(MouseWheelEvent e) {
if (e.isControlDown()) {
if (e.getWheelRotation() < 0) {
System.out.println("mouse wheel Up");
} else {
System.out.println("mouse wheel Down");
}
}
}
The JPanel
responds to this implementation for when both; the Ctrl is pressed down and the wheel is rotating and while the cursor is hovering over the JPanel
. But the default behaviour of the JScrollPane
is unexpectedly lost!!!
When I rotate the wheel while the cursor is hovering over the JPanel
the scrolls of the JScrollPane
is not responding!!!
It seems that; this implementation of MouseWheelListener
breaks the default of a JPanel
.
So; How to implement MouseWheelListener
for JPanel
without breaking its default implementation?
MouseWheelEvents
and the scrolling behavior have some subtle caveats.
For example, when you open this page (I mean THIS one, which you are currently reading), place the mouse in the middle, and start srolling down with the wheel, you will scroll over the code snippets. Note that although the code snippets are contained in code blocks that have a scrollbar, continuously rotating the mouse wheel will not trigger a scrolling in the code blocks, but only in the whole page. But when you once move the mouse while it is inside a code block, and afterwards roll the mouse wheel, then you will scroll in the code block only - and not the whole page.
Similarly, rotating the mouse wheel may not affect the hovered scrollable. I think it depends on the Window Manager and the Look & Feel, but in some cases, you will scroll the scroll pane that contains the focussed component - even if the mouse cursor is outside of this component, and even if it is over a scollable component (you can also observe this, for example, in the Windows Explorer)!
However, some of these mechanisms and subtleties can be found in the Swing components as well. For example, the redispatching mechanism that passes MouseWheelEvents
to the ancestors if they are not handled by the component itself.
Following this pattern, a solution (that is conceptually similar to the one that LuxxMiner proposed, but may be a tad more generic) may be to simply re-dispatch the MouseWheelEvent
to the parent component:
package stackoverflow;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
public class MouseWheelListenerForPanelInScrollpane
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
@Override
public void run()
{
createAndShowGUI();
}
});
}
private static void createAndShowGUI()
{
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().setLayout(new GridLayout(1,2));
MouseWheelListenerPanel m = new MouseWheelListenerPanel();
m.setPreferredSize(new Dimension(100,4000));
JScrollPane scrollPane = new JScrollPane(m);
f.getContentPane().add(scrollPane);
f.setSize(500,500);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}
class MouseWheelListenerPanel extends JPanel implements MouseWheelListener
{
MouseWheelListenerPanel()
{
addMouseWheelListener(this);
}
@Override
public void mouseWheelMoved(MouseWheelEvent e)
{
if (e.isControlDown())
{
if (e.getWheelRotation() < 0)
{
System.out.println("mouse wheel Up");
}
else
{
System.out.println("mouse wheel Down");
}
}
else
{
getParent().dispatchEvent(e);
}
}
}
Add an else
to re-dispatch the event directly to the scroll pane if ctrl is not down:
@Override
public void mouseWheelMoved(MouseWheelEvent e) {
if (e.isControlDown()) {
if (e.getWheelRotation() < 0) {
System.out.println("mouse wheel Up");
} else {
System.out.println("mouse wheel Down");
}
} else {
// pass the event on to the scroll pane
getParent().dispatchEvent(e);
}
}
I don't know if this really qualifies as an proper answer, since it's kind of a workaround, but I came up with the following solution: Just invoke the mouseWheelMoved
method of the scrollPane
only when Ctrl isn't being pressed:
if (e.isControlDown()) {
if (e.getWheelRotation() < 0) {
infoLabel.setText("Mouse Wheel Up");
} else {
infoLabel.setText("Mouse Wheel Down");
}
} else {
scrollPane.getListeners(MouseWheelListener.class)[0].mouseWheelMoved(e);
}
Full Example:
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.border.TitledBorder;
public class Example {
public Example() {
JFrame frame = new JFrame();
frame.setLayout(new BorderLayout());
frame.add(new ScrollPanePanel());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 400);
frame.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
new Example();
}
});
}
}
class ScrollPanePanel extends JPanel implements MouseWheelListener {
private JLabel infoLabel;
private JScrollPane scrollPane;
public ScrollPanePanel() {
JPanel panel = new JPanel(new GridLayout(0, 1));
for (int i = 1; i <= 100; i++) {
panel.add(new JLabel("Label " + i));
}
panel.addMouseWheelListener(this);
scrollPane = new JScrollPane(panel);
infoLabel = new JLabel(" ");
JPanel infoPanel = new JPanel();
infoPanel.add(infoLabel);
setLayout(new BorderLayout());
add(scrollPane);
add(infoPanel, BorderLayout.SOUTH);
}
@Override
public void mouseWheelMoved(MouseWheelEvent e) {
if (e.isControlDown()) {
if (e.getWheelRotation() < 0) {
infoLabel.setText("Mouse Wheel Up");
} else {
infoLabel.setText("Mouse Wheel Down");
}
} else {
scrollPane.getListeners(MouseWheelListener.class)[0].mouseWheelMoved(e);
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With