Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SWT Shell resize depending on children

I'm working on this Composite canvas on which other Composites may be added and removed.

My understanding of how the whole laying-out concept is still in the fog.

When children are added to the container, given the fact that the container has a GridData which fills in the parent, shouldn't the parent also know that the child resized? Children remain hidden after their container has been laid out, because of the shell (top parent).

If the question is too vague, do not hesitate to ask for more details. Also, try your best not pointing me to the Understanding layouts in SWT article.

/**
 * 
 * @author ggrec
 *
 */
public class SSCCE
{

    // ==================== 2. Instance Fields ============================

    private Composite componentContainer;

    private int componentCount = 0;

    // ==================== 3. Static Methods =============================

    public static void main(final String[] args)
    {
        new SSCCE();
    }

    // ==================== 4. Constructors ===============================

    private SSCCE()
    {
        final Display display = new Display();
        final Shell shell = new Shell(display);
        shell.setLayout(new GridLayout(1, false));

        createContents(shell);

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

    // ==================== 5. Creators ===================================

    private void createContents(final Composite parent)
    {
        parent.setLayout(new GridLayout());
        parent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));

        final Button button = new Button(parent, SWT.PUSH);
        button.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
        button.setText("Add New Component");

        button.addSelectionListener(new SelectionAdapter()
        {
            @Override public void widgetSelected(final SelectionEvent e)
            {
                addNewComponent();

                componentContainer.layout();
            }
        });

        componentContainer = new Composite(parent, SWT.BORDER);
        componentContainer.setLayout(new GridLayout());
        componentContainer.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
    }

    // ==================== 6. Action Methods =============================

    private void addNewComponent()
    {
        final Composite component = new Composite(componentContainer, SWT.BORDER);
        component.setLayout(new FillLayout());
        component.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));

        final Label label = new Label(component, SWT.NONE);
        label.setText( String.valueOf(componentCount++) );
    }
}

Fun fact: This question is veeeery related to this other one, that was posted 9 minutes ago. Someone is either psychic or stalking me.

like image 652
Georgian Avatar asked Nov 25 '13 22:11

Georgian


2 Answers

To get the Shell to resize you need to layout everything and recalculate its size:

shell.layout(true, true);

final Point newSize = shell.computeSize(SWT.DEFAULT, SWT.DEFAULT, true);  

shell.setSize(newSize);

You may be able to get away with calling layout() on a child Composite of the shell depending on what has changed.

like image 101
greg-449 Avatar answered Nov 06 '22 17:11

greg-449


The secret here to probably solve your problem is TELLING the parent that the children have been resized. So, no, they do not automatically know it has happened.

the way to fix this, is to call the:

Parent.layout(true)

from the swt api:

public void layout(boolean changed)

If the receiver has a layout, asks the layout to lay out (that is, set the size and location of) the receiver's children. If the argument is true the layout must not rely on any information it has cached about the immediate children. If it is false the layout may (potentially) optimize the work it is doing by assuming that none of the receiver's children has changed state since the last layout. If the receiver does not have a layout, do nothing.

If a child is resized as a result of a call to layout, the resize event will invoke the layout of the child. The layout will cascade down through all child widgets in the receiver's widget tree until a child is encountered that does not resize. Note that a layout due to a resize will not flush any cached information (same as layout(false)).

Note: Layout is different from painting. If a child is moved or resized such that an area in the parent is exposed, then the parent will paint. If no child is affected, the parent will not paint.

Parameters:
    changed - true if the layout must flush its caches, and false otherwise
Throws:
    SWTException -
    ERROR_WIDGET_DISPOSED - if the receiver has been disposed
    ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver

So in your case, calling the layout() function on the parent of your composites anytime they are added should help you out.

like image 30
WillBD Avatar answered Nov 06 '22 15:11

WillBD