Обнаружение перетаскивания разделителя JSplitPane, а не изменения размера компонента

Я хочу реализовать JSplitPane (горизонтальное разделение), где правый компонент имеет постоянную ширину, т.е. когда разделитель перетаскивается, он возвращается к правильному размеру, если разделитель не перетаскивается достаточно далеко вправо, и в этом случае правый компонент будет иметь нулевая ширина.

Чтобы снова отобразить правый компонент, пользователь может перетащить разделитель достаточно далеко влево.

У меня это в основном работает, но когда я изменяю размер окна в зависимости от того, насколько и как быстро я меняю размер окна, прыжки разделителя показывают или скрывают правильный компонент, где я хочу, чтобы он не изменил «состояние» т.е. если правый компонент не был виден, то он должен оставаться невидимым и наоборот.

Я пробовал кучу вещей, но главное препятствие заключается в том, что, похоже, нет способа узнать, был ли разделитель перетащен пользователем с помощью мыши или если код (моя логика разделителя и/или внутренняя логика JSplitPane) изменил позицию разделителя .

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

Не работает должным образом в Mac OS X Java 1.6 (Apple) или Java 7 (Oracle). С материалом Oracle рендеринг намного медленнее, и проблема более серьезная. Изменение размера окна работает медленно, но быстрое изменение размера окна вызывает проблемы.

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

import javax.swing.*;

import net.miginfocom.swing.MigLayout;

public class SplitTest {
    public static class MySplitPane extends JSplitPane {
        boolean m_RightCollapsed;

        public MySplitPane(int orientation, JComponent left, JComponent right) {
            super(orientation, left, right);

            addPropertyChangeListener(new PropertyChangeListener() {

                @Override
                public void propertyChange(PropertyChangeEvent evt) {

                }
            });
            addComponentListener(new ComponentListener() {

                @Override
                public void componentShown(ComponentEvent e) {
                    reposDivider();
                }

                @Override
                public void componentResized(ComponentEvent e) {
                    reposDivider();
                }

                @Override
                public void componentMoved(ComponentEvent e) {
                    reposDivider();
                }

                @Override
                public void componentHidden(ComponentEvent e) {
                }
            });

        }

        public void reposDivider() {
            setDividerLocation(getDividerLocation());
        }

        public void setDividerLocation(int location) {
            int newLocation;
            m_RightCollapsed = location > getSize().width - getRightComponent().getPreferredSize().width / 2;
            if (m_RightCollapsed)
                newLocation = getSize().width;
            else
                newLocation = getSize().width - getInsets().right - getDividerSize() - getRightComponent().getPreferredSize().width;
            super.setDividerLocation(newLocation);
        }
    }
    static class MyScrollable extends JPanel implements Scrollable {
        int m_Height;

        public MyScrollable(int height) {
            m_Height = height;
        }

        @Override
        public void paint(java.awt.Graphics g) {
            super.paint(g);
            g.setColor(Color.CYAN);
            g.fillOval(0, 0, getWidth(), 500);
        }

        @Override
        public Dimension getPreferredScrollableViewportSize() {
            //return super.getPreferredSize();
            return new Dimension(100, m_Height);
        }

        @Override
        public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {
            // TODO Auto-generated method stub
            return 10;
        }

        @Override
        public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) {
            return 20;
        }

        @Override
        public boolean getScrollableTracksViewportWidth() {
            return true;
        }

