Java Swing中刷新BuffereImage像素的惯用方法

Java Swing中刷新BuffereImage像素的惯用方法,java,multithreading,swing,pixel,event-dispatch-thread,Java,Multithreading,Swing,Pixel,Event Dispatch Thread,我有一个Swing UI,其中一部分由buffereImage组成,我需要在其上定期修改像素 创建JLabel并通过传递JLabel来调用该setIcon方法似乎很常见: new ImageIcon(bufferedImage) 例如,具有20K+代表的用户在此处接受的答案中,屏幕上显示BuffereImage的方式如下: 所以我也在做同样的事情:一个JLabel,它有一个图标设置为一个包含BuffereImage的ImageIcon,我的问题与多线程和Swing重绘有关:我应该如何修改Bu

我有一个Swing UI,其中一部分由
buffereImage
组成,我需要在其上定期修改像素

创建
JLabel
并通过传递
JLabel
来调用该
setIcon
方法似乎很常见:

new ImageIcon(bufferedImage)
例如,具有20K+代表的用户在此处接受的答案中,屏幕上显示BuffereImage的方式如下:

所以我也在做同样的事情:一个JLabel,它有一个图标设置为一个包含BuffereImage的ImageIcon,我的问题与多线程和Swing重绘有关:我应该如何修改
BuffereImage
中的像素,以确保用户看到更改

我认为如果我从一个非EDT线程的线程修改
buffereImage
,并且如果没有使用同步/锁定/内存屏障,那么没有任何东西可以保证更改是可见的

我可以直接在EDT上修改像素吗

一旦我修改了像素,我应该调用
JPanel
repaint
方法吗

这能保证我的更改始终可见吗?(这里“可见”的字面意思是“可见”,如屏幕上可见和EDT可见)


我宁愿保持这个简单,也不想使用非Swing API或3D API等。

如果我正确理解了这个问题,这个示例将使用
缓冲图像
并用红色像素替换该图像中的所有像素

这是通过使用
SwingWorker
实现的。基本上,这会复制原始图像并遍历像素数据,更新每个像素。然后,它通过复制该图像与UI重新同步

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.util.List;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class PixelMe {

    public static void main(String[] args) {
        new PixelMe();
    }

    public PixelMe() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException ex) {
                } catch (InstantiationException ex) {
                } catch (IllegalAccessException ex) {
                } catch (UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame("Test");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }

        });
    }

    public BufferedImage createImage() {

        BufferedImage image = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g = image.createGraphics();
        g.setColor(Color.WHITE);
        g.fillRect(0, 0, 100, 100);
        g.dispose();

        return image;

    }

    public class TestPane extends JPanel {

        private JLabel label;
        private BufferedImage master;

        public TestPane() {
            setLayout(new BorderLayout());
            label = new JLabel(new ImageIcon(createImage()));
            add(label);

            JButton update = new JButton("Update");
            add(update, BorderLayout.SOUTH);
            update.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    BufferedImage image = (BufferedImage) ((ImageIcon)label.getIcon()).getImage();
                    new UpdateWorker(image, label).execute();
                }

            });
        }

    }

    public class UpdateWorker extends SwingWorker<BufferedImage, BufferedImage> {

        private BufferedImage copy;
        private JLabel target;

        public UpdateWorker(BufferedImage master, JLabel target) {
            this.target = target;
            copy = makeCopy(master);
        }

        public BufferedImage makeCopy(BufferedImage master) {
            BufferedImage image = new BufferedImage(master.getWidth(), master.getHeight(), master.getType());
            Graphics2D g = image.createGraphics();
            g.drawImage(master, 0, 0, null);
            g.dispose();
            return image;
        }

        @Override
        protected void process(List<BufferedImage> chunks) {
            target.setIcon(new ImageIcon(chunks.get(chunks.size() - 1)));
        }

        @Override
        protected BufferedImage doInBackground() throws Exception {
            int pixel = Color.RED.getRGB();
            for (int row = 0; row < copy.getHeight(); row++) {
                for (int col = 0; col < copy.getWidth(); col++) {
                    copy.setRGB(col, row, pixel);
                    publish(makeCopy(copy));
                }
            }
            return null;
        }
    }
}
导入java.awt.BorderLayout;
导入java.awt.Color;
导入java.awt.EventQueue;
导入java.awt.Graphics2D;
导入java.awt.event.ActionEvent;
导入java.awt.event.ActionListener;
导入java.awt.image.buffereImage;
导入java.util.List;
导入javax.swing.ImageIcon;
导入javax.swing.JButton;
导入javax.swing.JFrame;
导入javax.swing.JLabel;
导入javax.swing.JPanel;
导入javax.swing.SwingWorker;
导入javax.swing.UIManager;
导入javax.swing.UnsupportedLookAndFeelException;
公共类像素{
公共静态void main(字符串[]args){
新像素();
}
公共像素{
invokeLater(新的Runnable(){
@凌驾
公开募捐{
试一试{
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}捕获(ClassNotFoundException ex){
}catch(实例化异常){
}捕获(非法访问例外){
}捕获(无支持的LookandFeelexception ex){
}
JFrame=新JFrame(“测试”);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(新的BorderLayout());
frame.add(newtestpane());
frame.pack();
frame.setLocationRelativeTo(空);
frame.setVisible(true);
}
});
}
公共缓冲区映像createImage(){
BuffereImage=新的BuffereImage(100100,BuffereImage.TYPE_INT_ARGB);
Graphics2D g=image.createGraphics();
g、 setColor(Color.WHITE);
g、 fillRect(0,0,100,100);
g、 处置();
返回图像;
}
公共类TestPane扩展了JPanel{
私人标签;
专用缓冲图像主控器;
公共测试窗格(){
setLayout(新的BorderLayout());
label=newjlabel(newimageicon(createImage());
添加(标签);
JButton update=新JButton(“更新”);
添加(更新,BorderLayout.SOUTH);
update.addActionListener(新ActionListener(){
@凌驾
已执行的公共无效操作(操作事件e){
BuffereImage=(BuffereImage)((ImageIcon)label.getIcon()).getImage();
新的UpdateWorker(图像、标签).execute();
}
});
}
}
公共类UpdateWorker扩展SwingWorker{
私有缓冲区图像副本;
私有JLabel目标;
公共UpdateWorker(BuffereImage主机,JLabel目标){
this.target=目标;
复制=制作副本(母版);
}
公共BuffereImage makeCopy(BuffereImage master){
BuffereImage=新的BuffereImage(master.getWidth(),master.getHeight(),master.getType());
Graphics2D g=image.createGraphics();
g、 drawImage(master,0,0,null);
g、 处置();
返回图像;
}
@凌驾
受保护的无效进程(列表块){
setIcon(新的ImageIcon(chunks.get(chunks.size()-1));
}
@凌驾
受保护的BuffereImage doInBackground()引发异常{
int pixel=Color.RED.getRGB();
对于(int row=0;row

应该注意的是,这是一个非常昂贵的示例,因为为像素的每次更改都会创建一个新的
buffereImage
。你可以建立一个图像库并使用这些图像,因为它们被视为只对最后一个图像感兴趣(在
过程中
方法中),或者减少更新次数,但这只是一个概念证明。

如果我正确理解这个问题,本例采用
buffereImage
并用红色像素替换该图像中的所有像素

这个