Java 如何使嵌套的JScrollPane正确工作?

Java 如何使嵌套的JScrollPane正确工作?,java,swing,jscrollpane,Java,Swing,Jscrollpane,如图所示,我有两个JScrollPane,A和B。我想要实现的是,当光标位于B上时,您滚动鼠标滚轮: 1) 如果B有可滚动的内容,只需滚动B即可 2) 如果B已经滚动到末尾,或者B只有很少的不可滚动的内容,请滚动A 现在发生的事情是,无论发生什么,鼠标滚轮事件总是被B使用,因此A永远无法滚动。有什么建议吗?提前感谢。这里有一个使用JLayer的可能实现: import java.awt.*; import java.awt.event.*; import javax.swing.*; impor

如图所示,我有两个JScrollPane,A和B。我想要实现的是,当光标位于B上时,您滚动鼠标滚轮:

1) 如果B有可滚动的内容,只需滚动B即可

2) 如果B已经滚动到末尾,或者B只有很少的不可滚动的内容,请滚动A


现在发生的事情是,无论发生什么,鼠标滚轮事件总是被B使用,因此A永远无法滚动。有什么建议吗?提前感谢。

这里有一个使用
JLayer
的可能实现:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.plaf.LayerUI;
import javax.swing.table.*;
import javax.swing.text.*;

public class WheelOverNestedScrollPaneTest {
  private static final String TEXT = "aaa\na\na\na\na\naaaa\na\na\na\naaaa\n";

  private JComponent makeUI() {
    JTextArea textArea = new JTextArea(TEXT + TEXT + TEXT);
    JTable table = new JTable(50, 3);
    JTree tree = new JTree();
    tree.setVisibleRowCount(5);

    JTextPane textPane = new JTextPane();
    textPane.setEditable(false);
    textPane.setMargin(new Insets(5, 10, 5, 5));
    Document doc = textPane.getDocument();
    try {
      doc.insertString(doc.getLength(), TEXT, null);
      textPane.insertComponent(createChildScrollPane(textArea));
      doc.insertString(doc.getLength(), "\n", null);
      doc.insertString(doc.getLength(), TEXT, null);
      textPane.insertComponent(createChildScrollPane(table));
      doc.insertString(doc.getLength(), "\n", null);
      doc.insertString(doc.getLength(), TEXT, null);
      textPane.insertComponent(new JScrollPane(tree));
      doc.insertString(doc.getLength(), "\n", null);
      doc.insertString(doc.getLength(), TEXT, null);
    } catch (BadLocationException ex) {
      ex.printStackTrace();
    }
    return new JLayer<JScrollPane>(
        new JScrollPane(textPane), new WheelScrollLayerUI());
  }
  protected static JScrollPane createChildScrollPane(Component view) {
    return new JScrollPane(view) {
      @Override public Dimension getPreferredSize() {
        Dimension d = super.getPreferredSize();
        d.height = 120;
        return d;
      }
    };
  }
  public static void main(String... args) {
    EventQueue.invokeLater(() -> {
      JFrame f = new JFrame();
      f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
      f.getContentPane().add(new WheelOverNestedScrollPaneTest().makeUI());
      f.setSize(320, 240);
      f.setLocationRelativeTo(null);
      f.setVisible(true);
    });
  }
}

