I have written a Java7-Application that creates a BufferedImage that gets drawn on by a background thread whenever the user changes something that has influence on the image. The problem is that when displaying the image, the correct image gets shown only for a few seconds, then an erratic imgage (in the right size) with rests of the frame buffer from the system is shown; see image below:

Here is what it should look like:

As soon as the drawing thread has finished, the BufferedImage will be drawn onto a JPanel component after being transformed with an AffineTransformation to reflect a certain zoom level.
The size of the BufferedImage is determined by a fixed number that is not dependent on the resolution of the MacBook or the JFrame (usually quite high, something like 4000x2000). The panel in which the BufferedImage gets drawn is inside a ScrollPane that adjusts to the size of the panel. It does not matter whether the BufferedImage is written over or created new each time a new version is drawn by the thread.
I have tested the tool on windows, a MacBook without retina display and three MacBooks with retina display, on all machines without retina display, the tool works perfectly. Any ideas?
Edit: This is how the program works: The class HexaVisExplorer is the JFrame GUI built with NetBeans of the project. It keeps a ScrollPane, and a VisualizationPanel that is the content of the ScrollPane, and whenever the user changes a property that has influence on the resulting image, the ActionListener for the component calls a method in the VisualizationPanel. There, a property is set and a Thread gets initialized and started that, based on the properties set in VisualizationPanel, will draw a new BufferedImage. When this is done, the new BufferedImage will be saved to the VisualizationPanel, which then will be repainted with an overridden paintComponent(), where the image will be transformed using a java.awt.geom.AffineTransform for efficient zooming. Finally, the viewport of the scroll pane gets modified to reflect the new image size. Here is the code:
Class 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());
}
});
//...
}
}
Class VisualizationPanel, method recalculate() creates a new VisualizationThread that generates the BufferedImage in question using the properties in VisualizationPanel. When recalculate is finisehd,
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 takes a VisualizationPanel, reads its properties and calculates a new BufferedImage based on that. When done, done()is called, which then sets the newBufferedImageto draw to theVisualizationPanel` and repaints it.
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();
}
}