【问题标题】:Java Graphics Not DisplayingJava 图形不显示
【发布时间】:2016-05-13 17:14:08
【问题描述】:

我一直在尝试显示我的游戏的图形,但面板上没有显示任何图形。

以下是我的代码。主类调用其他两个类的绘制方法。

import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;

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

public class Simulator extends JFrame implements KeyListener, Runnable, ActionListener {

    private final int WIDTH, HEIGHT;
    private Boolean right;
    private int xMotion;
    public Salt salt;
    public Player playR;
    Boolean running = false;
    private Thread thread;
    public static int score, highScore;
    private int saltSpeed;

    public Simulator(int width, int height) {
        JPanel panel = new JPanel();
        JFrame frame = new JFrame();
        frame.setResizable(false);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
        frame.setSize(width, height);
        panel.setBackground(Color.BLACK);
        frame.add(panel);

        playR = new Player();


        this.HEIGHT = height;
        this.WIDTH = width;
        int xCordSalt = (int) (Math.random() * 631);
        saltSpeed = 1;

        salt = new Salt(saltSpeed);
        right = true; 
        running = true;

    }


    public static void main(String[] args) {
        Simulator game = new Simulator(640, 480);

        game.start();
    }

    public void paintComponent(Graphics g)
    {


        salt.paint(g);
        playR.paint(g);



    }

    public void start() {

        running = true;
        thread = new Thread(this);
        thread.start();
        repaint();
        tick();
        run();


    }

    public void stop() {
        running = false;
        System.exit(0);
    }


    @Override
    public void keyPressed(KeyEvent e) {
        if (e.getKeyCode() == KeyEvent.VK_D) {
            right = true;
        } else if (e.getKeyCode() == KeyEvent.VK_A) {
            right = false;

        }

    }

    public void tick() {
        salt.tick(this, playR);
        playR.tick();

    }

    @Override
    public void keyReleased(KeyEvent e) {


    }

    @Override
    public void keyTyped(KeyEvent e) {
        if(e.getKeyCode() == KeyEvent.VK_D)
        {
            playR.setDirection(true);
        }
        else if(e.getKeyCode() == KeyEvent.VK_A)
        {
            playR.setDirection(false);
        }

    }