// http://java-swing-tips.blogspot.jp/2014/09/forward-mouse-wheel-scroll-event-in.html
class WheelScrollLayerUI extends LayerUI<JScrollPane> {
  @Override public void installUI(JComponent c) {
    super.installUI(c);
    if (c instanceof JLayer) {
      ((JLayer) c).setLayerEventMask(AWTEvent.MOUSE_WHEEL_EVENT_MASK);
    }
  }
  @Override public void uninstallUI(JComponent c) {
    if (c instanceof JLayer) {
      ((JLayer) c).setLayerEventMask(0);
    }
    super.uninstallUI(c);
  }
  @Override protected void processMouseWheelEvent(
      MouseWheelEvent e, JLayer<? extends JScrollPane> l) {
    Component c = e.getComponent();
    int dir = e.getWheelRotation();
    JScrollPane main = l.getView();
    if (c instanceof JScrollPane && !c.equals(main)) {
      JScrollPane child = (JScrollPane) c;
      BoundedRangeModel m = child.getVerticalScrollBar().getModel();
      int extent  = m.getExtent();
      int minimum = m.getMinimum();
      int maximum = m.getMaximum();
      int value   = m.getValue();
      if (value + extent >= maximum && dir > 0 || value <= minimum && dir < 0) {
        main.dispatchEvent(SwingUtilities.convertMouseEvent(c, e, main));
      }
    }
  }
}
import java.awt.*;
导入java.awt.event.*;
导入javax.swing.*;
导入javax.swing.plaf.LayerUI;
导入javax.swing.table.*;
导入javax.swing.text.*;
公共类车轮重叠滚动面板测试{
私有静态最终字符串TEXT=“aaa\na\na\na\na\naaaa\na\na\na\naaaa\n”;
私有JComponent makeUI(){
JTextArea textArea=新的JTextArea(文本+文本+文本);
JTable表=新的JTable(50,3);
JTree树=新的JTree();
树。设置VisibleRowCount(5);
JTextPane textPane=新的JTextPane();
textPane.setEditable(false);
setMargin(新的插图(5,10,5,5));
Document doc=textPane.getDocument();
试一试{
doc.insertString(doc.getLength(),文本,空);
插入组件(createChildScrollPane(textArea));
doc.insertString(doc.getLength(),“\n”,null);
doc.insertString(doc.getLength(),文本,空);
insertComponent(createChildScrollPane(表));
doc.insertString(doc.getLength(),“\n”,null);
doc.insertString(doc.getLength(),文本,空);
insertComponent(新的JScrollPane(树));
doc.insertString(doc.getLength(),“\n”,null);
doc.insertString(doc.getLength(),文本,空);
}捕获(BadLocationException ex){
例如printStackTrace();
}
返回新JLayer(
新的JScrollPane(textPane),新的WheelScrollLayerUI());
}
受保护的静态JScrollPane createChildScrollPane(组件视图){
返回新的JScrollPane(视图){
@重写公共维度getPreferredSize(){
维度d=super.getPreferredSize();
d、 高度=120;
返回d;
}
};
}
公共静态void main(字符串…参数){
EventQueue.invokeLater(()->{
JFrame f=新的JFrame();
f、 setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f、 getContentPane().add(新建WheelOverNestedScrollPaneTest().makeUI());
f、 设置大小(320240);
f、 setLocationRelativeTo(空);
f、 setVisible(真);
});
}
}
// http://java-swing-tips.blogspot.jp/2014/09/forward-mouse-wheel-scroll-event-in.html
类WheelScrollLayerUI扩展了LayerUI{
@覆盖公共void installUI(JComponent c){
super.installUI(c);
if(JLayer的c实例){
((JLayer)c).setLayerEventMask(awteEvent.MOUSE\u WHEEL\u EVENT\u MASK);
}
}
@覆盖公共用户界面(JComponent c){
if(JLayer的c实例){
((JLayer)c).SetLayerReventMask(0);
}
super.ui(c);
}
@重写受保护的void processMouseWheelEvent(

mouseweellevent e,JLayer这里有一个使用
JLayer
的可能实现:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.plaf.LayerUI;
import javax.swing.table.*;
import javax.swing.text.*;

public class WheelOverNestedScrollPaneTest {
  private static final String TEXT = "aaa\na\na\na\na\naaaa\na\na\na\naaaa\n";

  private JComponent makeUI() {
    JTextArea textArea = new JTextArea(TEXT + TEXT + TEXT);
    JTable table = new JTable(50, 3);
    JTree tree = new JTree();
    tree.setVisibleRowCount(5);

    JTextPane textPane = new JTextPane();
    textPane.setEditable(false);
    textPane.setMargin(new Insets(5, 10, 5, 5));
    Document doc = textPane.getDocument();
    try {
      doc.insertString(doc.getLength(), TEXT, null);
      textPane.insertComponent(createChildScrollPane(textArea));
      doc.insertString(doc.getLength(), "\n", null);
      doc.insertString(doc.getLength(), TEXT, null);
      textPane.insertComponent(createChildScrollPane(table));
      doc.insertString(doc.getLength(), "\n", null);
      doc.insertString(doc.getLength(), TEXT, null);
      textPane.insertComponent(new JScrollPane(tree));
      doc.insertString(doc.getLength(), "\n", null);
      doc.insertString(doc.getLength(), TEXT, null);
    } catch (BadLocationException ex) {
      ex.printStackTrace();
    }
    return new JLayer<JScrollPane>(
        new JScrollPane(textPane), new WheelScrollLayerUI());
  }
  protected static JScrollPane createChildScrollPane(Component view) {
    return new JScrollPane(view) {
      @Override public Dimension getPreferredSize() {
        Dimension d = super.getPreferredSize();
        d.height = 120;
        return d;
      }
    };
  }
  public static void main(String... args) {
    EventQueue.invokeLater(() -> {
      JFrame f = new JFrame();
      f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
      f.getContentPane().add(new WheelOverNestedScrollPaneTest().makeUI());
      f.setSize(320, 240);
      f.setLocationRelativeTo(null);
      f.setVisible(true);
    });
  }
}

// http://java-swing-tips.blogspot.jp/2014/09/forward-mouse-wheel-scroll-event-in.html
class WheelScrollLayerUI extends LayerUI<JScrollPane> {
  @Override public void installUI(JComponent c) {
    super.installUI(c);
    if (c instanceof JLayer) {
      ((JLayer) c).setLayerEventMask(AWTEvent.MOUSE_WHEEL_EVENT_MASK);
    }
  }
  @Override public void uninstallUI(JComponent c) {
    if (c instanceof JLayer) {
      ((JLayer) c).setLayerEventMask(0);
    }
    super.uninstallUI(c);
  }
  @Override protected void processMouseWheelEvent(
      MouseWheelEvent e, JLayer<? extends JScrollPane> l) {
    Component c = e.getComponent();
    int dir = e.getWheelRotation();
    JScrollPane main = l.getView();
    if (c instanceof JScrollPane && !c.equals(main)) {
      JScrollPane child = (JScrollPane) c;
      BoundedRangeModel m = child.getVerticalScrollBar().getModel();
      int extent  = m.getExtent();
      int minimum = m.getMinimum();
      int maximum = m.getMaximum();
      int value   = m.getValue();
      if (value + extent >= maximum && dir > 0 || value <= minimum && dir < 0) {
        main.dispatchEvent(SwingUtilities.convertMouseEvent(c, e, main));
      }
    }
  }
}
import java.awt.*;
导入java.awt.event.*;
导入javax.swing.*;
导入javax.swing.plaf.LayerUI;
导入javax.swing.table.*;
导入javax.swing.text.*;
公共类车轮重叠滚动面板测试{
私有静态最终字符串TEXT=“aaa\na\na\na\na\naaaa\na\na\na\naaaa\n”;
私有JComponent makeUI(){
JTextArea textArea=新的JTextArea(文本+文本+文本);
JTable表=新的JTable(50,3);
JTree树=新的JTree();
树。设置VisibleRowCount(5);
JTextPane textPane=新的JTextPane();
textPane.setEditable(false);
setMargin(新的插图(5,10,5,5));
Document doc=textPane.getDocument();
试一试{
doc.insertString(doc.getLength(),文本,空);
插入组件(createChildScrollPane(textArea));
doc.insertString(doc.getLength(),“\n”,null);
doc.insertString(doc.getLength(),文本,空);
insertComponent(createChildScrollPane(表));
doc.insertString(doc.getLength(),“\n”,null);
doc.insertString(doc.getLength(),文本,空);
insertComponent(新的JScrollPane(树));
doc.insertString(doc.getLength(),“\n”,null);
doc.insertString(doc.getLength(),文本,空);
}捕获(BadLocationException ex){
例如printStackTrace();
}
返回新JLayer(
新的JScrollPane(textPane),新的WheelScrollLayerUI());
}
受保护的静态JScrollPane createChildScrollPane(组件视图){
返回新的JScrollPane(视图){
@重写公共维度getPreferredSize(){
维度d=super.getPreferredSize();
d、 高度=120;
返回d;
}
};
}
公共静态void main(字符串…参数){
EventQueue.invokeLater(()->{
JFrame f=新的JFrame();
f、 setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f、 getContentPane().add(新建WheelOverNestedScrollPaneTest().makeUI());
f、 设置大小(320240);
f、 setLocationRelativeTo(空);
f、 setVisible(真);
});
}
}
// http://java-swing-tips.blogspot.jp/2014/09/forward-mouse-wheel-scroll-event-in.html
类WheelScrollLayerUI扩展了LayerUI{
@覆盖公共void installUI(JComponent c){
super.installUI(c);
if(JLayer的c实例){
((JLayer)c).setLayerEventMask(awteEvent.MOUSE\u WHEEL\u EVENT\u MASK);
}
}
@覆盖公共用户界面(JComponent c){
if(JLayer的c实例){
((JLayer)c).SetLayerReventMask(0);
}
super.ui(c);
}
@重写受保护的void processMouseWheelEvent(

MouseWheelEvent e,jLayer实现B的默认侦听器以通知A;您可以设置一些关于优先级的条件(如果B在其末尾…)实现B的默认侦听器以通知A;您可以设置一些关于优先级的条件(如果B在i