Skip to content

Screen-tearing and other visual artifacts when scrolling the FigureCanvas #753

@ptziegler

Description

@ptziegler

Consider the following snippet:

import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;

import org.eclipse.draw2d.ColorConstants;
import org.eclipse.draw2d.Figure;
import org.eclipse.draw2d.FigureCanvas;
import org.eclipse.draw2d.FlowLayout;
import org.eclipse.draw2d.Graphics;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.geometry.Dimension;

public class ScrollingBug {
	public static void main(String[] args) {
		System.setProperty("swt.autoScale.updateOnRuntime", "true");
		Shell shell = new Shell();
		shell.setSize(400, 400);
		shell.setLayout(new FillLayout());

		FigureCanvas canvas = new FigureCanvas(shell, SWT.NONE);
		Figure root = new Figure();
		root.setLayoutManager(new ListLayout());
		root.add(createLabel(ColorConstants.red));
		root.add(createLabel(ColorConstants.green));
		root.add(createLabel(ColorConstants.blue));
		root.add(createLabel(ColorConstants.yellow));
		root.add(createLabel(ColorConstants.cyan));
		root.add(createLabel(ColorConstants.white));
		root.add(createLabel(ColorConstants.gray));
		root.add(createLabel(ColorConstants.orange));
		canvas.getViewport().setContentsTracksHeight(true);
		canvas.getViewport().setContentsTracksWidth(true);
		canvas.getViewport().setContents(root);

		shell.open();

		Display display = shell.getDisplay();
		while (!display.isDisposed()) {
			display.readAndDispatch();
		}
	}

	private static IFigure createLabel(Color bg) {
		return new Figure() {
			@Override
			protected void paintFigure(Graphics graphics) {
				super.paintFigure(graphics);
				graphics.setBackgroundColor(bg);
				graphics.fillRectangle(getClientArea());
			}

			@Override
			public Dimension getPreferredSize(int wHint, int hHint) {
				return new Dimension(wHint, 100);
			}
		};
	}

	private static class ListLayout extends FlowLayout {
		public ListLayout() {
			setMajorSpacing(0);
		}
	}
}

To reproduce:

  1. Launch the snippet on a system with > 100% zoom (in my case 150%)
  2. Scroll the shell down to the bottom
  3. Scroll the shell up to the top

What I expect:

The first line should be 150px tall.

What I get:

The first line is 154px tall.

The left shell is the original one with the 150px tall row, the right shell the one after scrolling with 154px.

Image

Workaround:

Clicking on the canvas corrects the sizes for all figures. For non-trivial figures, this causes glitches and other visual artifacts. As a more "permanent" solution, one can hook a PropertyChangeListener to the scrollbar of the Viewport, that requests a repaint of the root figure, whenever the value changes.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions