我编写了一个Java7应用程序,它创建一个BufferedImage
,每当用户更改对图像有影响的内容时,后台线程就会使用它。问题是,当显示图像时,正确的图像仅显示几秒钟,然后显示不稳定的图像(大小正确)以及来自系统的帧缓冲区的其余部分;见下图:
它应该是这样的:
一旦绘制线程完成,BufferedImage
将在使用 AffineTransformation
进行转换后绘制到 JPanel
组件上以反射(reflect)一定的缩放级别。
BufferedImage 的大小由固定数字决定,该数字不依赖于 MacBook 或 JFrame 的分辨率(通常相当高,例如 4000x2000) 。绘制 BufferedImage 的面板位于可根据面板大小进行调整的 ScrollPane 内。每次线程绘制新版本时,BufferedImage
是否被重写或创建新的并不重要。
我已经在 Windows、一台不带视网膜显示屏的 MacBook 和三台带视网膜显示屏的 MacBook 上测试了该工具,在所有不带视网膜显示屏的机器上,该工具都能完美运行。有什么想法吗?
编辑:程序是这样工作的:HexaVisExplorer
类是使用项目的 NetBeans 构建的 JFrame
GUI。它保留一个 ScrollPane
和一个作为 ScrollPane
内容的 VisualizationPanel
,并且每当用户更改影响结果的属性时,图像,组件的 ActionListener
调用 VisualizationPanel
中的方法。在那里,设置了一个属性,并初始化并启动了一个 Thread
,该线程将根据 VisualizationPanel
中设置的属性绘制一个新的 BufferedImage
。完成此操作后,新的 BufferedImage 将被保存到 VisualizationPanel,然后将使用重写的 PaintComponent() 重新绘制,其中图像将使用 java.awt.geom.AffineTransform
进行转换,以实现高效缩放。最后,滚动 Pane 的视口(viewport)被修改以反射(reflect)新的图像大小。这是代码:
类 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
,它使用以下方法生成有问题的BufferedImage
VisualizationPanel 中的属性。当重新计算完成后,
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
采用一个 VisualizationPanel
,读取其属性并基于该属性计算一个新的 BufferedImage。完成后,调用
done(),然后将新的
BufferedImage 设置为绘制到
VisualizationPanel` 并重新绘制它。
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();
}
}
最佳答案
它看起来就像主机对等组件期望使用一种颜色模型渲染图像,但遇到另一种颜色模型。有太多的方法会导致这个问题无法得到明确的答案,但有几件事需要仔细审查:
验证您的
BufferedImage
是否具有兼容的颜色模型和空间,例如 example .考虑使用
AffineTransformOp
进行缩放,概述 here ,因为它可以创建“具有正确大小和波段数的目标图像。”当
done()
在 event dispatch thread 上执行时,验证程序的其余部分是否正确同步,对于 example .
关于java - 在配备 Retina 显示屏的 MacBook 上显示 Java BufferedImage 不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18700080/