свойство setVisible, вызываемое до создания любого рисунка - PullRequest
0 голосов
/ 01 февраля 2020

Я пытаюсь создать игру на Swing, я знаю, что могу использовать другие инструменты, но это только для целей обучения. Проблема, с которой я сталкиваюсь, связана с темами.

По сути, основной поток запускает свойство setVisible JFrame (класс Window) до того, как в JPanel (класс GamePanel) будет сделано любое рисование. После того, как я провел некоторое исследование, я обнаружил, что могу решить эту проблему, используя метод SwingUtilities.invokeLater(), который должен дать игровому потоку некоторое время для подготовки рисунков, сделанных на JPanel.

Я также пытался поместить свойство setVisible (true) в другой поток и заставил этот поток спать в течение 2, 3 секунд. Оба эти метода работают иногда, а иногда нет.

Я не знаю, если это имеет значение, но моя операционная система: macOS Catalina.

Тривиальный пример, который вызывает эту проблему потока .

GameLauncher

public class GameLauncher {

public GameLauncher(){
    new Window("MyGame");
}

public static void main(String[] args) {
    new GameLauncher();
}

}

Окно

public class Window extends JFrame {

    public Window(String title){
        setTitle(title);

        setContentPane(new GamePanel(1280, 1280));
        setLocationRelativeTo(null);
        setIgnoreRepaint(true);
        pack();
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//        setVisible(true);
        SwingUtilities.invokeLater(()->setVisible(true));
    }
}

GamePanel

package com.progresso.games;

import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;

public class GamePanel extends JPanel implements Runnable {

public int width;
public int height;

private BufferedImage bufferedImage;

private Thread gameThread;
private boolean isRunning = false;

Graphics2D graphics2D = null;

public GamePanel(int width, int height){
    this.width = width;
    this.height = height;

    setPreferredSize(new Dimension(width, height));
    setFocusable(true);
    requestFocus();
}

@Override
public void addNotify() {
    super.addNotify();
    if(gameThread == null){
        gameThread = new Thread(this, "GameThread");
        gameThread.start();
    }
}

private void init(){
    isRunning = true;

    bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
    graphics2D = (Graphics2D) bufferedImage.getGraphics();
}

@Override
public void run() {
    init();

    while (isRunning) {
        update();
        render(graphics2D);
        draw();
    }

}

private void update(){ }

private void render(Graphics2D g){
    if(g != null){
        g.setColor(Color.BLACK);
        g.fillRect(0,0, width, height);
    }
}

private void draw(){ }

}

1 Ответ

1 голос
/ 01 февраля 2020

Редко хорошей идеей является создание подкласса JFrame. Вместо этого расширьте JPanel и нарисуйте ваши вещи в его методе paintCpomponent (). Попробуйте что-то вроде этого (неполный код):

public class GamePanel extends JPanel {

   public GamePanel() {
      // Create panel content here
   }

   @Override
   public void paintComponent( Graphics g ) {
      super.paintComponent(g);
      g.setColor(Color.BLACK);
      g.fillRect(0,0, width, height);
   }

   public static void main(String args[]) {
      SwingUtilities.invokeLater(new Runnable() {

         @Override
         public void run() {
            JFrame frame = new JFrame();
            // create the component to display in the frame
            JPanel panel = new GamePanel();
            ;
            frame.add(panel, BorderLayout.CENTER);

            frame.pack();
            frame.setVisible(true);
            frame.addWindowListener(new WindowAdapter() {
               @Override
               public void windowClosing(WindowEvent arg0) {
                  System.exit(0);
               }
            });
         }

      });
   }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...