如何使用 swingworker 重新绘制多个图像
How to repaint more than one image with swingworker
我想学习 swing 中的线程。我找到了这个 SwingWorker class 并且我已经编写了简单的代码来移动一些图像。但我仍然有问题。只有一张图像是重新绘制的。当主线程处理它的图像时,第二个线程正在计算图像的位置并且它应该重新绘制。这是Image class的代码(负责更改整数位置和绘图):
public class Image extends JComponent
{
private BufferedImage image;
protected int x_location, y_location;
protected int window_size;
protected int speed;
void move_Up()
{
this.y_location -= speed;
}
void move_Down()
{
this.y_location += speed;
}
void move_Left()
{
this.x_location -= speed;
}
void move_Right()
{
this.x_location += speed;
}
public Image(String directory, int size)
{
File file = new File(directory);
try
{
image = ImageIO.read(file);
}
catch (IOException e)
{
e.printStackTrace();
}
x_location = 50;
y_location = 50;
speed = 1;
window_size = size;
setPreferredSize(new Dimension(50,50));
}
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D graphic = (Graphics2D) g;
graphic.drawImage(image, x_location, y_location, this);
}
}
扩展 Image 的 WalkingThread 代码,添加由 SwingWorker 处理的函数 运行()。函数负责移动图像:
public class WalkingThread extends Image
{
boolean directory;
public WalkingThread(String image, int size)
{
super(image, size);
}
void running()
{
System.out.println("Repainting");
this.repaint();
if( this.y_location == 0) this.directory = true;
else if( this.y_location+50 == this.window_size) this.directory = false;
if( this.directory == true ) this.move_Down();
else if( this.directory == false ) this.move_Up();
System.out.println(this.y_location+" "+ this.x_location);
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void start()
{
System.out.println("I'm in start");
SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>()
{
protected Void doInBackground() throws Exception
{
System.out.println("I'm in doInBackground");
while(true)
{
running();
}
}
};
worker.execute();
}
}
扩展JFrame并实现KeyListener的主框架代码:
public class Window extends JFrame implements KeyListener{
Image animal;
WalkingThread MonsterThread;
int window_Size;
public Window()
{
super("Walking Threads");
window_Size = 400;
setSize(window_Size, window_Size);
setLocation(400, 300);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
addKeyListener(this);
MonsterThread = new WalkingThread("kulka.png", window_Size);
MonsterThread.start();
add(MonsterThread);
animal = new Image("kulka.png", window_Size);
add(animal);
}
public void keyPressed(KeyEvent key)
{
int pressed = key.getKeyCode();
if( pressed == KeyEvent.VK_W)
animal.move_Up();
else if( pressed == KeyEvent.VK_S)
animal.move_Down();
else if( pressed == KeyEvent.VK_A)
animal.move_Left();
else if( pressed == KeyEvent.VK_D)
animal.move_Right();
animal.repaint();
}
}
和主要class,处理事件:
public class Main {
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
new Window();
}
});
}}
我找不到我的错误。
MosterThread
是唯一真正导致其图像发生任何类型更新的工作人员。该解决方案无法很好地扩展,您添加的图像越多,它就会变得越慢。而不是使用 "walking thread",您应该有一个线程来更新所有实体,安排重绘并在帧之间产生暂停。
注意,Swing 不是线程安全的,你永远不应该在事件调度线程的上下文之外更新 UI,这实际上是 SwingWorker
应该帮助解决的问题,通过提供 process
和 publish
方法,允许您将数据从后台线程发送到 EDT
查看 Concurrency in Swing 了解更多详情
我想学习 swing 中的线程。我找到了这个 SwingWorker class 并且我已经编写了简单的代码来移动一些图像。但我仍然有问题。只有一张图像是重新绘制的。当主线程处理它的图像时,第二个线程正在计算图像的位置并且它应该重新绘制。这是Image class的代码(负责更改整数位置和绘图):
public class Image extends JComponent
{
private BufferedImage image;
protected int x_location, y_location;
protected int window_size;
protected int speed;
void move_Up()
{
this.y_location -= speed;
}
void move_Down()
{
this.y_location += speed;
}
void move_Left()
{
this.x_location -= speed;
}
void move_Right()
{
this.x_location += speed;
}
public Image(String directory, int size)
{
File file = new File(directory);
try
{
image = ImageIO.read(file);
}
catch (IOException e)
{
e.printStackTrace();
}
x_location = 50;
y_location = 50;
speed = 1;
window_size = size;
setPreferredSize(new Dimension(50,50));
}
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D graphic = (Graphics2D) g;
graphic.drawImage(image, x_location, y_location, this);
}
}
扩展 Image 的 WalkingThread 代码,添加由 SwingWorker 处理的函数 运行()。函数负责移动图像:
public class WalkingThread extends Image
{
boolean directory;
public WalkingThread(String image, int size)
{
super(image, size);
}
void running()
{
System.out.println("Repainting");
this.repaint();
if( this.y_location == 0) this.directory = true;
else if( this.y_location+50 == this.window_size) this.directory = false;
if( this.directory == true ) this.move_Down();
else if( this.directory == false ) this.move_Up();
System.out.println(this.y_location+" "+ this.x_location);
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void start()
{
System.out.println("I'm in start");
SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>()
{
protected Void doInBackground() throws Exception
{
System.out.println("I'm in doInBackground");
while(true)
{
running();
}
}
};
worker.execute();
}
}
扩展JFrame并实现KeyListener的主框架代码:
public class Window extends JFrame implements KeyListener{
Image animal;
WalkingThread MonsterThread;
int window_Size;
public Window()
{
super("Walking Threads");
window_Size = 400;
setSize(window_Size, window_Size);
setLocation(400, 300);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
addKeyListener(this);
MonsterThread = new WalkingThread("kulka.png", window_Size);
MonsterThread.start();
add(MonsterThread);
animal = new Image("kulka.png", window_Size);
add(animal);
}
public void keyPressed(KeyEvent key)
{
int pressed = key.getKeyCode();
if( pressed == KeyEvent.VK_W)
animal.move_Up();
else if( pressed == KeyEvent.VK_S)
animal.move_Down();
else if( pressed == KeyEvent.VK_A)
animal.move_Left();
else if( pressed == KeyEvent.VK_D)
animal.move_Right();
animal.repaint();
}
}
和主要class,处理事件:
public class Main {
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
new Window();
}
});
}}
我找不到我的错误。
MosterThread
是唯一真正导致其图像发生任何类型更新的工作人员。该解决方案无法很好地扩展,您添加的图像越多,它就会变得越慢。而不是使用 "walking thread",您应该有一个线程来更新所有实体,安排重绘并在帧之间产生暂停。
注意,Swing 不是线程安全的,你永远不应该在事件调度线程的上下文之外更新 UI,这实际上是 SwingWorker
应该帮助解决的问题,通过提供 process
和 publish
方法,允许您将数据从后台线程发送到 EDT
查看 Concurrency in Swing 了解更多详情