我正在尝试制作一个小型Mosaic程序,在整个JPanel中随机绘制正方形。我想这样做,它每0秒吸收1平方(不是一次全部),但到目前为止我只能用while循环一次绘制所有。我已经尝试使用ActionListener和Timer,但我发现,我无法将相同的Graphics g传递给ActionListener。然后我尝试使用Thread.Sleep(200)然后应用程序冻结了。现在我尝试使用System.currentTimeMillis();但它与线程相同...在互联网上搜索但没有找到任何有用的东西。
主:
import javax.swing.JApplet;
public class Main extends JApplet{
public void init(){
setSize(500, 300);
Mosaic mosaic = new Mosaic();
setContentPane(mosaic);
}
}
应用:
import java.awt.Color;
import java.awt.Graphics;
import java.util.Random;
import javax.swing.JPanel;
public class Mosaic extends JPanel{
private int width, height;
private int ruut; // square
private int w = width / 2, h = height / 2; // middle of the app
Random rand = new Random();
Color color;
public Mosaic(){
this(500, 300, 10);
}
public Mosaic(int width, int height, int ruut){
this.width = width;
this.height = height;
this.ruut = ruut;
setBackground(Color.BLACK);
}
public void paintComponent(Graphics g){
super.paintComponent(g);
//draws random squares
while (true) {
moveNext(g);
wait(200);
}
}
//delay n millisec
public void wait(int n){
long t0, t1;
t0 = System.currentTimeMillis();
do {
t1 = System.currentTimeMillis();
} while ((t1 - t0) < n);
}
//next square
public void moveNext(Graphics g){
int r = rand.nextInt(4);
switch (r) {
case 1:
h += ruut;
wallTest();
break;
case 2:
h -= ruut;
wallTest();
break;
case 3:
w -= ruut;
wallTest();
break;
case 4:
w -= ruut;
wallTest();
break;
}
color = new Color(0, rand.nextInt(255-50)+50, 0);
g.setColor(color);
g.fillRect(w, h, ruut, ruut);
}
public void wallTest(){
if (h > height){
h = 0;
}
if (h < 0){
h = height;
}
if (w > width){
w = 0;
}
if (w < 0){
w = width;
}
}
}
答案 0 :(得分:2)
将javax.swing.Timer
类与重写paintComponent
方法结合使用。您 不 想要在EDT中执行长时间运行的任务,因为这会导致GUI冻结。
new javax.swing.Timer(DELAY_IN_MILLIS, new ActionListener(){
@Override
public void actionPerformed(ActionEvent e){
// do stuff
repaint();
}
});
答案 1 :(得分:2)
我尝试过ActionListener和Timer,但我发现,我无法将相同的图形g传递给ActionListener。
当然不是,Graphics
对象是暂时的。相反,要么做以下任何一种:
repaint()
(在循环中),一次绘制列表中的每个对象。BufferedImage
放入JLabel
,并一次向BufferedImage
添加一个“矩形”。答案 2 :(得分:2)
您需要维护一个屏幕外缓冲区,并在计时器事件的控制下将图块绘制到该缓冲区中。
然后paintComponent
只是将该缓冲区复制到屏幕上。
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.util.Random;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Mosaic extends JPanel{
private int width, height;
private int ruut; // square
private int w = width / 2, h = height / 2; // middle of the app
private BufferedImage buffer;
Random rand = new Random();
Color color;
public Mosaic(){
this(500, 300, 10);
}
public Mosaic(int width, int height, int ruut){
this.width = width;
this.height = height;
this.ruut = ruut;
this.buffer = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
setBackground(Color.BLACK);
setPreferredSize(new Dimension(width, height));
setDoubleBuffered(false);
new Timer(200, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
moveNext(buffer.getGraphics());
}
}).start();
}
public void paintComponent(Graphics g){
super.paintComponent(g);
g.drawImage(buffer, 0, 0, this);
}
//next square
public void moveNext(Graphics g){
int r = rand.nextInt(4);
switch (r) {
case 1:
h += ruut;
wallTest();
break;
case 2:
h -= ruut;
wallTest();
break;
case 3:
w -= ruut;
wallTest();
break;
case 4:
w -= ruut;
wallTest();
break;
}
color = new Color(0, rand.nextInt(255-50)+50, 0);
g.setColor(color);
g.fillRect(w, h, ruut, ruut);
repaint();
}
public void wallTest(){
if (h > height){
h = 0;
}
if (h < 0){
h = height;
}
if (w > width){
w = 0;
}
if (w < 0){
w = width;
}
}
}
答案 3 :(得分:1)
您可以使用计时器方法,因为这只是不冻结应用程序的方法。您可以在计时器触发时调用重绘或某种等效方法,然后根据要求在绘制方法中绘制。