java - 尝试连接到串行端口时使用 javax.swing.SwingWorker 时出现问题

标签 java swing user-interface serial-port xbee

我正在用 Java 开发一个应用程序,将从 Xbee 设备接收到的数据上传到在线数据库。功能已经存在并且一切正常,但是当开发 GUI(使用 WindowsPro Builder)时,一切都会变糟。问题是,应用程序需要能够检测 Xbee 设备,如果未连接,则等待它连接 - 无限期(或直到关闭)。我已经有一个方法可以检测串口是否是Xbee设备;就像我说的,一切正常,除非我将它与 GUI 集成。

我遇到的问题是创建一个 GUI,它首先检测 Xbee 设备是否已连接,如果没有,则显示一条消息,通知用户连接设备才能继续。同时(在显示消息时),我需要调用扫描串行端口的方法。我正在考虑线程,但我已经有一段时间没有使用它们了。请注意,当应用程序启动时,该方法已经运行一次,以便尝试连接。我没有代码可以显示,因为我所做的只是放置基本框架、按钮等(还没有事件)。我是 Java GUI 编程新手,有什么建议吗?

更新:所以我有点尝试实现 MadProgrammer 的建议,我相信它在 SwingWorker 教程中是有效的,但是没有任何反应。唯一运行的是设置 GUI。接下来是代码:

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;

import javax.swing.SwingWorker;


public class ConnectionWorker extends SwingWorker<Boolean, String> {

private ConnectionListener callBack;
private Xbee xbee = new Xbee();
private QboComm comm;

public ConnectionWorker(ConnectionListener listener, QboComm comm) {
    this.callBack = listener;
    this.comm = comm;
}


protected void process(List<String> chunks) {
    String msg = chunks.get(chunks.size() - 1);
    if (msg.equals("WAITING")) {
        comm.publishError();
    }
}

protected Boolean doInBackground() throws Exception {
    boolean isConnected = false;
    this.xbee = QboComm.xbee;
    ArrayList<String> list = new ArrayList<String>();
    if(!isConnected){
        publish("WAITING");
        while(!isConnected){
            list = xbee.getSerialPorts();
            for(String s : list){
                isConnected = xbee.connect(s);
                if(isConnected){
                    publish("DONE");
                    break;
                }
            }
        }
    }
    return isConnected;
}


protected void done() {
    boolean check;
    try {
        check = get();
        if (check) {
            comm.removeError();
            callBack.connectionEstablished();
        } else {
            callBack.connectionFailed();
        }
    } catch (InterruptedException | ExecutionException e) {
        e.printStackTrace();
    }
}  
}

import java.awt.EventQueue;


public class QboComm {

private JFrame frmQboCommunicator;
public static Xbee xbee = new Xbee();
private JInternalFrame internalFrame;
private JLabel lblConnected;

/**
 * Launch the application.
 */
public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
        public void run() {
            QboComm window = new QboComm();
            window.frmQboCommunicator.setVisible(true);
            ConnectionListener callback = new ConnectionListener() {
                public void connectionEstablished() {
                    try {
                        ArrayList<String> list = new ArrayList<String>();
                        list = xbee.fetch();
                        DBConnector db = DBConnector.getConnector();
                        if(db.connect()){
                            for(String s : list){
                                db.upload(s.substring(0, 5), s.substring(5));
                            }
                        }
                        db.disconnect();
                        xbee.printDBList();
                    } catch (Exception e) {
                        e.printStackTrace();
                    } 
                }
                public void connectionFailed() {
                    //IMPLEMENT
                }
            };
            new ConnectionWorker(callback, window).execute();
        }
    });
}

/**
 * Create the application.
 */
public QboComm() {
    initialize();
}

/**
 * Initialize the contents of the frame.
 */
