[英]multithreading with java swing for a simple 2d animation
我對這個應用程序的最終目標是使用每個項目的線程以不同的速度為同一JPanel中的幾個項目制作動畫。第一部分完成但是項目以相同的速度移動,我不知道如何解決這個問題。
package javagamestutos;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Toolkit;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JPanel;
public class Board extends JPanel implements Runnable {
private Star star;
private Thread animator;
ArrayList<Star> items=new ArrayList<Star>();
public Board() {
setBackground(Color.BLACK);
setDoubleBuffered(true);
star=new Star(25,0,0);
Star star2=new Star(50,20,25);
items.add(star2);
items.add(star);
}
public void addNotify() {
super.addNotify();
animator = new Thread(this);
animator.start();
}
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D)g;
for (Star s : this.items) {
g2d.drawImage(s.starImage, s.x, s.y, this);
}
Toolkit.getDefaultToolkit().sync();
g.dispose();
}
public void run() {
while(true){
try {
for (Star s : this.items) {
s.move();
}
repaint();
Thread.sleep(star.delay);
} catch (InterruptedException ex) {
Logger.getLogger(Board.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
這里是星級,它是移動物品。
package javagamestutos;
import java.awt.Image;
import javax.swing.ImageIcon;
/**
*
* @author fenec
*/
public class Star {
Image starImage;
int x,y;
int destinationX=200,destinationY=226;
boolean lockY=true;
int delay;
public Star(int delay,int initialX,int initialY){
ImageIcon ii = new ImageIcon(this.getClass().getResource("star.png"));
starImage = ii.getImage();
x=initialX;
y=initialY;
this.delay=delay;
}
void moveToX(int destX){
this.x += 1;
}
boolean validDestinatonX(){
if(this.x==this.destinationX){
this.lockY=false;
return true;
}
else
return false;
}
void moveToY(int destY){
this.y += 1;
}
boolean validDestinatonY(){
if(this.y==this.destinationY)
return true;
else
return false;
}
void move(){
if(!this.validDestinatonX() )
x+=1;
if(!this.validDestinatonY() && !this.lockY)
y+=1;
/*if(!this.validDestinatonY())
y+=1;
*/
}
}
這是擴展JFrame的動畫骨架:
package javagamestutos;
import javax.swing.JFrame;
public class Skeleton extends JFrame {
public Skeleton() {
add(new Board());
setTitle("Stars");
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(300, 280);
setLocationRelativeTo(null);
setVisible(true);
setResizable(false);
}
public static void main(String[] args) {
new Skeleton();
}
}
你知道如何實現我的目標嗎?我是否真的使用線程? 先感謝您。
那是因為你以第一個“開始”延遲指定的固定速率調用“移動”方法
Thread.sleep(star.delay);
因此,如果你每隔“n”毫秒移動一下它們,它們似乎會在同樣的平靜中移動。
如果你想讓它們以不同的速度移動,你必須在不同的線程中移動它們(你現在只使用一個)請記住omry的注釋,
編輯
我最近做了類似的事
我有兩個不同的東西,所以動畫,所以我有兩個定時器(定時器使用下面的線程,但他們可以每個固定的速率重復執行代碼)。
第一個將文本應用於JLabel每秒(1000毫秒)
final Timer timer = new Timer();
timer.scheduleAtFixedRate( new TimerTask() {
public void run(){
setText();
}
}, 0, 1000 );
其他每隔10秒(10,000毫秒)更改顯示圖像
final Timer imageTimer = new Timer();
imageTimer.scheduleAtFixedRate( new TimerTask() {
public void run() {
setImage();
}
}, 0, 10000 );
我在這里有一個結果視頻:
對於更高級(和更好)的時間管理,您必須查看“時序框架”項目,該項目為計時器增加了額外的功能。
你應該在AWTDispatchThread中繪畫。 要做到這一點,你會想要使用像SwingUtilities.invokeLater(Runnable);
這不僅適用於您的動畫,也適用於JFrame
的創建和設置。 如果不這樣做可能會導致繪制線程出現死鎖。 此外,在將繪制操作移動到SwingUtilites
方法中時,您不希望包含任何while(true)
循環,因為這將占用您的繪制線程。
通常,應使用AWT事件調度線程(EDT)中的Swing組件。 repaint
是可以在EDT上使用的方法之一。 但是,您的Star
不是也不應該是線程安全的。
最簡單的方法是僅限EDT(至少從一開始)。 而不是使用Thread
使用在EDT上觸發的javax.swing.Timer
。
其他評論:您的paint
方法不需要處理發送給它的圖形對象,也不需要使用Toolkit
進行同步。 組件不需要設置為雙緩沖,但應設置為不透明( JPanel
不保證不透明)。 您應該只擴展JComponent
而不是JPanel
,因為這不是一個面板。 外部類實現Runnable
通常不是一個好主意。 首選私有變量。
我建議你看一下開源庫三叉戟就是這樣,它的作者Kirill Grouchnikov在Swing世界中很有名(他是着名的Substance外觀和感覺的作者)。
Trident應該幫助您解決讓不同對象以不同速度移動的問題,而不必為每個對象創建一個線程(這最終是一個問題)。
如果您確定要在線程中繪畫,可以使用:
update(getGraphics());
而不是重畫。 這通常被認為是不好的做法,因為你通常在AWT線程中繪制東西。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.