我试图编写软件以从三个RS232串行端口读取数据,并且我编写了一些代码来提供有关程序实际监听的端口的可视反馈。我知道程序正在侦听COM1,因为我已经打印到控制台告诉我它正在收听哪个端口。问题是它没有更新JTextField以在实际GUI中通知用户。我写的代码如下:
if (Serial.currPortId == (null)) {
listenState.setText("NONE");
listenState.revalidate();
}
while (Serial.currPortId != (null)) {
listenState.setText(Serial.currPortId.getName());
listenState.revalidate();
if (Serial.currPortId.getName().equals("COM1")) {
tab1sheet.setText(ImportMenu.serialImport.datafeed);
tab1sheet.revalidate();
}
else if (Serial.currPortId.getName().equals("COM2")) {
tab2sheet.setText(ImportMenu.serialImport.datafeed);
tab2sheet.revalidate();
}
else if (Serial.currPortId.getName().equals("COM3")) {
tab3sheet.setText(ImportMenu.serialImport.datafeed);
tab3sheet.revalidate();
}
else {tab1sheet.setText("N/A");
tab1sheet.revalidate();
tab2sheet.setText("N/A");
tab2sheet.revalidate();
tab3sheet.setText("N/A");
tab3sheet.revalidate();
}
}
出于某种原因,它只能设置" listenState"字段为NONE,然后不更新,尽管声称在控制台中正在侦听COM1。
答案 0 :(得分:1)
您的代码正在打破Swing线程规则。它可能正在尝试在Swing事件线程上运行监听代码(我们无法根据您发布的代码段来判断),但它肯定会尝试以线程方式更新文本字段。相反,我建议您使用SwingWorker来监听后台线程中的端口,特别是SwingWorker<Void, String>
使用发布/进程方法对将文本发送到JTextArea。或者,如果您需要使用更复杂的信息更新GUI到GUI的多个位置,那么可以通过将一个PropertyChangeListener附加到SwingWorker来实现,这将通知任何侦听器(GUI)工作者状态的更改。
有关详情,请查看Lesson: Concurrency in Swing
您的代码可以看起来像这样 :
class MyWorker extends SwingWorker<Void, Void> {
// properties to listen for changes to:
public static final String LISTEN_STATE = "listen state";
public static final String CURRENT_PORT_ID = "current port id";
public static final String DATA_FEED = "data feed";
private String listenState = "None";
private String dataFeed = "";
private String currentPortId = "";
@Override
protected Void doInBackground() throws Exception {
while (true) {
if (Serial.currPortId != (null)) {
// change properties when data comes in
String currPortId = Serial.currPortId.getName();
setListenState(currPortId);
setCurrentPortId(currPortId);
setDataFeed(ImportMenu.serialImport.datafeed);
} else {
setListenState("None");
break; // ??
}
}
return null;
}
public String getListenState() {
return listenState;
}
public void setListenState(String listenState) {
// set the prop change parameters
String oldValue = this.listenState;
String newValue = listenState;
// update the propertie's state
this.listenState = listenState;
// notify listeners of the change
firePropertyChange(LISTEN_STATE, oldValue, newValue);
}
public String getDataFeed() {
return dataFeed;
}
public void setDataFeed(String dataFeed) {
// same rationale as for the other setter method
String oldValue = this.dataFeed;
String newValue = dataFeed;
this.dataFeed = dataFeed;
firePropertyChange(DATA_FEED, oldValue, newValue);
}
public String getCurrentPortId() {
return currentPortId;
}
public void setCurrentPortId(String currentPortId) {
// same rationale as for the other setter method
String oldValue = this.currentPortId;
String newValue = currentPortId;
this.currentPortId = currentPortId;
firePropertyChange(CURRENT_PORT_ID, oldValue, newValue);
}
}
然后,您可以附加响应更改的侦听器,然后更新GUI中的显示
private class MyWorkerListener implements PropertyChangeListener {
@Override
public void propertyChange(PropertyChangeEvent evt) {
switch (evt.getPropertyName()) {
case MyWorker.LISTEN_STATE:
String listenState = evt.getNewValue().toString();
// show in text field
break;
case MyWorker.CURRENT_PORT_ID:
String currentPortId = evt.getNewValue().toString();
// use this to decide which tab to change to
break;
case MyWorker.DATA_FEED:
String dataFeed = evt.getNewValue().toString();
// show where needed
break;
default:
break;
}
}
}
然后你就像gui一样把它连接起来:
MyWorker worker = new MyWorker();
worker.addPropertyChangeListener(new MyWorkerListener());
worker.execute();
您还希望将另一个PropertyChangeListener添加到SwingWorker以侦听SwingWorker.StateValue.DONE newValue,当它发生时,调用worker上的get()
以捕获并处理任何异常