private void initialize() {
    frmQboCommunicator = new JFrame();
    frmQboCommunicator.setTitle("Qbo Communicator");
    frmQboCommunicator.getContentPane().setBackground(new Color(165, 42, 42));
    frmQboCommunicator.getContentPane().setForeground(new Color(211, 211, 211));
    frmQboCommunicator.setBounds(100, 100, 450, 300);
    frmQboCommunicator.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frmQboCommunicator.getContentPane().setLayout(null);

    /**
     * Connection Error Pop-up
     */
    this.internalFrame = new JInternalFrame("Connection Error");
    internalFrame.setBorder(new LineBorder(new Color(153, 180, 209), 3));
    internalFrame.setBounds(103, 46, 227, 157);
    frmQboCommunicator.getContentPane().add(internalFrame);
    internalFrame.getContentPane().setLayout(null);
    JTextPane txtpnAQboCommunicator = new JTextPane();
    txtpnAQboCommunicator.setText("A Qbo Communicator is not connected. Please connect a Qbo Communicator to continue.");
    txtpnAQboCommunicator.setEditable(false);
    txtpnAQboCommunicator.setBounds(0, 0, 211, 128);
    internalFrame.getContentPane().add(txtpnAQboCommunicator);
    internalFrame.setVisible(false);

    /**
     * Application Name
     */
    JLabel lblQboCommunicator = DefaultComponentFactory.getInstance().createTitle("QBO COMMUNICATOR");
    lblQboCommunicator.setForeground(new Color(255, 255, 255));
    lblQboCommunicator.setBackground(new Color(255, 255, 240));
    lblQboCommunicator.setHorizontalAlignment(SwingConstants.CENTER);
    lblQboCommunicator.setBounds(144, 0, 146, 14);
    frmQboCommunicator.getContentPane().add(lblQboCommunicator);

    /**
     * Connected label, displayed when connected to Xbee device
     */
    this.lblConnected = DefaultComponentFactory.getInstance().createLabel("CONNECTED");
    lblConnected.setForeground(new Color(255, 255, 255));
    lblConnected.setFont(new Font("Tahoma", Font.BOLD, 14));
    lblConnected.setHorizontalAlignment(SwingConstants.CENTER);
    lblConnected.setBounds(144, 25, 146, 14);
    frmQboCommunicator.getContentPane().add(lblConnected);

    /**
     * Scroll Panel that displays uploaded data
     */

    JScrollPane scrollPane = new JScrollPane();
    scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
    scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
    scrollPane.setBounds(53, 65, 344, 131);
    frmQboCommunicator.getContentPane().add(scrollPane);

    JPanel panel = new JPanel();
    panel.setBorder(new LineBorder(new Color(255, 255, 255)));
    panel.setBackground(new Color(165, 42, 42));
    scrollPane.setViewportView(panel);

    /**
     * Progress Bar
     */
    JProgressBar progressBar = new JProgressBar();
    progressBar.setStringPainted(true);
    progressBar.setFont(new Font("Tahoma", Font.BOLD, 12));
    progressBar.setBackground(new Color(255, 255, 255));
    progressBar.setForeground(new Color(255, 140, 0));
    progressBar.setBounds(53, 214, 344, 25);
    frmQboCommunicator.getContentPane().add(progressBar);
}

public void publishError(){
    this.internalFrame.setVisible(true);
    this.lblConnected.setText("DISCONNECTED");
}

public void removeError(){
    this.internalFrame.setVisible(false);
    this.lblConnected.setText("CONNECTED");
}
}

第二个代码块是启动应用程序的主类。有什么建议吗?

最佳答案

我强烈建议使用诸如 SwingWorker 之类的东西。

您不想做的是在事件调度线程上执行任何会阻止 UI 的操作,这将阻止您更新 UI(包括显示消息)以及 UI 进行 self 更新,使其看起来像挂了。

查看Concurrency in Swing了解更多详情。

Swing 是一个事件驱动的环境(我确信),基本上,您希望应用程序简单地运行直到建立连接,可能会显示某种消息窗口,表明它正在等待连接。

我将通过一个相对简单的过程来设置一个可以为另一个类提供回调的 SwingWorker

import java.awt.EventQueue;
import java.util.List;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class WaitForSwingWorker {

    public static void main(String[] args) {
        new WaitForSwingWorker();
    }

    public WaitForSwingWorker() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                ConnectionListener callback = new ConnectionListener() {

                    @Override
                    public void connectionEstablished() {
                        // Continue running the app
                    }

                    @Override
                    public void connectionFailed() {
                        // Show error message :(
                    }
                };

                new ConnectionWorker(callback).execute();

                // Execution will continue here...

            }
        });
    }

    public interface ConnectionListener {
        public void connectionEstablished();
        // If possible, you should provide a message as to why...
        public void connectionFailed();
    }

    public class ConnectionWorker extends SwingWorker<Void, String> {

        private ConnectionListener callBack;

        public ConnectionWorker(ConnectionListener listener) {
            callBack = listener;
        }

        @Override
        protected void process(List<String> chunks) {
            // Back in the EDT...
            String msg = chunks.get(chunks.size() - 1);
            if (msg.equals("WAITING")) {
                // Show waiting for connection message...
            }
        }

        @Override
        protected Void doInBackground() throws Exception {
            // Within our own thread
            // Establish connection...
            if (!isConnected) {
                publish("WAITING");
                // Wait for incoming connection, this can block...
            }
            return null;
        }

        @Override
        protected void done() {
            // Back in the EDT
            if (isConnected) {
                // Show failed to connect message?
                callBack.connectionEstablished();
            } else {
                callBack.connectionFailed();
            }
        }

    }

}

nb-这是一个概念证明,您需要填写功能

关于java - 尝试连接到串行端口时使用 javax.swing.SwingWorker 时出现问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15823004/

相关文章:

java - 设置为 null 到底有什么作用?

java - 密码本其他值

java - if 语句中的 JOptionPane

java - 从网页获取数据到桌面应用程序

java - 创建 JTable java

python - 如何获取 Tkinter 文本小部件中文本的当前长度

Java:尽管字符串是不变的,但如何将字符串设为 "mutate"?

javascript - 避免重复代码

android - 如何使菜单出现在 flutter 的下拉菜单按钮下方

java - 如何通过外部提供列索引对 JTable 进行排序