如何在不破坏其默认实现的情况下为 JPanel 实现 MouseWheelListener?
How to implement MouseWheelListener for JPanel without breaking its default implementation?
简单;我在 JScrollPane
;
里面有一个 JPanel
符合预期; JScrollPane
默认监听 MouseWheelEvent
以便当滚轮旋转时以及光标悬停在 JPanel
.
上时滚动效果很好
但是之后;我刚刚更新了 JPanel
以便它实现 MouseWheelListener
,并且我为 JPanel
本身添加了这个鼠标滚轮侦听器。
@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");
}
}
}
JPanel
响应此实现的同时; Ctrl 被按下,滚轮正在旋转,同时光标悬停在 JPanel
上。但是 JScrollPane
的默认行为意外丢失了!!!
当我在光标悬停在 JPanel
上时旋转滚轮时 JScrollPane
的卷轴没有响应!!!
好像是; MouseWheelListener
的这个实现打破了 JPanel
.
的默认值
所以;如何在不破坏其默认实现的情况下为 JPanel
实现 MouseWheelListener
?
我不知道这是否真的是一个正确的答案,因为它是一种解决方法,但我想出了以下解决方案:只需调用 [=13= 的 mouseWheelMoved
方法] 仅当未按下 Ctrl 时:
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);
}
完整示例:
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);
}
}
}
如果 ctrl 不是 按下,则添加 else
以将事件直接重新分派到滚动窗格:
@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);
}
}
MouseWheelEvents
和滚动行为有一些微妙的注意事项。
例如,当您打开此页面(我的意思是您当前正在阅读的这个页面)时,将鼠标放在中间,然后开始使用滚轮向下滚动,您将滚动代码片段。请注意,虽然代码片段包含在有滚动条的代码块中,但连续旋转鼠标滚轮不会 在 代码块中触发滚动 ,但仅限于整个页面。但是当你移动鼠标时在一个代码块内,并且之后滚动鼠标滚轮,那么您将只在代码块中滚动 - 而 而不是 整个页面。
同样,旋转鼠标滚轮可能不会影响悬停的滚动条。我认为这取决于 Window 管理器和外观,但在某些情况下,您将滚动 包含聚焦组件的滚动窗格 - 即使鼠标光标在此组件之外,即使它位于可滚动组件之上(您也可以观察到这一点,例如,在 Windows 资源管理器中)!
但是,在 Swing 组件中也可以找到其中一些机制和细微之处。例如,redispatching mechanism 将 MouseWheelEvents
传递给祖先,如果它们不是由组件本身处理的话。
按照这种模式,一个解决方案(在概念上类似于 ,但可能更通用)可能是简单地将 MouseWheelEvent
重新分派给父组件:
package Whosebug;
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);
}
}
}
简单;我在 JScrollPane
;
JPanel
符合预期; JScrollPane
默认监听 MouseWheelEvent
以便当滚轮旋转时以及光标悬停在 JPanel
.
但是之后;我刚刚更新了 JPanel
以便它实现 MouseWheelListener
,并且我为 JPanel
本身添加了这个鼠标滚轮侦听器。
@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");
}
}
}
JPanel
响应此实现的同时; Ctrl 被按下,滚轮正在旋转,同时光标悬停在 JPanel
上。但是 JScrollPane
的默认行为意外丢失了!!!
当我在光标悬停在 JPanel
上时旋转滚轮时 JScrollPane
的卷轴没有响应!!!
好像是; MouseWheelListener
的这个实现打破了 JPanel
.
所以;如何在不破坏其默认实现的情况下为 JPanel
实现 MouseWheelListener
?
我不知道这是否真的是一个正确的答案,因为它是一种解决方法,但我想出了以下解决方案:只需调用 [=13= 的 mouseWheelMoved
方法] 仅当未按下 Ctrl 时:
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);
}
完整示例:
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);
}
}
}
如果 ctrl 不是 按下,则添加 else
以将事件直接重新分派到滚动窗格:
@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);
}
}
MouseWheelEvents
和滚动行为有一些微妙的注意事项。
例如,当您打开此页面(我的意思是您当前正在阅读的这个页面)时,将鼠标放在中间,然后开始使用滚轮向下滚动,您将滚动代码片段。请注意,虽然代码片段包含在有滚动条的代码块中,但连续旋转鼠标滚轮不会 在 代码块中触发滚动 ,但仅限于整个页面。但是当你移动鼠标时在一个代码块内,并且之后滚动鼠标滚轮,那么您将只在代码块中滚动 - 而 而不是 整个页面。
同样,旋转鼠标滚轮可能不会影响悬停的滚动条。我认为这取决于 Window 管理器和外观,但在某些情况下,您将滚动 包含聚焦组件的滚动窗格 - 即使鼠标光标在此组件之外,即使它位于可滚动组件之上(您也可以观察到这一点,例如,在 Windows 资源管理器中)!
但是,在 Swing 组件中也可以找到其中一些机制和细微之处。例如,redispatching mechanism 将 MouseWheelEvents
传递给祖先,如果它们不是由组件本身处理的话。
按照这种模式,一个解决方案(在概念上类似于 MouseWheelEvent
重新分派给父组件:
package Whosebug;
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);
}
}
}