Michael
Michael

Reputation: 4341

SWT Resize Error

I've been using SWT and have found an issue.

When selecting and deselecting check boxes and maximizing the window it will cause the icon of the first button to be set even though it is null. Also the layout of the text on the buttons can end up incorrect.

To recreate the error:

  1. Select checkbox 1
  2. Deselect checkbox 1
  3. Select checkbox 3
  4. Maximize the window

The icon for checkbox 1 should be null (empty) but instead it has the cross icon.

  public static void main(String[] args) {
       final Display d = new Display();
       Shell s = new Shell(d);
       s.setLayout(new GridLayout(2, false));
       s.setSize(500, 500);

       new Label(s, SWT.NONE).setText("C");
       final Button c = new Button(s, SWT.CHECK);

       new Label(s, SWT.NONE).setText("L1");
       final Button b = new Button(s, SWT.PUSH | SWT.FLAT);
       b.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
       b.setText("Button 1");
       b.setEnabled(false);

       new Label(s, SWT.NONE).setText("C2");
       final Button c2 = new Button(s, SWT.CHECK);

       new Label(s, SWT.NONE).setText("L2");
       final Button b2 = new Button(s, SWT.PUSH | SWT.FLAT);
       b2.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
       b2.setImage(null);
       b2.setText("Button 2");
       b2.setEnabled(false);

       new Label(s, SWT.NONE).setText("C3");
       final Button c3 = new Button(s, SWT.CHECK);

       new Label(s, SWT.NONE).setText("L3");
       final Button b3 = new Button(s, SWT.PUSH | SWT.FLAT);
       b3.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
       b3.setText("Button 3");
       b3.setEnabled(false);

       c.addSelectionListener(new SelectionAdapter() {
           @Override
           public void widgetSelected(SelectionEvent e) {
               if (!b.isEnabled()) {
                   b.setImage(d.getSystemImage(SWT.ICON_ERROR));
                   b.setEnabled(true);
               } else {
                   b.setImage(null);
                   b.setEnabled(false);
               }
           }
       });

       c2.addSelectionListener(new SelectionAdapter() {
           @Override
           public void widgetSelected(SelectionEvent e) {
               if (!b2.isEnabled()) {
                   b2.setImage(d.getSystemImage(SWT.ICON_ERROR));
                   b2.setEnabled(true);
               } else {
                   b2.setImage(null);
                   b2.setEnabled(false);
               }
           }
       });

       c3.addSelectionListener(new SelectionAdapter() {
           @Override
           public void widgetSelected(SelectionEvent e) {
               if (!b3.isEnabled()) {
                   b3.setImage(d.getSystemImage(SWT.ICON_ERROR));
                   b3.setEnabled(true);
               } else {
                   b3.setImage(null);
                   b3.setEnabled(false);
               }
           }
       });

       s.open();
       while (!s.isDisposed()) {
           if (!d.readAndDispatch())
               d.sleep();
       }
       d.dispose();
   }

Upvotes: 4

Views: 169

Answers (1)

avojak
avojak

Reputation: 2360

This isn't ideal by any means, but if you need a workaround, one thing you could try is wrapping Button and using a StackLayout to flip between an enabled Button and a disabled Button. That way you're not adding/removing the Image. This also fixes the layout issues because the actual Button instances are not changing state.

For example:

public static class MyButton {

    private final Button buttonEnabled;
    private final Button buttonDisabled;

    private final Composite stackComposite;
    private final StackLayout stackLayout;

    public MyButton(final Composite parent, final String text) {
        stackComposite = new Composite(parent, SWT.NONE);
        stackLayout = new StackLayout();
        stackComposite.setLayout(stackLayout);
        stackComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));

        buttonEnabled = createButton(stackComposite, text, true);
        buttonDisabled = createButton(stackComposite, text, false);

        stackLayout.topControl = buttonEnabled;
    }

    public void setEnabled(final boolean enabled) {
        stackLayout.topControl = enabled ? buttonEnabled : buttonDisabled;
        stackComposite.layout();
    }

    public boolean isEnabled() {
        return stackLayout.topControl.equals(buttonEnabled) ? true : false;
    }

    private static Button createButton(final Composite parent,
            final String text, final boolean enabled) {
        final Button button = new Button(parent, SWT.PUSH | SWT.FLAT);
        button.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
        button.setText(text);
        button.setEnabled(enabled);
        if (enabled) {
            button.setImage(parent.getDisplay().getSystemImage(SWT.ICON_ERROR));
        }
        return button;
    }

}

Again, this isn't ideal, but you can always add methods (addListener(...), etc.) to the MyButton class to call methods on the enabled Button, which is now just an implementation detail.

Changes to your main method:

public static void main(final String[] args) {

    // ...

    new Label(s, SWT.NONE).setText("C");
    final Button c = new Button(s, SWT.CHECK);

    new Label(s, SWT.NONE).setText("L1");
    final MyButton b = new MyButton(s, "Button 1");

    // ...

    c.addSelectionListener(new SelectionAdapter() {
        @Override
        public void widgetSelected(final SelectionEvent e) {
            b.setEnabled(!b.isEnabled());
        }
    });

    // ...

}

Result: (note that I only changed the first button)

enter image description here enter image description here

Upvotes: 1

Related Questions