Java 图形 window 在通过事件从另一个 window 打开时不绘制

Java graphics window doesn't draw when opened from another window through an event

我有三个class,第一个是主要的window smthn like

public class Starter extends JFrame{
JButton b=new JButton("Game");
Starter(){

    setSize(200,200);
    add(b);
    b.addActionListener(new ActionListener(){
        public void actionPerformed(ActionEvent e){
            TryGraph gg=new TryGraph();
        }
    });
    setVisible(true);

}
public static void main(String [] args){
    Starter g= new Starter();

}

}

然后第二个 class 是一个 window,它有一个面板,图形将在上面绘制

public class TryGraph {
static int w=640,h=480;
TryGraph(){
    JFrame mF=new JFrame();
    GPan pan=new GPan();

    mF.setLocationRelativeTo(null);
    mF.setResizable(false);
    mF.setSize(w,h);

    mF.add(pan);

    mF.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    mF.setVisible(true);

    pan.playGame();
}

public static void main(String []args){
    TryGraph t=new TryGraph();
}

}

最后是画图的面板class

public class GPan extends JPanel{

private boolean running;
private BufferedImage image;
private Graphics2D g;
int x,y;

public GPan(){
    x=TryGraph.w;
    y=TryGraph.h;
    init();
}

public void init(){
    running=true;
    image=new BufferedImage(x,y,BufferedImage.TYPE_INT_RGB);
    g=(Graphics2D)image.getGraphics();
    g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
}

public void playGame(){
    while(running){
         g.setColor(new Color(102,102,102));
        g.fillRect(0,0,x,y);
        g.setColor(new Color(255,0,0));
        g.fillOval(0, 0, 100,100);
        repaint();
    }
}

public void paintComponent(Graphics g){
    Graphics2D g2 = (Graphics2D)g;
    g2.drawImage(image,0,0,x,y,null);

    g2.dispose();
}

}

问题是,如果我使用从 Starter class window 到 TryGraph class window 的事件,GPan 面板将不会绘制图形当它循环播放 game() 方法时。但是当直接执行 TryGraph class 时它工作正常

我注意到几个问题。

  1. 当您在 TryGraph 中调用 main 时,您创建了一个新实例。但是当按下按钮时,您已经有了一个 TryGraph 实例。

  2. 不要扩展 JFrame。这是不好的做法。只需创建它的实例即可。

  3. 只使用one static main entry point.

  4. 最大的问题是您将 repaint() 置于一个紧密的循环中。不要那样做。只需调用 repaint()。请记住,重绘是 Event Dispatch Thread 上的 运行。因此,如果该线程被占用,则其他任何方法都不起作用。

  5. 不要处理图形上下文。如果您创建一个新的但不要删除它,则可以这样做。

  6. 最后,将 super.paintComponent() 作为 JPanel paintComponent 方法中的第一条语句。

我建议您阅读 Java Tutorials 中有关绘画和 EDT 的内容。

这是修改后的代码,全部在一个文件中。

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class Starter {
   JButton b     = new JButton("Game");
   JFrame  frame = new JFrame();

   Starter() {

      frame.setSize(200, 200);
      frame.add(b);
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      b.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent e) {
            TryGraph gg = new TryGraph();
         }
      });
      frame.setVisible(true);

   }
   public static void main(String[] args) {
      Starter g = new Starter();

   }
}

class TryGraph {
   static int w = 640, h = 480;

   TryGraph() {
      JFrame mF = new JFrame();
      GPan pan = new GPan();

      mF.setLocationRelativeTo(null);
      mF.setResizable(false);
      mF.setSize(w, h);

      mF.add(pan);

      mF.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      mF.setVisible(true);

      pan.playGame();
   }

}

class GPan extends JPanel {

   private boolean       running;
   private BufferedImage image;
   private Graphics2D    g;
   int                   x, y;

   public GPan() {
      x = TryGraph.w;
      y = TryGraph.h;
      init();
   }

   public void init() {
      running = true;
      image = new BufferedImage(x, y, BufferedImage.TYPE_INT_RGB);
      g = (Graphics2D) image.getGraphics();
      g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_ON);
   }

   public void playGame() {
      repaint();

   }

   public void paintComponent(Graphics g) {
      super.paintComponent(g);
      Graphics2D g2 = (Graphics2D) g.create();

      g2.setColor(new Color(102, 102, 102));
      g2.fillRect(0, 0, x, y);
      g2.setColor(new Color(255, 0, 0));
      g2.fillOval(0, 0, 100, 100);
      // g2.drawImage(image,0,0,x,y,null);

      g2.dispose();
   }
}

另外一个建议。在您的原始代码中,我相信您通过在私有 class 中实现接口来实现监听器。好主意,但您应该为给定接口扩展适配器 class。例如,对于 mouseListener,扩展 MouseAdapter。它提供了虚拟方法,因此您不必自己创建它们。它有助于使您的代码更具可读性。当然,单一方法接口没有(或不需要)适配器。