ScrolledComposite parent with GridLayout
Asked Answered
T

3

8

I'd like to have a ScrolledComposite which has a parent with GridLayout but the scrollbar doesn't show up, unless I use FillLayout. My problem with FillLayout is that its children takes equal parts of the available space.

In my case there are two widgets, the one on top should take not more than 1/4 of the window and the ScrolledComposite should take the remainder space. However, both of them take half of it.

Is there a way to use a GridLayout with ScrolledComposite or is it possible to modify the behaviour of FillLayout?

Here's my code:

private void initContent() {

    //GridLayout shellLayout = new GridLayout();
    //shellLayout.numColumns = 1;
    //shellLayout.verticalSpacing = 10;
    //shell.setLayout(shellLayout);
    shell.setLayout(new FillLayout(SWT.VERTICAL));

    searchComposite = new SearchComposite(shell, SWT.NONE);
    searchComposite.getSearchButton().addListener(SWT.Selection, this);

    ScrolledComposite scroll = new ScrolledComposite(shell, SWT.V_SCROLL | SWT.H_SCROLL | SWT.BORDER);
    scroll.setLayout(new GridLayout(1, true));

    Composite scrollContent = new Composite(scroll, SWT.NONE);
    scrollContent.setLayout(new GridLayout(1, true));

    for (ChangeDescription description : getChanges(false)) {
        ChangesComposite cc = new ChangesComposite(scrollContent, description);
    }

    scroll.setMinSize(scrollContent.computeSize(SWT.DEFAULT, SWT.DEFAULT));
    scroll.setContent(scrollContent);
    scroll.setExpandVertical(true);
    scroll.setExpandHorizontal(true);
    scroll.setAlwaysShowScrollBars(true);

}
Torrez answered 5/7, 2012 at 8:23 Comment(1)
Steve K answer should be accepted: it works fine.Nonrecognition
K
4

In addition to setLayout(), it is necessary to call setLayoutData(). In the following code example, take a look at how the GridData objects are constructed and passed to each of the two setLayoutData() calls.

private void initContent(Shell shell)
{
    // Configure shell
    shell.setLayout(new GridLayout());

    // Configure standard composite
    Composite standardComposite = new Composite(shell, SWT.NONE);
    standardComposite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));

    // Configure scrolled composite
    ScrolledComposite scrolledComposite = new ScrolledComposite(shell, SWT.V_SCROLL | SWT.H_SCROLL | SWT.BORDER);
    scrolledComposite.setLayout(new GridLayout());
    scrolledComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
    scrolledComposite.setExpandVertical(true);
    scrolledComposite.setExpandHorizontal(true);
    scrolledComposite.setAlwaysShowScrollBars(true);

    // Add content to scrolled composite
    Composite scrolledContent = new Composite(scrolledComposite, SWT.NONE);
    scrolledContent.setLayout(new GridLayout());
    scrolledComposite.setContent(scrolledContent);
}
Kirimia answered 22/2, 2014 at 7:41 Comment(1)
Calling scrolledComposite.setLayout(...) does nothing. ScrolledComposite overrides the method and does not set a layout, as it already has a ScrolledCompositeLayout by default. So don't know what happens on .setLayoutData calls on its children.Hie
R
2

NB! This answer is based on Eclipse RAP which might behave differently then regular SWT.

I was struggling with the exact same issue a couple of days ago. I had two ScrolledComposites on the same page and i needed that the left one would not take more space then needed (even if the space would be available).

While trying out different solutions i noticed that the behavior of a ScrolledComposite depends on its LayoutData as follows:

  • If the layoutData is set to new GridData(SWT.LEFT, SWT.TOP, false, true), then the ScrolledComposite will keep it's intended size regardless of parent Composite size changes.
  • If the layoutData is set to new GridData(SWT.LEFT, SWT.TOP, true, true), then the ScrolledComposite will shrink/expand according to the size changes of the parent Composite. This also includes expanding to greater width that was desired (meaning that the columns are kept equal).

