tags:

views:

790

answers:

1

I'm using the most recent stable version of SWT.

I have a Shell containing a ToolBar, a ScrolledComposite, and a Canvas. The Canvas is set as the ScrolledComposite's content (e.g. scrolledComposite.setContent(canvas)). The Canvas is created with a specific size that never changes (say, 400 x 400). Whereas the ScrolledComposite is constantly growing or shrinking to fill the available parent shell's client area.

I have a resize listener attached to the parent Shell that attempts to do the following: a) grow the ScrolledComposite as described above and b) center the Canvas both horizontally and vertically within the ScrolledComposite (see below for example code).

This works exactly as it should on Mac OS X, however on Windows the resize event is fired and the new locations are properly calculated but ultimately the Canvas snaps back to 0,0. One other small piece of information is that if you continuously resize the window, you can see the canvas flickering and it looks as if it's being briefly drawn at the correct location.

_shell.addListener (SWT.Resize, new Listener () {
    public void handleEvent (Event e)
    {
        int toolBarOffset = _toolBar.getSize().y;

        Rectangle clientArea = _shell.getClientArea();

        _scrollComposite.setBounds(0, toolBarOffset, clientArea.width, clientArea.height - toolBarOffset);

        Point canvasSize = _canvas.getSize();

        int canvasX = Math.max(0, (clientArea.width / 2) - (canvasSize.x / 2));
        int canvasY = Math.max(0, ((clientArea.height - toolBarOffset) / 2) - (canvasSize.y / 2));

        _canvas.setLocation(canvasX, canvasY);
    }
});
+1  A: 

Hi dromo,

Not sure if you've already figured it out, but the problem is that the ScrolledComposite always sets the content to 0/0 when it is resized. I'm not sure why your approach works on OS X, and I've not tested my example as I don't have a Mac here.

The solution is to use a filler composite that is always at least as big as the client area from the ScrolledComposite. In that filler, you can then center the Canvas correctly.

I've made a small example, as an added bonus it also centers the canvas if the client area of the SC is smaller than the canvas ( because I've first thought that was your question :) )

You may have to make some minor adjustments, I guess there are some glitches on OS X with that code...

package test;

import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.events.ControlAdapter;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.FillLayout;
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 Test {

    public static void main(final String[] args) {
        final Display display = new Display();
        final Shell shell = new Shell(display);

        shell.setLayout( new FillLayout() );

        final ScrolledComposite sComp = new ScrolledComposite( shell, SWT.H_SCROLL | SWT.V_SCROLL );
        final Composite fillComp = new Composite( sComp, SWT.NONE );

        sComp.setLayout( new FillLayout() );

        final Canvas c = new Canvas( fillComp, SWT.DOUBLE_BUFFERED );
        c.addPaintListener( new PaintListener() {
            public void paintControl(PaintEvent e) {
                Point p = c.getSize();
                e.gc.setBackground( display.getSystemColor( SWT.COLOR_RED ));
                e.gc.fillRectangle( 0, 0, p.x, p.y );

                e.gc.setBackground( display.getSystemColor( SWT.COLOR_BLUE ));
                e.gc.fillRectangle( p.x / 2 - 10, p.y / 2 - 10, 20, 20 );
            }
        });

        c.setSize( 400, 400 );
        sComp.setContent( fillComp );

        sComp.addControlListener( new ControlAdapter() {
            @Override
            public void controlResized(ControlEvent e) {
                Rectangle clientArea = sComp.getClientArea();

                Point cSize = c.getSize();
                int fillX = Math.max( clientArea.width, cSize.x );
                int fillY = Math.max( clientArea.height, cSize.y );
                fillComp.setSize( fillX, fillY );

                int cX = ( clientArea.width - cSize.x ) / 2;
                int cY = ( clientArea.height - cSize.y ) / 2;

                sComp.setOrigin( -cX, -cY );

                int locX = Math.max( cX, 0 );
                int locY = Math.max( cY, 0 );
                c.setLocation( locX, locY );
            }
        });

        shell.open();
        shell.pack();
        while (!shell.isDisposed()) {
            if (!display.readAndDispatch()) {
                display.sleep();
            }
        }   
    }
}
derBiggi