JTextPane阻止在父JScrollPane中滚动

我有以下“树”的对象:

JPanel JScrollPane JPanel JPanel JScrollPane JTextPane 

当使用鼠标滚轮滚动外部JScrollPane我遇到一个恼人的问题。 一旦鼠标光标触及内部JScrollPane,似乎滚动事件就会传递到JScrollPane中,并且第一个不再处理。 这意味着滚动“父”JScrollPane停止。

是否可以禁用内部JScrollPane上的鼠标滚轮? 或者更好的是,如果没有要滚动的内容(大多数情况下textpane只包含1-3行文本),则禁用滚动,但如果有更多内容启用它?

我也遇到过这个恼人的问题,而Sbodd的解决方案对我来说是不可接受的,因为我需要能够在表格和JTextAreas中滚动。 我希望行为与浏览器相同,鼠标hover在可滚动控件上将滚动该控件直到控件降至最低点,然后继续滚动父滚动窗格,通常是整个页面的滚动窗格。

这个课就是这么做的。 只需使用它代替常规的JScrollPane即可。 我希望它对你有所帮助。

 /** * A JScrollPane that will bubble a mouse wheel scroll event to the parent * JScrollPane if one exists when this scrollpane either tops out or bottoms out. */ public class PDControlScrollPane extends JScrollPane { public PDControlScrollPane() { super(); addMouseWheelListener(new PDMouseWheelListener()); } class PDMouseWheelListener implements MouseWheelListener { private JScrollBar bar; private int previousValue = 0; private JScrollPane parentScrollPane; private JScrollPane getParentScrollPane() { if (parentScrollPane == null) { Component parent = getParent(); while (!(parent instanceof JScrollPane) && parent != null) { parent = parent.getParent(); } parentScrollPane = (JScrollPane)parent; } return parentScrollPane; } public PDMouseWheelListener() { bar = PDControlScrollPane.this.getVerticalScrollBar(); } public void mouseWheelMoved(MouseWheelEvent e) { JScrollPane parent = getParentScrollPane(); if (parent != null) { /* * Only dispatch if we have reached top/bottom on previous scroll */ if (e.getWheelRotation() < 0) { if (bar.getValue() == 0 && previousValue == 0) { parent.dispatchEvent(cloneEvent(e)); } } else { if (bar.getValue() == getMax() && previousValue == getMax()) { parent.dispatchEvent(cloneEvent(e)); } } previousValue = bar.getValue(); } /* * If parent scrollpane doesn't exist, remove this as a listener. * We have to defer this till now (vs doing it in constructor) * because in the constructor this item has no parent yet. */ else { PDControlScrollPane.this.removeMouseWheelListener(this); } } private int getMax() { return bar.getMaximum() - bar.getVisibleAmount(); } private MouseWheelEvent cloneEvent(MouseWheelEvent e) { return new MouseWheelEvent(getParentScrollPane(), e.getID(), e .getWhen(), e.getModifiers(), 1, 1, e .getClickCount(), false, e.getScrollType(), e .getScrollAmount(), e.getWheelRotation()); } } } 

@Nemi已经有了一个很好的解决方案。

我把它煮了一点,把下面的方法放在我的库中:

 static public void passMouseWheelEventsToParent(final Component pComponent, final Component pParent) { pComponent.addMouseWheelListener((final MouseWheelEvent pE) -> { pParent.dispatchEvent(new MouseWheelEvent(pParent, pE.getID(), pE.getWhen(), pE.getModifiers(), 1, 1, pE.getClickCount(), false, pE.getScrollType(), pE.getScrollAmount(), pE.getWheelRotation())); }); } 

遗憾的是,显而易见的解决方案(JScrollPane.setWheelScrollingEnabled(false))实际上并没有取消注册MouseWheelEvents,因此它无法达到您想要的效果。

这是一种粗略的hackery方式,完全禁用滚动,让MouseWheelEvents到达外部JScrollPane:

 for (MouseWheelListener mwl : scrollPane.getMouseWheelListeners()) { scrollPane.removeMouseWheelListener(mwl); } 

如果对内部JScrollPane执行此操作,它将永远不会响应滚轮事件; 外部JScrollPane将获得所有这些。

如果你想“干净地”完成它,你需要实现自己的ScrollPaneUI,并使用setUI()将其设置为JScrollPane的UI。 不幸的是,你不能只是扩展BasicScrollPaneUI并禁用它的鼠标滚轮监听器,因为相关的成员变量是私有的,并且ScrollPaneUI安装其MouseWheelListener时没有任何标志或保护。

对于“更好”的解决方案,您必须深入挖掘ScrollPaneUI,找到滚动条可见/不可见的钩子,并在这些点添加/删除MouseWheelListener。

希望有所帮助!