我编写了一个 Java7 应用程序,BufferedImage
每当用户更改对图像有影响的内容时,它都会创建一个由后台线程绘制的应用程序。问题是在显示图像时,正确的图像只显示几秒钟,然后显示一个不稳定的图像(大小正确),其中包含来自系统的帧缓冲区的其余部分;见下图:
这是它的样子:
绘制线程完成后,将在使用 转换以反映某个缩放级别BufferedImage
后将其绘制到JPanel
组件上。AffineTransformation
的大小BufferedImage
由一个固定的数字决定,该数字不依赖于 MacBook 的分辨率或JFrame
(通常相当高,例如 4000x2000)。BufferedImage
绘制的面板位于ScrollPane
可调整面板大小的 a 内。BufferedImage
每次线程绘制新版本时,是否重写或创建新版本都没有关系。
我已经在 windows 上测试了该工具,一台不带视网膜显示屏的 MacBook 和三台带视网膜显示屏的 MacBook,在所有没有视网膜显示屏的机器上,该工具都能完美运行。有任何想法吗?
编辑:这是程序的工作方式:该类HexaVisExplorer
是JFrame
使用项目的 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
生成有问题的。当重新计算完成时,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
获取 a VisualizationPanel
,读取其属性并计算一个新的BufferedImage based on that. When done,
done() is called, which then sets the new
BufferedImage to draw to the
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();
}
}