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),但也无济于事。

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

回答:

while (true)正在阻止Swing事件线程使应用程序进入睡眠状态。

对于简单的动画和游戏循环,请使用Swing计时器。如果需要长时间运行的代码需要在后台运行,请使用后台线程(例如SwingWorker),但要确保所有更改Swing组件状态的调用都应在Swing事件线程上进行。

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

    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)的代码:

int timerDelay = 20;

new Timer(timerDelay, new ActionListener(){

public void actionPerformed(ActionEvent e) {

x = randomposition(x);

y = randomposition(y);

repaint();

}

}).start();


关于DSquare的评论:

  • 确实,您不是应该在Swing事件线程上运行GUI的,但是您的while真正循环仍会冻结绘画,因为无限循环会阻止组件完全创建自身。
  • 如上所述,您实际上应该在Swing事件线程上启动所有Swing GUI,您可以通过将Swing创建代码放入Runnable并通过SwingUtilities方法invokeLater对事件线程上的Runnable排队来完成。
  • 您需要在paintComponent覆盖中调用上级的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()在循环或线程中不起作用 的全部内容, 来源链接: utcz.com/qa/414607.html

回到顶部