    @Override
    public void run() {
        while (running) {
            tick();
            repaint();

            try {
                thread.sleep(7);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }



    public void incrementScore() {
        score++;

    }


    @Override
    public void actionPerformed(ActionEvent e) {
        repaint();
        tick();

    }

}

这里是方法 salt 的代码:

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.util.ArrayList;



public class Salt extends Rectangle{

    private final int WIDTH = 10;
    private final int HEIGHT = 10;
    public int xCordSalt, yCordSalt;
    private int speed;
    Rectangle boundBox;
    public Salt(int speedx)
    {

        xCordSalt = (int)Math.random()*641;
        yCordSalt = 0;
        speed = speedx;
        boundBox = new Rectangle(xCordSalt, yCordSalt, WIDTH, HEIGHT);
        boundBox.setBounds(xCordSalt, yCordSalt, WIDTH, HEIGHT);



    }

    public void tick(Simulator sim, Player playR)
    {
        boundBox.setBounds(xCordSalt, yCordSalt, WIDTH, HEIGHT);

        if(yCordSalt >= 480)
        {
            //sim.stop();
        }

        else if(checkCollision(playR))
        {
            sim.incrementScore();
            speed++;
            yCordSalt = -speed;

        }


        yCordSalt = yCordSalt + speed;


    }




    public boolean checkCollision(Player playR)
    {
        if(this.getBoundBox().intersects(playR.getBoundBox()))
        {
            return true;
        }
        return false;
    }

    public void paint(Graphics g) {
        g.setColor(Color.WHITE);
        g.fillRect(xCordSalt, yCordSalt, WIDTH, HEIGHT);
    }

    public Rectangle getBoundBox()
    {
        return boundBox;
    }

    public double getSpeed()
    {
        return speed;
    }


}

最后是方法 player,它使用 imageIcon 类来显示图像:

import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;

import javax.swing.ImageIcon;
import javax.swing.JPanel;

public class Player extends JPanel {
    private int xCord, yCord;
    public Rectangle boundBox;
    private static ImageIcon ryan;
    boolean isRight;

    public Player() {
        ryan = new ImageIcon("E:\ryan.png");
        xCord = 640/2;
        yCord = 460;
        boundBox = new Rectangle(xCord, yCord, 20, 20);


    }

    public static void main(String[] args) {

    }

    public void tick() {

    }

    public void setDirection(Boolean right)
    {
        if(right)
            isRight = true;
        else
            isRight = false;
    }


    public void paint(Graphics g) {
        Graphics2D g2d = (Graphics2D)g;
        g2d.drawImage(ryan.getImage(), xCord, yCord, null);


    }

    public Rectangle getBoundBox()
    {
        return boundBox;
    }

}

现在有些不完整,但我不明白为什么它没有显示任何图形。运行时,只出现一个黑框/面板。我在每个类的tick()方法、每个类的paint()方法和paintComponent()方法、start()方法中添加了一些打印语句。游戏将开始,运行每个类的tick 方法,但paintComponent() 或任何paint() 方法都会被调用!

【问题讨论】:

  • 您需要将"E:\ryan.png" 更改为"E:\\ryan.png"。反斜杠 (\) 是转义字符;要在字符串中放置实际的反斜杠,您需要用另一个反斜杠转义反斜杠。
  • @ursinusTheStrong 哦,天哪,我怎么能忘记转义序列!谢谢你提醒我!
  • JFrame 没有paintComponent 方法,所以它永远不会被调用,这就是你应该使用@Override 的原因。创建从 JPanel 扩展的类,覆盖它的 paintComponent 方法并在那里执行您的自定义喘气,确保首先调用 super.paintComponent。一个想法是创建一个实体,它描述游戏中的某些元素,高做“东西”其中一个元素将是“可绘制的”,它有一些方法可以传递图形的引用并绘制自己,这个方式,您需要做的就是维护一个实体列表,更新并绘制它们
  • @MadProgrammer /@Override 给了我这个错误:gyazo.com/13aee2a2ac1ffa81669c38dfcb05def8 所以你是说我应该创建一个单独的类来处理图形?我有点困惑你说我应该做什么。
  • 是的,我建议添加@Override 的原因是,当你“认为”你正在重写一个方法时,它会给你一个编译器警告,而你不是,这是一个很好的健全性检查。是的,我会为你所有的自定义绘画使用一个单独的类(我在这种情况下)

标签: java graphics graphics2d


【解决方案1】:

让我们从显而易见的开始......

public class Simulator extends JFrame ... {
    //...
    public void paintComponent(Graphics g) {

        salt.paint(g);
        playR.paint(g);

    }

JFrame 没有名为paintComponent 的方法,因此您的paintComponent 将永远不会被调用,因此saltplayR 将永远不会绘制。

您可以通过将 @Override 添加到 paintComponent 来测试这一点,该 paintComponent 会为您进行编译时完整性检查

public class Simulator extends JFrame ... {
    //...
    @Override
    public void paintComponent(Graphics g) {

        salt.paint(g);
        playR.paint(g);

    }

这将无法编译。

现在,您可以改写paint,但becausebecausebecausebecausebecause...我不推荐它...

退后一步。 JFrame 真正负责什么?提供一个容器,您可以在其中添加您的 gui 并将其显示在屏幕上。您并没有真正向JFrame 添加任何新功能,因此我不会将其用作您的“主要”组件,而是创建它的一个实例并添加您想要使用的任何组件它。

相反,我会从JPanel 开始并覆盖它的paintComponent 方法并将所有自定义绘画放入其中。

然后我会使用这个组件作为您的核心逻辑和控制器的起点。

您甚至可以创建几个组件来充当菜单和选项视图之类的东西,并使用CardLayoutOverlayoutLayout 来显示它们。

我还建议您查看How to Use Key Bindings 而不是KeyListener,这将回答您的下一个问题。

【讨论】:

  • 投反对票有什么理由吗?它不回答操作问题吗?在哪些方面可以改进?
  • 不是你的反对者;我同意“Swing 程序应该覆盖paintComponent() 而不是覆盖paint()。”—Painting in AWT and Swing: The Paint Methods
【解决方案2】:

首先,您要创建一个多余的框架 - 类本身就是一个框架,因此不需要更多:

    setSize(width, height);
    setVisible(true);

第二次在上面添加一个面板:它将覆盖所有内容;

第三个 JFrame 没有paintComponent - 而是使用paint()。

第四,在调用start()启动线程时,会自动调用run()方法——不需要调用run()。

这是我的工作构造函数和绘制方法:

public Simulator(int width, int height) {
    setSize(width, height);
    panel.setBackground(Color.BLACK);
    setVisible(true);

    try {
      bim=ImageIO.read(new File(.....));
    }
    catch (Exception ex) { ex.printStackTrace(); }


    this.HEIGHT = height;
    this.WIDTH = width;
    int xCordSalt = (int) (Math.random() * 631);
    saltSpeed = 1;

    right = true; 
    running = true;

}


public void paint(Graphics g)
{

  g.setColor(Color.magenta);
  g.fillRect(0, 0, 100, 100);
  g.drawImage(bim, 100, 0, null);

}

【讨论】:

  • 那么我应该在paint方法中添加salt.paint(带参数)和playR.paint()吗?另外,非常感谢您的帮助!我和我的同龄人非常困惑为什么它不起作用。
  • 不要直接在 JFrame 上绘制。使用添加到 JFrame 的 JPanel 的 paintComponent 方法进行绘制。这是example
  • @GilbertLeBlanc 这是我在我的程序中所做的,那么为什么它不会在屏幕上打印任何内容呢?如果我运行未编辑的代码会发生什么情况:gyazo.com/a4540ae5d3233c22c791cf7f0fb7afec 我还在paintComponent 方法、salt 和播放器类的paint 方法中使用了一个打印语句,但它们都没有打印任何内容,这意味着它们不能被调用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-29
  • 2021-03-12
  • 1970-01-01
  • 1970-01-01
  • 2021-08-15
相关资源
最近更新 更多