Java Swing中的MouseMotionListener,将其与组件内部的组件一起使用

我正在使用Swing中的Touch User界面。 虽然我知道这不是最佳的,但我的截止日期很短,没有时间使用触摸屏特定的GUI包(如果有的话)。

我希望我的用户能够在屏幕上“滑动”他们的手指,并且我制作的特殊JScrollPane的视图随之移动。 代码很简单 –

public class PanScrollPane extends JScrollPane implements MouseMotionListener{ public PanScrollPane() { super(); this.addMouseMotionListener(this); } @Override public void mouseDragged(MouseEvent arg0) { System.out.println("Mouse Dragged!"); } @Override public void mouseMoved(MouseEvent arg0) { System.out.println("Mouse Moved!"); } 

我遇到的问题是JScrollPane是各种JComponents的容器。 当我第一次开始研究这个时,我发现MouseMovedEvent和MouseDraggedEvent会向上传播’GUI树’,直到他们遇到一个带有专门针对该事件的侦听器的Component。 现在看来,我添加到panScrollPane的任何组件都会阻止任何这些MouseMotion事件,让我无法平移。

  panScrollPane.add(new JButton("This thing blocks any mouse motion events")); 

我想用手传播MouseEvent(将侦听器添加到每个组件,然后让它们将事件发送给它们的父组件)将起作用。 然而,这是一项非常耗时的工作,因为我宁愿把时间花在其他事情上,所以我想知道你是否知道任何解决这个问题的方法。

感谢您的阅读,并希望感谢您的回答! 🙂

编辑:让我的意图更清晰。 我只希望panPanel捕获mousemotion事件,任何其他事件(如MouseClick,MouseRelease)应该正常处理

使用GlassPane怎么样 ? 我认为它的意思是准确地解决这些类型的情况。

临时方法利用了通常在键绑定中使用的现有JScrollPane操作。 您必须将N调整为Scrollable的实现。

 import java.awt.Color; import java.awt.Dimension; import java.awt.EventQueue; import java.awt.Graphics; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import javax.swing.Action; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JViewport; import javax.swing.Timer; /** @see http://stackoverflow.com/questions/7201509 */ public class ScrollAction extends JPanel { private static final int TILE = 64; private static final int DELTA = 16; public ScrollAction() { this.setOpaque(false); this.setFocusable(true); this.setPreferredSize(new Dimension(50 * TILE, 50 * TILE)); } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); g.setColor(Color.lightGray); int w = this.getWidth() / TILE + 1; int h = this.getHeight() / TILE + 1; for (int row = 0; row < h; row++) { for (int col = 0; col < w; col++) { if ((row + col) % 2 == 0) { g.fillRect(col * TILE, row * TILE, TILE, TILE); } } } } private void display() { JFrame f = new JFrame("ScrollAction"); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); final JScrollPane scrollPane = new JScrollPane(this); final ScrollTimer left = new ScrollTimer(scrollPane, "scrollLeft"); final ScrollTimer right = new ScrollTimer(scrollPane, "scrollRight"); final ScrollTimer up = new ScrollTimer(scrollPane, "scrollUp"); final ScrollTimer down = new ScrollTimer(scrollPane, "scrollDown"); final JViewport viewPort = scrollPane.getViewport(); viewPort.setPreferredSize(new Dimension(5 * TILE, 5 * TILE)); viewPort.addMouseMotionListener(new MouseAdapter() { @Override public void mouseMoved(MouseEvent e) { left.stop(); if (e.getX() < DELTA) { left.start(); } right.stop(); if (e.getX() > viewPort.getWidth() - DELTA) { right.start(); } up.stop(); if (e.getY() < DELTA) { up.start(); } down.stop(); if (e.getY() > viewPort.getHeight() - DELTA) { down.start(); } } }); f.add(scrollPane); f.pack(); f.setLocationRelativeTo(null); f.setVisible(true); } private static final class ScrollTimer implements ActionListener { private static int N = 10; private static int DELAY = 100; private String cmd; private Timer timer; private Action action; private JScrollPane scrollPane; private int count; public ScrollTimer(JScrollPane scrollPane, String action) { this.cmd = action; this.timer = new Timer(DELAY, this); this.action = scrollPane.getActionMap().get(action); this.scrollPane = scrollPane; } @Override public void actionPerformed(ActionEvent e) { if (count++ < N) { action.actionPerformed(new ActionEvent(scrollPane, 0, cmd)); } else { timer.stop(); } } public void start() { count = 0; timer.start(); } public void stop() { timer.stop(); count = 0; } } public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { @Override public void run() { new ScrollAction().display(); } }); } } 

为组件及其所有子组件获取mouseEvent是非常棘手的。 您可能会考虑依赖稳定(并经过广泛测试的:-)代码。 jdk7的做法是使用JLayer(它在内部注册一个AWTEventListener,因为它具有所有权限)。 对于早期版本,您可以使用其前身JXLayer