簡體   English   中英

當分隔線在 ComponentListener 內移動時,JSplitPane 阻止 PropertyChangeEvent

[英]JSplitPane prevent PropertyChangeEvent when divider moved inside ComponentListener

我有一個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 function 觸發PropertyChangeEvent正確方法是什么? 我是否必須 go 完全刪除PropertyChangeListener同時調整組件大小並在之后再次添加它? 那會有幫助嗎?

注意:有時顯示更新可能會有一點延遲,這一點最為明顯。 這是一個可以證明問題的SSCCE(盡管恐怕不是那么“小”)。 問題的結果在這個 SSCCE 中並不總是很明顯,因為 window 中沒有太多內容(我發現右邊緣向左急劇拖動是一種搞亂它的好方法,而且速度更慢,圖形更密集,LaF幫助),但在完整的程序中非常明顯。 然而,效果可以看出,調整 window 的大小會導致“CE”output(ComponentEvent)並立即出現“PCE”output(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( ((BasicSplitPaneUI)getUI()).getDivider.addMouseListener(...) )將 MouseListener 附加到分隔器並將位置數據保存在mouseReleased()事件中. 它可以工作,但如果有辦法抑制 PropertyChangeEvents 還是很高興的...

但如果有辦法抑制 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));
        }
    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM