检测何时拖动JSplitPane分隔符,而不是调整组件的大小

时间:2013-01-20 16:18:21

标签: java swing jsplitpane

我想实现一个JSplitPane(水平分割),其中右侧组件具有恒定宽度,即当拖动分隔线时,它将跳回到正确的大小,除非分隔线被拖得足够远,在这种情况下最右边组件的宽度为零。

要重新显示正确的组件,用户可以将分隔线拖到左侧足够远。

我有这个主要工作,但当我调整窗口大小取决于我改变窗口大小的多少和多快时,分频器跳跃显示或隐藏正确的组件,我想要的是它不应该改变'state',即如果右侧组件不可见,那么它应该保持不可见,反之亦然。

我已经尝试了很多东西,但主要的障碍是似乎没有办法知道天气,用户通过鼠标拖动分隔线,或者代码(我的分频逻辑和/或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);
    }
}

3 个答案:

答案 0 :(得分:5)

不确定是否有可能捕获dragging事件,但肯定可以捕获propertyChange事件。移动JSplitPane分隔符后捕获事件可以通过PropertyChangeListener JSplitPane类实现。确保提供DIVIDER_LOCATION_PROPERTY作为参数,以便此侦听器将持久修改分隔符位置事件。 如果您不将此作为addPropertyChangeListener()方法中的第一个参数提供,则如果PropertyChangeEvent的{​​{1}}方法返回getPropertyName()作为值,则始终可以放置条件语句

dividerLocation

答案 1 :(得分:2)

将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) {

答案 2 :(得分:1)

  

...除非将分隔线拖得足够右,在这种情况下是正确的   大多数组件的宽度为零。

     

要重新显示正确的组件,用户可以拖动分隔符   远在左边。

听起来你要做的就是禁用splitPane来禁用拖动,

然后将setOneTouchExpandable()设置为true。您可能需要删除其中一个'expandable'

按钮禁用扩展错误的方式