I am implementing a Gantt component for SWT and this takes a bit to repaint (like, 200 ms for the whole visible part of the diagram).
Now, when I scroll, I only repaint what is needed regarding the clipping rectangle. This makes the application look very bad when I scroll fast, because then the still visible part after scrolling seems to be moved by the OS first, and when I finished painting the remaining part (the part which has become visible during scrolling), immediatly a new scrolling step begins, moving half of my diagram to the right and lets me repaint the other half. This effectively looks like my diagram flickers in the middle during scrolling.
This doesn't look really nice. Is there a way to get around this? Is this question understandable?
EDIT: Here is a "small" test program that shows exactly the behaviour described. You only need SWT in the classpath to run it.
package de.ikoffice.gui;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
public class SlowRepaintProblem {
public Color[] colors = new Color[501];
public SlowRepaintProblem() {
Display display = Display.getDefault();
for( int i=0; i<=500; i++ ) {
int r = ( i * 10 ) % 256;
int g = ( i * 20 ) % 256;
int b = ( i * 30 ) % 256;
colors[i] = new Color(display,r,g,b);
}
Shell shell = new Shell(display);
shell.setText("SlowRepaintTest");
ScrolledComposite comp = new ScrolledComposite(shell,
SWT.H_SCROLL | SWT.V_SCROLL | SWT.DOUBLE_BUFFERED | SWT.NO_BACKGROUND);
SlowRepaintingCanvas canvas = new SlowRepaintingCanvas(comp,SWT.NONE| SWT.NO_BACKGROUND);
comp.setContent(canvas);
canvas.setSize(5000,5000);
// Layouting
shell.setLayout(new GridLayout());
comp.setLayoutData(new GridData(GridData.FILL_BOTH));
shell.setBounds(50, 50, 800, 600);
// Showing the control
shell.open();
while (!shell.isDisposed()) {
try {
if (!shell.getDisplay().readAndDispatch()) {
shell.getDisplay().sleep();
}
} catch (Throwable e) {
String message = e.getMessage();
if( message == null || !e.getMessage().equals("Widget is diposed") ) {
e.printStackTrace();
}
break;
}
}
}
public static void main(String[] args) {
new SlowRepaintProblem(); // Evil constructor call to start main program flow.
}
class SlowRepaintingCanvas extends Canvas {
public SlowRepaintingCanvas(Composite parent, int style) {
super(parent, style);
addPaintListener(new PaintListener() {
@Override
public void paintControl(PaintEvent e) {
GC gc = e.gc;
Rectangle r = gc.getClipping();
gc.setAlpha(255);
// gc.setBackground(ColorUtils.WHITE);
// gc.fillRectangle(r);
int x = r.x - (r.x % 10);
int width = (r.width + r.x - x) - (r.width + r.x - x) % 10 + 10;
int y = r.y - (r.y % 10);
int height = (r.height + r.y - y) - (r.height + r.y - y) % 10 + 10;
gc.setAlpha(128);
for( int i = x; i < x+width; i+= 10 ) {
gc.setBackground(colors[i/10]);
gc.fillRectangle(i, r.y, 10, r.height);
}
for( int j = y; j < y+height; j+= 10 ) {
gc.setBackground(colors[j/10]);
gc.fillRectangle(r.x, j, r.width, 10);
}
}
});
}
}
}