Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ScrolledComposite parent with GridLayout

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);

}
like image 653
gombost Avatar asked Jul 05 '12 08:07

gombost


2 Answers

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);
}
like image 119
Steve K Avatar answered Oct 01 '22 05:10

Steve K


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.

like image 22
FableBlaze Avatar answered Oct 01 '22 04:10

FableBlaze