【问题标题】:how can you programmatically set the JSplitPane to hide the right/bottom component when OneTouchExpandable is set to true?当 OneTouchExpandable 设置为 true 时,如何以编程方式将 JSplitPane 设置为隐藏右侧/底部组件?
【发布时间】:2012-02-28 22:27:16
【问题描述】:

JSplitPane 中,您有setOneTouchExpandable 方法,该方法为您提供2 个按钮来快速完全隐藏或完全显示JSplitPane

我的问题是如何以编程方式“单击”JSplitPane 上的隐藏按钮?

我可能错误地解释了自己。我希望拆分窗格在开始时仅显示 2 个组件中的一个(这就是我单击的意思)。

这行得通:

import javax.swing.*;

class SplitPaneDefault {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                JSplitPane sp = new JSplitPane(
                    JSplitPane.HORIZONTAL_SPLIT,
                    new JTree(),
                    new JTree());
                sp.setOneTouchExpandable(true);
                sp.setDividerLocation(0.0);
                JOptionPane.showMessageDialog(null, sp);
            }
        });
    }
}

但是用1.0 替换0.0 并不会隐藏正确的组件。这是我的问题!

【问题讨论】:

  • 这样做的用例是什么?你想达到什么目的?
  • @AndrewThompson 我希望拆分窗格在开始时仅显示 2 个组件中的一个

标签: java swing jsplitpane


【解决方案1】:

结合其他答案,doClickAncestorListener 的延迟对我有用。 见说明:

if (wantHiddenPane) {
  // The splitPane's "onload" event approximation =
  // the hierarchy ancestor changes when the pane gets packed/made visible on screen
  // Which is when the splitPane dimensions have been initialized based on available screen space
  // So that edits to the divider location can take effect after that.
   splitPane.addAncestorListener(new AncestorListener() {
       public void ancestorAdded(AncestorEvent ev) {
          // Pressing the oneTouch button shows/hides a pane while remembering the last custom dragged size
          BasicSplitPaneUI ui = (BasicSplitPaneUI) splitPane.getUI();
          JButton neededOneTouchBtn = (JButton) ui.getDivider().getComponent(isHiddenPaneLeftTop ? 0 : 1);
          neededOneTouchBtn.doClick();
        }
        // only run once
         splitPane.removeAncestorListener(this);
       }

       public void ancestorRemoved(AncestorEvent ev) {
       }

       public void ancestorMoved(AncestorEvent ev) {
       }
     });
 }

