如何设置 JSplitPane-Divider 折叠/展开状态?

发布于 2024-10-16 10:04:06 字数 2745 浏览 4 评论 0原文

我有一个带有 JSplitPane 的 JFrame,它是 OneTouchExpandable。 我想记住 JFrame 上 JSplitPane 的最后一个分隔符位置,并在重新打开 JFrame 时恢复位置。

它工作得很好,但如果用户通过 oneTouchExpandable UI-Widget 展开一侧,那么 我在处理时仅存储“int”位置,并再次将“int”位置设置回来,结果是在 JFrame 调整大小时,JSplitPane-Divider 跳转到折叠的组件首选大小。

如何获取/设置折叠/展开状态?

编辑

现在:调整大小行为正常,但它与第一​​次打开的行为不完全相同 - 因为现在我没有MinimumDividerLocation。我想要 SnapIn,但更想要折叠状态。

public class SplitPaneState {
    public static void main( String[] args ) {
        SwingUtilities.invokeLater( new Runnable() {
            @Override
            public void run() {
                new SplitPaneState().createAndSowGUI();
            }
        });
    }

    private int position = -1;
    private Dimension size = new Dimension( 500, 300 );

    private void createAndSowGUI() {
        final JFrame frame = new JFrame("frame");
        frame.setSize( 200, 100 );
        frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
        frame.setLocationRelativeTo( null );
        frame.getContentPane().add( new JButton( new AbstractAction(){
           {
               putValue( Action.NAME, "Open Dialog" );
           }
            @Override
            public void actionPerformed( ActionEvent e ) {
                final JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, new JLabel( "left Component" ), new JLabel( "right Component" ));
                splitPane.setContinuousLayout( true );
                splitPane.setOneTouchExpandable( true );
                if(position != -1) {
                    boolean LeftIsCollapsed = position < splitPane.getMinimumDividerLocation();
                    if(LeftIsCollapsed) {
                        splitPane.getLeftComponent().setMinimumSize(new Dimension()); // fix by Martijn Courteaux
                        splitPane.setDividerLocation(0.0d);                           // fix by Martijn Courteaux
                    }else {
                        splitPane.setDividerLocation(position);
                    }
                }
                JDialog dialog = new JDialog(frame,"dialog"){
                    @Override
                    public void dispose() {
                        position = splitPane.getDividerLocation();
                        size = this.getSize();
                        super.dispose();
                    }
                };
                dialog.setSize( size );
                dialog.setDefaultCloseOperation( JFrame.DISPOSE_ON_CLOSE );
                dialog.setLocationRelativeTo( frame );
                dialog.getContentPane().add( splitPane );
                dialog.setVisible( true );
                }
           }
       ));
       frame.setVisible( true );
    }
}

I have a JFrame with a JSplitPane that is OneTouchExpandable.
I want to remember the last Divider position of the JSplitPane on JFrame dispose and restore the Position if the JFrame is reopened.

It works well, but if the User expand one Side via the oneTouchExpandable UI-Widget then
I store only the 'int'-Position on dispose and set the 'int'-Position back again with the consequence on JFrame-resizing the JSplitPane-Divider jumps to the collapsed Component preferredSize.

How can I get/set the collapse/expand State?

EDIT

Now: the resize-Behavior is OK, but it is not exactly the same behavior like the first-time-open - cause now I have no MinimumDividerLocation. I wanted the SnapIn but further the collapsedState.

public class SplitPaneState {
    public static void main( String[] args ) {
        SwingUtilities.invokeLater( new Runnable() {
            @Override
            public void run() {
                new SplitPaneState().createAndSowGUI();
            }
        });
    }

    private int position = -1;
    private Dimension size = new Dimension( 500, 300 );