        @Override
        public boolean getScrollableTracksViewportHeight() {
            return false;
        }

    }

    public static class ShrinkGrow extends JPanel {
        public ShrinkGrow(final JComponent component, final JSplitPane split) {
            JButton grow = new JButton("+++");
            JButton shrink = new JButton("---");
            add(grow);
            add(shrink);

            grow.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    Dimension oldSize = component.getPreferredSize();
                    Dimension newSize = new Dimension(oldSize.width, oldSize.height + 10);
                    component.setPreferredSize(newSize);
                    component.setSize(newSize);
                }
            });
            shrink.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    Dimension oldSize = component.getPreferredSize();
                    Dimension newSize = new Dimension(oldSize.width, oldSize.height - 10);
                    component.setPreferredSize(newSize);
                    component.setSize(newSize);
                }
            });
        }
    }

    public static void main(String[] args) {
        JFrame window = new JFrame();

        JPanel mainView = new JPanel();
        JPanel top = new JPanel();
        top.setLayout(new BoxLayout(top, BoxLayout.Y_AXIS));
        JPanel bottom = new JPanel();
        bottom.setLayout(new BoxLayout(bottom, BoxLayout.Y_AXIS));

        final JSplitPane rightSplit = new JSplitPane(JSplitPane.VERTICAL_SPLIT);

        JPanel topContent = new MyScrollable(200);
        JPanel topFixed = new ShrinkGrow(topContent, rightSplit);
        topFixed.setLayout(new BoxLayout(topFixed, BoxLayout.X_AXIS));

        JScrollPane topFlexible = new JScrollPane(topContent);
        topFlexible.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
        topFlexible.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);

        JPanel bottomContent = new MyScrollable(300);
        JPanel bottomFixed = new ShrinkGrow(bottomContent, rightSplit);
        bottomFixed.setLayout(new BoxLayout(bottomFixed, BoxLayout.X_AXIS));

        JScrollPane bottomFlexible = new JScrollPane(bottomContent);
        bottomFlexible.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
        bottomFlexible.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);

        mainView.setBackground(Color.red);
        topFixed.setBackground(Color.green);
        topContent.setBackground(Color.green.darker());
        bottomFixed.setBackground(Color.blue);
        bottomContent.setBackground(Color.blue.darker());

        mainView.setMinimumSize(new Dimension(100, 100));
        mainView.setPreferredSize(new Dimension(400, 300));
        mainView.setMaximumSize(new Dimension(10000, 10000));

        topFixed.setMinimumSize(new Dimension(topFixed.getMinimumSize().width, 30));
        topFixed.setPreferredSize(new Dimension(topFixed.getPreferredSize().width, 30));
        topFixed.setMaximumSize(new Dimension(topFixed.getMaximumSize().width, 30));

        bottomFixed.setMinimumSize(new Dimension(bottomFixed.getMinimumSize().width, 40));
        bottomFixed.setPreferredSize(new Dimension(bottomFixed.getPreferredSize().width, 40));
        bottomFixed.setMaximumSize(new Dimension(bottomFixed.getMaximumSize().width, 40));

        topContent.setPreferredSize(new Dimension(100, 500));
        bottomContent.setPreferredSize(new Dimension(100, 400));

        top.add(topFixed);
        top.add(topFlexible);
        bottom.add(bottomFixed);
        bottom.add(bottomFlexible);
        rightSplit.setLeftComponent(top);
        rightSplit.setRightComponent(bottom);

        rightSplit.setMinimumSize(new Dimension(0, 0));

        final JSplitPane mainSplit = new MySplitPane(JSplitPane.HORIZONTAL_SPLIT, mainView, rightSplit);

        window.add(mainSplit);
        window.pack();
        window.setVisible(true);
    }
}

person nyholku    schedule 20.01.2013    source источник


Ответы (3)


Не уверен, что можно поймать событие dragging, но точно можно поймать событие propertyChange. Перехват событий после перемещения разделителя JSplitPane можно сделать возможным с помощью класса PropertyChangeListener JSplitPane. Убедитесь, что вы указали DIVIDER_LOCATION_PROPERTY в качестве параметра, чтобы этот прослушиватель прослушивал измененные события местоположения делителя. Если вы не укажете это в качестве первого параметра в методе addPropertyChangeListener(), вы всегда можете поместить условный оператор, если метод getPropertyName() из PropertyChangeEvent возвращает dividerLocation в качестве значения.

jSplitPane1.addPropertyChangeListener(JSplitPane.DIVIDER_LOCATION_PROPERTY, new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent pce) {
    // do here
}
});
person Archer    schedule 20.01.2013
comment
Спасибо, это я уже пробовал. Но проблема в том, что невозможно узнать, изменилось ли свойство в результате перетаскивания разделителя или из-за изменения размера компонента JSlitPane. Если в первом случае я хочу уважать выбор пользователя и просто округлить местоположение до одной или другой из двух допустимых позиций, а в последнем случае я хочу восстановить его до того, что было до изменения. Проблема в том, что 1-4 из этих свойств изменяются при изменении размера окна. - person nyholku; 20.01.2013

Добавьте MouseListener в разделитель JSplitPane, чтобы определить, когда разделитель перетаскивается. При перетаскивании реагировать на события изменения свойства. Образец:

https://community.oracle.com/thread/1352161?start=0&tstart=0

SplitPaneUI spui = splitPane.getUI();
    if (spui instanceof BasicSplitPaneUI) {
      // Setting a mouse listener directly on split pane does not work, because no events are being received.
      ((BasicSplitPaneUI) spui).getDivider().addMouseListener(new MouseAdapter() {
        public void mouseClicked(MouseEvent e) {
person jusu    schedule 11.12.2014

... если разделитель не перетащен достаточно далеко вправо, и в этом случае самый правый компонент будет иметь нулевую ширину.

Чтобы снова отобразить правый компонент, пользователь может перетащить разделитель достаточно далеко влево.

похоже, все, что вам нужно сделать, это отключить splitPane, чтобы отключить перетаскивание,

затем установите для OneTouchExpandable() значение true. вам может потребоваться удалить один из «расширяемых»

кнопки для отключения неправильного расширения

person Michael Dunn    schedule 20.01.2013