1

我有一个名为 SpacePotaters(JFrame 的子类)的顶级 GUI 类,并在其内容窗格中添加了一个名为 panelViews 的 JPanel(它使用 CardLayout 布局管理器)。除其他外,我将 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);

}

现在我只绘制背景图像 - 稍后我将添加 JButtons,单击它会切换到不同的卡片。

这个想法是我从主菜单卡开始,必要时切换到其他卡。我运行程序并注意到主菜单卡在被为 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()的效果仍然显示!真的很迷茫。

4

1 回答 1

0

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

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

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

至于我将如何使这种理解与我当前的程序相协调——因为我不想重写所有内容,所以我决定使用混合方法。我将使用被动渲染在面板视图/“卡片”之间切换(使用 CardLayout)。只有当我切换到 gameView 时,我才会打开它的主动渲染行为。当我退出并返回另一张卡时,我关闭了 gameView 的主动渲染。我知道不鼓励混合被动和主动渲染,但希望不会出现问题,因为我从不同时使用这两种策略。这种方法目前适用于在 mainMenu 和 gameView 之间切换,因此我希望在添加其他被动渲染组件时它也能正常工作。

于 2011-11-29T18:51:39.423 回答