【问题标题】:How do I change JPanel inside a JFrame on the fly?如何动态更改 JFrame 内的 JPanel?
【发布时间】:2010-09-18 02:29:58
【问题描述】:

简单地说,有一个简单的 java swing 应用程序,它由 JFrame 和一些组件组成。其中一个组件是一个 JPanel,它可以在用户操作时被另一个 JPanel 替换。

那么,做这种事情的正确方法是什么?我试过了

panel = new CustomJPanelWithComponentsOnIt();
parentFrameJPanelBelongsTo.pack();

但这行不通。你有什么建议?

【问题讨论】:

    标签: java swing jpanel layout-manager cardlayout


    【解决方案1】:

    您的用例似乎非常适合 CardLayout

    在卡片布局中,您可以在同一位置添加多个面板,然后一次显示或隐藏一个面板。

    【讨论】:

    • 使用 CardLayout 时,请记住,使用它的面板的首选尺寸将是布局中最大面板的尺寸。如果要回收空间,则需要使用 setVisible(false) 和 setPreferredSize(new Dimension(0,0)) 来隐藏组件。
    • 我以前没有听说过 CardLayout。谢谢 - 非常适合我需要做的事情。
    • 是的。这是正确的方法。也许是最好的。
    【解决方案2】:

    1) 设置第一个面板:

    JFrame frame=new JFrame();
    frame.getContentPane().add(new JPanel());
    

    2)更换面板:

    frame.getContentPane().removeAll();
    frame.getContentPane().add(new JPanel());
    

    还请注意,您必须在事件线程中执行此操作,以确保使用SwingUtilities.invokeLaterSwingWorker

    【讨论】:

      【解决方案3】:
      frame.setContentPane(newContents());
      frame.revalidate(); // frame.pack() if you want to resize.
      

      请记住,Java 使用“按值复制引用”参数传递。因此,更改变量不会更改传递给其他方法的引用副本。

      另请注意JFrame 在可用性方面非常令人困惑。添加组件或设置布局(通常)在内容窗格上执行操作。奇怪的是,获取布局确实为您提供了框架的布局管理器。

      【讨论】:

      • 汤姆,感谢您的回复。我的目标不是替换内容窗格,只是在上面放置一个 jpanel(如 frame.add(jpanel1)、frame.add(jpanel2)、frame.add(jpanel3))。你能在代码中提出一个理智的解决方案吗?
      • 嗨,John,您的用例似乎非常适合 CardLayout。 java.sun.com/docs/books/tutorial/uiswing/layout/card.html 在卡片布局中,您可以在同一个位置添加多个面板,然后一次显示或隐藏一个面板。
      • 您在使用 setContentPane() 方法时可能会遇到问题。我遇到过所有(自定义)光标在调用后不再显示的情况。
      【解决方案4】:

      希望这段代码能让您了解如何在 JFrame 中更改 jPanel。

      public class PanelTest extends JFrame {
      
              Container contentPane;
      
              public PanelTest()  {
                 super("Changing JPanel inside a JFrame");
                 contentPane=getContentPane();
              }
      
              public void createChangePanel() {
                 contentPane.removeAll();
                 JPanel newPanel=new JPanel();
                 contentPane.add(newPanel);
                 System.out.println("new panel created");//for debugging purposes
                 validate();
                 setVisible(true);
              }
      }
      

      【讨论】:

        【解决方案5】:

        关于用户操作:

        // 你必须按照以下方式做一些事情

        myJFrame.getContentPane().removeAll()
        myJFrame.getContentPane().invalidate()
        
        myJFrame.getContentPane().add(newContentPanel)
        myJFrame.getContentPane().revalidate()
        

        然后你可以根据需要调整你的窗口大小。

        【讨论】:

          【解决方案6】:

          这完全取决于它的使用方式。如果您想在这两个面板之间来回切换,请使用 CardLayout。如果您只是从第一个切换到第二个并且(而不是返回),那么我会使用telcontars 的建议并替换它。虽然如果 JPanel 不是你框架中唯一的东西,我会使用 remove(java.awt.Component) 而不是 removeAll。

          如果您介于这两种情况之间,则基本上是时空权衡。 CardLayout 将节省您的时间,但由于必须始终将整个其他面板保留在内存中,因此会占用更多内存。但是,如果您只是在需要时更换面板并按需构建,则不必保留这些记忆,但切换需要更多时间。

          您也可以尝试使用 JTabbedPane 来使用选项卡(它比 CardLayout 更容易,因为它会自动处理显示/隐藏)

          【讨论】:

            【解决方案7】:

            其他人回答了这个问题。我想建议您使用 JTabbedPane 而不是替换内容。作为一般规则,让应用程序的视觉元素消失或被其他内容替换是不好的。当然,每条规则都有例外,只有您和您的用户社区才能决定最佳方法。

            【讨论】:

              【解决方案8】:

              问题:我的组件添加到容器后没有出现。

              您需要调用revalidaterepaint在添加组件之后在它显示在您的容器中之前

              来源:http://docs.oracle.com/javase/tutorial/uiswing/layout/problems.html

              【讨论】:

                【解决方案9】:

                我也遇到了同样的问题!!不可思议!!我找到的解决方案是:

                1. 将所有组件(JPanels)添加到容器中;
                2. 对所有这些都使用 setVisible(false) 方法;
                3. 在用户操作时,将 setVisible(true) 设置为我想要的面板 显示。
                // Hiding all components (JPanels) added to a container (ex: another JPanel)
                for (Component component : this.container.getComponents()) {
                      component.setVisible(false);
                }
                // Showing only the selected JPanel, the one user wants to see
                panel.setVisible(true);
                

                不需要 revalidate(),不需要 validate(),不需要 CardLayout。

                【讨论】:

                  【解决方案10】:

                  layout.replace() 答案仅存在/适用于 GroupLayout 管理器。

                  其他 LayoutManagers(CardLayout、BoxLayout 等)不支持此功能,但需要您先 RemoveLayoutComponent( 然后 AddLayoutComponent( 再回来。:-) [直接设置记录]

                  【讨论】:

                    【解决方案11】:
                    Game game =  new Game();
                    getContentPane().removeAll(); 
                    setContentPane(game);  
                    getContentPane().revalidate(); //IMPORTANT
                    getContentPane().repaint();    //IMPORTANT
                    

                    【讨论】:

                    • 嗨 Adnane Afifi,考虑为您的解决方案添加一些解释。
                    【解决方案12】:

                    我建议您在创建框架时添加两个面板,然后通过在两者上调用 setVisible(true/false) 来更改可见面板。 调用 setVisible 时,会通知父级并要求重新绘制自己。

                    【讨论】:

                      【解决方案13】:
                      class Frame1 extends javax.swing.JFrame {
                      
                          remove(previouspanel); //or getContentPane().removeAll();
                      
                          add(newpanel); //or setContentPane(newpanel);
                      
                          invalidate(); validate(); // or ((JComponent) getContentPane()).revalidate();
                      
                          repaint(); //DO NOT FORGET REPAINT
                      
                      }
                      

                      有时您可以在不使用重新验证的情况下完成工作,有时不使用重新绘制。我的建议是两者都使用。

                      【讨论】:

                        【解决方案14】:

                        只需在设置ContentPane,(java 1.7,可能更旧)之后调用方法pack(),如下所示:

                        JFrame frame = new JFrame();  
                        JPanel panel1 = new JPanel(); 
                        JPanel panel2 = new JPanel(); 
                        ....
                        frame.setContentPane(panel1);
                        frame.pack();
                        ...
                        
                        frame.setContentPane(panel2);
                        frame.pack();
                        ...
                        

                        【讨论】:

                          猜你喜欢
                          • 1970-01-01
                          • 2021-12-23
                          • 1970-01-01
                          • 2021-12-16
                          • 1970-01-01
                          • 1970-01-01
                          • 1970-01-01
                          • 2022-11-10
                          相关资源
                          最近更新 更多