Java 在滚动条上注册侦听器';拇指

Java 在滚动条上注册侦听器';拇指,java,swing,jscrollpane,mouselistener,jscrollbar,Java,Swing,Jscrollpane,Mouselistener,Jscrollbar,我正在使用一个scrollpane设置来使用一个自定义滚动条,除此之外,我还想在滚动条的拇指上安装一个监听器,这样每当鼠标进入拇指区域时,它就可以改变颜色或边框。我搜索了BasicScrollBarUI(由我的自定义scrollbar UI扩展)并找到了installListeners()方法,因此我重写了它并使它为thumb区域调用了一个以上的侦听器 SSCCE: public class TestScrollBar extends JFrame { public TestScrol

我正在使用一个scrollpane设置来使用一个自定义滚动条,除此之外,我还想在滚动条的拇指上安装一个监听器,这样每当鼠标进入拇指区域时,它就可以改变颜色或边框。我搜索了BasicScrollBarUI(由我的自定义scrollbar UI扩展)并找到了installListeners()方法,因此我重写了它并使它为thumb区域调用了一个以上的侦听器

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);
            }
        });
    }
}
当鼠标从右侧或左侧进入拇指区域时,侦听器可以正常工作,但它并不总是在顶部或底部工作。对于这些侧边,它仅在拇指触摸其中一个按钮时起作用。例如,当滚动条位于最上方时,当鼠标从上方按钮进入拇指区域而不是从下方进入拇指区域时,侦听器仅工作(除了左右侧)。当滚动条触碰减少按钮时,会发生相反的情况(仅适用于右/左/底部,但不适用于顶部)。当拇指在两个按钮之间的某个位置而不触碰任何按钮时,则只有左右两侧起作用。如果运行代码,您可以看到所有这些

我还尝试使用一个现有的监听器(而不是创建我自己的监听器),BasicScrollBarUI.TrackListener,在这里我添加了一个方法,只监听thumb区域,但结果完全相同:

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");
            }
        }
    }
}

问题是你在听滚动条,这意味着它是拇指和拇指可以移动的区域(轨迹)。因此,mouseEntered方法中的测试条件并不总是正确的。例如,假设拇指位于垂直滚动条的顶部,通过底部输入意味着您将首先输入滚动条轨迹,然后将鼠标移动到拇指区域-->无鼠标输入事件

这是您的代码的一个稍加修改的版本。它主要做的是监听鼠标“移动”事件(通过将您的监听器添加为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);
            }
        });
    }
}
导入java.awt.BorderLayout;
导入java.awt.Dimension;
导入java.awt.event.MouseAdapter;
导入java.awt.event.MouseEvent;
导入javax.swing.Box;
导入javax.swing.BoxLayout;
导入javax.swing.JFrame;
导入javax.swing.JLabel;
导入javax.swing.JPanel;
导入javax.swing.JScrollPane;
导入javax.swing.SwingUtilities;
导入javax.swing.plaf.basic.BasicScrollBarUI;
公共类TestScrollBar扩展了JFrame{
公共静态类CustomScrollBarUI扩展了BasicScrollBarUI{
@凌驾
受保护的void installListeners(){
super.installListeners();
CustomListener=新建CustomListener();
scrollbar.addMouseListener(侦听器);
scrollbar.addMouseMotionListener(listener);
}
受保护的类CustomListener扩展了MouseAdapter{
布尔值isInsideThumb=false;
@凌驾
公共无效鼠标事件(鼠标事件e){
handleMouseEvent(e);
}
@凌驾
public void mouseMoved(MouseEvent e){
handleMouseEvent(e);
}
@凌驾
公共无效mouseExited(MouseEvent e){
handleMouseEvent(e);
}
私有无效handleMouseEvent(MouseeEvent e){
if(getThumbBounds().contains(e.getX(),e.getY())){
如果(!isInsideThumb){
System.out.println(“拇指”);
isInsideThumb=真;
}
}否则{
如果(isInsideThumb){
System.out.println(“拇指外”);
isInsideThumb=假;
}
}
}
}
}
公共测试滚动条(){
JPanel innerPanel=新的JPanel();
setLayout(新的BoxLayout(innerPanel,BoxLayout.Y_轴));

对于(int i=1;i当您在轨迹中而不是在拇指中输入鼠标时,鼠标输入被激活。您的代码仅在您在轨迹之外并同时在轨迹上和拇指中输入时有效

改为使用mouseMove事件,您将使其正常工作:

@Override
public void mouseMoved(MouseEvent e) {
    currentMouseX = e.getX();
    currentMouseY = e.getY();
    if (getThumbBounds().contains(currentMouseX, currentMouseY)) {
        System.out.println("THUMB");
    }
}

也许不能回答您的问题,但您已经了解了AdjustmentListener,那么从理论上讲,转换鼠标点的位置无关紧要,下面是一些有关此问题的示例

@Override
public void mouseMoved(MouseEvent e) {
    currentMouseX = e.getX();
    currentMouseY = e.getY();
    if (getThumbBounds().contains(currentMouseX, currentMouseY)) {
        System.out.println("THUMB");
    }
}