James Harpe
James Harpe

Reputation: 4345

SWT: Periodically update GUI

I have an SWT GUI which displays a list taken from a database. What I would like for it to do is to periodically update the GUI, which would involve clearing everything in the shell and running the populateList() method again. I have tried several suggested strategies for this, but the GUI never updates. My latest attempt is using display.asyncexec to create a thread to handle this. This appears to give me an invalid thread access error.

Here's my code:

package display;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Timer;
import java.util.TimerTask;

import object_models.Request;
import util.RestClient.RequestMethod;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.layout.RowData;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;


import util.RestClient;


public class StoragePickupDisplay {

    protected Shell shell;


    private ArrayList<Request> pendingRequests;
    /**
     * Launch the application.
     * @param args
     */
    public static void main(String[] args) {
        try {
            StoragePickupDisplay window = new StoragePickupDisplay();
            window.open();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * Open the window.
     * @throws InterruptedException 
     */
    public void open() throws InterruptedException {
        Display display = Display.getDefault();
        createContents();
        populateList();
        shell.open();
        shell.layout();

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



        display.asyncExec(new Runnable() {
            public void run() {
              populateList();
            }
          });
        Thread.sleep(1000);

        }
    }

    /**
     * Create contents of the window.
     */
    protected void createContents() {
        shell = new Shell();
        //shell.setMaximized(true);

        //shell.setFullScreen(true);
        shell.setText("Request Pickup");
        shell.setMaximized(true);


        GridLayout gridLayout= new GridLayout(1,false);

        shell.setLayout(gridLayout);




    }
    protected void populateList(){


        pendingRequests=new ArrayList<Request>();

        RestClient client = new RestClient("http://XXXXXX:8080/StorageWebService/rest/operations/getPendingRequests");

        try {
            client.Execute(RequestMethod.GET);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        String response = client.getResponse();


        pendingRequests= parseResponse(response);



        for(Request request: pendingRequests){
            Composite row = new Composite(shell,SWT.NONE);

            GridLayout gridLayout = new GridLayout(4,true);
            gridLayout.marginTop=5;
            row.setLayout(gridLayout);
            row.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false));


            Composite left = new Composite(row,SWT.NONE);
            left.setLayout(new GridLayout(2,false));
            left.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false));

            Label label = new Label(left,SWT.LEFT);
            label.setText(""+request.getId());

            label.setFont(new Font(Display.getDefault(),"Arial",30, SWT.NONE));
            label.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, false, false));


            label = new Label(left,SWT.LEFT);
            label.setText(request.getNickname());
            label.setFont(new Font(Display.getDefault(),"Arial",30, SWT.NONE));
            label.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false));

            label = new Label(row,SWT.LEFT);
            label.setText(""+request.getNumberCompleted()+" of "+request.getNumberItems()+" Picked");
            label.setFont(new Font(Display.getDefault(),"Arial",30, SWT.NONE));
            label.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false));

            label = new Label(row,SWT.LEFT);
            label.setText("Estimated Wait Time:");
            label.setFont(new Font(Display.getDefault(),"Arial",30, SWT.NONE));
            label.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false));



            Label separator = new Label(shell, SWT.HORIZONTAL|SWT.SEPARATOR|SWT.PUSH);

            GridData gridData = new GridData(SWT.FILL, SWT.BEGINNING, true, false);
            //gridData.horizontalSpan=4;
            separator.setLayoutData(gridData);



        }

    }
    public ArrayList<Request> parseResponse(String response){
        ArrayList<Request> list = new ArrayList<Request>();
        try {



            XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser();
            parser.setInput(new StringReader(response));

            int eventType = parser.getEventType();


            Request curRequest = new Request();


            while (eventType != XmlPullParser.END_DOCUMENT) {
                if (eventType == XmlPullParser.START_TAG) {
                    String name = parser.getName();
                    if (name.equalsIgnoreCase("id")) {
                        String text = parser.nextText();
                        curRequest.setId(Integer.parseInt(text));

                    }
                    if (name.equalsIgnoreCase("nickname")) {
                        String text = parser.nextText();
                        curRequest.setNickname(text);

                    }
                    if (name.equalsIgnoreCase("numberCompleted")) {
                        String text = parser.nextText();
                        curRequest.setNumberCompleted(Integer.parseInt(text));

                    }
                    if (name.equalsIgnoreCase("numberItems")) {
                        String text = parser.nextText();
                        curRequest.setNumberItems(Integer.parseInt(text));

                    }
                    if (name.equalsIgnoreCase("status")) {
                        String text = parser.nextText();
                        curRequest.setStatus(Integer.parseInt(text));

                    }

                }

                if (eventType == XmlPullParser.END_TAG) {
                    if (parser.getName().equalsIgnoreCase("Request")) {
                        list.add(curRequest);
                        curRequest = new Request();
                    }
                }
                eventType = parser.next();
            }

        } catch (XmlPullParserException e) {

            e.printStackTrace();
        } catch (IOException e) {

            e.printStackTrace();
        }

        return list;

    }




}

Upvotes: 0

Views: 6626

Answers (3)

sambi reddy
sambi reddy

Reputation: 3085

Use below method on Display

 public void timerExec (int milliseconds, Runnable runnable)

execute it before you run event loop.

ex:
 display.timerExec(30000, new Runnable() {
            public void run() {
              populateList();
            }
          });

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

Upvotes: 1

Tobias Willig
Tobias Willig

Reputation: 1144

As Liam15 has already mentioned, you should start a different thread. Otherwise you will block the UI and it will become unresponsive. The thread should handle the data acquisition and then update the UI synchronously or asynchronously.

Here is an example how your open() method could look like:

public void open() throws InterruptedException {
    Display display = Display.getDefault();
    createContents();
    shell.open();

    Thread updateThread = new Thread() {
        public void run() {
            while (true) {
                final ArrayList<Request> pendingRequests = getPendingRequests();
                Display.getDefault().syncExec(new Runnable() {

                    @Override
                    public void run() {
                        populateList(pendingRequests);
                    }
                });

                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    };
    // background thread
    updateThread.setDaemon(true);
    updateThread.start();

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

In order to clear the shell and update the shell contents, you can add the following lines of code to your populateList() method.

At the beginning of the method add:

Control[] oldControls = shell.getChildren();

At the end of the method add:

for (Control oldControl : oldControls) {
    oldControl.dispose();
}
shell.layout();

Upvotes: 3

Liam15
Liam15

Reputation: 75

You could run a separate thread with a loop that periodically re-opens the GUI or just updates some information.

Upvotes: 0

Related Questions