在不同的JPanels之间切换

3

我正在尝试制作一款游戏。游戏中有几个不同的屏幕,例如主菜单和实际游戏屏幕。每个屏幕都是一个单独的jpanel扩展。我已经将它们添加到我的JFrame类(Game)中。在我的游戏类中,我有以下方法:

public void addPanel( JPanel p ) {
    panels.add( p ); // An array of all the different panels I need
    this.getContentPane().add( p );
}

public void switchToPanel( JPanel p ) {
    for ( JPanel somePanel : panels ) {
        somePanel.setVisible( false );
    }

    p.setVisible( true );
    repaint();
}

这里的意思是,我有许多不同的面板,当我需要显示特定的面板,例如菜单屏幕时,我调用switchToPanel(myPanel)。基本上就是隐藏每个面板,然后取消隐藏我需要看到的那个。唯一的问题是,当我切换到它们时,这些面板不会出现。唯一会出现的是我最后添加的面板。在Objective C中,我经常使用这种方法在视图之间切换,从来没有遇到过任何问题。在Java中,这种事情不允许吗?
编辑:现在在切换后调用repaint(),但仍然不起作用。

我有一段时间没有碰这些了,但我认为如果你想看到它,你需要涂漆/重新涂漆框架。 - Sean F
4个回答

9

是的,我认为CardLayout是最好的选择。 - Sean F
@SeanF 这个设计用来做你想做的事情,为什么要重新发明轮子呢(我现在懒得了;) - MadProgrammer
实际上,我已经弄清楚了,由于某种原因,每次我向我的框架添加jpanel时都必须调用pack()。我不能只是添加它们然后调用pack(),我必须在每个面板添加后调用它一次。奇怪! - Christian Daley
1
@ChristianDaley 谨慎使用 pack()。如果内容大小发生变化,框架的大小也会改变。这可能不是您想要的效果。最好使用 invalidate()repaint() ... 或者使用更好的解决方案CardLayout ;) - MadProgrammer
谢谢你的建议,但我添加的所有jpanel都使用与我的主jframe相同的宽度和高度进行初始化,并且宽度和高度不会改变。 - Christian Daley

4
如果你正在制作游戏,你需要在一个与EDT不同的线程中进行制作。大多数游戏通过不更改面板而展示不同的屏幕,但它们使用单个面板,根据GameState进行渲染。
以下是一个例子。
public class MyGame extends JPanel implements Runnable {

    public static enum GameState {
        MENU, INTRO, LEVELS, END, TITLES
    }

    GameState state = GameState.MENU;

    public MyGame(){
        setDoubleBuffered(true);
        // Initialize the resources
        new Thread(this).start();
    }

    public void update(long elapsedTime){
        switch (state){
            case MENU:
                // Show the menu
                break;
            ....
        }
    }

    private void GameLoop(){
        // Game Loop goes here
    }

    public void run(){
        GameLoop();
    }

    public void paint(Graphics g){
        // switch and draw your game
    }

    public static void main(String[] args){
        JFrame f = new JFrame("MyGame");
        f.setSize(640, 480);
        f.add(new MyGame());
        f.setVisible(true);
    }

如果一个状态即某个菜单已完成,改变state变量。在开始编写自己的代码之前,先学习如何使用GameEngine


2
如果您想在两个面板之间切换,将这些面板添加到另一个JPanel中并使用cardLayout。然后,在添加JPanel之前,请先删除当前的面板。像这样:
parentPanel.removeAll();
parentPanel.repaint();
parentPanel.revalidate();

parentPanel.add(childPanel1);
parentPanel.repaint();
parentPanel.revalidate();

同样的,对于其他子面板也要做同样的事情。

0
    public static void main(String[] args) {
        JFrame jFrame = new JFrame("Test");
        jFrame.setSize(500, 500);
        jFrame.setLocationRelativeTo(jFrame.getOwner());
        jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        jFrame.setLayout(new BorderLayout());
        var jPanel = new JPanel(new BorderLayout());


        jFrame.add(jPanel, BorderLayout.CENTER);

        AtomicBoolean b = new AtomicBoolean(false);

        jFrame.add(new JButton("Switch") {
            {
                addActionListener(e -> {
                    b.set(!b.get());

                    jPanel.removeAll();
                    jPanel.repaint();
                    jPanel.revalidate();

                    jPanel.add(b.get() ? new JPanel() {
                        @Override
                        protected void paintComponent(Graphics g) {
                            setBackground(Color.RED);
                            super.paintComponent(g);
                        }
                    } : new JPanel() {
                        @Override
                        protected void paintComponent(Graphics g) {
                            setBackground(Color.GREEN);
                            super.paintComponent(g);
                        }
                    });
                    jPanel.repaint();
                    jPanel.revalidate();

                });
            }
        }, BorderLayout.SOUTH);

        jFrame.setVisible(true);
    }

目前你的回答不够清晰,请编辑并添加更多细节,以帮助其他人理解它如何回答问题。你可以在帮助中心找到有关如何编写好答案的更多信息。 - Community

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接