【发布时间】:2013-09-13 01:13:36
【问题描述】:
我编写了一个 Java7 应用程序,该应用程序创建一个 BufferedImage,每当用户更改对图像有影响的内容时,它就会被后台线程绘制。问题是在显示图像时,正确的图像只显示几秒钟,然后显示一个不稳定的图像(大小正确),其中包含来自系统的帧缓冲区的其余部分;见下图:
它应该是这样的:
绘制线程完成后,BufferedImage 将被绘制到 JPanel 组件上,并使用 AffineTransformation 进行转换以反映一定的缩放级别。
BufferedImage 的大小由一个不依赖于 MacBook 或JFrame 分辨率的固定数字决定(通常相当高,例如 4000x2000)。绘制BufferedImage 的面板位于ScrollPane 内,该面板可根据面板的大小进行调整。每次线程绘制新版本时,BufferedImage 是被覆盖还是创建新的都没有关系。
我已经在 windows 上测试了该工具,一台不带视网膜显示屏的 MacBook 和三台带视网膜显示屏的 MacBook,在所有没有视网膜显示屏的机器上,该工具都能完美运行。有什么想法吗?
编辑:程序是这样工作的:HexaVisExplorer 类是使用项目的 NetBeans 构建的 JFrame GUI。它保留了一个ScrollPane,和一个VisualizationPanel,它是ScrollPane 的内容,并且每当用户更改对结果图像有影响的属性时,组件的ActionListener 就会调用@ 中的一个方法987654338@。在那里,一个属性被设置,一个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,它使用VisualizationPanel 中的属性生成有问题的BufferedImage。当重新计算完成时,
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 based on that. When done, done()is called, which then sets the newBufferedImageto 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();
}
}
【问题讨论】:
-
显示一些代码,否则我们并没有真正需要帮助的信息
-
你在使用
AffineTransformOp吗? -
dataTransformation 是 java.awt.geom.AffineTransform,所以我没有使用 AffineTransformOp。我添加了一些代码,希望您现在可以更好地理解!
-
@jurib:使用
@来称呼cmets 中的人;我只是偶然看到你的更新。
标签: java swing osx-mountain-lion retina-display