MouseMotionListener in Java Swing, using it with components inside components etc

This ad hoc approach leverages the existing JScrollPane actions that are usually used in key bindings. You’ll have to tune N to your implementation of 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();
            }
        });
    }
}

Leave a Comment