SWT update / redraw / layout prοblem

17,793

Ok, i've corrected the answer from ginu:

New Runnable().run() does actually not much to nothing, but the idea is correct:

You need a new thread to do your work in. Problem is, from that thread you can't call setEnabled on the buttons, because that can only be done from within the SWT-Event thread.

So you need another runnable to reset the buttons. The second runnable is passed to Display.callAsync and returns before it is actually executed, but that doesn't matter here. You could also use Display.callSync( Runnable ), that call would block your calling thread until the runnable returns.

Tested it in Eclipse, looks good so far.

Edit: Btw, the reason why calling layout() or Display.update() did not work is that you're currently blocking the SWT-Thread with your work, so the calls to layout/update are queued and only executed when you leave the event handler. Never block an event handler to do long work. :)

package test;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;

public class Test {

public static void main(final String[] args) {
    final Display display = new Display();
    final Shell shell = new Shell(display);
    shell.setLayout(new GridLayout(3, false));
    final Button button1 = new Button(shell, SWT.PUSH);
    button1.setText("Click");
    final Button button2 = new Button(shell, SWT.PUSH);
    button2.setText("Me");
    final Button button3 = new Button(shell, SWT.PUSH);
    button3.setText("Dude");

    button1.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
    button2.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
    button3.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));

    button2.setEnabled(false);
    button3.setEnabled(false);

    button1.addSelectionListener(new SelectionAdapter() {
        @Override
        public void widgetSelected(final SelectionEvent e) {
            button1.setEnabled(false);
            button2.setEnabled(true);
            button3.setEnabled(true);

            new Thread( new Runnable() {
                public void run() {
                    try {
                        // Do your operation here.
                        //
                        // Dummy sleep performed here instead.
                        Thread.sleep(1000);
                    } catch (InterruptedException e1) {
                        e1.printStackTrace();
                    }
                    shell.getDisplay().asyncExec( new Runnable() {
                        public void run() {
                          button1.setEnabled(true);
                          button2.setEnabled(false);
                          button3.setEnabled(false);
                        }
                    });
                }
            } ).start();
        }
    });

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

}

}

Share:
17,793
Admin
Author by

Admin

Updated on June 04, 2022

