最近一門課要求編寫一個上位機串口通信工具,我基於Java編寫了一個帶有圖形界面的簡單串口通信工具,下面詳述一下過程,供大家參考^_^
一:
首先,你需要下載一個額外的支持Java串口通信操作的jar包,由於java.comm比較老了,而且不支持64位系統,這裡推薦Rxtx這個jar包(32位/64位均支持)。
官方下載地址:http://fizzed.com/oss/rxtx-for-java (注:可能需要FQ才能下載)
不能FQ的童鞋,可以在這裡下載:
http://xiazai.VeVB.COm/201612/yuanma/javamfzrxtx(VeVB.COm).rar(32位)
http://xiazai.VeVB.COm/201612/yuanma/javamfzrxtx(VeVB.COm).rar(64位)
二:
下載解壓jar包並在Java Build Path 下引入:
捕獲
注:如果運行過程中拋出java.lang.UnsatisfiedLinkError錯誤,請將rxtx解壓包中的rxtxParallel.dll,rxtxSerial.dll 這兩個文件複製到C:/Windows/System32 目錄下即可解決該錯誤。
三:
關於該jar包的使用,我寫了一個SerialTool.java類,該類提供關於串口通信的各簡單服務,代碼如下(注意該類位於serialPort 包裡):
package serialPort;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.util.ArrayList;import java.util.Enumeration;import java.util.TooManyListenersException;import gnu.io.CommPort;import gnu.io.CommPortIdentifier;import gnu.io.NoSuchPortException;import gnu.io.PortInUseException;import gnu.io.SerialPort;import gnu.io.SerialPortEventListener;import gnu.io.UnsupportedCommOperationException;import serialException.*;/** * 串口服務類,提供打開、關閉串口,讀取、發送串口數據等服務(採用單例設計模式) * @author zhong * */public class SerialTool { private static SerialTool serialTool = null; static { //在該類被ClassLoader加載時就初始化一個SerialTool對象if (serialTool == null) { serialTool = new SerialTool(); } } //私有化SerialTool類的構造方法,不允許其他類生成SerialTool對象private SerialTool() {} /** * 獲取提供服務的SerialTool對象* @return serialTool */ public static SerialTool getSerialTool() { if (serialTool == null) { serialTool = new SerialTool(); } return serialTool; } /** * 查找所有可用端口* @return 可用端口名稱列表*/ public static final ArrayList<String> findPort() { //獲得當前所有可用串口Enumeration<CommPortIdentifier> portList = CommPortIdentifier.getPortIdentifiers(); ArrayList<String> portNameList = new ArrayList<>(); //將可用串口名添加到List並返回該List while (portList.hasMoreElements()) { String portName = portList.nextElement().getName(); portNameList.add(portName); } return portNameList; } /** * 打開串口* @param portName 端口名稱* @param baudrate 波特率* @return 串口對象* @throws SerialPortParameterFailure 設置串口參數失敗* @throws NotASerialPort 端口指向設備不是串口類型* @throws NoSuchPort 沒有該端口對應的串口設備* @throws PortInUse 端口已被佔用*/ public static final SerialPort openPort(String portName, int baudrate) throws SerialPortParameterFailure, NotASerialPort, NoSuchPort, PortInUse { try { //通過端口名識別端口CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(portName); //打開端口,並給端口名字和一個timeout(打開操作的超時時間) CommPort commPort = portIdentifier.open(portName, 2000); //判斷是不是串口if (commPort instanceof SerialPort) { SerialPort serialPort = (SerialPort) commPort; try { //設置一下串口的波特率等參數serialPort.setSerialPortParams(baudrate, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE); } catch (UnsupportedCommOperationException e) { throw new SerialPortParameterFailure(); } //System.out.println("Open " + portName + " sucessfully !"); return serialPort; } else { //不是串口throw new NotASerialPort(); } } catch (NoSuchPortException e1) { throw new NoSuchPort(); } catch (PortInUseException e2) { throw new PortInUse(); } } /** * 關閉串口* @param serialport 待關閉的串口對象*/ public static void closePort(SerialPort serialPort) { if (serialPort != null) { serialPort.close(); serialPort = null; } } /** * 往串口發送數據* @param serialPort 串口對象* @param order 待發送數據* @throws SendDataToSerialPortFailure 向串口發送數據失敗* @throws SerialPortOutputStreamCloseFailure 關閉串口對象的輸出流出錯*/ public static void sendToPort(SerialPort serialPort, byte[] order) throws SendDataToSerialPortFailure, SerialPortOutputStreamCloseFailure { OutputStream out = null; try { out = serialPort.getOutputStream(); out.write(order); out.flush(); } catch (IOException e) { throw new SendDataToSerialPortFailure(); } finally { try { if (out != null) { out.close(); out = null; } } catch (IOException e) { throw new SerialPortOutputStreamCloseFailure(); } } } /** * 從串口讀取數據* @param serialPort 當前已建立連接的SerialPort對象* @return 讀取到的數據* @throws ReadDataFromSerialPortFailure 從串口讀取數據時出錯* @throws SerialPortInputStreamCloseFailure 關閉串口對象輸入流出錯*/ public static byte[] readFromPort(SerialPort serialPort) throws ReadDataFromSerialPortFailure, SerialPortInputStreamCloseFailure { InputStream in = null; byte[] bytes = null; try { in = serialPort.getInputStream(); int bufflenth = in.available(); //獲取buffer裡的數據長度while (bufflenth != 0) { bytes = new byte[bufflenth]; //初始化byte數組為buffer中數據的長度in.read(bytes); bufflenth = in.available(); } } catch (IOException e) { throw new ReadDataFromSerialPortFailure(); } finally { try { if (in != null) { in.close(); in = null; } } catch(IOException e) { throw new SerialPortInputStreamCloseFailure(); } } return bytes; } /** * 添加監聽器* @param port 串口對象* @param listener 串口監聽器* @throws TooManyListeners 監聽類對象過多*/ public static void addListener(SerialPort port, SerialPortEventListener listener) throws TooManyListeners { try { //給串口添加監聽器port.addEventListener(listener); //設置當有數據到達時喚醒監聽接收線程port.notifyOnDataAvailable(true); //設置當通信中斷時喚醒中斷線程port.notifyOnBreakInterrupt(true); } catch (TooManyListenersException e) { throw new TooManyListeners(); } } }注:該類方法中throw 的Exception 都是我自定義的Exception,之所以這麼做是為了方便在主程序中進行相應處理,下面貼其中一個Exception出來給大家做下說明:
(注意我所有自定義的Exception 都放在serialException 包裡)
package serialException;public class SerialPortParameterFailure extends Exception { /** * */ private static final long serialVersionUID = 1L; public SerialPortParameterFailure() {} @Override public String toString() { return "設置串口參數失敗!打開串口操作未完成!"; } }每個自定義的Exception類我都重寫了它的toString() 方法,便於主程序捕捉到該Exception後打印對應的錯誤信息
其中在serialException包裡還有一個專門將接收到的Exception對象內的錯誤信息提取出來轉換成字符串並返回的類,代碼如下:
package serialException;import java.io.IOException;import java.io.PrintWriter;import java.io.StringWriter;/** * 負責將傳入的Exception中的錯誤信息提取出來並轉換成字符串; * @author zhong * */public class ExceptionWriter { /** * 將Exception中的錯誤信息封裝到字符串中並返回該字符串* @param e 包含錯誤的Exception * @return 錯誤信息字符串*/ public static String getErrorInfoFromException(Exception e) { StringWriter sw = null; PrintWriter pw = null; try { sw = new StringWriter(); pw = new PrintWriter(sw); e.printStackTrace(pw); return "/r/n" + sw.toString() + "/r/n"; } catch (Exception e2) { return "出錯啦!未獲取到錯誤信息,請檢查後重試!"; } finally { try { if (pw != null) { pw.close(); } if (sw != null) { sw.close(); } } catch (IOException e1) { e1.printStackTrace(); } } }}四:
主程序類的使用,Client.java裡含有程序的入口地址(main方法),它的作用是顯示一個歡迎界面並調用DataView.java這個類進行實際的串口數據顯示。
Client.java代碼如下:
package serialPort;import java.awt.Color;import java.awt.FlowLayout;import java.awt.Font;import java.awt.Frame;import java.awt.Graphics;import java.awt.GridLayout;import java.awt.Image;import java.awt.Label;import java.awt.Panel;import java.awt.Toolkit;import java.awt.event.KeyAdapter;import java.awt.event.KeyEvent;import java.awt.event.WindowAdapter;import java.awt.event.WindowEvent;import javax.swing.JOptionPane;import serialException.ExceptionWriter;/** * 主程序* @author zhong * */public class Client extends Frame{ /** * */ private static final long serialVersionUID = 1L; /** * 程序界面寬度*/ public static final int WIDTH = 800; /** * 程序界面高度*/ public static final int HEIGHT = 620; /** * 程序界面出現位置(橫坐標) */ public static final int LOC_X = 200; /** * 程序界面出現位置(縱坐標) */ public static final int LOC_Y = 70; Color color = Color.WHITE; Image offScreen = null; //用於雙緩衝//設置window的icon(這裡我自定義了一下Windows窗口的icon圖標,因為實在覺得哪個小咖啡圖標不好看= =) Toolkit toolKit = getToolkit(); Image icon = toolKit.getImage(Client.class.getResource("computer.png")); //持有其他類DataView dataview = new DataView(this); //主界麵類(顯示監控數據主面板) /** * 主方法* @param args // */ public static void main(String[] args) { new Client().launchFrame(); } /** * 顯示主界面*/ public void launchFrame() { this.setBounds(LOC_X, LOC_Y, WIDTH, HEIGHT); //設定程序在桌面出現的位置this.setTitle("CDIO工程項目"); //設置程序標題this.setIconImage(icon); this.setBackground(Color.white); //設置背景色this.addWindowListener(new WindowAdapter() { //添加對窗口狀態的監聽public void windowClosing(WindowEvent arg0) { //當窗口關閉時System.exit(0); //退出程序} }); this.addKeyListener(new KeyMonitor()); //添加鍵盤監聽器this.setResizable(false); //窗口大小不可更改this.setVisible(true); //顯示窗口new Thread(new RepaintThread()).start(); //開啟重畫線程} /** * 畫出程序界面各組件元素*/ public void paint(Graphics g) { Color c = g.getColor(); g.setFont(new Font("微軟雅黑", Font.BOLD, 40)); g.setColor(Color.black); g.drawString("歡迎使用上位機實時監控系統", 45, 190); g.setFont(new Font("微軟雅黑", Font.ITALIC, 26)); g.setColor(Color.BLACK); g.drawString("Version:1.0 Powered By:ZhongLei", 280, 260); g.setFont(new Font("微軟雅黑", Font.BOLD, 30)); g.setColor(color); g.drawString("――――點擊Enter鍵進入主界面――――", 100, 480); //使文字"――――點擊Enter鍵進入主界面――――" 黑白閃爍if (color == Color.WHITE) color = Color.black; else if (color == color.BLACK) color = Color.white; } /** * 雙緩衝方式重畫界面各元素組件*/ public void update(Graphics g) { if (offScreen == null) offScreen = this.createImage(WIDTH, HEIGHT); Graphics gOffScreen = offScreen.getGraphics(); Color c = gOffScreen.getColor(); gOffScreen.setColor(Color.white); gOffScreen.fillRect(0, 0, WIDTH, HEIGHT); //重畫背景畫布this.paint(gOffScreen); //重畫界面元素gOffScreen.setColor(c); g.drawImage(offScreen, 0, 0, null); //將新畫好的畫布“貼”在原畫布上} /* * 內部類形式實現對鍵盤事件的監聽*/ private class KeyMonitor extends KeyAdapter { public void keyReleased(KeyEvent e) { int keyCode = e.getKeyCode(); if (keyCode == KeyEvent.VK_ENTER) { //當監聽到用戶敲擊鍵盤enter鍵後執行下面的操作setVisible(false); //隱去歡迎界面dataview.setVisible(true); //顯示監測界面dataview.dataFrame(); //初始化監測界面} } } /* * 重畫線程(每隔250毫秒重畫一次) */ private class RepaintThread implements Runnable { public void run() { while(true) { repaint(); try { Thread.sleep(250); } catch (InterruptedException e) { //重畫線程出錯拋出異常時創建一個Dialog並顯示異常詳細信息String err = ExceptionWriter.getErrorInfoFromException(e); JOptionPane.showMessageDialog(null, err, "錯誤", JOptionPane.INFORMATION_MESSAGE); System.exit(0); } } } } }運行截圖:
注:實際運行過程中最下面的“點擊Enter鍵進入主界面”有一個一閃一閃的效果(是通過每隔一段時間重畫一次界面,讓這句話以白黑兩色反復交替出現實現的),雙緩衝方式利於解決重畫時界面閃爍的問題(如果不使用雙緩衝方式的話相當於每次重畫時是在舊界面上一點一點畫上新東西,而雙緩衝實質上是通過先在內存中直接畫好一張新界面圖,然後一次性直接用新界面覆蓋掉舊界面)
DataView.java代碼如下:(該類用於實時顯示串口數據)
簡單說明:
硬件設備每隔一段時間通過串口發送一次數據到計算機,該串口工具成功連接至硬件設備並添加監聽後,會在每次接收到數據時解析數據並更新界面;
你在使用時很可能需求跟我不一樣,該類僅供參考,實際使用中你很可能需要重新製作數據顯示界面以及數據解析方式
package serialPort;import java.awt.Button;import java.awt.Choice;import java.awt.Color;import java.awt.Font;import java.awt.Frame;import java.awt.Graphics;import java.awt.Image;import java.awt.Label;import java.awt.Toolkit;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import java.awt.event.WindowAdapter;import java.awt.event.WindowEvent;import java.util.List;import java.util.TooManyListenersException;import javax.swing.JOptionPane;import gnu.io.SerialPort;import gnu.io.SerialPortEvent;import gnu.io.SerialPortEventListener;import serialException.*;/** * 監測數據顯示類* @author Zhong * */public class DataView extends Frame { /** * */ private static final long serialVersionUID = 1L; Client client = null; private List<String> commList = null; //保存可用端口號private SerialPort serialPort = null; //保存串口對象private Font font = new Font("微軟雅黑", Font.BOLD, 25); private Label tem = new Label("暫無數據", Label.CENTER); //溫度private Label hum = new Label("暫無數據", Label.CENTER); //濕度private Label pa = new Label("暫無數據", Label.CENTER); //壓強private Label rain = new Label("暫無數據", Label.CENTER); //雨量private Label win_sp = new Label("暫無數據", Label.CENTER); //風速private Label win_dir = new Label("暫無數據", Label.CENTER); //風向private Choice commChoice = new Choice(); //串口選擇(下拉框) private Choice bpsChoice = new Choice(); //波特率選擇private Button openSerialButton = new Button("打開串口"); Image offScreen = null; //重畫時的畫布//設置window的icon Toolkit toolKit = getToolkit(); Image icon = toolKit.getImage(DataView.class.getResource("computer.png")); /** * 類的構造方法* @param client */ public DataView(Client client) { this.client = client; commList = SerialTool.findPort(); //程序初始化時就掃描一次有效串口} /** * 主菜單窗口顯示; * 添加Label、按鈕、下拉條及相關事件監聽; */ public void dataFrame() { this.setBounds(client.LOC_X, client.LOC_Y, client.WIDTH, client.HEIGHT); this.setTitle("CDIO工程項目"); this.setIconImage(icon); this.setBackground(Color.white); this.setLayout(null); this.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent arg0) { if (serialPort != null) { //程序退出時關閉串口釋放資源SerialTool.closePort(serialPort); } System.exit(0); } }); tem.setBounds(140, 103, 225, 50); tem.setBackground(Color.black); tem.setFont(font); tem.setForeground(Color.white); add(tem); hum.setBounds(520, 103, 225, 50); hum.setBackground(Color.black); hum.setFont(font); hum.setForeground(Color.white); add(hum); pa.setBounds(140, 193, 225, 50); pa.setBackground(Color.black); pa.setFont(font); pa.setForeground(Color.white); add(pa); rain.setBounds(520, 193, 225, 50); rain.setBackground(Color.black); rain.setFont(font); rain.setForeground(Color.white); add(rain); win_sp.setBounds(140, 283, 225, 50); win_sp.setBackground(Color.black); win_sp.setFont(font); win_sp.setForeground(Color.white); add(win_sp); win_dir.setBounds(520, 283, 225, 50); win_dir.setBackground(Color.black); win_dir.setFont(font); win_dir.setForeground(Color.white); add(win_dir); //添加串口選擇選項commChoice.setBounds(160, 397, 200, 200); //檢查是否有可用串口,有則加入選項中if (commList == null || commList.size()<1) { JOptionPane.showMessageDialog(null, "沒有搜索到有效串口! ", "錯誤", JOptionPane.INFORMATION_MESSAGE); } else { for (String s : commList) { commChoice.add(s); } } add(commChoice); //添加波特率選項bpsChoice.setBounds(526, 396, 200, 200); bpsChoice.add("1200"); bpsChoice.add("2400"); bpsChoice.add("4800"); bpsChoice.add("9600"); bpsChoice.add("14400"); bpsChoice.add("19200"); bpsChoice.add("115200"); add(bpsChoice); //添加打開串口按鈕openSerialButton.setBounds(250, 490, 300, 50); openSerialButton.setBackground(Color.lightGray); openSerialButton.setFont(new Font("微軟雅黑", Font.BOLD, 20)); openSerialButton.setForeground(Color.darkGray); add(openSerialButton); //添加打開串口按鈕的事件監聽openSerialButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { //獲取串口名稱String commName = commChoice.getSelectedItem(); //獲取波特率String bpsStr = bpsChoice.getSelectedItem(); //檢查串口名稱是否獲取正確if (commName == null || commName.equals("")) { JOptionPane.showMessageDialog(null, "沒有搜索到有效串口!", "錯誤", JOptionPane.INFORMATION_MESSAGE); } else { //檢查波特率是否獲取正確if (bpsStr == null || bpsStr.equals("")) { JOptionPane.showMessageDialog(null, "波特率獲取錯誤! ", "錯誤", JOptionPane.INFORMATION_MESSAGE); } else { //串口名、波特率均獲取正確時int bps = Integer.parseInt(bpsStr); try { //獲取指定端口名及波特率的串口對象serialPort = SerialTool.openPort(commName, bps); //在該串口對像上添加監聽器SerialTool.addListener(serialPort, new SerialListener()); //監聽成功進行提示JOptionPane.showMessageDialog(null, "監聽成功,稍後將顯示監測數據!", "提示", JOptionPane.INFORMATION_MESSAGE); } catch (SerialPortParameterFailure | NotASerialPort | NoSuchPort | PortInUse | TooManyListeners e1) { //發生錯誤時使用一個Dialog提示具體的錯誤信息JOptionPane.showMessageDialog(null, e1, "錯誤", JOptionPane.INFORMATION_MESSAGE); } } } } }); this.setResizable(false); new Thread(new RepaintThread()).start(); //啟動重畫線程} /** * 畫出主界面組件元素*/ public void paint(Graphics g) { Color c = g.getColor(); g.setColor(Color.black); g.setFont(new Font("微軟雅黑", Font.BOLD, 25)); g.drawString(" 溫度: ", 45, 130); g.setColor(Color.black); g.setFont(new Font("微軟雅黑", Font.BOLD, 25)); g.drawString(" 濕度: ", 425, 130); g.setColor(Color.black); g.setFont(new Font("微軟雅黑", Font.BOLD, 25)); g.drawString(" 壓強: ", 45, 220); g.setColor(Color.black); g.setFont(new Font("微軟雅黑", Font.BOLD, 25)); g.drawString(" 雨量: ", 425, 220); g.setColor(Color.black); g.setFont(new Font("微軟雅黑", Font.BOLD, 25)); g.drawString(" 風速: ", 45, 310); g.setColor(Color.black); g.setFont(new Font("微軟雅黑", Font.BOLD, 25)); g.drawString(" 風向: ", 425, 310); g.setColor(Color.gray); g.setFont(new Font("微軟雅黑", Font.BOLD, 20)); g.drawString(" 串口選擇: ", 45, 410); g.setColor(Color.gray); g.setFont(new Font("微軟雅黑", Font.BOLD, 20)); g.drawString(" 波特率: ", 425, 410); } /** * 雙緩衝方式重畫界面各元素組件*/ public void update(Graphics g) { if (offScreen == null) offScreen = this.createImage(Client.WIDTH, Client.HEIGHT); Graphics gOffScreen = offScreen.getGraphics(); Color c = gOffScreen.getColor(); gOffScreen.setColor(Color.white); gOffScreen.fillRect(0, 0, Client.WIDTH, Client.HEIGHT); //重畫背景畫布this.paint(gOffScreen); //重畫界面元素gOffScreen.setColor(c); g.drawImage(offScreen, 0, 0, null); //將新畫好的畫布“貼”在原畫布上} /* * 重畫線程(每隔30毫秒重畫一次) */ private class RepaintThread implements Runnable { public void run() { while(true) { //調用重畫方法repaint(); //掃描可用串口commList = SerialTool.findPort(); if (commList != null && commList.size()>0) { //添加新掃描到的可用串口for (String s : commList) { //該串口名是否已存在,初始默認為不存在(在commList裡存在但在commChoice裡不存在,則新添加) boolean commExist = false; for (int i=0; i<commChoice.getItemCount(); i++) { if (s.equals(commChoice.getItem(i))) { //當前掃描到的串口名已經在初始掃描時存在commExist = true; break; } } if (commExist) { //當前掃描到的串口名已經在初始掃描時存在,直接進入下一次循環continue; } else { //若不存在則添加新串口名至可用串口下拉列表commChoice.add(s); } } //移除已經不可用的串口for (int i=0; i<commChoice.getItemCount(); i++) { //該串口是否已失效,初始默認為已經失效(在commChoice裡存在但在commList裡不存在,則已經失效) boolean commNotExist = true; for (String s : commList) { if (s.equals(commChoice.getItem(i))) { commNotExist = false; break; } } if (commNotExist) { //System.out.println("remove" + commChoice.getItem(i)); commChoice.remove(i); } else { continue; } } } else { //如果掃描到的commList為空,則移除所有已有串口commChoice.removeAll(); } try { Thread.sleep(30); } catch (InterruptedException e) { String err = ExceptionWriter.getErrorInfoFromException(e); JOptionPane.showMessageDialog(null, err, "錯誤", JOptionPane.INFORMATION_MESSAGE); System.exit(0); } } } } /** * 以內部類形式創建一個串口監聽類* @author zhong * */ private class SerialListener implements SerialPortEventListener { /** * 處理監控到的串口事件*/ public void serialEvent(SerialPortEvent serialPortEvent) { switch (serialPortEvent.getEventType()) { case SerialPortEvent.BI: // 10 通訊中斷JOptionPane.showMessageDialog(null, "與串口設備通訊中斷", "錯誤", JOptionPane.INFORMATION_MESSAGE); break; case SerialPortEvent.OE: // 7 溢位(溢出)錯誤case SerialPortEvent.FE: // 9 幀錯誤case SerialPortEvent.PE: // 8 奇偶校驗錯誤case SerialPortEvent.CD: // 6 載波檢測case SerialPortEvent.CTS: // 3 清除待發送數據case SerialPortEvent.DSR: // 4 待發送數據準備好了case SerialPortEvent.RI: // 5 振鈴指示case SerialPortEvent.OUTPUT_BUFFER_EMPTY: // 2 輸出緩衝區已清空break; case SerialPortEvent.DATA_AVAILABLE: // 1 串口存在可用數據//System.out.println("found data"); byte[] data = null; try { if (serialPort == null) { JOptionPane.showMessageDialog(null, "串口對象為空!監聽失敗! ", "錯誤", JOptionPane.INFORMATION_MESSAGE); } else { data = SerialTool.readFromPort(serialPort); //讀取數據,存入字節數組//System.out.println(new String(data)); // 自定義解析過程,你在實際使用過程中可以按照自己的需求在接收到數據後對數據進行解析if (data == null || data.length < 1) { //檢查數據是否讀取正確JOptionPane.showMessageDialog(null, "讀取數據過程中未獲取到有效數據!請檢查設備或程序!", "錯誤", JOptionPane.INFORMATION_MESSAGE); System.exit(0); } else { String dataOriginal = new String(data); //將字節數組數據轉換位為保存了原始數據的字符串String dataValid = ""; //有效數據(用來保存原始數據字符串去除最開頭*號以後的字符串) String[] elements = null; //用來保存按空格拆分原始字符串後得到的字符串數組//解析數據if (dataOriginal.charAt(0) == '*') { //當數據的第一個字符是*號時表示數據接收完成,開始解析dataValid = dataOriginal.substring(1); elements = dataValid.split(" "); if (elements == null || elements.length < 1) { //檢查數據是否解析正確JOptionPane.showMessageDialog(null, "數據解析過程出錯,請檢查設備或程序!", "錯誤", JOptionPane.INFORMATION_MESSAGE); System.exit(0); } else { try { //更新界面Label值/*for (int i=0; i<elements.length; i++) { System.out.println(elements[i]); }*/ //System.out.println("win_dir: " + elements[5]); tem.setText(elements[0] + " ℃"); hum.setText(elements[1] + " %"); pa.setText(elements[2] + " hPa"); rain.setText(elements[3] + " mm"); win_sp.setText(elements[4] + " m/s"); win_dir.setText(elements[5] + " °"); } catch (ArrayIndexOutOfBoundsException e) { JOptionPane.showMessageDialog(null, "數據解析過程出錯,更新界面數據失敗!請檢查設備或程序! ", "錯誤", JOptionPane.INFORMATION_MESSAGE); System.exit(0); } } } } } } catch (ReadDataFromSerialPortFailure | SerialPortInputStreamCloseFailure e) { JOptionPane.showMessageDialog(null, e, "錯誤", JOptionPane.INFORMATION_MESSAGE); System.exit(0); //發生讀取錯誤時顯示錯誤信息後退出系統} break; } } } }運行截圖:
整個項目源碼打包下載:http://xiazai.VeVB.COm/201612/yuanma/javaserialMonitor(VeVB.COm).rar
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。