【讨论】:

    【解决方案2】:

    这是另一种解决方案,可能有点脏,但它有效;) 我希望代码不言自明。

    public class ExtOneTouchJSplitPane extends JSplitPane {
        private static final long serialVersionUID = -2320161961382260438L;
    
        JButton jBLeftUp;
        JButton jBRightDown;
    
        public ExtOneTouchJSplitPane() {
            super();
            setOneTouchExpandable(true);
            extractDividerButtons();
        }
    
        public ExtOneTouchJSplitPane(int newOrientation) {
            super(newOrientation);
            setOneTouchExpandable(true);
            extractDividerButtons();
        }
    
        public ExtOneTouchJSplitPane(int newOrientation, boolean newContinuousLayout) {
            super(newOrientation, newContinuousLayout);
            setOneTouchExpandable(true);
            extractDividerButtons();
        }
    
        public ExtOneTouchJSplitPane(int newOrientation, boolean newContinuousLayout, Component newLeftComponent, Component newRightComponent) {
            super(newOrientation, newContinuousLayout, newLeftComponent, newRightComponent);
            setOneTouchExpandable(true);
            extractDividerButtons();
        }
    
        public ExtOneTouchJSplitPane(int newOrientation, Component newLeftComponent, Component newRightComponent) {
            super(newOrientation, newLeftComponent, newRightComponent);
            setOneTouchExpandable(true);
            extractDividerButtons();
        }
    
        private void extractDividerButtons() {
            BasicSplitPaneUI ui = (BasicSplitPaneUI) getUI();
            jBLeftUp = (JButton) ui.getDivider().getComponent(0);
            jBRightDown = (JButton) ui.getDivider().getComponent(1);
        }
    
        public void oneTouchClickLeft() {
            jBLeftUp.doClick();
        }
    
        public void oneTouchClickRight() {
            jBRightDown.doClick();
        }
    
        public void oneTouchClickUp() {
            jBLeftUp.doClick();
        }
    
        public void oneTouchClickDown() {
            jBRightDown.doClick();
        }
    }
    

    以及如何使用它的示例:

    public class SplitPaneDemo extends JFrame implements Runnable {
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(new SplitPaneDemo());
        }
    
        ExtOneTouchJSplitPane hSplitPane;
        ExtOneTouchJSplitPane vSplitPane;
    
        public SplitPaneDemo() {
            createView();
        }
    
        public void createView() {
            setTitle("SplitPane-Demo");
            setLayout(new BorderLayout(0, 0));
    
            hSplitPane = new ExtOneTouchJSplitPane();
            JButton jBLeft = new JButton("<html><body> &nbsp;<br>Left Component<br> &nbsp;</body></html>");
            JButton jBRight = new JButton("<html><body> &nbsp;<br>Right Component<br> &nbsp;</body></html>");
            jBLeft.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    hSplitPane.oneTouchClickLeft();
                }
            });
            jBRight.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    hSplitPane.oneTouchClickRight();
                }
            });
            hSplitPane.setLeftComponent(jBLeft);
            hSplitPane.setRightComponent(jBRight);
    
            add(hSplitPane, BorderLayout.CENTER);
    
            vSplitPane = new ExtOneTouchJSplitPane(JSplitPane.VERTICAL_SPLIT);
            JButton jBUp = new JButton("<html><body> &nbsp;<br>Up Component<br> &nbsp;</body></html>");
            JButton jBDown = new JButton("<html><body> &nbsp;<br>Down Component<br> &nbsp;</body></html>");
            jBUp.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    vSplitPane.oneTouchClickUp();
                }
            });
            jBDown.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    vSplitPane.oneTouchClickDown();
                }
            });
            vSplitPane.setTopComponent(jBUp);
            vSplitPane.setBottomComponent(jBDown);
    
            add(vSplitPane, BorderLayout.SOUTH);
        }
    
        @Override
        public void run() {
            setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
            setSize(400, 400);
            setVisible(true);
    
            hSplitPane.oneTouchClickLeft();
        }
    }
    

    【讨论】:

      【解决方案3】:

      @0__'s answer 暗示您应该使用AncestorListener 来设置分隔线位置,并考虑到这一点ComponentListener 还不够,我不确定为什么)。

      然而,这还不够:如果拆分平面以某种方式被调整大小(例如,因为它的布局管理器决定它应该,当框架被调整大小时),你想要的组件的一小部分hide 仍然会显示。 这是因为组件的最小尺寸不为零。可以通过使用 setMinimumSize(new Dimension()) 将其归零来解决它(如 that other answer 中所述),但如果这不是一个选项,您可以侵入拆分窗格 UI:

      如果您使用标准的BasicSplitPaneUI,您可以破解其keepHidden 布尔字段并将其强制为true,因此分隔符将粘在任一侧:

      sp.addAncestorListener(new AncestorListener() {
          @Override
          public void ancestorAdded(AncestorEvent event) {
              sp.setDividerLocation(1.0); // Divider is positioned
              Field m = BasicSplitPaneUI.class.getDeclaredField("keepHidden");
              m.setAccessible(true);
              m.set(sp.getUI(), true); // Divider position will stick
              //sp.removeAncestorListener(this); // Uncomment for a one-shot event
          }
      
          @Override public void ancestorRemoved(AncestorEvent event) { }
          @Override public void ancestorMoved(AncestorEvent event) { }
      });
      

      【讨论】:

        【解决方案4】:

        解决setDividerLocation(1.0) 在框架变为可显示之前无法工作的问题,可以使用AncestorListener

        sp.addAncestorListener(new AncestorListener {
          def ancestorAdded  (event: AncestorEvent): Unit = sp.setDividerLocation(1.0)
        
          def ancestorRemoved(event: AncestorEvent): Unit = ()
          def ancestorMoved  (event: AncestorEvent): Unit = ()
        })
        

        【讨论】:

        • 那是什么语言?
        • @Matthieu Scala,另一种 JVM 语言
        【解决方案5】:
        import javax.swing.*;
        
        class SplitPaneDefault {
            public static void main(String[] args) {
                SwingUtilities.invokeLater(new Runnable() {
                    public void run() {
                        JSplitPane sp = new JSplitPane(
                            JSplitPane.HORIZONTAL_SPLIT,
                            new JTree(),
                            new JTree());
                        sp.setOneTouchExpandable(true);
                        sp.setDividerLocation(0.0);
                        JOptionPane.showMessageDialog(null, sp);
                    }
                });
            }
        }
        

        用 1.0 替换 0.0,你就会明白我的问题

        阅读精美手册,解决问题。

        此方法会根据当前大小立即更改拆分窗格的大小。 如果拆分窗格没有正确实现并显示在屏幕上,此方法将无效 ...

        import javax.swing.*;
        
        class SplitPaneDefault {
            public static void main(String[] args) {
                SwingUtilities.invokeLater(new Runnable() {
                    public void run() {
                        JSplitPane sp = new JSplitPane(
                            JSplitPane.HORIZONTAL_SPLIT,
                            new JTree(),
                            new JTree());
                        sp.setOneTouchExpandable(true);
                        JFrame f = new JFrame("Split Pane To Right");
                        f.add(sp);
                        f.pack();
                        // sp now has a non-zero size!
                        sp.setDividerLocation(1.0);
                        f.setLocationByPlatform(true);
                        f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                        f.setVisible(true);
                    }
                });
            }
        }
        

        【讨论】:

        • 用 1.0 替换 0.0,你就会明白我的问题 :)
        • @AdelBoutros,要求人们阅读文档并没有错。你的问题不是很清楚。当人们要求提供更多信息时,您更新了问题以使其更加清晰。这不是我们不断返回问题以获取更新信息的最佳利用时间。我早就失去耐心了。所有信息都应该从一开始就在问题中。从这个问题中学习并继续前进。
        【解决方案6】:

        你可以简单地使用这个:

        public void setDividerLocation(double proportionalLocation)
        
        splitPane.setDividerLocation(0.0d);
        

        或者。

        splitPane.setDividerLocation(1.0d);
        

        取决于您要先隐藏左侧组件还是右侧组件。

        【讨论】:

        • 没用,我试过了。使用0.0d,它通过隐藏顶部来工作。但是1.0d 并没有隐藏底部,它仍然显示了它的很大一部分。这正常吗?
        • 当我在 SSCCE 中尝试它时它起作用了(如答案所示)。 向我们展示一个行为不同的SSCCE怎么样?
        • 菲尔回答。为它 +1。
        猜你喜欢
        • 2012-05-27
        • 2016-03-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-07-05
        • 2023-03-04
        • 1970-01-01
        • 2018-08-14
        相关资源
        最近更新 更多