【问题标题】:paintComponent and repaint methods not working for my JPanel, Graphics2DpaintComponent 和 repaint 方法不适用于我的 JPanel、Graphics2D
【发布时间】:2014-05-13 16:38:48
【问题描述】:

我正在尝试制作一个图形用户界面,其中页面中间有一个矩形车辆对象,关于 x 坐标和车辆两侧的两个矩形对象。

我正在扩展一个JPanel,所以我在run方法中调用repaint来调用paintComponent方法,但是我什至没有进入paintComponent方法。此外,由于我使用的是 Graphics2D,我是否必须做一些不同的事情?

import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Path2D;
import java.awt.geom.Rectangle2D;

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

public class Display extends JPanel implements Runnable{
    public static final int frameWidth=1300;
    public static final int frameHeight=800;
    public double score;
    public double updateTimeInterval=25;
    public double prevUpdatedTime=0;

public Display(){
    JFrame frame = new JFrame();
    frame.setSize(frameWidth, frameHeight);
    frame.setTitle("You are playing HoverTeam!!!");
    frame.setVisible(true);
    JPanel panel = new JPanel();
    frame.getContentPane().add(panel);
    System.out.println("completed constructor.");
}
public void paintComponent(Graphics g){
    System.out.println("currently painting.");
    Graphics2D g2 = (Graphics2D) g;
    /*
     * Testing with random GameState
     */
    double[] pos = {28,6,Math.PI/8};
    double[] vel = {5,5,0};
    int[] nearList = {4,8,7,5};
    GameState gs = new GameState(pos,vel,2,2,nearList,3);
    //GameState gs = GameClient.getGameState();
    /*
     * Drawing the vehicle in the center of the screen with regards to the x-coordinate and then referencing the walls to it.
     */
    Path2D.Double vehic = gs.getVehicleShapePath(frameWidth/2, gs.getPosition()[1]);
    g2.draw(vehic);
    int[] nearObstHeights = gs.getNearObstList();
    double vehiclePast = gs.getPosition()[0]%5; //distance that the vehicle is past the second obstacle--reference to where to draw obstacles
    for (int i =0; i<nearObstHeights.length;i++){
        Rectangle2D.Double obstacle = new Rectangle2D.Double(frameWidth/2 -vehiclePast+5*(i-1),nearObstHeights[i],1,nearObstHeights[i]);
        g2.draw(obstacle);
    }
    score = gs.getPosition()[0]/5;
    g.drawString("Score:"+score, frameWidth/2, frameHeight-10);

}
public void run(){
    /*
     * No maximum score, game goes on forever.
     */

    System.out.println("entereed run method.");
    while (true){   
        long currentTime = System.currentTimeMillis();
        if (currentTime-prevUpdatedTime>updateTimeInterval){
            System.out.println("entered if statement");
            prevUpdatedTime = currentTime;
            repaint();
            System.out.println("should have just repainted.");
        }
    }

}
public static void main(String[] args){
    (new Thread(new Display())).start();
}

}

谢谢

【问题讨论】:

  • 你认为你在哪里实例化一个对象Display,它会使用paintComponent(即它在GUI中显示)?
  • 是的,您将一些普通的 JPanel 添加到您的 JFrame 中,而不是将 Display 类的任何对象添加到显示的任何内容中。另外,顺便说一句,您的 paintComponent 方法似乎很危险,因为您似乎在此方法中有代码逻辑,它会更改您的类的状态,而这不应该是。
  • 我想通过在main方法中调用(new Thread(new Display())).start();我将调用 Display 对象的 run 方法,当我在 run 方法中调用 repaint 时,它又调用 paintComponent。
  • @user3014093 调用 start() 肯定会执行 run()。但是您永远不会在您的 GUI 中放置任何 Display 对象。 Display 是一个 JPanel,它必须放在 Frame 中。在弄乱paintComponent 之前,只需尝试制作一个简单的GUI。您缺少对 Swing 的一些关键理解。
  • 是的,目前我有paintComponent 方法调用同步方法来获取gameState,然后绘制它。但是,为了测试它,我只是做了一个示例 gameState 并想看看它是否显示。为什么这么危险?

标签: java swing jpanel paintcomponent graphics2d


【解决方案1】:

您的代码非常混乱,每个对象都必须处理自己的职责,仅此而已。特别是:

  • Display 是 JPanel... 还是 Runnable?这是为什么?您可以让一个可运行的对象使用 GUI(小心),但它不应该是 GUI 本身。
  • Display 是一个 JPanel,但它的构造函数正在做各种各样的事情,比如创建一个框架。 Display 的构造函数只需要处理构造 JPanel。创建您自己的类 MyApplication 来完成所有工作,或者创建一个静态方法 createAndShowGUI() 并从您的 main 中调用它。
  • 为什么要在主线程中创建线程?或者更确切地说,为什么创建
  • 的同一语句

那你的代码有问题:

  • 您在paintComponent 中几乎肯定会做的第一件事就是致电super.paintComponent(g)
  • 您应该了解什么是事件调度线程。看看如何设置initial threads in Swing。简而言之,您必须在 main 中调用 invokeLater 并摆脱 new Thread()。而且无论您如何组织代码,都不要在 EDT 中执行该可运行文件,它有一个无限循环并且 GUI 会冻结。
  • 您永远不会在您的框架中放置任何显示对象。创建 GUI 的代码应该是这样的:

.

//we create the GUI here, this is called by main inside the runnable of `invokeLater`.
public static creteAndShowGUI(){
    JFrame frame = new JFrame();
    frame.setSize(frameWidth, frameHeight);
    frame.setTitle("You are playing HoverTeam!!!");


    //JPanel panel = new JPanel(); //this is an empty panel, you want the Display subclass that you created.

    //we use the Display panel that will use the `paintComponent` to paint itself
    Display panel = new Display();

    frame.getContentPane().add(panel);
    System.out.println("completed constructor.");

    frame.setVisible(true);
}

你根本不需要那个可运行的,GUI 会在它自己需要时重新绘制。如果您使用代码对其进行更改,则只需调用 repaint()。

编辑:根据您的 cmets,我将澄清一些事情:repaint() 所做的是安排在屏幕中重新绘制对象,该过程包括在某些时候调用 paintComponent .但是,您正在对不在屏幕中的对象调用repaint()。您的调用repaint() 或者更确切地说this.repaint() 正在重新绘制您在main 中创建的对象new Display()(并且是new Thread() 的参数但是您没有将该对象添加到任何帧中,它不在GUI 中所以屏幕上没有可重绘的内容。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-13
    • 1970-01-01
    • 1970-01-01
    • 2017-01-03
    • 2015-03-30
    • 1970-01-01
    相关资源
    最近更新 更多