我有一个名为SpacePotaters(JFrame的子类)的顶级GUI类,并将一个名为panelViews(使用CardLayout布局管理器)的JPanel添加到其内容窗格中。除其他外,我将MainMenu对象(JPanel的子类)和GameView对象(JPanel的子类)添加为panelView的卡片。

public SpacePotaters(){
    super("Space Potaters");
    Container content = getContentPane();

    // initialize components
    gameView = new GameView(this);
    mainMenu = new MainMenu(this);
    leaderboard = new Leaderboard(this);
    instructions = new JPanel(); // to do
    cLayout = new CardLayout();

    // add "cards" to CardLayout manager
    panelViews = new JPanel(cLayout);
    panelViews.setPreferredSize(new Dimension(WINDOW_WIDTH, WINDOW_HEIGHT));
    panelViews.add("gameView", gameView);
    panelViews.add("mainMenu", mainMenu);
    panelViews.add("leaderboard", leaderboard);
    panelViews.add("instructions", instructions);

    // initially display menu menu
    content.add(panelViews);
    cLayout.show(panelViews,"mainMenu");

    addWindowListener(this);
    pack();
    setResizable(false);

    // relocate window to center of screen
    setLocationRelativeTo(getRootPane());
}


如果有用,主菜单绘制方法在这里:

@Override
public void paintComponent(Graphics g){
    super.paintComponent(g);
    g.drawImage(mainMenuBackground, 0, 0, spTop.getWindowWidth(), spTop.getWindowHeight(), null);

}


现在,我只绘制背景图像-稍后我将添加JButton,单击这些按钮将切换到其他卡。

我的想法是,我从主菜单卡开始,并在必要时切换到其他卡。我运行了程序,发现主菜单卡短暂闪烁,然后被为gameView创建的图像替换。我知道我应该等到实际切换到这张卡后再渲染gameView图形,这样游戏才不会过早启动。那不是我感到困惑的地方。即使我不等待,gameView是否也应该在无法查看的情况下开始运行?换句话说,无论gameView内部发生了什么,mainMenu都不应该是唯一可见的卡片吗?

我认为问题出在gameView中,它使用了主动渲染和双缓冲。 GameView具有此方法,在游戏的每个循环中都会调用一次:

public void paintScreen(){
    // get fresh graphics context for GameView each time
    Graphics context = getGraphics();
    if (context != null && dbImage != null){
        context.drawImage(dbImage, 0, 0, null);
    }
    context.dispose();
}


注释掉此方法的主体可产生所需的结果-仅显示mainMenu。我对为什么会这样感到困惑。我认为每个组件(JFrame,JPanel等)都有自己的图形上下文。因此,当我在GameView中调用getGraphics()时,是否不应该返回gameView面板的图形上下文,而不是spTop或panelViews的图形上下文?并且由于它仅更改特定的图形上下文,因此如果gameView面板不可见(如果我在mainMenu对象上使用CardLayout的show()方法,则不应该如此),那么它不应影响我对主菜单的查看。有任何想法吗?

注意:如果我使用isVisible()测试gameView和mainMenu,则gameView返回false,mainMenu返回true。另外,我使用getGraphics()来测试mainMenu,spTop和gameView图形上下文是否全部不同-确实如此。因此,gameView在其自己的图形上下文上绘制图像,并且不可见,但是paintScreen()中的drawImage()效果仍在显示!真的很困惑。

最佳答案

在花了太多时间试图弄清楚到底发生了什么之后,我只能得出一个结论:嵌入式图形组件(至少以我使用的形式)内的活动渲染会忽略该组件的可见性。因此,paintScreen()中的drawImage()将始终显示可见的结果,无论从其调用的JPanel是否可见。

我不确定,但我认为这种混淆可能与尝试将主动渲染与被动渲染混合在一起有关。 mainMenu覆盖paintComponent(),因此使用被动渲染来绘制自身。通过将我的gameView的可见性设置为false,顶级JFrame可能不会调用gameView的paintComponent()。但是,由于gameView使用paintScreen()进行绘制,因此将其可见性设置为false不会影响其行为。所有这些都是基于实验的推测,因为我找不到关于此的任何具体信息。

另外,如果我尝试使用BufferStrategy执行主动渲染,也不确定是否会得到相同的结果(即如果BufferStrategy的show()也忽略了其相关图形组件的可见性并绘制到可见屏幕上)以及)。这仍然需要研究。

至于我如何将这种理解与我当前的程序进行调和-由于我不想重写所有内容,因此我决定使用混合方法。我将使用被动渲染在panelViews /“卡片”之间切换(使用CardLayout)。仅当我切换到gameView时,才打开其活动渲染行为。当我退出并返回另一张卡时,我关闭了gameView的主动渲染。我知道不建议混合使用被动渲染和主动渲染,但是希望不会出现任何问题,因为我从不会同时使用这两种策略。这种方法目前可以​​在mainMenu和gameView之间切换,因此我希望在添加其他被动渲染组件时它可以起作用。

10-04 19:46