簡體   English   中英

為什么我的方法不能正確重繪?

[英]Why doesn't my method repaint correctly?

我最近才開始學習Java,我的目標是用它制作一個簡單的圖形游戲,以便隨時指出任何樣式錯誤。

從我的主標題屏幕過渡到主屏幕時,我的舊標題屏幕沒有刷新,用於單擊以轉到主屏幕的按鈕被凍結,基本上,圖像被凍結,主屏幕上的paintComponent沒有被調用,並且程序只是進入無限循環而不會關閉(必須通過任務管理器關閉)。

需要注意的有趣一點是,沒有while循環,它就可以正常工作,paintComponent被調用,並且一切都可以正常工作,當重新引入while循環時,同樣的問題仍然存在。

public class Game {

private static final int HEIGHT = 650;
private static final int WIDTH = 820;
private static final int FRAMES_PER_SEC = 60;
private JFrame frame = new JFrame("Game");
private boolean inIntroScreen = true;
private boolean game_running = false;
private int x  = 1;
private int y  = 1;
private int dx = 1;
private int dy = 1;

/* method to set up GUI for the game. */
public void initGUI () {
    //Build Frame
    frame.setSize(WIDTH, HEIGHT);
    frame.setVisible(true);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setResizable(false);
    //End Build Frame

    /* Intro screen build */
    class drawIntro extends JPanel {

        public void paintComponent(Graphics g) {
            if (inIntroScreen) {
            Graphics2D g2d = (Graphics2D) g;
            //Background
            g2d.setPaint(Color.BLACK);
            g2d.fillRect(0, 0, 820, 650);
            //Title 
            BufferedImage img = null;
            try { img = ImageIO.read(new File("game.png")); }
            catch (IOException e) { System.out.println("Error image"); }
            g2d.drawImage(img, 180, 52, null);

            g2d.setPaint(Color.WHITE);
            g2d.fillOval(550, 60, 40, 40);
            g2d.fillOval(195, 60, 40, 40);
            System.out.println("Intro screen painted");
            }

        } //end paint
    } //end draw inner class

    final drawIntro introScreen = new drawIntro();
    final JPanel introPanel = new JPanel();
    final JButton startButton = new JButton("Start");

    frame.getContentPane().add(introPanel,BorderLayout.SOUTH);
    introPanel.setBackground(Color.BLACK);
    frame.getContentPane().add(introScreen, BorderLayout.CENTER);
    startButton.setPreferredSize(new Dimension(100,50));
    startButton.setBackground(Color.BLACK);
    startButton.setForeground(Color.WHITE);
    introPanel.add(startButton);
    introScreen.repaint();
    //End intro screen build
    startButton.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            introPanel.removeAll();
            introPanel.revalidate();
            inIntroScreen = false;
            game_running = true;
            System.out.println("button clicked");
            Start();
        }
    });

} //End initGUI

/* Level building class */
class Level extends JPanel {
    @Override 
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g;
        //Background
        g2d.setPaint(Color.BLACK);
        g2d.fillRect(0, 0, 820, 650);
        //Anti-aliasing 
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);

        g2d.setPaint(Color.BLUE);
        g2d.fillOval(x, y, 70, 70);
        x += dx;
        y += dy;


        System.out.println("Main screen painted");
    } //End paint component
}


/* Game loop */
public void Start () {
    Level player = new Level();
    frame.add(player);
    player.repaint();

    int FPS = 1000 / FRAMES_PER_SEC;

        while(game_running) {   /* PROBLEM HERE, if while loop is removed everything works as intended */
        frame.repaint();
        try { Thread.sleep(FPS); } 
        catch (InterruptedException e) {}
        }


}


public static void main(String[] args) {
    Game game = new Game();
    game.initGUI();
    System.out.println("Program terminated");

}

} //end game class

您的問題是經典的Swing線程問題,您需要在Swing事件線程上執行長時間運行的任務。 實際上,您似乎正在使用繪畫方法執行長時間運行的代碼,因此絕對不應執行某些操作,因為這將在每次執行重新繪畫時重復執行此任務,從而使繪畫速度變慢。