Based on this behavior i was able to solve the problem by adding a resize listener to the parent Composite that changes the layoutData of the left ScrolledComposite based on the parent Composite size.

This approach is illustrated the following example:

public class LayoutingScrolledComposites extends AbstractEntryPoint {
    public void createContents( Composite parent ) {    
        parent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
        parent.setLayout(new GridLayout(2, false));

        ScrolledComposite sc1 = new ScrolledComposite(parent, SWT.H_SCROLL | SWT.V_SCROLL);
        Composite c1 = new Composite(sc1, SWT.BORDER);
        sc1.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, true, true));
        c1.setLayout(new GridLayout(3, false));
        sc1.setContent(c1);
        Label l1 = new Label (c1, SWT.BORDER);
        l1.setText("Some text");
        l1 = new Label (c1, SWT.BORDER);
        l1.setText("Some text");
        l1 = new Label (c1, SWT.BORDER);
        l1.setText("Some text");
        c1.setSize(c1.computeSize(SWT.DEFAULT, SWT.DEFAULT));

        ScrolledComposite sc2 = new ScrolledComposite(parent, SWT.H_SCROLL | SWT.V_SCROLL);
        sc2.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, true, true));
        Composite c2 = new Composite(sc1, SWT.BORDER);
        c2.setLayout(new GridLayout(3, false));
        sc2.setContent(c2);
        Label l2 = new Label (c2, SWT.BORDER);
        l2.setText("Some text");
        l2 = new Label (c2, SWT.BORDER);
        l2.setText("Some text");
        l2 = new Label (c2, SWT.BORDER);
        l2.setText("Some text");
        c2.setSize(c2.computeSize(SWT.DEFAULT, SWT.DEFAULT));

        parent.addListener(SWT.Resize, new Listener() {
            public void handleEvent(Event e) {
                int sc1_x = sc1.getContent().getSize().x;
                int sc2_x = sc2.getContent().getSize().x;

                //Enable/Disable grabExcessHorizontalSpace based on whether both sc's would fit in the shell
                if (LayoutingScrolledComposites.this.getShell().getSize().x > sc1_x+sc2_x) {
                    if (((GridData)sc1.getLayoutData()).grabExcessHorizontalSpace) {
                        //sc1 does not change width in this mode
                        ((GridData)sc1.getLayoutData()).grabExcessHorizontalSpace=false;                        
                    }
                } else {
                    if (!((GridData)sc1.getLayoutData()).grabExcessHorizontalSpace) {
                        //sc1 changes width in this mode
                        ((GridData)sc1.getLayoutData()).grabExcessHorizontalSpace=true;                     
                    }
                }
                parent.layout(); //Needed so that the layout change would take effect during the same event
            }
        });
    }
}

However this approach does seem to me a bit too "hackish" solution. Therefore i would love to see a better approach.

Regulation answered 6/4, 2016 at 16:7 Comment(0)
K
1

I think what you're missing here is to define the GridData for the children.

A layout controls the position and size of children. And every layout class has a corresponding layout data class which allows to configure each specific children within the layout, if they fill up the whole space, how many cells they take, etc.

I guess your grid layout could have 4 rows, with the widget on top taking just one cell and the other child taking the rest (3). This is achieved through the GridData.verticalSpan property.

Take a look at Understanding Layouts in SWT and try the different layout data properties to see what they do.

Kodok answered 5/7, 2012 at 10:32 Comment(2)
Sorry, I think I wasn't clear enough. The main problem is that the ScrolledComposite doesn't show its scrollbar if I put it in a GridLayout, it works only with a FillLayout - but it doesn't fit my needs. I'll edit the original post to make this clear.Torrez
FillLayout forces controls to be the same size. Initially, the controls will be as tall as the tallest control and as wide as the widest. It seems that this layout causes your controls to be large enough for the ScrolledComposite to show the scroll bars. But when you've got a GridLayout you must specify the way controls lay out in each cell through GridData objects. This determines their sizes. If you don't do it maybe the content is not large enough. Just guessing O:)Dillion

© 2022 - 2024 — McMap. All rights reserved.