Java 如何动态更改 JFrame 内的 JPanel?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/218155/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 11:33:46  来源:igfitidea点击:

How do I change JPanel inside a JFrame on the fly?

javaswingjpanellayout-managercardlayout

提问by yanchenko

To put it simple, there's a simple java swing app that consists of JFrame with some components in it. One of the components is a JPanel that is meant to be replaced by another JPanel on user action.

简单来说,有一个简单的 java swing 应用程序,它由 JFrame 和一些组件组成。其中一个组件是一个 JPanel,旨在根据用户操作由另一个 JPanel 替换。

So, what's the correct way of doing such a thing? I've tried

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

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

but this won't work. What would you suggest?

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

采纳答案by Swapnonil Mukherjee

Your use case, seems perfect for CardLayout.

您的用例似乎非常适合CardLayout

In card layout you can add multiple panels in the same place, but then show or hide, one panel at a time.

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

回答by Tom Hawtin - tackline

frame.setContentPane(newContents());
frame.revalidate(); // frame.pack() if you want to resize.

Remember, Java use 'copy reference by value' argument passing. So changing a variable wont change copies of the reference passed to other methods.

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

Also note JFrameis very confusing in the name of usability. Adding a component or setting a layout (usually) performs the operation on the content pane. Oddly enough, getting the layout really does give you the frame's layout manager.

还要注意JFrame可用性的名称非常混乱。添加组件或设置布局(通常)在内容窗格上执行操作。奇怪的是,获取布局确实为您提供了框架的布局管理器。

回答by Riduidel

I suggest you to add both panel at frame creation, then change the visible panel by calling setVisible(true/false) on both. When calling setVisible, the parent will be notified and asked to repaint itself.

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

回答by Telcontar

1) Setting the first Panel:

1)设置第一个面板:

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

2)Replacing the panel:

2)更换面板:

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

Also notice that you must do this in the Event's Thread, to ensure this use the SwingUtilities.invokeLateror the SwingWorker

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

回答by James A Wilson

The other individuals answered the question. I want to suggest you use a JTabbedPane instead of replacing content. As a general rule, it is bad to have visual elements of your application disappear or be replaced by other content. Certainly there are exceptions to every rule, and only you and your user community can decide the best approach.

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

回答by luke

It all depends on how its going to be used. If you will want to switch back and forth between these two panels then use a CardLayout. If you are only switching from the first to the second once and (and not going back) then I would use telcontars suggestion and just replace it. Though if the JPanel isn't the only thing in your frame I would use remove(java.awt.Component)instead of removeAll.

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

If you are somewhere in between these two cases its basically a time-space tradeoff. The CardLayout will save you time but take up more memory by having to keep this whole other panel in memory at all times. But if you just replace the panel when needed and construct it on demand, you don't have to keep that meory around but it takes more time to switch.

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

Also you can try a JTabbedPane to use tabs instead (its even easier than CardLayout because it handles the showing/hiding automitically)

你也可以尝试使用 JTabbedPane 来代替标签(它比 CardLayout 更容易,因为它自动处理显示/隐藏)

回答by ShawnD

On the user action:

在用户操作上:

// you have to do something along the lines of

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

myJFrame.getContentPane().removeAll()
myJFrame.getContentPane().invalidate()

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

Then you can resize your wndow as needed.

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

回答by ShawnD

Hope this piece of code give you an idea of changing jPanels inside a JFrame.

希望这段代码能让您了解如何在 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);
        }
}

回答by Gabriel

I was having exactly the same problem!! Increadible!! The solution I found was:

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

  1. Adding all the components (JPanels) to the container;
  2. Using the setVisible(false) method to all of them;
  3. On user action, setting setVisible(true) to the panel I wanted to show.
  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);

No revalidate(), no validate(), no CardLayout needed.

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

回答by giannis christofakis

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

}

Sometimes you can do the work without using the revalidation and sometimes without using the repaint.My advise use both.

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