Java Swing +线程
此代码绘制两行,但等待一秒钟.. 我正在寻找如何做到这一点在一个单独的线程,所以它不会冻结应用程序.. 要绘制一条线,并将其显示给用户和那么第二.. 很抱歉,但我很困惑..发现太多的解决方案Java Swing +线程
public class Askisi2_3 extends JFrame {
private class LineJPanel extends JPanel {
public LineJPanel() {
setSize(500,500);
}
private void drawRandomLines(Graphics g) {
g.drawLine(5, 4, 50, 100);
try{
Thread.sleep(1000);
} catch(InterruptedException ex) {
}
g.drawLine(5, 4, 50, 200);
}
@Override
public void paint(Graphics g) {
super.paint(g);
drawRandomLines(g);
}
}
public Askisi2_3() {
initialiseComponents();
}
private void initialiseComponents() {
JPanel panel = new LineJPanel();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
add(panel);
setSize(500, 500);
setVisible(true);
}
}
编辑
谢谢您的回复! 对此的要求是使用
try{
Thread.sleep(1000);
}
这可能吗?
这是我更新的代码
@Override
public void paint(Graphics g) {
super.paint(g);
for (int i = 0; i < lines.length; i++) {
try{
Thread.sleep(1000);
}catch(InterruptedException e) {
}
g.drawLine(lines[i].getX1(),lines[i].getY1(), lines[i].getX2(), lines[i].getY2());
}
}
打开这个线程之前用Google搜索了一下,发现约定时器..但我不得不使用Thread.Sleep()
..所以有没有解决或没有?
因此,你建议把外面的睡眠以某种方式?
简短的回答
您可以使用Thread.sleep
但不能从paint方法。从外面使用它,只需重新打开面板。
龙答案
因为它是现在,你的代码绘制的面板,直至暂停是完成它返回。从视觉上看,油漆需要花费太多时间才能完成。
你需要什么,是有一个“型号”画。你的组件只会绘制该模型并完成。
然后,您每秒钟都会向模型中添加更多“事物”,就是这样。
例如,比方说,你的模式是线组成的数组:
class Line {
int x1, y1, x2, y2;
}
class LineJPanel extends JPanel {
// this is the private model
private Line[] lines = new Line[10];
.....
您需要在paint方法做的是画那些线:
// exactly as you have them:
@Override
public void paint(Graphics g) {
super.paint(g);
drawRandomLines(g);
}
// Changed. Do no "sleep" here, or you'll freeze the GUI
// just draw whatever your model is/has.
private void drawRandomLines(Graphics g) {
for(Line line : lines){
if(line != null){
g.drawLine(line.x1, line.y1, line.x2, line.y2);
}
}
}
就是这样。这样你就不会冻结GUI。
要添加具有越来越多行的效果,您将创建一个单独的线程并向其中添加行。
为了简单起见,你可以添加线程在构造函数中:
public LineJPanel() {
setSize(500,500);
Thread t = new Thread(){
public void run(){
while(true) {
// add random lines and repaint
// sleep for a while
// and repeat.
}
}
};
t.start();
}
这应该增加更多线路到“模式”(阵列)一样简单,让组件重新油漆他们。
左右的时间完成,我们可以添加,创建一个线addRandomLine
方法,设置一些随机值,并把它在阵列中的代码:
private void addRandomLine(){
Line line = new Line();
line.x1 = random.nextInt(500);
line.y1 = random.nextInt(500);
line.x2 = random.nextInt(500);
line.y2 = random.nextInt(500);
lines[count++] = line;//put it in the next position
// if we reach the limit, start all over again
// from 0
if(count == lines.length){
count = 0;
}
}
所以,结束了你的新的线程将如下所示:
Thread t = new Thread(){
public void run(){
while(true){
addRandomLine();
repaint();
// and as per the requiement:
try{
Thread.sleep(1000);
}catch(InterruptedException ie){}
}
}
};
请注意,这将在其他线程中调用repaint
与EDT不同。为了解决这个问题,我们将使用:SwingUtilities.invokeLater
这让我们定义一个方法被调用“最终”在EDT:
所以,最终的代码(从我的一部分某些格式的改进)将是:
import javax.swing.*;
import java.awt.*;
import java.util.Random;
public class Askisi2_3 extends JFrame {
public Askisi2_3() {
initialiseComponents();
}
private void initialiseComponents() {
JPanel panel = new LineJPanel();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
add(panel);
setSize(500, 500);
setVisible(true);
}
public static void main(String [] args) {
new Askisi2_3();
}
}
// line abstraction
class Line {
int x1, y1, x2, y2;
}
class LineJPanel extends JPanel {
// this is the private model
private Line[] lines = new Line[10];// fixed of size 10 by now.
// private internal index position
private int count = 0;
// generates "random" numbers
private Random random = new Random();
// create the panel and start adding more lines in a separate thread.
public LineJPanel() {
setSize(500,500);
Thread t = new Thread(){
public void run(){
// forever:
while(true){
//add another line
addRandomLine();
// rapaint it
SwingUtilities.invokeLater(new Runnable(){
public void run(){
repaint();
}
});
// sleep for while
try{
Thread.sleep(1000);
}catch(InterruptedException ie){}
}
}
};
t.start();
}
// just draw the model
private void drawRandomLines(Graphics g) {
for(Line line : lines){
if(line != null){
g.drawLine(line.x1, line.y1, line.x2, line.y2);
}
}
}
@Override
public void paint(Graphics g) {
super.paint(g);
drawRandomLines(g);
}
// add another line to the "model"
private void addRandomLine(){
Line line = new Line();
line.x1 = random.nextInt(500);
line.y1 = random.nextInt(500);
line.x2 = random.nextInt(500);
line.y2 = random.nextInt(500);
lines[count++] = line;
if(count == lines.length){
count = 0;
}
}
}
结果是一个非常好的 “行动画” 面板:
like this http://img689.imageshack.us/img689/8414/capturadepantalla201006bk.png
总结与if语句对于一些挥发性布尔(例如drawSecondLine)第二的drawLine:
if (drawSecondLine) {
g.drawLine(5, 4, 50, 200);
}
然后安排java.util.Timer
运行定时任务,设置一个布尔为true后1000毫秒。从该计时器任务中,请在面板上拨打repaint()
。
new Timer().schedule(new TimerTask() {
public void run() {
drawSecondLine = true;
panel.repaint();
}
}, 1000);
(可选)使用Swing定时器,以便在EDT上进行切换,因此您不需要易失性布尔值。
回应提问者的“答案”:
可以避开定时任务,仍然由主线程设置布尔使用的Thread.sleep(不 Swing事件分派线程!)。例如,您可以将run()
以上的逻辑作为一个示例,在Thread.sleep(1000)
后面的initializeComponents的末尾。
您需要从线条设置中分离出绘制机制。
创建LineJPanel,以便它存储它应该绘制的线的坐标。写绘画方法以便绘制存储的线条:例如
class LineJPanel extends JPanel {
int x1,y1,x2,y2;
void setLine(int newX1,int newY1,newX2,newY2) {
x1=newX1; ///...etc
repaint();
}
void paint(Graphics g) {
g.drawLine(x1,y1,x2,y2);
}
}
然后创建一个单独的线程,在LineJPanel上以1秒为间隔调用setLine。这将每秒更改一行,但如果您执行其他操作,如暴露窗口或调整其大小,则不会更改该行。
只是去'javax.swing.Timer'。如果可能,避免多线程 - 这很难得到正确的结果。一些声称在Swing中是线程安全的方法不是。 – 2010-06-21 18:23:48