MIM
MIM

Reputation: 519

SWT - How to change the size of Text box dynamically

I am trying to create a Simple UI which contains a combo, a text box and a browse button. The combo will be containing two values: Execution Times and Execute with File. When the Execution Times option is selected, the combo box followed by a text box should be displayed. enter image description here

enter image description here

when the Execute with File option is selected, the combo box, a text box, and a browse button should be displayed.

enter image description here

When I am switching between these options, the widgets are not getting aligned properly. Refer to the below image. The text box size is not getting expanded to the available space. Image 4

public class TestUI {

    public static void main(String[] args)
    {
        Display display = new Display();
        final Shell shell = new Shell(display);
        shell.setText("StackOverflow");
        shell.setLayout(new GridLayout(1, true));

        Composite composite = new Composite(shell, SWT.NONE);
        composite.setLayout(new GridLayout(3, false));
        composite.setLayoutData(new GridData(GridData.FILL_BOTH));

        Combo combo = new Combo(composite, SWT.READ_ONLY);
        String[] input = { "Execution Times", "Execute with File" };
        combo.setItems(input);

        Text loopText = new Text(composite, SWT.SINGLE | SWT.BORDER);
        GridData gridData = new GridData(SWT.BEGINNING | GridData.FILL_HORIZONTAL);
        gridData.horizontalSpan = 2;
        loopText.setLayoutData(gridData);
        loopText.setEnabled(false);

        Button browseButton = new Button(composite, SWT.PUSH);
        browseButton.setText("Browse...");
        browseButton.setVisible(false);

        combo.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                String text2 = combo.getText();
                System.out.println(text2);

                if (text2.equals("Execution Times")) {
                    loopText.setEnabled(true);
                    loopText.setText("1");//$NON-NLS-1$
                    GridData gridData1 = new GridData(SWT.BEGINNING, SWT.TOP, false, false);
                    gridData1.grabExcessHorizontalSpace = true;
                    gridData1.horizontalSpan = 2;
                    loopText.setLayoutData(gridData1);
                    browseButton.setVisible(false);
                    loopText.getParent().layout();
                }
                if (text2.equals("Execute with File")) {
                    GridData gridData1 = new GridData(SWT.BEGINNING, SWT.TOP, false, false);
                    gridData1.grabExcessHorizontalSpace = true;
                    loopText.setLayoutData(gridData1);
                    gridData.exclude= false;
                    browseButton.setVisible(true);
                    browseButton.setFocus();
                    loopText.setText("");
                    loopText.setEnabled(false);
                    loopText.getParent().layout();
                }
            }

        });

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

Can any one help me on this?

Upvotes: 0

Views: 1795

Answers (2)

Rüdiger Herrmann
Rüdiger Herrmann

Reputation: 21025

From what I understand, depending on the combo selection, the text field and text field plus button serve different purposes:

  • when Execution Times is selected, the number of times is to be entered
  • otherwise Execute with File requires a file name to be entered or browsed for

Therefore, I would use a Composite next to the combo widget to hold either a text field to enter a number (or even a Spinner) or a text field and button to enter/select a file name.

Composite composite = new Composite( parent, SWT.NONE );
Text executionTimesText = new Text( composite, SWT.BORDER );
composite.setLayout( new StackLayout() );
Composite executionFileComposite = new Composite( composite, SWT.NONE );
// use a GridLayout to position the file name text field and button within the executionFileComposite
combo.addListener( SWT.Selection, event -> {
  StackLayout layout = ( StackLayout )composite.getLayout();
  if( combo.getSelectionIndex() == 0 ) {
    layout.topControl = executionTimesText;
  } else if( combo.getSelectionIndex() == 1 ) {
    layout.topControl = executionFileComposite;
  }
  composite.layout();
}

The StackLayout allows you to stack the different input fields and switch betwen them as needed (i.e. according to the combo's selection).

Upvotes: 3

avojak
avojak

Reputation: 2360

For starters, you don't need to recreate the GridData for the Text widget every time. Instead, just modify the original via gridData.horizontalSpan, or if in practice you don't have access to the GridData instance, you can get at it via ((GridData) gridData.getLayoutData()).horizontalSpan, etc.

The reason you're seeing the blank space at the bottom of the Shell is because you've created a layout with 3 columns, and then added the following:

  1. The Combo
  2. The Text (with horizontalSpan set to 2, so this uses 2 columns)
  3. The Button

The Combo and the Text take up all 3 columns, so a new row is added for the Button. Then you call pack(), and the preferred size is calculated, which will be for 2 rows, and the first row only sized for 2 widgets.

Instead of calling pack() and shrinking the size of the Shell down to the preferred size, we can just set a size on the Shell via Shell.setSize(...). In general you don't want to mix setSize(...) and layouts, but you've tagged your post with "RCP", so your Shell will already have a size and you won't be manually calling pack() and open().

Full example:

public static void main(String[] args) {
    Display display = new Display();
    final Shell shell = new Shell(display);
    shell.setSize(300, 80);
    shell.setText("StackOverflow");
    shell.setLayout(new GridLayout(1, true));

    Composite composite = new Composite(shell, SWT.NONE);
    composite.setLayout(new GridLayout(3, false));
    composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));

    final Combo combo = new Combo(composite, SWT.READ_ONLY);
    String[] input = {"Execution Times", "Execute with File"};
    combo.setItems(input);

    final Text loopText = new Text(composite, SWT.SINGLE | SWT.BORDER);
    final GridData textGridData = new GridData(SWT.FILL, SWT.FILL, true, false);
    textGridData.horizontalSpan = 2;
    loopText.setLayoutData(textGridData);
    loopText.setEnabled(false);

    final Button browseButton = new Button(composite, SWT.PUSH);
    browseButton.setText("Browse...");
    browseButton.setVisible(false);

    combo.addSelectionListener(new SelectionAdapter() {

        @Override
        public void widgetSelected(SelectionEvent e) {
            String text2 = combo.getText();
            System.out.println(text2);

            if (text2.equals("Execution Times")) {
                loopText.setEnabled(true);
                loopText.setText("1");

                // Can also do ((GridData) textGridData.getLayoutData())...
                textGridData.grabExcessHorizontalSpace = true;
                textGridData.horizontalSpan = 2;

                browseButton.setVisible(false);
                loopText.getParent().layout();
            }
            if (text2.equals("Execute with File")) {
                loopText.setEnabled(false);
                loopText.setText("");

                textGridData.grabExcessHorizontalSpace = true;
                textGridData.horizontalSpan = 1;

                browseButton.setVisible(true);
                browseButton.setFocus();
                loopText.getParent().layout();
            }
        }

    });

    shell.open();

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

Alternatively, if you are actually creating and opening a new Shell, then call pack() (to get the preferred size) prior to making the Text widget take up two columns:

shell.pack();

// Move these two lines down to the end
textGridData.horizontalSpan = 2;
browseButton.setVisible(false);
shell.layout(true, true);

shell.open();

What we've done is add all 3 widgets without adjusting the horizontalSpan. Then, call pack() to set the size of the Shell assuming that all 3 widgets appear in a single row. After calling pack(), set the horizontalSpan to 2, and hide the Button. When the Shell is opened, you will see:

enter image description here

Upvotes: 0

Related Questions