Comments

  • Admin
    Admin about 2 years

    I know many people experience this problem, but the solutions I found online do not seem to solve mine. I have a composite that has three buttons. What I want is the following : When I click one button, I want some other button to be grayed out ( setEnabled(false) ) and after a while (after a method execution), I want the button to be enabled again.

    Many such problems are solved by calling layout() method on the parent container, or this very similar one is solved by calling Display.getCurrent().update();

    Simply, my code could be summarized as follows :

    
    import org.eclipse.swt.events.SelectionEvent;
    import org.eclipse.swt.events.SelectionListener;
    import org.eclipse.swt.layout.GridData;
    import org.eclipse.swt.layout.GridLayout;
    import org.eclipse.swt.widgets.Display;
    import org.eclipse.swt.widgets.Label;
    import org.eclipse.swt.widgets.Shell;
    import org.eclipse.swt.widgets.Composite;
    import org.eclipse.swt.SWT;
    import org.eclipse.swt.widgets.Button;
    
    
    public class app1 {
    
        protected Shell shell;
    
        /**
         * Launch the application.
         * @param args
         */
        public static void main(String[] args) {
            try {
                app1 window = new app1();
                window.open();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        /**
         * Open the window.
         */
        public void open() {
            Display display = Display.getDefault();
            createContents();
            shell.open();
            shell.layout();
            while (!shell.isDisposed()) {
                if (!display.readAndDispatch()) {
                    display.sleep();
                }
            }
        }
    
        /**
         * Create contents of the window.
         */
        Button button1 , button2 , button3;
        Label label;
        protected void createContents() {
            shell = new Shell();
            shell.setSize(450, 300);
            shell.setText("SWT Application");
            shell.setLayout(new GridLayout(1,false));
            {
                final Composite composite = new Composite(shell, SWT.NONE);
                composite.setLayout(new GridLayout(3,false));
                GridData gd_composite = new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.VERTICAL_ALIGN_FILL);
                gd_composite.grabExcessHorizontalSpace = true;          
                gd_composite.horizontalSpan = 10;   //?
                gd_composite.verticalIndent = 5;
                composite.setLayoutData(gd_composite);
                GridData gd_button;
    
                {
                    button1 = new Button(composite, SWT.NONE);
                    button1.setText("Button 1");
                    gd_button = new GridData(SWT.FILL, GridData.BEGINNING, false, false);
                    gd_button.horizontalSpan = 1;
                    button1.setLayoutData(gd_button);
                    button1.addSelectionListener(new SelectionListener(){
                        public void widgetSelected(SelectionEvent e){
                            try{
                            button2.setEnabled(false);
                            button2.redraw();
                            button2.update();
    
                            //composite.redraw();
                            //composite.update();
                            //composite.layout();
    
                            shell.redraw();
                            shell.update();
                            shell.layout();                     
                            Display.getCurrent().update();
                            }   catch   (Exception e2)  {
                                System.err.println("exception e : " + e2.toString());
                            }
    
                            System.out.println("basla");
    
    
                            try {
                                System.out.println("sleep1");
                                Thread.sleep(100);
                            } catch (InterruptedException e1) {
                                e1.printStackTrace();
                            }   catch (Throwable th)    {
                                System.err.println("th: " + th.toString());
                            }
                            try {
                                System.out.println("sleep2");
                                Thread.sleep(100);
                            } catch (InterruptedException e1) {
                                e1.printStackTrace();
                            }   catch (Throwable th)    {
                                System.err.println("th: " + th.toString());
                            }
                            try {
                                System.out.println("sleep3");
                                Thread.sleep(100);
                            } catch (InterruptedException e1) {
                                e1.printStackTrace();
                            }   catch (Throwable th)    {
                                System.err.println("th: " + th.toString());
                            }
    
                            for(int i=0 ; i &lt 10000 ; i++)
                            {
                                System.out.println(i);
                            }
                        }
                        public void widgetDefaultSelected(SelectionEvent e) {
                            System.err.println("widgetDefault !");
                        }
                    });
                }
                {
                    button2 = new Button(composite, SWT.NONE);
                    button2.setText("Button 2");
                    gd_button = new GridData(SWT.FILL, GridData.CENTER, false, false);
                    gd_button.horizontalSpan = 1;
                    button2.setLayoutData(gd_button);
                    button2.addSelectionListener(new SelectionListener(){
                        public void widgetSelected(SelectionEvent e){
                            button1.setEnabled(false);
                            composite.layout();
                            for (int i=1; i&lt=100; i++) {
                                 try {
                                      Thread.sleep(10);
                                 } catch (Throwable th) {}
                                label.setText(i + " %");
                                label.update();
                            }
                        }
                        public void widgetDefaultSelected(SelectionEvent e) {}
                    });
                }
    
                {
                    label = new Label(composite , SWT.NONE);
                    label.setText("0 %");
                    label.update();
                }
            }
        }
    }
    

    What happens is, the button gets disabled after the end of widgetSelected() method is reached. However, the label gets updated frequently without any problem (even when the label.update() method is not there)

    Additional information : Say, I disable the button, then put a Thread.sleep() and then enable the button ; it sleeps first and then quickly disables and enables the button. So I believe all such paint requests are queued and are processed at the end of the execution.

    Useful information: I realized that, when I create and display a MessageBox right after my display changes, the display changes occur. So, if I make the following change in my widgetSelected method :

    
    button2.setEnabled(false)
    MessageBox mBox = new MessageBox(Display.getCurrent().getActiveShell(), SWT.ICON_INFORMATION | SWT.OK);
    mBox.setText("Information");
    mBox.setMessage("Buttons updated!");
    mBox.open();
    

    the button will be grayed out as soon as the widgetSelected() method is called. This makes me believe my solution lies within Display.getCurrent() methods. However, I tried

    Display.getCurrent().getActiveShell().redraw()
    Display.getCurrent().getActiveShell().update()
    Display.getCurrent().getActiveShell().layout() 
    

    methods and they didnt solve my problem.

    Thanks, Ege

  • Admin
    Admin almost 15 years
    Thanks a lot, it works. However, I still could not get your explanation 100%. I know it is not possible to perform SWT actions in a thread different than the SWT-thread. When I write a SelectionAdapter that first disables all the buttons then performs a sleep (in the same thread, without creating a new thread) and then enables all the buttons it shows indeterministic behavior. Sometimes it disables the 3rd button, sleeps and then enables them all. Sometimes it disables the 2nd button, sleeps and then enables them all, etc. Could you explain me this indeterministic behavior? Thank you again.