Search code examples
swt

Java, SWT how to make RowLayout working within a ScrolledCompositite?


I had a long fight getting into the guts of SWT, and I'm, not really half done with it (angry face here).

I have Group with RowLayout, that wraps. The group is within other Composites, and might get too large for the display, so I wrapped it by a ScrolledComposite.

This is where the trouble starts.

Whatever is within a ScrolledComposite gets its way in way of width and height, whatever the dimensions might be. It has some logic, as the SrolledComposite can take care of that with ScrollBars.

The thing is (or at least looks to me like), that if a RowLayout can have its way with width, it will never, ever, wrap, and this is not what it should do inside a parent that is itself restricted.

What is the intended solution to this problem?


Solution

  • The layout of the control that is set as the content of the scrolled composite (i.e. the argument of sc.setContent) doesn't matter. A layout affects only the immediate children of the control that was set to.

    Most likely, your group widget doesn't adapt to the size of the containing scrolled composite. Note: it often helps to color relevant widgets differently (with setBackground) to see which space they actually take.

    The following snippet creates a ScrolledComposite that scrolls vertically, if the content control is larger than the client area of the scrolled composite.

    public static void main(String[] args) {
        Display display = new Display();
        Shell shell = new Shell(display);
        shell.setText("ScrolledComposite in 'browser' mode");
        shell.setLayout(new FillLayout());
        ScrolledComposite scrolledComposite = new ScrolledComposite(shell, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL);
        Composite content = new Composite(scrolledComposite, SWT.NONE);
        content.setLayout(new RowLayout(SWT.HORIZONTAL));
        for (int i = 0; i < 300; i++) {
            Label label = new Label(content, SWT.NONE);
            label.setText("label " + i);
        }
        scrolledComposite.setContent(content);
        scrolledComposite.addListener(SWT.Resize, event -> {
            int width = scrolledComposite.getClientArea().width;
            scrolledComposite.setMinSize(content.computeSize(width, SWT.DEFAULT));
        });
        scrolledComposite.setExpandHorizontal(true);
        scrolledComposite.setExpandVertical(true);
        shell.setSize(600, 300);
        shell.open();
        while (!shell.isDisposed()) {
            if (!display.readAndDispatch())
                display.sleep();
        }
        display.dispose();
    }
    
    

    The code uses the 'browser mode' as described in the JavaDoc

    Set the minimum size of the control and the ScrolledComposite will show scroll bars if the visible area is less than the minimum size of the control and it will expand the size of the control if the visible area is greater than the minimum size. This requires invoking both setMinWidth(), setMinHeight() and setExpandHorizontal(), setExpandVertical().

    Setting the minSize in a resize-listener ensures that the minimum size adapts to the size of the scrolled composite.