建議:

  • 在諸如SwingWorker提供的后台線程中執行長時間運行的任務,例如讀取文件。
  • 僅使用繪畫方法繪畫,請勿做其他任何事情。
  • 在您的覆蓋中調用super的paintComponent方法,以允許JPanel進行其內部管理繪畫。
  • 如果您要交換視圖 ,請使用CardLayout來方便且安全地進行交換。
  • while (game_running) {循環正在做同樣的事情-綁定Swing事件線程,凍結GUI。 為此,請使用Swing計時器。
  • 在繪畫方法(paintComponent方法)中已經有了游戲邏輯,您可以在其中設置x和y變量。 不要這樣做,而是在Swing Timer的代碼中更改它們。 您永遠無法完全控制是否調用paintComponent方法,因此,您希望在此方法內沒有程序邏輯,也沒有更改字段的代碼。

例如:

// start method name should start with a lower-case letter
public void start() {
  final Level player = new Level();
  frame.add(player);
  player.repaint();

  int fps = 1000 / FRAMES_PER_SEC;

  // use a field called timer
  timer = new Timer(fps, new ActionListener() {

     @Override
     public void actionPerformed(ActionEvent e) {
        // get this out of the paintComponent method
        x += dx;
        y += dy;
        player.repaint();
     }
  });
  timer.start();
}

例如:

import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;

import javax.imageio.ImageIO;
import javax.swing.*;

@SuppressWarnings("serial")
public class Game2 extends JPanel {
   public static final String INTRO = "intro";
   public static final String GAME = "game";
   public static final int FPS = 15;
   private CardLayout cardLayout = new CardLayout();

   public Game2() throws IOException {
      URL imgUrl = new URL(IntroScreen.IMAGE_PATH);
      BufferedImage img = ImageIO.read(imgUrl);
      IntroScreen introScreen = new IntroScreen(img);
      introScreen.setLayout(new BorderLayout());

      JButton startButton = new JButton(new StartAction("Start"));
      JPanel bottomPanel = new JPanel();
      bottomPanel.setOpaque(false);
      bottomPanel.add(startButton);
      introScreen.add(bottomPanel, BorderLayout.PAGE_END);

      setLayout(cardLayout);
      add(introScreen, INTRO);
   }

   private class StartAction extends AbstractAction {
      public StartAction(String name) {
         super(name);
         int mnemonic = (int) name.charAt(0);
         putValue(MNEMONIC_KEY, mnemonic);
      }

      @Override
      public void actionPerformed(ActionEvent e) {
         GamePanel gamePanel = new GamePanel(FPS);
         Game2.this.add(gamePanel, GAME);
         cardLayout.show(Game2.this, GAME);
         gamePanel.start();
      }
   }

   private static void createAndShowGui() {
      Game2 game2 = null;
      try {
         game2 = new Game2();
      } catch (IOException e) {
         e.printStackTrace();
         System.exit(-1);
      }

      JFrame frame = new JFrame("Game");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(game2);
      frame.pack();
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
   }

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

@SuppressWarnings("serial")
class IntroScreen extends JPanel {
   public static final String IMAGE_PATH = "https://duke.kenai.com/"
         + "glassfish/GlassFishMedium.jpg";
   private BufferedImage img;

   public IntroScreen(BufferedImage img) {
      this.img = img;
   }

   @Override
   protected void paintComponent(Graphics g) {
      super.paintComponent(g);
      if (img != null) {
         g.drawImage(img, 0, 0, this);
      }
   }

   @Override
   public Dimension getPreferredSize() {
      if (img != null) {
         int width = img.getWidth();
         int height = img.getHeight();
         return new Dimension(width, height);
      }
      return super.getPreferredSize();
   }
}

@SuppressWarnings("serial")
class GamePanel extends JPanel {
   protected static final int DX = 2;
   protected static final int DY = DX;
   private int x;
   private int y;
   private Timer timer;
   private int fps = 0;

   public GamePanel(int fps) {
      this.fps = fps;
   }

   @Override 
   public void paintComponent(Graphics g) {
       super.paintComponent(g);
       Graphics2D g2d = (Graphics2D) g;
       //Background
       g2d.setPaint(Color.BLACK);
       g2d.fillRect(0, 0, 820, 650);
       //Anti-aliasing 
       g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
       g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);

       g2d.setPaint(Color.BLUE);
       g2d.fillOval(x, y, 70, 70);
   }

   public void start() {
      // use a field called timer
      timer = new Timer(fps, new ActionListener() {

         @Override
         public void actionPerformed(ActionEvent e) {
            // get this out of the paintComponent method
            x += DX;
            y += DY;
            repaint();
         }
      });
      timer.start();
   }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM