【问题标题】:calling repaint does not result in paint method being called in thread调用重绘不会导致在线程中调用绘制方法
【发布时间】:2014-12-25 19:40:20
【问题描述】:

由于鼠标按下事件,正在执行以下线程:

// simulates bouncing ball
class Ball extends JPanel implements Runnable {  
  int Horz = 200;  
  int Vert = 200;  
  int xDim = 10;  
  int yDim = 10;  
  private int xPos;  
  private int yPos;  
  private int dxPos;  
  private int dyPos;  

  // constructor - set initial ball position to where mouse clicked; deltas to random numbers
  public Ball(int startx, int starty)  
  {  
    xPos   = startx;  
    yPos   = starty;  
    dxPos =  (int) (Math.random() * 5 + 2);  
    dyPos =  (int) (Math.random() * 5 + 2);  
  }
  // logic to update position of ball
  public void move() {

    xPos += dxPos;
    yPos += dyPos;

    if (xPos < 0) {
      xPos = 0;
      dxPos = -dxPos;
    }
    if (xPos + xDim >= Horz) {
      xPos = Horz - xDim;
      dxPos = -dxPos;
    }
    if (yPos < 0) {
      yPos = 0;
      dyPos = -dyPos;
    }

    if (yPos + yDim >= Vert) {
      yPos = Vert - yDim;
      dyPos = -dyPos;
    }
  }

调用调用repaint的Run方法

  @Override
  // run --- paint, sleep, update position - this is being executed
  public void run()     
  {  
    while (true)  
    {         
        System.out.println("I am in RUN");  
        repaint();  

        try
        {
            // sleep thread for 20 milliseconds
            Thread.sleep(20);
        }
        catch (InterruptedException e)
        {
            // interrupted
            System.out.println("Terminated prematurely due to interruption");
        }

        move();               
    }   
  }

但是不调用paint

     // draw ball at current position  
     @Override  
     public void paint( Graphics g )  
     {  
       // THIS IS NOT BEING EXECUTED  
       System.out.println("I am in paint");  

       super.paint( g );  
       g.setColor( Color.BLUE );   
       g.fillOval( xPos, yPos, 10, 10 );   
    }   
}

这是为什么呢?重绘不应该调用paint方法吗?

【问题讨论】:

  • 有什么问题?

标签: java swing


【解决方案1】:

Repaint 不会立即调用paint;它安排要重新绘制的组件,这将导致一旦事件队列可以到达它就会调用绘制。您很可能通过在其上运行计时器循环来阻止event dispatch thread,因此它无法处理绘制事件(或任何其他事件)。在不同的线程上运行循环,或者(更简单、更安全)用 Swing Timer 替换它:

Timer t = new Timer(20, (ActionEvent e) -> {
    move();
    repaint();
});
t.start();

【讨论】:

    【解决方案2】:

    @Boan 是对的。 虽然我会先看看线程是否启动:

    Thread((Ball)ball);
    thread.setDaemon(true);
    thread.start();
    

    【讨论】:

    • 我知道线程已启动,因为我进入了 run 方法。我不确定我会将 Boann 建议的代码放在 Ball 类的哪个位置。
    • 挥杆计时器可以进入球,因此可以调用move()。请注意,这是 Timer 构造函数的第二个参数的 java 8 表示法; new ActionListener() { ... } 用于较旧的 java。
    猜你喜欢
    • 2011-07-02
    • 2012-10-18
    • 2016-06-30
    • 2023-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-04
    • 1970-01-01
    相关资源
    最近更新 更多