Swing repaint() 在循环或线程中不起作用 [英] Swing repaint() doesn't work in loop or thread

查看:28
本文介绍了Swing repaint() 在循环或线程中不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下代码:

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.Random;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.text.View;

public class ex10 extends JPanel  {
    private int x=1;
    int y=1;

    //Constructor 
    public ex10() {


        while(true) {

          System.out.println("x ->"+ x);
          System.out.println("y ->" + y);


          x = randomposition(x);
          y = randomposition(y);

          this.repaint();
        }
    }

  public int randomposition(int value) {
        Random random = new Random();

    if (random.nextBoolean() == true) {
      if (value+1 != 500) {
        value++;
      }
    }
    else {
      if (value-1 != 0) {
        value--;  
      }
    }
    return value;
  }
    @Override
    public void paintComponent(Graphics g) {
        //super.paintComponent(g);
        g.setColor(Color.green);
    g.fillRect(x, y, 20, 20);
    }


    public static void main(String[] args) {
        JFrame frame = new JFrame();
        frame.setSize(500, 500);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
        frame.add(new ex10());
    }

}

不幸的是,当 this.repaint() 被调用时,点没有被显示,但我仍然得到了 System.out.println.我尝试单独设置一个新线程,但无济于事.我尝试了其他一些解决方案(invokelaterpaintimmediately),也无济于事.

Unfortunately, when this.repaint() is called, the point isn't being displayed, but I still got the System.out.println. I tried setting a new thread separatedly, but to no avail. I tried out some other solution (invokelater, and paintimmediately), also to no avail.

我的目标是设置一个在屏幕上徘徊的绿点.你有什么解决办法吗?

My goal is to set a green point which wanders on the screen. Do you have any solution?

推荐答案

您的 while (true) 正在阻塞使应用程序进入睡眠状态的 Swing 事件线程.

Your while (true) is blocking the Swing event thread putting the application to sleep.

对于简单的动画和游戏循环,请使用 Swing Timer.如果您有长时间运行的代码需要在后台运行,请使用后台线程,例如 SwingWorker,但要注意确保所有更改 Swing 组件状态的调用都应在 Swing 事件线程上完成.

For simple animation and game loop, use a Swing Timer. If you have long running code that needs to be in the background, then use a background thread such as a SwingWorker, but taking care to make sure that all calls that change the state of your Swing components should be done on the Swing event thread.

例如,您可以更改此内容:

For example, you could change this:

    while(true) {

      System.out.println("x ->"+ x);
      System.out.println("y ->" + y);


      x = randomposition(x);
      y = randomposition(y);

      this.repaint();
    }

使用 Swing Timer (javax.swing.Timer) 的这个:

to this that uses a Swing Timer (javax.swing.Timer):

int timerDelay = 20;
new Timer(timerDelay, new ActionListener(){
  public void actionPerformed(ActionEvent e) {
    x = randomposition(x);
    y = randomposition(y);
    repaint();
  }
}).start();

<小时>

关于 DSquare 的评论:


Regarding DSquare's comments:

  • 确实,您并没有在 Swing 事件线程上运行 GUI,这是您应该做的事情,但您的 while true 循环仍然冻结了您的绘画,因为您的无限循环阻止了组件完全自我创建.
  • 如上所述,实际上您应该在 Swing 事件线程上启动所有 Swing GUI,您可以通过将 Swing 创建代码放入 Runnable 并通过 SwingUtilities 方法 invokeLater 在事件线程上排队 Runnable 来实现.
  • 您需要在您的paintComponent 覆盖中调用super 的paintComponent 方法,以便JPanel 可以执行其内务图形工作,包括清除脏"像素.

例如,更改此:

public static void main(String[] args) {
    JFrame frame = new JFrame();
    frame.setSize(500, 500);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setVisible(true);
    frame.add(new ex10());
}

到此:

public static void main(String[] args) {
  SwingUtilities.invokeLater(new Runnable() {
     public void run() {
        JFrame frame = new JFrame();
        frame.setSize(500, 500);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
        frame.add(new Ex10());
     }
  });
}

并改变这一点:

@Override
public void paintComponent(Graphics g) {
  //super.paintComponent(g);
  g.setColor(Color.green);
  g.fillRect(x, y, 20, 20);
}

到此:

@Override
public void paintComponent(Graphics g) {
  super.paintComponent(g);
  g.setColor(Color.green);
  g.fillRect(x, y, 20, 20);
}

这篇关于Swing repaint() 在循环或线程中不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