0

我编写了一个 Java7 应用程序,BufferedImage每当用户更改对图像有影响的内容时,它都会创建一个由后台线程绘制的应用程序。问题是在显示图像时,正确的图像只显示几秒钟,然后显示一个不稳定的图像(大小正确),其中包含来自系统的帧缓冲区的其余部分;见下图:

图片

这是它的样子:

正确的图像

绘制线程完成后,将在使用 转换以反映某个缩放级别BufferedImage后将其绘制到JPanel组件上。AffineTransformation

的大小BufferedImage由一个固定的数字决定,该数字不依赖于 MacBook 的分辨率或JFrame(通常相当高,例如 4000x2000)。BufferedImage绘制的面板位于ScrollPane可调整面板大小的 a 内。BufferedImage每次线程绘制新版本时,是否重写或创建新版本都没有关系。

我已经在 windows 上测试了该工具,一台不带视网膜显示屏的 MacBook 和三台带视网膜显示屏的 MacBook,在所有没有视网膜显示屏的机器上,该工具都能完美运行。有任何想法吗?

编辑:这是程序的工作方式:该类HexaVisExplorerJFrame使用项目的 NetBeans 构建的 GUI。它保留 aScrollPane和 aVisualizationPanel的内容ScrollPane,并且每当用户更改对结果图像有影响的属性时,ActionListener组件都会调用VisualizationPanel. 在那里,一个属性被设置,一个Thread被初始化并开始,基于在 中设置的属性VisualizationPanel,将绘制一个新的BufferedImage. 完成后,新的BufferedImage将被保存到VisualizationPanel,然后将使用覆盖的 重新绘制paintComponent(),其中图像将使用java.awt.geom.AffineTransform用于高效缩放。最后,滚动窗格的视口被修改以反映新的图像大小。这是代码:

类 HexavisExplorer.java

public class HexaVisExplorer extends javax.swing.JFrame {

    private VisualizationPanel visualizationPanel;
    private javax.swing.JScrollPane jScrollPane1;

    public HexaVisExplorer() {
        //...Example where a component listener calls a method in VisualizationPanel.java to set a property
        polygonBorderCheckbox.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                visualizationPanel.setPolygonBorders(polygonBorderCheckbox.isSelected());
            }
        });
        //...
    } 
}  

VisualizationPanel,方法recalculate()创建一个新的,使用 中的属性VisualizationThread生成有问题的。当重新计算完成时,BufferedImageVisualizationPanel

public class VisualizationPanel extends JPanel {

   private boolean polygonBorders;
   //here be more property class variables and getter/setter for them

    public void setPolygonBorders(boolean polygonBorders) {
        this.polygonBorders = polygonBorders;
        recalculate();
        this.revalidate();
        this.repaint();
    }

    public void recalculate(){
        vt = new VisualizationThread(this);
        vt.execute();
    }

    @Override
    protected void paintComponent(Graphics g) {


        Graphics2D g2d = (Graphics2D) g;
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
        dataTransformation.setToScale(transform_factor, transform_factor);
        g2d.transform(dataTransformation);
        g2d.drawImage(toDraw, 0, 0, null);
        this.setSize((int) Math.ceil(transform_factor * maxwidth), (int) Math.ceil(transform_factor * maxheight));
        this.setPreferredSize(new Dimension((int) Math.ceil(transform_factor * maxwidth), (int) Math.ceil(transform_factor * maxheight)));
        this.revalidate();
        hx.modifyVisPanelViewport(this);
    }
}

VisualizationThread获取 a VisualizationPanel,读取其属性并计算一个新的BufferedImage based on that. When done, done() is called, which then sets the newBufferedImage to draw to theVisualizationPanel` 并重新绘制它。

public class VisualizationThread extends SwingWorker<Object, Object> {
    private VisualizationPanel vp;
    private BufferedImage toDraw;
    
    @Override
    protected Object doInBackground() throws Exception {
    // The bufferedImage  gets drawn on here.
    }

    @Override
    protected void done() {
        vp.setToDraw(toDraw);
        vp.setPreferredSize(new Dimension(toDraw.getWidth(), toDraw.getHeight()));
        vp.repaint();
        vp.revalidate();
    }
}
4

1 回答 1

2

看起来主机对等组件期望使用一种颜色模型渲染图像但遇到另一种颜色模型。对于一个明确的答案,有太多的方法会出错,但有几件事需要仔细审查:

  • 验证您BufferedImage的颜色模型和空间是否兼容,例如.

  • 考虑使用此处AffineTransformOp概述的 缩放,因为它可以创建“具有正确大小和带数的目标图像”。

  • 事件调度线程done()上执行时,验证程序的其余部分是否正确同步,例如.

于 2013-09-10T11:39:55.607 回答