Java 如何同时重复循环
这是我为java开发的一个图形程序,我在使用stars时遇到了问题。背景已设置为黑色。我希望有多颗星星同时闪烁,而不是一次闪烁一颗。我该怎么做?我对一颗星闪烁没有问题。我所需要的就是同时多个。我不知道线程是什么。我使用了从互联网上获得的Thread.sleep()。如果线程可以工作,请告诉我 代码如下: 公共类graphicwkst9扩展小程序 {Java 如何同时重复循环,java,graphics,Java,Graphics,这是我为java开发的一个图形程序,我在使用stars时遇到了问题。背景已设置为黑色。我希望有多颗星星同时闪烁,而不是一次闪烁一颗。我该怎么做?我对一颗星闪烁没有问题。我所需要的就是同时多个。我不知道线程是什么。我使用了从互联网上获得的Thread.sleep()。如果线程可以工作,请告诉我 代码如下: 公共类graphicwkst9扩展小程序 { }我相信在您提供的代码中,程序正在创建一个星形,在线程延迟的情况下将其保持500毫秒,然后将其删除。因此,在循环的每次迭代中,您只生成一颗星 我将创
}我相信在您提供的代码中,程序正在创建一个星形,在线程延迟的情况下将其保持500毫秒,然后将其删除。因此,在循环的每次迭代中,您只生成一颗星 我将创建一个名为“Star”的新类或类似的类,该类采用X位置和Y位置(适当地创建set和get方法),然后生成一些随机星,并将它们放入一个星数组中,以跟踪需要显示的内容、延迟,然后再次断电。这可以通过使用一个循环来实现,因为它会一次创建所有循环,延迟程序,然后一次将它们全部关闭 您的代码应该如下所示:
public void paint(Graphics g)
{
g.setColor(Color.BLACK);
g.fillRect(0,0,500,500);
while(true){
g.setColor(Color.WHITE);
star[] array = new star[numberOfStars (put a number here)];
for(int i = 0; i < numberOfStars; i++)
{
int x = (int)(Math.random()*495+1);
int y = (int)(Math.random()*200+1);
array[i] = new star(x, y);
g.fillOval(x,y,5,5);
}
try {
Thread.sleep(500);
} catch(InterruptedException ex) {
Thread.currentThread().interrupt();
}
g.setColor(Color.BLACK);
for(int i = 0; i < numberOfStars; i++)
{
int x = array[i].getX();
int y = array[i].getY();
g.fillOval(x,y,5,5);
}
}
}
public void绘制(图形g)
{
g、 设置颜色(颜色为黑色);
g、 fillRect(0,0500);
while(true){
g、 setColor(Color.WHITE);
star[]数组=新星[numberOfStars(在这里输入一个数字)];
对于(int i=0;i
让我们谈谈问题所在
AWT(和Swing)使用单个线程,称为事件调度线程(也称为EDT),负责处理用户输入(如鼠标和键盘事件)、系统事件(如内部和外部组件的更改(来自操作系统))以及最重要的绘制请求
AWT(和Swing)使用所谓的被动绘制算法。也就是说,绘画是根据要求完成的,所以只有那些需要改变的东西才会被改变
当EDT处理绘制事件时,EDT(最终)调用paint
方法。期望paint
方法将尽可能快地执行并返回。这一点很重要,因为paint
方法中的任何延迟都会导致程序更新速度的延迟
因此,阻止EDT的任何东西(如长时间运行的外观或Thread.sleep
)都将阻止它处理新事件,尤其是在这种情况下,绘画请求
有关更多详细信息,请参阅了解更多详细信息
现在,如何修复它
基本上,您需要某种方式来运行后台任务,对要绘制的内容进行更新,然后将这些更新推送到屏幕上。这可确保EDT未被阻止,并可继续处理传入事件
例如
private int x = 0;
private int y = 0;
private Thread t;
private volatile boolean keepRunning;
@Override
public void init()
{
setBackground(Color.BLACK);
}
@Override
public void start()
{
keepRunning = true;
t = new Thread(new Runnable() {
private boolean state = false;
public void run() {
while (keepRunning) {
if (state) {
setForeground(Color.BLACK);
} else {
x = (int)(Math.random()*495+1);
y = (int)(Math.random()*200+1);
setForeground(Color.WHITE);
}
state = !state;
repaint();
try {
Thread.sleep(500);
} catch(InterruptedException ex) {
keepRunning = false;
}
}
}
});
}
@Override
public void stop() {
keepRunning = false;
}
@Override
public void paint(Graphics g)
{
super.paint(g);
g.setColor(getForeground());
g.fillOval(x,y,5,5);
}
因此,基本上,启动时,小程序
会创建一个线程
,负责对小程序进行更改,并最终请求重新绘制小程序
现在,问题
这两种方法(你的和我的)都有很多问题。第一个是Applet
s不是双缓冲的,这意味着它在绘制时会产生闪烁
下一个问题是,您正在绘制的值正在被另一个线程更新,这意味着当paint
方法更新UI时,随着值的更改,您可能最终会得到脏的绘制
相反,我会利用Swing API,因为它的组件在默认情况下是双缓冲的,因此更容易执行快速更新
它还允许您利用javax.swing.Timer
,可以将其配置为计划在EDT上下文中执行的定期更新。这意味着,在更改组件的状态时,不能对其进行绘制,从而使其更安全
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JApplet;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class RandomApplet extends JApplet {
private RandomPane randomPane;
private Timer timer;
public RandomApplet() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
}
@Override
public void init() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
setLayout(new BorderLayout());
randomPane = new RandomPane();
add(randomPane);
}
});
}
@Override
public void start() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
// Just want to make sure that the timer is not started before the
// UI is initalised...
if (timer != null && timer.isRunning()) {
timer.stop();
}
timer = new Timer(500, new ActionListener() {
private boolean state = false;
@Override
public void actionPerformed(ActionEvent e) {
if (state) {
randomPane.setForeground(Color.BLACK);
} else {
randomPane.randomise();
randomPane.setForeground(Color.WHITE);
}
state = !state;
repaint();
}
});
timer.start();
}
});
}
@Override
public void stop() {
timer.stop();
}
public class RandomPane extends JPanel {
private int xPos;
private int yPos;
public RandomPane() {
setBackground(Color.BLACK);
setForeground(Color.BLACK);
}
@Override
public Dimension getPreferredSize() {
return new Dimension(495, 200);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(getForeground());
g2d.fillOval(xPos, yPos, 5, 5);
g2d.dispose();
}
public void randomise() {
xPos = (int) (Math.random() * (getWidth() - 5));
yPos = (int) (Math.random() * (getHeight() - 5));
}
}
}
查看更多详细信息…此代码是否会同时绘制所有星星,然后再次将它们遮住?有没有一种方法可以让一些星星熄灭,然后是其他星星,然后是其他星星。如果它们同时都消失了,看起来会有点奇怪。“你的代码应该是这样的”-不应该。决不能在事件调度线程的上下文中使用循环或Thread.sleep,尤其是在任何绘制方法中。这将阻止任何形式的绘画,everChris-是的,这就是我认为你要求的。如果不是我的错。MadProgrammer-你能澄清一下为什么你不应该这样做吗?我自己还是一个程序员新手,所以,我从来没有真正使用过线程延迟。我以前只在绘制方法中使用循环来同时在屏幕/框架/小程序上获取多个图像,因此我不知道如果不这样做,将如何进行。绘制方法将由事件调度线程调用。除其他事项外,它还负责处理系统内的喷漆请求。如果您在EDT中阻塞(和或睡眠),您将停止它处理任何事件,使其看起来像您的程序已挂起(因为它无法再执行绘制更新或响应用户事件)。好的,这是有道理的。谢谢你,疯了。
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JApplet;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class RandomApplet extends JApplet {
private RandomPane randomPane;
private Timer timer;
public RandomApplet() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
}
@Override
public void init() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
setLayout(new BorderLayout());
randomPane = new RandomPane();
add(randomPane);
}
});
}
@Override
public void start() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
// Just want to make sure that the timer is not started before the
// UI is initalised...
if (timer != null && timer.isRunning()) {
timer.stop();
}
timer = new Timer(500, new ActionListener() {
private boolean state = false;
@Override
public void actionPerformed(ActionEvent e) {
if (state) {
randomPane.setForeground(Color.BLACK);
} else {
randomPane.randomise();
randomPane.setForeground(Color.WHITE);
}
state = !state;
repaint();
}
});
timer.start();
}
});
}
@Override
public void stop() {
timer.stop();
}
public class RandomPane extends JPanel {
private int xPos;
private int yPos;
public RandomPane() {
setBackground(Color.BLACK);
setForeground(Color.BLACK);
}
@Override
public Dimension getPreferredSize() {
return new Dimension(495, 200);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(getForeground());
g2d.fillOval(xPos, yPos, 5, 5);
g2d.dispose();
}
public void randomise() {
xPos = (int) (Math.random() * (getWidth() - 5));
yPos = (int) (Math.random() * (getHeight() - 5));
}
}
}