【问题标题】:How to draw a gif in another thread in java?如何在java的另一个线程中绘制gif?
【发布时间】:2016-02-24 19:12:26
【问题描述】:

这是我第一次尝试在java中使用另一个线程,有人可以告诉我如何让它工作吗?我已经阅读了有关它的其他主题,但我没有找到解决方案。

我想在另一个线程中绘制一个 gif(在随机位置和动画期间绘制)。

问题是第二个线程中的 drawImage() 没有做任何事情。我的计数器运行良好(它打印 1.. 2.. 3 ...),但没有绘制图像(或者我看不到它)。

条件一开始为假,然后在某一时刻为真(只创建一个新线程而没有更多),然后又为假。

if (condition) {
    (new ThreadGif(this,g)).start();
}

但是,当我删除 paintComponent() 中的条件时,它会绘制一些东西,这意味着 drawImage() 可以工作。因此,当它创建许多新线程时,gif 的每个图像都在随机位置绘制,并且它会一次又一次地启动 gif(并且计数器仍然可以正常工作)。

这可能很好,但我不认为创建数千个新线程是答案:我只需要一个。而且,每个 gif 只需要一个随机位置,而不是 gif 的每张图像都有一个不同的位置。

我希望我已经足够清楚了。请帮助我了解如何使其工作:) 非常感谢。

这是我的两个课程的简化版本:

ThreadGif.java:

public class ThreadGif extends Thread { 

    Screen screen;
    Graphics g;
    boolean running = true;

    public ThreadGif(Screen screen, Graphics g) {
        this.g = g;
        this.screen = screen;
    }

    public void run() {

        int aleaX = new Random().nextInt(300)/100;
        int aleaY = new Random().nextInt(300)/100;
        int compt = 1;

        while (running) {
            g.drawImage(new ImageIcon("res/feu.gif").getImage(), screen.tailleCase*aleaX, screen.tailleCase*aleaY, screen.tailleCase*2, screen.tailleCase*2, screen);
            System.out.println("thread " + compt);
            compt++;
            try {
                Thread.sleep(sleepTime);
            } catch(InterruptedException e) {
                e.printStackTrace ();
            }
        }
    }       
}

屏幕.java:

public class Screen extends JPanel implements Runnable {
    Thread thread = new Thread(this);

    public Screen(Frame frame) {
        this.frame = frame;
        thread.start();
    }

    public void paintComponent(Graphics g) {
        g.clearRect(0, 0, this.frame.getWidth(), this.frame.getHeight());
        if (condition) {
            (new ThreadGif(this,g)).start();
        }
    }

    public void run() { 
        while (running) {
            repaint();
            try {
                Thread.sleep(sleepTime);
            } catch(InterruptedException e) {
                e.printStackTrace ();
            }
        }
        System.exit(0);
    }
}

【问题讨论】:

  • 使用关闭 Swing 事件线程的 paintComponent Graphics 参数进行绘画闻起来像是线程灾难的邀请,不是吗?不应该反过来吗? -- 创建一个SwingWorker<Void, Image>,它有自己的内部定时器,在 SwingWorker 中创建图像,通过发布/处理方法对将图像导出到 GUI,然后调用 repaint?
  • 还有这个:g.drawImage(new ImageIcon("res/feu.gif").getImage(), ....); 坏了。既然只读取一次并将其存储到变量中更简单、更经济,为什么还要一遍又一遍地重新读取同一个图像?
  • 我会搜索 SwingWork 谢谢。是的,我绝对同意,我正在改变它。

标签: java multithreading swing paint animated-gif


【解决方案1】:

很简单:您混合了两种方法。
paintComponent-方法在每次被调用时都会启动一个新的ThreadGif,并且ThreadGif 本身会在它的线程中绘制直到它被终止,但不会刷新屏幕。

这两种方法结合起来可能会导致奇怪的行为,例如两个图像相互重叠,或者新的ThreadGif 只是在您每次重新绘制屏幕时呈现新图像。

解决方案:首先为每个班级分配特定的任务,不要混淆任何内容,或在两个班级之间拆分任务。例如:

  • ThreadGif 本身不绘制任何东西,而是重新绘制 ScreenScreen 可以向ThreadGif 请求应显示的图像。
  • ThreadGif 设为自己的Component,处理它自己的渲染,并省略Screen-class 绘制任何内容。

【讨论】:

  • 使用关闭 Swing 事件线程的 paintComponent Graphics 参数进行绘制闻起来像是线程灾难的邀请,不是吗?不应该反过来吗? -- 创建一个SwingWorker<Void, Image>,它有自己的内部定时器,在 SwingWorker 中创建图像,通过发布/处理方法对将图像导出到 GUI,然后调用 repaint?
  • @HovercraftFullOfEels 好吧,如何/何时刷新屏幕是另一点。 SwingWorker 将是一个选项,但这取决于我想说的 OP。
  • 感谢您的回答 :) 如果条件为真,paintComponent 只会启动一个新的 ThreadGif,这只会发生一次。我试着不只是看看它是否会画出一些东西,但我知道这是个坏主意。确实,您所描述的必须是在没有条件的情况下发生的情况。但是为什么我只创建一个新线程时它不起作用?为您提供解决方案: 第一个:我创建了 ThreadGif 类,因为在 Screen.paintComponent() 中绘制 gif 太难了。它没有其他用途。 “屏幕可以请求图像......”是什么意思?你能说更多吗?第二个:
  • 第二个:我不知道该怎么处理它对不起我真的不知道组件是什么,我需要研究一下。我是初学者。
  • @Dreamk33 通过“屏幕可以请求图像...”我的意思是你可以向ThreadGif-class 添加一个getter,它返回应该在getter 时绘制的图像叫做。至于第二个:基本上我的意思是你可以合并ThreadGifScreen-class,因为它们显然具有 1:1 的关系。所以让Screen 启动它自己的线程来更新图像,而不是将这部分留给单独的类。虽然一般来说:为什么你甚至需要一个线程?您的代码只会一遍又一遍地绘制相同的图像。
猜你喜欢
  • 2013-04-23
  • 2011-11-09
  • 2014-04-10
  • 2014-01-22
  • 2017-03-22
  • 1970-01-01
  • 2010-12-13
  • 1970-01-01
  • 2017-10-08
相关资源
最近更新 更多