gpt4 book ai didi

swing - 为什么 JScrollPane 不对鼠标滚轮事件使用react?

转载 作者:行者123 更新时间:2023-12-03 22:09:51 24 4
gpt4 key购买 nike

我有一个 JScrollPane包含一个带有 BoxLayout 的面板(页轴)。

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

我找到了 thread我没有MouseMotionListenerMouseWheelListener , 只有一个 MouseListener .我认为我的问题来自我的 JScrollPaneJPanel 采取行动包含其他面板本身。所以当鼠标在JScrollPane内的一个面板上时似乎该事件已被此面板消耗,我从未在滚动 Pane 中看到过。

是否有正确的方法使滚动 Pane 的子级捕获的事件对此滚动 Pane 可见?

SSCCE:

enter image description here

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

框架:

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定义:
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似乎消耗了该事件,因为当鼠标光标在其中时,使用滚轮的滚动不起作用。我必须将鼠标光标放在文本区域之外才能使其再次工作。

最佳答案

沃尔特打败了我来分析这个问题:-)

添加一点细节:

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

scrollPane.setWheelScrollingEnabled(false); 

不幸的是,这不起作用。它不起作用的原因是此属性在最终调用 eventTypeEnabled 的事件调度链中没有影响:
case MouseEvent.MOUSE_WHEEL:
if ((eventMask & AWTEvent.MOUSE_WHEEL_EVENT_MASK) != 0 ||
mouseWheelListener != null) {
return true;
}

如果安装了 mouseWheelListener,则返回 true - 这是由 BasicScrollPaneUI 无条件完成的,并且在 wheelEnabled 属性更改时不会被删除(ui 甚至不监听该属性......)另外,如果该属性是,监听器什么也不做错误的。这些事实中至少有一个是错误,用户界面应该
  • 根据 wheelEnabled
  • 删除/添加监听器
  • 或:实现监听器,使其沿链向上调度事件(如 Walter 在他的示例中所做的那样)

  • 第一个选项可以由应用程序代码处理:
    scrollPane = new JScrollPane();
    scrollPane.removeMouseWheelListener(scrollPane.getMouseWheelListeners()[0]);

    这有点像 hack(因为 bug 变通方法总是 :-),生产代码必须听 wheelEnable 以在需要时重新安装,并听 LAF 更改以更新/重新删除由 ui 安装的监听器。

    通过对 JScrollPane 进行子类化并在 wheelEnabled 为 false 时将事件分派(dispatch)给父级,在轻微修改中实现第二个选项(关于 Walter 的调度):
    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);

    关于swing - 为什么 JScrollPane 不对鼠标滚轮事件使用react?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12911506/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com