JTextField不从串行端口更新

时间:2017-11-30 16:12:51

标签: java swing serial-port

我试图编写软件以从三个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。

1 个答案:

答案 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()以捕获并处理任何异常