2

我想实现一个 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);
    }
}
4

3 回答 3

5

不确定是否可以捕获dragging事件,但可以肯定您可以捕获propertyChange事件。JSplitPane可以通过PropertyChangeListenerJSplitPane 类在移动 的分隔符后捕获事件。确保您提供 DIVIDER_LOCATION_PROPERTY作为参数,以便此侦听器将侦听修改的分隔线位置事件。如果您不将此作为方法中的第一个参数提供,则如果' 的方法作为值返回,addPropertyChangeListener()则始终可以放置条件语句。PropertyChangeEventgetPropertyName()dividerLocation

jSplitPane1.addPropertyChangeListener(JSplitPane.DIVIDER_LOCATION_PROPERTY, new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent pce) {
    // do here
}
});
于 2013-01-20T16:28:59.197 回答
2

将 MouseListener 添加到 JSplitPane Divider 以检测何时拖动分隔线。拖动时,响应属性更改事件。样本:

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) {
于 2014-12-11T21:13:19.093 回答
1

...除非分隔线被拖得足够远,在这种情况下,最右边的组件将具有零宽度。

为了重新显示正确的组件,用户可以将分隔线向左拖得足够远。

听起来您所要做的就是禁用 splitPane 以禁用拖动,

然后 setOneTouchExpandable() 为真。您可能需要删除“可扩展”之一

按钮禁用扩展错误的方式

于 2013-01-20T18:50:30.063 回答