JSplitPane предотвращает PropertyChangeEvent, когда разделитель перемещается внутри ComponentListener - PullRequest
0 голосов
/ 02 ноября 2019

У меня есть подкласс JSplitPane, который предназначен для того, чтобы разрешить фиксированное расположение делителя с правого или нижнего края вместо левого или верхнего.

С этой целью яиспользование ComponentChangeListener для определения размера компонента и пересчета местоположения разделителя относительно ширины или высоты.

Все это работает безупречно. Но теперь я добавляю PropertyChangeListener, чтобы зафиксировать настройку разделенного местоположения пользователем и сохранить это левое / верхнее относительное значение в качестве смещения от правой / нижней границы для последующего использования при изменении размера.

Но у меня есть своего рода каскадная проблема:

  • Вы изменяете размер компонента
  • A 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). Это тот PCE, следующий за CE, который мне нужно подавить.

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();
    }
}

Обновление: Мне удалось решить эту проблему, подключив MouseListener к разделителю через пользовательский интерфейс(((BasicSplitPaneUI)getUI()).getDivider.addMouseListener(...)) и сохраните данные о местоположении в событии mouseReleased(). Это работает, но было бы хорошо знать, есть ли способ подавления PropertyChangeEvents ...

1 Ответ

0 голосов
/ 02 ноября 2019

но было бы неплохо узнать, есть ли способ подавления 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));
        }
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...