我正在使用滚动窗格设置来使用自定义滚动条,除此之外我还想在滚动条的拇指上安装一个监听器,这样每当鼠标进入拇指区域时,它就会改变颜色或边框。我搜索了BasicScrollBarUI(由我的自定义滚动条UI扩展)并找到了方法installListeners(),所以我覆盖了它并让它再调用一个拇指区域的监听器。
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);
}
});
}
}
滚动条的简单自定义用户界面:
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");
}
}
}
}
当鼠标从右侧或左侧进入拇指区域时,听众工作正常,但它并不总是适用于顶部或底部。对于这些侧面,它仅在拇指触摸其中一个按钮时起作用。例如,当滚动条位于最顶部时,当鼠标从顶部按钮进入拇指区域但不从下方进入时,侦听器仅起作用(左右侧除外)。滚动条触摸减小按钮时会发生相反的情况(仅适用于右/左/底侧,但不适用于顶部)。当拇指介于两者之间而没有触摸任何按钮时,只有左右两侧工作。如果运行代码,您可以看到所有这些。
我还尝试使用一个现有的侦听器(而不是创建我自己的),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");
}
}
}
}
答案 0 :(得分:1)
问题在于您正在侦听滚动条,这意味着它是Thumb和Thumb可以移动的区域(轨道)。因此,mouseEntered方法中的测试条件并不总是如此。例如,假设拇指位于垂直滚动条的顶部,通过底部进入意味着您将首先进入滚动条轨道,然后将鼠标移动到拇指区域 - &gt;没有鼠标进入事件。
以下是您的代码的略微修改版本。它主要做的还是监听鼠标“移动”事件(通过将你的监听器添加为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);
}
});
}
}
答案 1 :(得分:1)
也许没有回答你的问题,但是你看看了AdjustmentListener,那么理论上并不重要的是哪里转换了MousePoint,这里有一些关于这个问题的例子
答案 2 :(得分:0)
当您在轨道中而不是在拇指中输入鼠标时,将激活mouseEntered。您的代码仅在您不在轨道上并且同时在拇指上输入时才有效
改为使用mouseMove事件,您将使其正常工作:
@Override
public void mouseMoved(MouseEvent e) {
currentMouseX = e.getX();
currentMouseY = e.getY();
if (getThumbBounds().contains(currentMouseX, currentMouseY)) {
System.out.println("THUMB");
}
}