java - 如何使用 Swingworker 重新绘制多个图像

标签 java image swing swingworker

我想学习 swing 中的线程。我找到了这个 SwingWorker 类,并且我已经编写了简单的代码来移动一些图像。但我仍然有一个问题。只有一张图像被重新绘制。当主线程处理其图像时,第二个线程正在计算图像的位置,并且应该重新绘制。这是Image类的代码(负责更改整数位置和绘图):

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);
    }
}

WalkingThread 的代码扩展了 Image,添加了由 SwingWorker 处理的函数 running()。函数负责移动图像:

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();
    }
}

和主类,处理事件:

public class Main {

    public static void main(String[] args) 
        {
            EventQueue.invokeLater(new Runnable()
            {
                public void run()
                {
                    new Window();
                }
            }); 
        }}

我找不到我的错误。

最佳答案

MosterThread 是唯一真正导致其图像发生任何类型更新的工作线程。该解决方案无法很好地扩展,添加的图像越多,速度就越慢。您应该使用一个线程来更新所有实体、安排重绘并在帧之间生成暂停,而不是使用“行走线程”。

但请注意,Swing 不是线程安全的,您永远不应该在事件调度线程的上下文之外更新 UI,这实际上是 SwingWorker 应该帮助解决的问题,通过提供 processpublish 方法,允许您将数据从后台线程发送到 EDT

看看Concurrency in Swing了解更多详情

关于java - 如何使用 Swingworker 重新绘制多个图像,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30202623/

相关文章:

java - 如何重定向到过滤器中的引荐来源网址?

css - 为什么 flexbox 元素图像会根据其初始大小调整不同的大小?

java - 退出弹出窗口时防止调用 mouseExited

使用 FileFilter 的 JavaFX 过滤器 ListView 文件元素

java - 如何使用 Java API 获得 Elasticsearch 5.2.2 搜索突出显示

java - 我在向数据库插入记录时遇到 java 堆空间错误?

iphone - Xcode 将 PDF 保存为图像?

c++ - 读取bmp文件中的像素值

java - 如何防止 JButton 改变大小?

Java ActionListener 不适用于 JMenuItem