1

カスタムスクロールバーを使用するためにスクロールペインセットを使用しています。とりわけ、スクロールバーの親指にリスナーをインストールして、マウスが親指領域に入ると色や境界線を変更できるようにしたいと考えていました。BasicScrollBarUI (カスタム スクロールバー UI で拡張) を検索したところ、メソッド installListeners() が見つかったので、それをオーバーライドして、サム領域のもう 1 つのリスナーを呼び出すようにしました。

SSCCE:

public class TestScrollBar extends JFrame {

    public TestScrollBar() {

        JPanel innerPanel = new JPanel();
        innerPanel.setLayout(new BoxLayout(innerPanel, BoxLayout.Y_AXIS));
        for (int i=1; i<=10; i++) {
            innerPanel.add(new JLabel("Label "+i));
            innerPanel.add(Box.createRigidArea(new Dimension(0, 20)));
        }

        JScrollPane scrollPane = new JScrollPane(innerPanel);
        scrollPane.setPreferredSize(new Dimension(innerPanel.getPreferredSize().width, innerPanel.getPreferredSize().height/2));

        scrollPane.getVerticalScrollBar().setUI(new CustomScrollBarUI());

        this.setLayout(new BorderLayout());
        this.add(Box.createRigidArea(new Dimension(0, 20)), BorderLayout.NORTH);
        this.add(Box.createRigidArea(new Dimension(0, 20)), BorderLayout.SOUTH);
        this.add(Box.createRigidArea(new Dimension(20, 0)), BorderLayout.EAST);
        this.add(Box.createRigidArea(new Dimension(20, 0)), BorderLayout.WEST);
        this.add(scrollPane, BorderLayout.CENTER);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                TestScrollBar frame = new TestScrollBar();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }
}

スクロールバー用のシンプルなカスタム UI:

public class CustomScrollBarUI extends BasicScrollBarUI {

    @Override
    protected void installListeners() {
        super.installListeners();
        scrollbar.addMouseListener(new CustomListener());
    }

    protected class CustomListener extends MouseAdapter {
        public void mouseEntered(MouseEvent e) {
            if (getThumbBounds().contains(e.getX(), e.getY())) {
                System.out.println("THUMB");
            }
        }
    }
}

リスナーは、マウスが右または左から親指領域に入ると正常に動作しますが、常に上または下側では機能するとは限りません。これらの面では、親指がボタンの 1 つに触れている場合にのみ機能します。たとえば、スクロールバーが一番上にある場合、リスナーは、マウスが下からではなく上のボタンからサム領域に入ったときにのみ (左右を除いて) 動作します。スクロールバーが減少ボタンに触れると、反対のことが起こります (右/左/下側でのみ機能し、上では機能しません)。親指がボタンのいずれにも触れずにその間のどこかにある場合、左右の側面のみが機能します。コードを実行すると、これらすべてを確認できます。

また、(独自のリスナーを作成する代わりに) 既存のリスナーの 1 つ、BasicScrollBarUI.TrackListener を使用しようとしました。ここでは、親指領域のみをリッスンするメソッドを追加しましたが、結果はまったく同じです。

public class CustomScrollBarUI extends BasicScrollBarUI {
    @Override
    protected TrackListener createTrackListener(){
        return new TrackListener();
    }

    protected class TrackListener extends BasicScrollBarUI.TrackListener {
        public void mouseEntered(MouseEvent e) {
            currentMouseX = e.getX();
            currentMouseY = e.getY();
            if (getThumbBounds().contains(currentMouseX, currentMouseY)) {
                System.out.println("THUMB");
            }
        }
    }
}
4

3 に答える 3

1

あなたの質問には答えないかもしれませんが、AdjustmentListener を見たことがあります。理論的には、MousePoint がどこに変換されるかは問題ではありません。この問題に関するいくつかの例を次に示します。

于 2012-09-12T20:31:15.953 に答える
1

問題は、スクロールバーをリッスンすることです。つまり、それは Thumb であり、Thumb が移動できる領域 (トラック) です。したがって、mouseEntered メソッドのテスト条件が常に true とは限りません。たとえば、親指が垂直スクロールバーの上部にあるとします。下部から入力すると、最初にスクロールバートラックに入り、次にマウスを親指領域に移動することを意味します --> マウス入力イベントはありません。

これは、コードのわずかに変更されたバージョンです。主に行うことは、マウスの「移動」イベントもリッスンし (リスナーを MouseMotionListener として追加することにより)、期待どおりに動作します。

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import javax.swing.plaf.basic.BasicScrollBarUI;

public class TestScrollBar extends JFrame {

    public static class CustomScrollBarUI extends BasicScrollBarUI {

        @Override
        protected void installListeners() {
            super.installListeners();
            CustomListener listener = new CustomListener();
            scrollbar.addMouseListener(listener);
            scrollbar.addMouseMotionListener(listener);
        }

        protected class CustomListener extends MouseAdapter {
            boolean isInsideThumb = false;

            @Override
            public void mouseEntered(MouseEvent e) {
                handleMouseEvent(e);
            }

            @Override
            public void mouseMoved(MouseEvent e) {
                handleMouseEvent(e);
            }

            @Override
            public void mouseExited(MouseEvent e) {
                handleMouseEvent(e);
            }

            private void handleMouseEvent(MouseEvent e) {
                if (getThumbBounds().contains(e.getX(), e.getY())) {
                    if (!isInsideThumb) {
                        System.out.println("THUMB");
                        isInsideThumb = true;
                    }
                } else {
                    if (isInsideThumb) {
                        System.out.println("OUT OF THUMB");
                        isInsideThumb = false;
                    }
                }
            }
        }
    }

    public TestScrollBar() {

        JPanel innerPanel = new JPanel();
        innerPanel.setLayout(new BoxLayout(innerPanel, BoxLayout.Y_AXIS));
        for (int i = 1; i <= 10; i++) {
            innerPanel.add(new JLabel("Label " + i));
            innerPanel.add(Box.createRigidArea(new Dimension(0, 20)));
        }

        JScrollPane scrollPane = new JScrollPane(innerPanel);
        scrollPane.setPreferredSize(new Dimension(innerPanel.getPreferredSize().width, innerPanel.getPreferredSize().height / 2));

        scrollPane.getVerticalScrollBar().setUI(new CustomScrollBarUI());

        this.setLayout(new BorderLayout());
        this.add(Box.createRigidArea(new Dimension(0, 20)), BorderLayout.NORTH);
        this.add(Box.createRigidArea(new Dimension(0, 20)), BorderLayout.SOUTH);
        this.add(Box.createRigidArea(new Dimension(20, 0)), BorderLayout.EAST);
        this.add(Box.createRigidArea(new Dimension(20, 0)), BorderLayout.WEST);
        this.add(scrollPane, BorderLayout.CENTER);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                TestScrollBar frame = new TestScrollBar();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }
}
于 2012-09-12T18:43:05.740 に答える
0

mouseEntered は、親指ではなくトラックにマウスを入力するとアクティブになります。あなたのコードは、あなたがトラックの外にいて、同時に親指に入ったときにのみ機能します

代わりに mouseMove イベントを使用すると、動作するようになります:

@Override
public void mouseMoved(MouseEvent e) {
    currentMouseX = e.getX();
    currentMouseY = e.getY();
    if (getThumbBounds().contains(currentMouseX, currentMouseY)) {
        System.out.println("THUMB");
    }
}
于 2012-09-12T18:53:07.737 に答える