    private void createAndSowGUI() {
        final JFrame frame = new JFrame("frame");
        frame.setSize( 200, 100 );
        frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
        frame.setLocationRelativeTo( null );
        frame.getContentPane().add( new JButton( new AbstractAction(){
           {
               putValue( Action.NAME, "Open Dialog" );
           }
            @Override
            public void actionPerformed( ActionEvent e ) {
                final JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, new JLabel( "left Component" ), new JLabel( "right Component" ));
                splitPane.setContinuousLayout( true );
                splitPane.setOneTouchExpandable( true );
                if(position != -1) {
                    boolean LeftIsCollapsed = position < splitPane.getMinimumDividerLocation();
                    if(LeftIsCollapsed) {
                        splitPane.getLeftComponent().setMinimumSize(new Dimension()); // fix by Martijn Courteaux
                        splitPane.setDividerLocation(0.0d);                           // fix by Martijn Courteaux
                    }else {
                        splitPane.setDividerLocation(position);
                    }
                }
                JDialog dialog = new JDialog(frame,"dialog"){
                    @Override
                    public void dispose() {
                        position = splitPane.getDividerLocation();
                        size = this.getSize();
                        super.dispose();
                    }
                };
                dialog.setSize( size );
                dialog.setDefaultCloseOperation( JFrame.DISPOSE_ON_CLOSE );
                dialog.setLocationRelativeTo( frame );
                dialog.getContentPane().add( splitPane );
                dialog.setVisible( true );
                }
           }
       ));
       frame.setVisible( true );
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

霓裳挽歌倾城醉 2024-10-23 10:04:06

我发现可以通过将组件的最小尺寸设置为 new Dimension() 来折叠分割面板的一侧,然后设置分隔线位置:

// Hide left or top
pane.getLeftComponent().setMinimumSize(new Dimension());
pane.setDividerLocation(0.0d);

// Hide right or bottom
pane.getRightComponent().setMinimumSize(new Dimension());
pane.setDividerLocation(1.0d);

您可以使用这些设置来存储和恢复折叠/展开状态。

I found that it is possible to collapse one side of the splitpane by setting the minimum size of the component to new Dimension() and then set the divider location:

// Hide left or top
pane.getLeftComponent().setMinimumSize(new Dimension());
pane.setDividerLocation(0.0d);

// Hide right or bottom
pane.getRightComponent().setMinimumSize(new Dimension());
pane.setDividerLocation(1.0d);

You can play with these settings to store and restore the collapse/expand state.

九歌凝 2024-10-23 10:04:06

强制分隔线位置为非常小/很大的值以隐藏顶部/底部组件是可行的,但由于组件最小尺寸,当调整分割窗格大小时会失败。将该大小设置为 0(如接受的答案中建议的那样)是可行的,但在某些情况下您不能/不想覆盖它。

查看 BasicSplitPaneUI 和关联的类后,发现“一键展开”按钮正在调用 BasicSPlitPaneUI.setKeepHidden(true),因此分隔线将粘在任一端调整大小时。

不幸的是,该方法是包私有的,但可以使用内省来设置关联的keepHidden字段,如所示另一个答案

sp.setDividerLocation(<0 or 999999>); // Divider is positioned at the top/bottom
Field m = BasicSplitPaneUI.class.getDeclaredField("keepHidden");
m.setAccessible(true);
m.set(sp.getUI(), true); // Divider position will stick

Forcing the divider position to a very small/large value to hide the top/bottom component works, but is defeated when the split pane gets resized, because of the component minimum size. Setting that size to 0 (as proposed in the accepted answer) works, but there are cases when you cannot/don't want to override that.

After looking into the BasicSplitPaneUI and associated classes, it turns out the "one touch expanding" buttons are calling BasicSPlitPaneUI.setKeepHidden(true), so the divider will stick to either end when resized.

Unfortunately, that method is package-private but setting the associated keepHidden field can be done using introspection, as shown in another answer:

sp.setDividerLocation(<0 or 999999>); // Divider is positioned at the top/bottom
Field m = BasicSplitPaneUI.class.getDeclaredField("keepHidden");
m.setAccessible(true);
m.set(sp.getUI(), true); // Divider position will stick
淡紫姑娘! 2024-10-23 10:04:06

我改进了切换功能的版本:

/**
 * toggle JSplitPane
 * @param sp - splitpane to toggle
 * @param upLeft - is it left or top component to collapse? or button or right
 * @param collapse - true component should be collapsed
 */
public void toggle(JSplitPane sp, boolean upLeft, boolean collapse) {
    try {
        //get divider object
        BasicSplitPaneDivider bspd = ((BasicSplitPaneUI) sp.getUI()).getDivider();
        Field buttonField;

        //get field button from divider
        if (upLeft) {
            if (collapse != (sp.getDividerLocation() < sp.getMinimumDividerLocation())) {
                return;
            }
            buttonField = BasicSplitPaneDivider.class.getDeclaredField(collapse ? "rightButton" : "leftButton");
        } else {
            if (collapse != (sp.getDividerLocation() > sp.getMaximumDividerLocation())) {
                return;
            }

            buttonField = BasicSplitPaneDivider.class.getDeclaredField(collapse ? "leftButton" : "rightButton");
        }
        //allow access
        buttonField.setAccessible(true);
        //get instance of button to click at
        JButton button = (JButton) buttonField.get(((BasicSplitPaneUI) sp.getUI()).getDivider());
        //click it
        button.doClick();
        //if you manage more dividers at same time before returning from event,
        //you should update layout and ui, otherwise nothing happens on some dividers:
        sp.updateUI();
        sp.doLayout();


    } catch (Exception e) {
        e.printStackTrace();
    }
}

I improved version of toggle function:

/**
 * toggle JSplitPane
 * @param sp - splitpane to toggle
 * @param upLeft - is it left or top component to collapse? or button or right
 * @param collapse - true component should be collapsed
 */
public void toggle(JSplitPane sp, boolean upLeft, boolean collapse) {
    try {
        //get divider object
        BasicSplitPaneDivider bspd = ((BasicSplitPaneUI) sp.getUI()).getDivider();
        Field buttonField;

        //get field button from divider
        if (upLeft) {
            if (collapse != (sp.getDividerLocation() < sp.getMinimumDividerLocation())) {
                return;
            }
            buttonField = BasicSplitPaneDivider.class.getDeclaredField(collapse ? "rightButton" : "leftButton");
        } else {
            if (collapse != (sp.getDividerLocation() > sp.getMaximumDividerLocation())) {
                return;
            }

            buttonField = BasicSplitPaneDivider.class.getDeclaredField(collapse ? "leftButton" : "rightButton");
        }
        //allow access
        buttonField.setAccessible(true);
        //get instance of button to click at
        JButton button = (JButton) buttonField.get(((BasicSplitPaneUI) sp.getUI()).getDivider());
        //click it
        button.doClick();
        //if you manage more dividers at same time before returning from event,
        //you should update layout and ui, otherwise nothing happens on some dividers:
        sp.updateUI();
        sp.doLayout();


    } catch (Exception e) {
        e.printStackTrace();
    }
}
傻比既视感 2024-10-23 10:04:06

隐藏对话框/框架是一个选项吗?

// Create the dialog/frame which contains the JSplitPane
final JFrame frame = new JFrame("JSplitPane Problem");
frame.setCloseOperation(JFrame.HIDE_ON_CLOSE);
// ...
myButton.addActionListener(new ActionListener()
{
    public void actionPerformed(ActionEvent ae)
    {
        if (!frame.isVisible())
           frame.setVisible(true);
    }

});

Is hiding your dialog/frame an option?

// Create the dialog/frame which contains the JSplitPane
final JFrame frame = new JFrame("JSplitPane Problem");
frame.setCloseOperation(JFrame.HIDE_ON_CLOSE);
// ...
myButton.addActionListener(new ActionListener()
{
    public void actionPerformed(ActionEvent ae)
    {
        if (!frame.isVisible())
           frame.setVisible(true);
    }

});
蓝眼睛不忧郁 2024-10-23 10:04:06

http://docs.oracle.com/javase/ 7/docs/api/javax/swing/JSplitPane.html

void javax.swing.JSplitPane.setDividerLocation(双比例位置)

将分隔线位置设置为百分比
JSplitPane 的大小。该方法的实现方式是
setDividerLocation(int).此方法立即改变大小
基于当前大小的分割窗格。如果分割窗格没有
正确实现并在屏幕上,此方法将不起作用(新
分隔线位置将变为(当前大小 * 比例位置)
这是 0)。

所以基本上你需要创建整个 UI,在主 JFrame 上调用 .pack()
之后您可以使用 JSplitPane.setDividerLocation(double)。如果您在 UI 布局之前执行此操作并且完成所有这些操作,则该方法将不会执行任何操作,正如文档中所述并且您已经经历过的那样。

http://docs.oracle.com/javase/7/docs/api/javax/swing/JSplitPane.html

void javax.swing.JSplitPane.setDividerLocation(double proportionalLocation)

Sets the divider location as a percentage of the
JSplitPane's size. This method is implemented in terms of
setDividerLocation(int). This method immediately changes the size of
the split pane based on its current size. If the split pane is not
correctly realized and on screen, this method will have no effect (new
divider location will become (current size * proportionalLocation)
which is 0).

So basically you need to have created your whole UI, called .pack() on the main JFrame
AND after that you can use JSplitPane.setDividerLocation(double). If you do it before UI layouting and all that stuff is done, the method will just do nothing as it states in the documentation and you already experienced.

锦上情书 2024-10-23 10:04:06

JSplitPane 有一个方法 setDividerLocation(double),它将分隔线位置设置为 JSplitPane 大小的百分比。
我前段时间尝试创建类似的功能。我也有同样的问题。但即使我使用 setDividerLocation(double) 方法,它也无法正常工作。我相信这只是 JSplitPane 错误。

JSplitPane has a method setDividerLocation(double), which sets the divider location as a percentage of the JSplitPane's size.
I tried to create similar functionality some time ago. I had the same problem. But even when I use the setDividerLocation(double) method, it didn't work properly. I believe that it's just JSplitPane bug.

活雷疯 2024-10-23 10:04:06
public static void toggle(JSplitPane sp, boolean collapse) {
        try {
            BasicSplitPaneDivider bspd = ((BasicSplitPaneUI) sp.getUI()).getDivider();
            Field buttonField = BasicSplitPaneDivider.class.
                    getDeclaredField(collapse ? "rightButton" : "leftButton");
            buttonField.setAccessible(true);
            JButton button = (JButton) buttonField.get(((BasicSplitPaneUI) sp.getUI()).getDivider());
            button.getActionListeners()[0].actionPerformed(new ActionEvent(bspd, MouseEvent.MOUSE_CLICKED,
                    "bum"));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
public static void toggle(JSplitPane sp, boolean collapse) {
        try {
            BasicSplitPaneDivider bspd = ((BasicSplitPaneUI) sp.getUI()).getDivider();
            Field buttonField = BasicSplitPaneDivider.class.
                    getDeclaredField(collapse ? "rightButton" : "leftButton");
            buttonField.setAccessible(true);
            JButton button = (JButton) buttonField.get(((BasicSplitPaneUI) sp.getUI()).getDivider());
            button.getActionListeners()[0].actionPerformed(new ActionEvent(bspd, MouseEvent.MOUSE_CLICKED,
                    "bum"));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文