如何将 mouseListener 添加到 jscrollbar?

How do you add a mouseListener to a jscrollbar?

我有 mouseEntered 和 mouseExited 事件导致 jPanel 内容发生变化,从而改变了 jPanel 的大小。在 mouseEntered 之后,内容会增长并且可以滚动。在 mouseExited 后,内容会缩小并且不可滚动。

问题是将鼠标悬停在滚动条上会触发 jPanel 的 mouseExited 事件,因此当用户想要拖动滚动条的旋钮时,当他们点击它时它会消失。

如果我可以将 mouseListener 添加到滚动条本身,我想我可以防止内容缩小。但我从未将 mouseListener 添加到滚动条。如何通过滚动条在 mouseEntered/Exited 上触发事件?

是的,您可以将 mouseListener 附加到滚动条。当您的内容在 mouseEntered/mouseExited WRT a jPanel 上更改时,这是必要的,因为将鼠标悬停在 jPanel 的滚动条上会触发 mouseExited。您必须实现 2 个方面,以保持内容就像您悬停在 jPanel 上一样:mouseEntered/mouseExited 和 mouseClicked/mouseReleased。这样做的原因是当拖动滚动条的旋钮时,鼠标可以悬停在滚动条上,而您不希望内容在滚动中途发生变化。

你只需要将监听器直接添加到滚动条即可:

myscrollbar.addMouseListener(new MouseAdapter() {

        @Override
        public void mouseEntered(MouseEvent e) {
            if(overScrollOffTimer != null) {
                overScrollOffTimer.stop();
                overScrollOffTimer = null;
            }
            mymodel.setOverScrollbar(true);
        }

        @Override
        public void mouseExited(MouseEvent e) {
            if(overScrollOffTimer == null) {
                overScrollOffTimer = new Timer(250,
                        overScrollOffListener);
                overScrollOffTimer.start();
            }
        }

        @Override
        public void mousePressed(MouseEvent e) {
            if(activeScrollOffTimer != null) {
                activeScrollOffTimer.stop();
                activeScrollOffTimer = null;
            }
            mymodel.setBeingScrolled(true);
        }

        @Override
        public void mouseReleased(MouseEvent e) {
            if(activeScrollOffTimer == null) {
                activeScrollOffTimer =
                    new Timer(250,
                              activeScrollOffListener);
                activeScrollOffTimer.start();
            }
        }
    });

在我的 mouseListener 中,我添加了 2 个计时器来启动 jPanel 内容的更改(250 毫秒后)(加上 jPanel 悬停的第三个计时器)。如果没有计时器,当您将鼠标从面板悬停到滚动条或返回时,内容可能会在视觉上打嗝。一个计时器在 mouseExited 从滚动条开始。另一个在 mouseReleased 滚动条旋钮时启动。我跟踪鼠标是否在滚动条上、移动滚动条以及鼠标是否在 jPanel 上。如果这些事情中的任何一个是真的,我就会展示我的大量内容。不然如果都是假的,我就画我的小内容了

这里有一个定时器的例子:

private javax.swing.Timer overScrollOffTimer;
ActionListener overScrollOffListener = new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent evt) {
        if(evt.getSource() == overScrollOffTimer) {
            /* Stop timer */
            overScrollOffTimer.stop();
            overScrollOffTimer = null;

            mymodel.setOverScrollbar(false);
            mymodel.notifyObservers();
            revalidate();
            repaint();
        }
    }
};

private javax.swing.Timer activeScrollOffTimer;
ActionListener activeScrollOffListener = new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent evt) {
        if (evt.getSource() == activeScrollOffTimer) {
            /* Stop timer */
            activeScrollOffTimer.stop();
            activeScrollOffTimer = null;

            mymodel.setBeingScrolled(false);
            mymodel.notifyObservers();
            revalidate();
            repaint();
        }
    }
};

我没有为 jPanel 添加计时器或鼠标侦听器,但在没有 clicked/released 方法的情况下也是类似的尝试。

请注意,我跟踪了模型中悬停和滚动的状态,因为其他 jPanel 也基于此悬停交互显示不同的内容,并且它们都可以访问该模型。

顺便说一句,我使用了 "OffTimer"、"OffListener" 等术语,因为我基本上只在将鼠标悬停在一组面板上时显示真实内容。将鼠标悬停在任何这些面板上基本上都会导致内容消失。我希望内容消失的原因是,当您将鼠标悬停在内容上时,内容会发生变化,我不希望用户被静态不动的内容所迷惑,并导致他们做出错误的视觉结论(例如,在 2 个面板中关联视觉对齐的数据其对齐方式根据悬停位置而变化)。

为什么不将滚动窗格放在另一个 JPanel 中,而是在该外部窗格中添加侦听器。然后移动到滚动条不会触发 mouseExited 事件;仅当您通过滚动条(退出外部面板)或沿另一个方向超出滚动面板时才会触发它。