我有一个 JSplitPane
的子类,它的目的是允许分隔线从右边缘或下边缘(而不是左边缘或上边缘)固定位置。
为此,我使用 ComponentChangeListener
来捕获组件大小的调整,并重新计算相对于宽度或高度的分隔线位置。
一切都完美无缺。但现在我添加一个 PropertyChangeListener
来捕获用户对分割位置的调整,并将左/顶部相对值存储为距右/下边框的偏移量,以便稍后在调整大小时使用。
但是我这里有一种级联问题:
- 您调整组件的大小
- 触发
ComponentChangeEvent
- 分隔线已移至正确位置
- 这会导致触发
PropertyChangeEvent
- 然后使用不正确的数据重新计算移动分隔线的位置
所以分隔线最终会到处弹跳。
我尝试手动放入一个“禁止”标志(只是一个简单的 boolean 值
),它有时可以阻止事件,但通常不会,所以这就是不是绕过它的方法。
有什么线索吗?
我的 propertyChange
方法如下所示:
public void propertyChange(PropertyChangeEvent e) {
if (inhibit) return;
if (e.getPropertyName().equals("dividerLocation")) {
int pos = (Integer)e.getNewValue();
if (right == -1) {
left = pos;
} else {
Dimension d = getSize();
if (orient == JSplitPane.VERTICAL_SPLIT) {
right = d.height - pos;
} else {
right = d.width - pos;
}
}
}
}
componentResized
是:
public void componentResized(ComponentEvent e) {
if (!inhibit) {
updateDividerLocation();
}
}
void updateDividerLocation() {
inhibit = true;
if (right == -1) { // Left / top is fixed
setDividerLocation(left);
} else {
Dimension d = getSize();
if (orient == JSplitPane.VERTICAL_SPLIT) {
setDividerLocation(d.height - right);
} else {
setDividerLocation(d.width - right);
}
}
inhibit = false;
}
如您所见,我在那里有 inhibit
标志,正如我所说,它不能正常工作。
那么阻止 setDividerLocation
函数触发 PropertyChangeEvent
的正确方法是什么?我是否必须在调整组件大小并随后再次添加时完全删除 PropertyChangeListener
?这会有帮助吗?
注意:当显示更新可能有点滞后时,这一点最为明显。这是一个可以演示该问题的 SSCCE(尽管恐怕不是那么“小”)。问题的结果在这个 SSCCE 中并不总是很明显,因为窗口中没有太多内容(我发现将右边缘向左急剧拖动是搞乱它的好方法,并且速度较慢,图形更加密集,LaF有帮助),但这在整个程序中非常明显。然而,效果可以从以下事实中看出:调整窗口大小会导致“CE”输出(ComponentEvent)并立即产生“PCE”输出(PropertyChangeEvent)。我需要抑制的是 CE 之后的 PCE。
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.beans.*;
public class TestClass {
class AbsoluteSplitPane extends JSplitPane implements ComponentListener, PropertyChangeListener {
int left = -1; // and top
int right = -1; // and bottom
int orient;
public AbsoluteSplitPane(int orientation, Component a, Component b) {
super(orientation, a, b);
orient = orientation;
addComponentListener(this);
addPropertyChangeListener(this);
}
void updateDividerLocation() {
if (right == -1) { // Left / top is fixed
setDividerLocation(left);
} else {
Dimension d = getSize();
if (orient == JSplitPane.VERTICAL_SPLIT) {
setDividerLocation(d.height - right);
} else {
setDividerLocation(d.width - right);
}
}
}
public void setLeftSize(int s) {
left = s;
right = -1;
updateDividerLocation();
}
public void setRightSize(int s) {
left = -1;
right = s;
updateDividerLocation();
}
public void setTopSize(int s) {
left = s;
right = -1;
updateDividerLocation();
}
public void setBottomSize(int s) {
left = -1;
right = s;
updateDividerLocation();
}
public void componentHidden(ComponentEvent e) {
}
public void componentShown(ComponentEvent e) {
}
public void componentMoved(ComponentEvent e) {
}
public void componentResized(ComponentEvent e) {
updateDividerLocation();
System.err.println(String.format(" CE: Left: %d Right: %d", left, right));
}
public void propertyChange(PropertyChangeEvent e) {
if (e.getPropertyName().equals("dividerLocation")) {
int pos = (Integer)e.getNewValue();
if (right == -1) {
left = pos;
} else {
Dimension d = getSize();
if (orient == JSplitPane.VERTICAL_SPLIT) {
right = d.height - pos;
} else {
right = d.width - pos;
}
}
System.err.println(String.format("PCE: Left: %d Right: %d", left, right));
}
}
}
public TestClass() {
JFrame frame = new JFrame("Test Window");
JPanel left = new JPanel();
JPanel mid = new JPanel();
JPanel right = new JPanel();
AbsoluteSplitPane split1 = new AbsoluteSplitPane(JSplitPane.HORIZONTAL_SPLIT, mid, right);
AbsoluteSplitPane split2 = new AbsoluteSplitPane(JSplitPane.HORIZONTAL_SPLIT, left, split1);
split1.setRightSize(200);
split2.setLeftSize(200);
frame.add(split2);
frame.setSize(400, 400);
frame.setVisible(true);
}
public static void main(String[] args) {
new TestClass();
}
}
<小时/>
更新:我已经成功通过 UI 将 MouseListener 附加到分隔符来解决该问题 (((BasicSplitPaneUI)getUI()).getDivider.addMouseListener(... )
) 并将位置数据保存在 mouseReleased()
事件中。它有效,但知道是否有办法抑制 PropertyChangeEvents 仍然是件好事...
最佳答案
but it'd still be good to know if there is a way of suppressing PropertyChangeEvents...
public void componentResized(ComponentEvent e) {
removePropertyChangeListener( this );
updateDividerLocation();
addPropertyChangeListener( this );
System.err.println(String.format(" CE: Left: %d Right: %d", left, right));
}
编辑:
也许您可以查看 EDT 上导致生成 PropertyChangeEvent 的事件?
public void propertyChange(PropertyChangeEvent e)
{
if (e.getPropertyName().equals("dividerLocation"))
{
AWTEvent event = EventQueue.getCurrentEvent();
if (event != null
&& (event.getID() != MouseEvent.MOUSE_RELEASED))
return;
int pos = (Integer)e.getNewValue();
if (right == -1) {
left = pos;
} else {
Dimension d = getSize();
if (orient == JSplitPane.VERTICAL_SPLIT) {
right = d.height - pos;
} else {
right = d.width - pos;
}
}
System.err.println(String.format("PCE: Left: %d Right: %d", left, right));
}
}
关于java - 当分隔符移动到 ComponentListener 内时,JSplitPane 会阻止 PropertyChangeEvent,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58666224/