java - 在进行任何绘图之前调用 setVisible 属性

标签 java multithreading swing

我正在尝试在 Swing 中构建游戏,我知道我可以使用其他工具,但这仅用于学习目的。我面临的问题与线程有关。

基本上,在对 JPanel(GamePanel 类)进行任何绘制之前,主线程会运行 JFrame(Window 类)的 setVisible 属性。在我做了一些研究之后,我发现我可以使用 SwingUtilities.invokeLater() 方法解决这个问题,该方法应该给游戏线程一些时间来准备在 JPanel 上制作的绘图。

我还尝试将 setVisible (true) 属性放置在不同的线程中,并使该线程 hibernate 2、3 秒。这两种方法有时有效,有时无效。

我不知道这是否有什么不同,但我的操作系统是:macOS Catalina。

导致此线程问题的简单示例。

游戏启动器

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));
    }
}

游戏面板

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(){ }

}

最佳答案

对 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);
               }
            });
         }

      });
   }
}

关于java - 在进行任何绘图之前调用 setVisible 属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60020128/

相关文章:

java - Android java+原生数据可见性

c++ - 无法获取 std::mutex 来正确保护线程访问

java - 哪个线程正在使用文件

java - 为什么我的文本区域不可见?

java - JFrame 无法解析为类型

java - sql server 数据插入错误

java - Hibernate 为一对多域对象的每个创建查询插入两条记录

java - 向现有 android 项目添加服务时的注意事项?

java - 编译并在内存中执行java源文件

Java swing JButton 顺序和大小