Home >Java >javaTutorial >How to Effectively Use MouseMotionListener in Java Swing with Nested Components?
In developing a touch user interface within Swing, one may encounter the challenge of using the MouseMotionListener interface effectively when nested components obstruct event propagation.
The MouseMovedEvent and MouseDraggedEvent are intended to propagate up the GUI hierarchy, but they can become blocked by components within the container. For instance, when adding a JButton to a JScrollPane, events might不再trigger the JScrollPane's MouseMotionListener.
To overcome this issue, we present an ad hoc approach that utilizes the JScrollPane's built-in actions, typically used for key bindings. By adjusting the N variable to align with your implementation, this solution enables event propagation without the need for extensive manual event forwarding.
Here's a working example:
<code class="java">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; public class ScrollAction extends JFrame { private static final int TILE = 64; private static final int DELTA = 16; public ScrollAction() { setupAndDisplay(); } private void setupAndDisplay() { setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JPanel panel = new JPanel() { @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); } } } } }; panel.setOpaque(false); panel.setFocusable(true); panel.setPreferredSize(new Dimension(50 * TILE, 50 * TILE)); final JScrollPane scrollPane = new JScrollPane(panel); final JViewport viewport = scrollPane.getViewport(); viewport.addMouseMotionListener(new MouseAdapter() { @Override public void mouseMoved(MouseEvent e) { handleMouseMovement(scrollPane, e); } }); add(scrollPane); } 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; } } private void handleMouseMovement(JScrollPane scrollPane, MouseEvent e) { 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"); 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(); } } public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { @Override public void run() { new ScrollAction().setVisible(true); pack(); } }); } }</code>
The above is the detailed content of How to Effectively Use MouseMotionListener in Java Swing with Nested Components?. For more information, please follow other related articles on the PHP Chinese website!