5

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.

Community
  • 1
  • 1
Georgian
  • 8,795
  • 8
  • 46
  • 87

3 Answers3

14

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.

iberbeu
  • 15,295
  • 5
  • 27
  • 48
greg-449
  • 109,219
  • 232
  • 102
  • 145
  • Your solution seems to work for a more complex example. I wonder if the `shell.setSize(Point)` is mandatory in my case (it's basically `pack(true)`). I will get back to you guys after I'm done implementing the whole thing. – Georgian Nov 26 '13 at 13:46
  • `pack(true)` does the same thing as my last two lines. The code I extracted this from also checks for a minimum size which can't be done with `pack`. – greg-449 Nov 26 '13 at 14:01
  • @greg-449 is the same true for a JFace combobox. I have asked a question [here](http://stackoverflow.com/questions/32561924/how-to-truncate-a-long-name-in-a-jface-combobox). – Saras Arya Sep 14 '15 at 11:41
  • @SarasArya This is only for a Shell. How individual controls are sized depends on the Layout you are using. – greg-449 Sep 14 '15 at 12:18
  • shell.pack(true) solved my problem on changing dialog size automatically when I add/remove the children. Thx – WineYe Sep 14 '15 at 23:07
  • pack(true) allowed my dialog to get larger than the display, so I used @greg-449's code and checked the newSize against shell.getDisplay().getPrimaryMonitor().getClientArea().width and height. – Danny Jul 11 '19 at 09:11
3

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.

Baz
  • 36,440
  • 11
  • 68
  • 94
WillBD
  • 1,919
  • 1
  • 18
  • 26
  • In another case, I've tried calling `layout` on the `Shell`. Didn't seem to work at the time. Does this apply for `Dialog`s and `Wizard`s as well? How *high* up do you have to go to call the API? – Georgian Nov 25 '13 at 23:01
  • I have a copy of some code I wrote a little while ago doing this exact same thing, when I get home from work I'll break it open and see what the differences are. I do remember there being a few subtlety's that I had to toy with until it worked. One of which was indeed calling `layout(true)` every time I made a new composite, but I'll be in touch in a few hours! unless I have inspiration and memory, then it'll be sooner. – WillBD Nov 25 '13 at 23:03
  • Ok, so after re-reading both your question, and the one you mentioned at the bottom, I may have confused myself here. Is the main issue that you aren't able to see the new dynamic buttons at all? or that the whole shell won't resize after you make too many of them? – WillBD Nov 25 '13 at 23:12
  • Main issue is that the container lays out fine, but the shell doesn't. Doesn't matter what new children I am adding, in my case I wrote composites with labels to prove a point. I just want the shell/wizard/dialog to be packed so that I can see all components nicely. – Georgian Nov 25 '13 at 23:43
  • ahh... That is a bit different than what I've done previously. and re-calling `shell.pack(true)` hasn't worked for re-sizing everything nicely? – WillBD Nov 25 '13 at 23:45
  • Ok, I'm starting to follow. What about the case where I have other composites in the specified `Shell`? Meaning... the component container isn't the only thing on the shell. Would it still work? What if the composite hierarchy is very long? Could I still call `pack(true)` on some `Composite`s? – Georgian Nov 26 '13 at 06:51
  • The reason I'm asking these questions is because I want my component container (including the ADD button) to be a separate widget, which can be plugged in other places. And those places need to conform to this widget's size and needs. – Georgian Nov 26 '13 at 07:58
0

As you've said our both questions are similar, I'm posting the solution what I've achieved. Let me know if this helps you.

import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Combo;


public class DynamicDialog extends Dialog {
   private Composite composite_2;


    /**
     * Create the dialog.
     * @param parentShell
     */
    public DynamicDialog(Shell parentShell) {
        super(parentShell);
    }

    /**
     * Create contents of the dialog.
     * @param parent
     */
    @Override
    protected Control createDialogArea(Composite parent) {
        Composite container = (Composite) super.createDialogArea(parent);
        container.setLayout(new FillLayout(SWT.HORIZONTAL));

        ScrolledComposite scrolledComposite = new ScrolledComposite(container, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL);
        scrolledComposite.setExpandHorizontal(true);
        scrolledComposite.setExpandVertical(true);

        final Composite composite = new Composite(scrolledComposite, SWT.NONE);
        composite.setLayout(new GridLayout(1, false));
        scrolledComposite.setContent(composite);
        scrolledComposite.setSize(composite.computeSize(SWT.DEFAULT, SWT.DEFAULT));

        Composite composite_1 = new Composite(composite, SWT.NONE);
        composite_1.setLayout(new GridLayout(2, false));
        GridData gd_composite_1 = new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1);
        gd_composite_1.heightHint = 49;
        gd_composite_1.widthHint = 427;
        composite_1.setLayoutData(gd_composite_1);

        Label lblDefault = new Label(composite_1, SWT.NONE);
        lblDefault.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
        lblDefault.setText("Default:");

        Combo combo = new Combo(composite_1, SWT.NONE);
        combo.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1));

        composite_2 = new Composite(composite, SWT.NONE);
        composite_2.setLayout(new GridLayout(4, false));
        GridData gd_composite_2 = new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1);
        /*gd_composite_2.heightHint = 32;
        gd_composite_2.widthHint = 426;*/
        composite_2.setLayoutData(gd_composite_2);

        Composite composite_3 = new Composite(composite, SWT.NONE);
        composite_3.setLayout(new GridLayout(1, false));
        GridData gd_composite_3 = new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1);
        gd_composite_3.heightHint = 38;
        gd_composite_3.widthHint = 427;
        composite_3.setLayoutData(gd_composite_3);

        Button btnAdd = new Button(composite_3, SWT.NONE);
        btnAdd.setText("Add");
        btnAdd.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {


                Label label2 = new Label(composite_2, SWT.NONE);
                label2.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false,
                        false, 1, 1));
                label2.setText("1");

                Text text_12 = new Text(composite_2, SWT.BORDER);
                text_12.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true,
                        false, 1, 1));

                Text text13 = new Text(composite_2, SWT.BORDER);
                text13.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true,
                        false, 1, 1));

                Button btnDelete = new Button(composite_2, SWT.NONE);
                btnDelete.setText("delete");
                composite_2.layout(true);


                composite_2.layout();
                // Point p = composite.getSize();
                // composite.setSize(SWT.DEFAULT,SWT.DEFAULT);
                // composite.setSize(p);

                composite.layout();


            }
        });






        return container;
    }

    /**
     * Create contents of the button bar.
     * @param parent
     */
    @Override
    protected void createButtonsForButtonBar(Composite parent) {
        createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL,
                true);
        createButton(parent, IDialogConstants.CANCEL_ID,
                IDialogConstants.CANCEL_LABEL, false);
    }

    /**
     * Return the initial size of the dialog.
     */
    @Override
    protected Point getInitialSize() {
        return new Point(450, 300);
    }

public static void main(String[] args){

    Shell shell =  new Shell(new Display());
    //shell.setLayout(new FillLayout());
    DynamicDialog dd = new DynamicDialog(shell);
    dd.open();

}
}
Juseeth
  • 467
  • 1
  • 6
  • 18
  • Apparently this solved your issue, but not mine. See the thing is... when you add to many, they tend to go off-screen, and you can't resize the dialog manually to see them. The dialog should resize automatically -> see the other 2 answers. :-) – Georgian Nov 26 '13 at 17:29
  • @GGrec yes exactly, now this is my problem, whenever i create new widgets in the composite, when ever it comes to end of default size, it is going down in to the dialog and scroll bar doesn't appear. Do you know how to solve this, because i didn't quite understand the solutions above? , thanks – Juseeth Nov 26 '13 at 17:59