为什么JScrollPane不会对鼠标滚轮事件做出反应? [英] Why JScrollPane does not react to mouse wheel events?

查看:355
本文介绍了为什么JScrollPane不会对鼠标滚轮事件做出反应?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 JScrollPane ,其中包含一个带有 BoxLayout (PAGE AXIS)的面板。

I have a JScrollPane containing a panel with a BoxLayout (PAGE AXIS).

我的问题是JScrollPane对鼠标滚轮事件没有反应。要使用鼠标滚轮进行滚动,我需要在 JScrollBar 上。

My problem is that the JScrollPane does not react to mouse wheel events. To make it scroll using the mouse wheel i need to be on the JScrollBar.

我发现这个线程,我没有 MouseMotionListener MouseWheelListener ,只有一个 MouseListener 。我认为我的问题来自于我的 JScrollPane 对包含其他面板本身的 JPanel 的事实。因此,当鼠标位于 JScrollPane 内的面板上时,似乎该面板消耗的事件我从未在滚动窗格中看到。

I found this thread and i have no MouseMotionListener or MouseWheelListener, only a MouseListener. I think my problem come from the fact that my JScrollPane act on a JPanel that contains other panels itself. So when the mouse is on a panel within the JScrollPane it seems that the event is consumed by this panel i never seen by the scroll pane.

是否有正确的方式,使滚动窗格的子项所捕获的事件在此滚动窗格中可见?

Is there a correct way to make the events caught by the children of the scroll pane visible to this scroll pane?

SSCCE:

这是一个简单的测试用例,试图在我的Swing应用程序中尝试显示。

Here a simple test case trying to show when i try to do in my Swing application.

框架:

public class NewJFrame extends javax.swing.JFrame {

    public NewJFrame() {
        initComponents();
        for (int i = 0; i < 50; i++) {
            jPanel1.add(new TestPanel());
        }
    }

private void initComponents() {
        jScrollPane1 = new javax.swing.JScrollPane();
        jPanel1 = new javax.swing.JPanel();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        jPanel1.setLayout(new javax.swing.BoxLayout(jPanel1,    javax.swing.BoxLayout.PAGE_AXIS));
        jScrollPane1.setViewportView(jPanel1);

        getContentPane().add(jScrollPane1, java.awt.BorderLayout.CENTER);

        pack();
    }

    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {
           @Override
            public void run() {
                new NewJFrame().setVisible(true);
           }
        });
    }
}

TestPanel 定义:

And the TestPanel definition:

public class TestPanel extends javax.swing.JPanel {

    public TestPanel() {
        initComponents();
    }

    private void initComponents() {

        jLabel1 = new javax.swing.JLabel();
        jLabel2 = new javax.swing.JLabel();
        jScrollPane1 = new javax.swing.JScrollPane();
        jTextArea1 = new javax.swing.JTextArea();

        jLabel1.setText("jLabel1");

        setBackground(new java.awt.Color(255, 51, 51));
        setLayout(new java.awt.BorderLayout());

        jLabel2.setText("TEST LABEL");
        jLabel2.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        add(jLabel2, java.awt.BorderLayout.PAGE_START);

        jTextArea1.setEditable(false);
        jTextArea1.setColumns(20);
        jTextArea1.setRows(5);
        jTextArea1.setFocusable(false);
        jScrollPane1.setViewportView(jTextArea1);

        add(jScrollPane1, java.awt.BorderLayout.CENTER);
   }
}

JTextArea 似乎消耗了事件,因为当鼠标光标在它内部时,滚动使用轮不起作用。我必须将鼠标光标放在文本区域之外,使其再次工作。

The JTextArea seems to consume the event since when the mouse cursor is inside it, the scrolling using wheel does not work. I have to put the mouse cursor outside the text area to make it works again.

推荐答案

Walter打败了我来分析问题: - )

Walter beat me to analysing the issue :-)

添加一些细节:

JScrollPane支持mouseWheelHandling是正确的。根据mouseEvent调度的规则,最顶层(以z顺序)组件获取事件,这是在textArea周围的scrollPane。所以如果不需要转动文本区域,一个简单的解决方案可能是在其scrollPane中禁用轮子支持。而JScrollPane甚至有api来做:

It's correct that a JScrollPane supports mouseWheelHandling. According to the rules of mouseEvent dispatching, the top-most (in z-order) component gets the event, and that's the scrollPane around the textArea. So if wheeling the textarea is not required, a simple solution might be to disable the wheel-support in its scrollPane. And JScrollPane even has api for doing it:

scrollPane.setWheelScrollingEnabled(false); 

不幸的是,这不行。原因不起作用是在事件调度链中最终调用到eventTypeEnabled中的此属性不起作用:

Unfortunately, that doesn't work. Reason it's not working is that this property has no effect in the event dispatch chain which ultimately calls into eventTypeEnabled:

case MouseEvent.MOUSE_WHEEL:
      if ((eventMask & AWTEvent.MOUSE_WHEEL_EVENT_MASK) != 0 ||
          mouseWheelListener != null) {
          return true;
      }

如果安装了mouseWheelListener,则返回true - 这是由BasicScrollPaneUI无条件完成的,并且当wheelEnabled属性被更改时(ui甚至不监听该属性...),并且在属性为false的情况下,监听器根本不执行任何操作,并且。这些事实中至少有一个是一个错误,你应该

This returns true if a mouseWheelListener is installed - which is done unconditionally by BasicScrollPaneUI, and not removed when the wheelEnabled property is changed (the ui doesn't even listen to that property ...) Plus the listener simply does nothing if the property is false. At least one of those facts is a bug, the ui should


  • 根据wheelEnabled
  • $ b删除/添加监听器$ b
  • 或者:实现监听器,以便将事件发送到链上(就像Walter在他的例子中)

  • either remove/add the listener depending on wheelEnabled
  • or: implement the listener such that it dispatches the event up the chain (as Walter does in his example)

第一个选项可以通过应用程序代码来处理:

The first option can be handled by application code:

scrollPane = new JScrollPane();
scrollPane.removeMouseWheelListener(scrollPane.getMouseWheelListeners()[0]);

这是一个黑客(作为bug-解决方法总是:-),生产代码将听轮可以重新安装,如果需要加听LAF更改更新/重新删除由ui安装的听众。

it's a bit of a hack (as bug-workarounds always are :-), production code would have to listen to the wheelEnable to re-install if needed plus listen to LAF changes to update/re-remove the listeners installed by the ui.

轻微实现第二个选项如果wheelEnabled为false,则通过子类化JScrollPane并将事件发送到父级来修改(关于Walter的调度):

Implementing the second option in slight modification (as to Walter's dispatching) by subclassing the JScrollPane and dispatch the event to parent if the wheelEnabled is false:

scrollPane = new JScrollPane() {

    @Override
    protected void processMouseWheelEvent(MouseWheelEvent e) {
        if (!isWheelScrollingEnabled()) {
            if (getParent() != null) 
                getParent().dispatchEvent(
                        SwingUtilities.convertMouseEvent(this, e, getParent()));
            return;
        }
        super.processMouseWheelEvent(e);
    }

};
scrollPane.setWheelScrollingEnabled(false); 

这篇关于为什么JScrollPane不会对鼠标滚轮事件做出反应?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