gpt4 book ai didi

java - 当分隔符移动到 ComponentListener 内时,JSplitPane 会阻止 PropertyChangeEvent

转载 作者:行者123 更新时间:2023-12-01 22:10:11 25 4
gpt4 key购买 nike

我有一个 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/

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