Неправильная JPanel отображается в CardLayout. Проблемы с getGraphics () - PullRequest
1 голос
/ 28 ноября 2011

У меня есть класс графического интерфейса верхнего уровня под названием SpacePotaters (подкласс JFrame), и я добавляю JPanel с именем panelViews (который использует менеджер макетов 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 просто начать работать без возможности его просмотра? Другими словами, не должно ли mainMenu оставаться единственной видимой картой независимо от того, что происходит внутри gameView?

Я подумал, что проблема была в 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();
}

Закомментирование тела этого метода дает желаемые результаты - отображается только главное меню. Я не понимаю, почему это так. Я думал, что каждый компонент (JFrame, JPanel и т. Д.) Имеет свой собственный графический контекст. Поэтому, когда я вызываю getGraphics () внутри GameView, должен ли он возвращать графический контекст для панели gameView, а не графический контекст для spTop или panelViews? И поскольку он только изменяет этот конкретный графический контекст, если панель gameView не видна (чего не должно быть, если я использую метод show () CardLayout для объекта mainMenu), то это не должно влиять на мой вид главного меню. , Есть идеи?

Примечание. Если я протестирую gameView и mainMenu с помощью isVisible (), gameView возвращает false, а mainMenu возвращает true. Кроме того, я использовал getGraphics (), чтобы проверить, были ли контексты графики mainMenu, spTop и gameView разными. Таким образом, gameView рисует изображение в своем собственном графическом контексте и не виден, , но эффекты drawImage () в paintScreen () по-прежнему показывают ! Действительно смущен.

1 Ответ

0 голосов
/ 29 ноября 2011

Потратив слишком много времени, пытаясь выяснить, что происходит, я могу только заключить, что активный рендеринг во встроенном графическом компоненте (по крайней мере в той форме, в которой я его использую) игнорирует видимость этого компонента. Поэтому drawImage () внутри paintScreen () всегда будет отображать видимые результаты, независимо от того, является ли JPanel, из которого она вызывается, видимым или нет.

Я не совсем уверен, но я думаю, что эта путаница может быть связана с попыткой смешать активный рендеринг с пассивным рендерингом. MainMenu переопределяет paintComponent () и поэтому использует пассивный рендеринг для рисования самого себя. Возможно, установив false для видимости моего gameView, JFrame верхнего уровня просто не вызывает paintComponent () в gameView. Однако, поскольку gameView рисует с помощью paintScreen (), установка его видимости в false не влияет на его поведение. Это все предположения, основанные на экспериментах, поскольку я не смог найти никакой конкретной информации об этом.

Кроме того, я не уверен, что получил бы те же результаты, если бы попытался выполнить активный рендеринг с использованием BufferStrategy (т. Е. Если бы BufferStrategy show () также игнорировал бы видимость связанного с ним графического компонента и рисовал в видимый экран также). Это то, что еще нужно исследовать.

Что касается того, как я собираюсь согласовать это понимание с моей текущей программой - поскольку я не хочу переписывать все, я решил использовать гибридный подход. Я собираюсь использовать пассивный рендеринг для переключения между моими панельными панелями / «картами» (используя CardLayout). Только когда я переключаюсь на gameView, я включаю его активное рендеринг. Когда я выхожу и возвращаюсь на другую карту, я отключаю активный рендеринг gameView. Я знаю, что смешивать пассивный и активный рендеринг не рекомендуется, но, надеюсь, никаких проблем не возникает, поскольку я никогда не использую обе стратегии одновременно. Этот подход в настоящее время работает для переключения между mainMenu и gameView, поэтому я ожидаю, что он будет работать, когда я добавлю другие пассивно визуализированные компоненты.

...