javabuttonswtredrawstyledtext

refresh gui in swt button listener


I have following class.

  1. Why the btnDecorate is allways enabled? I wanted to disable the button when the loop is under processing.
  2. Why text.redraw() works only in the end of loop? I wanted to see the box sequently on every character.

 

import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.*;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.*;
import org.eclipse.swt.widgets.*;

public class SampleRefreshStyledText {

public static void main(String[] args) {
    final Display display = new Display();
    Shell shell = new Shell(display);
    shell.setLayout(new FillLayout(SWT.VERTICAL));
    final Button btnDecorate = new Button(shell, SWT.NONE);
    btnDecorate.setText("Decorate");

    final StyledText text = new StyledText(shell, SWT.NONE);
    text.setText("ABCDEFGHIJKLMNOPRQ\n1234567890");

    btnDecorate.addSelectionListener(new SelectionListener() {
        @Override
        public void widgetSelected(SelectionEvent event) {
            btnDecorate.setEnabled(false);

            for (int i = 0; i < text.getText().length(); i++) {
                StyleRange styleRange = new StyleRange();
                styleRange.start = i;
                styleRange.length = 1;
                styleRange.borderColor = display.getSystemColor(SWT.COLOR_RED);
                styleRange.borderStyle = SWT.BORDER_SOLID;
                styleRange.background = display.getSystemColor(SWT.COLOR_GRAY);

                text.setStyleRange(null);
                text.setStyleRange(styleRange);
                text.redraw();

                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            btnDecorate.setEnabled(true);
        }

        @Override
        public void widgetDefaultSelected(SelectionEvent arg0) {}           
    });        

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

Solution

  • You can't write loops like this with SWT.

    All UI operations occur on the single UI thread. Calling Thread.sleep puts the UI thread to sleep and nothing at all will happen.

    The redraw call only requests that the text is redrawn, it will not actually happen until the next time the display.readAndDispatch() is run, so doing this repeatedly in a loop doesn't work.

    What you have to do is run the first step of your loop once. You must then arrange to run the next step 500ms later without blocking the thread. You can do this using the Display.timerExec method to request that code is run at a later time:

    display.timerExec(500, runnable);
    

    where runnable is a class implementing Runnable that does the next step. At the end of this code you call timerExec again until you have worked your way through all the steps.