我有一个SWT GUI,显示从数据库中获取的列表。我想要它做的是定期更新GUI,这将涉及清除shell中的所有内容并再次运行populateList()方法。我已经尝试了几种建议的策略,但GUI永远不会更新。我最近的尝试是使用display.asyncexec创建一个线程来处理这个问题。这似乎给我一个无效的线程访问错误。
这是我的代码:
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;
}
}
答案 0 :(得分:3)
正如Liam15已经提到的,你应该开始一个不同的线程。否则你将阻止用户界面,它将无法响应。线程应处理数据采集,然后同步或异步更新UI。
以下是open()方法的示例:
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();
}
}
}
为了清除shell并更新shell内容,可以在populateList()方法中添加以下代码行。
在方法的开头添加:
Control[] oldControls = shell.getChildren();
在方法结束时添加:
for (Control oldControl : oldControls) {
oldControl.dispose();
}
shell.layout();
答案 1 :(得分:1)
在Display
public void timerExec (int milliseconds, Runnable runnable)
在运行事件循环之前执行它。
ex:
display.timerExec(30000, new Runnable() {
public void run() {
populateList();
}
});
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
答案 2 :(得分:0)
您可以使用循环运行单独的线程,该循环会定期重新打开GUI或仅更新某些信息。