天天看點

管道流量采集實驗指導書

管道流量采集實驗指導書

      項目較大,是我畢業設計的成果之一,完成整個項目需要的時間大概為8小時(1天,非常熟悉MFC程式設計),24小時(3天,熟悉MFC程式設計),48小時(6天,較熟悉),2周(隻懂得文法)

  • ​​管道流量采集實驗指導書​​
  • ​​一、 實驗目的​​
  • ​​二、 實驗環境及裝置​​
  • ​​三、 裝置簡介​​
  • ​​3.1 RS-485現場總線​​
  • ​​3.2 MODBUS協定​​
  • ​​3.3 水倉系統​​
  • ​​3.4 KJ402-F1礦用本安型水文檢測分站​​
  • ​​3.5 GLC30/50礦用磁漩渦流量傳感器​​
  • ​​3.6 FD15直流穩壓電源​​
  • ​​四、 實驗原理​​
  • ​​4.1 發送幀​​
  • ​​4.2 接收幀​​
  • ​​五、 實驗步驟​​
  • ​​5.1系統架構建構​​
  • ​​5.2外部插件導入​​
  • ​​5.2.1序列槽插件導入​​
  • ​​5.2.2折線圖插件導入​​
  • ​​5.3對話框設計​​
  • ​​5.3.1檢視參數​​
  • ​​5.3.2曆史流量​​
  • ​​5.3.3流量預測​​
  • ​​5.3.4設定參數​​
  • ​​5.3.5統計表​​
  • ​​5.3.6協定測試​​
  • ​​5.3.7原理講解​​
  • ​​5.3.8主對話框​​
  • ​​5.4單例類​​
  • ​​5.5系統資料庫讀寫​​
  • ​​5.6折線圖、統計表、資料庫bean類​​
  • ​​5.7對話框功能實作​​
  • ​​5.7.1統計表​​
  • ​​5.7.2流量預測​​
  • ​​5.7.3曆史流量折線圖​​
  • ​​5.7.4原理講解​​
  • ​​5.7.5檢視參數​​
  • ​​5.7.6設定參數​​
  • ​​5.7.7協定測試​​
  • ​​5.7.8主對話框(實時流量)​​
  • ​​5.8資料庫額外操作​​
  • ​​5.9常見錯誤​​
  • ​​5.10替換标題欄圖示​​
  • ​​5.11打包​​
  • ​​六、 總結​​

一、 實驗目的

1.1 了解485現場總線;

1.2 了解Visual Studio 2015編譯環境;

1.3 了解磁漩渦流量傳感器測量原理;

1.4 掌握MODBUS協定

1.5 掌握C++中MFC類庫程式設計;

1.6 掌握MFC程式打包;

1.7 掌握MySQL資料庫;

1.8 掌握CRC校驗碼計算;

1.9 掌握序列槽程式設計。

二、 實驗環境及裝置

      Windows系統、MySQL資料庫、Visual Studio 2015、水倉系統、KJ402-F1礦用本安型水文檢測分站、GLC30/50礦用磁漩渦流量傳感器、FD15直流穩壓電源。

三、 裝置簡介

3.1 RS-485現場總線

      電子工業協會于 1983 年在 RS-422 工業總線标準的基礎之上,制訂并釋出了 RS-485 總線工業标準。RS-485 工業總線标準能夠有效支援多個分節點和通信距離遠,并且對于資訊的接收靈敏度較高等特性。在工業通信網絡中,RS-485 總線一般主要用于與外部各種工業裝置進行資訊傳輸和資料交換,所具備的對于噪聲的有效抑制能力、高效的資料傳輸速率與良好的資料傳輸的可靠性能以及可擴充的通信電纜的長度是其他的許多工業通信标準所無法比拟的。是以,RS-485 總線在諸多個領域得到了廣泛的應用,比如在工業控制領域、交通的自動化控制領域和現場總線通信網絡等。

      RS-485 總線标準規定了總線接口的電氣特性标準即對于 2 個邏輯狀态的定義:正電平在+2V~+6V 之間,表示一個邏輯狀态;負電平在-2V~-6V 之間,則表示另一個邏輯狀态;數字信号采用差分傳輸方式,能夠有效減少噪聲信号的幹擾。

3.2 MODBUS協定

      MODBUS通信協定是在1978年由美國的可程式設計控制器供應商莫迪康公司進行制定的一種工業現場總線控制器的通信網絡協定。由于MODBUS通信協定具有高度的自由開放性以及使用者可以快速熟悉的掌握通信協定,使得變得簡單且易學,進而使得它比很多其他受商業利益驅使的工業控制通信協定标準取得更快的發展,是以普遍受到大量的第三方産品設計廠商、各種各樣的終端使用者以及大量的系統晶片內建商的廣泛支援,并且被應用于智能化儀表通信網絡和現場總線控制技術等領域。

      MODBUS通信協定是可以認為是屬于在應用層的工業控制技術的通信協定,在實體層方面将可以遵循RS-485總線标準或者光纖等資訊傳輸線路,将會主要應用于主機和從機以及遠端通信控制子產品三者之間進行的網絡資訊傳輸。現在在世界各地已經有大量釆用MODBUS通信協定的工業現場總線技術和裝置以及各種工業通信網絡的控制子產品應用于國内外的各種工業控制現場。

      通過MODBUS通信協定建構各種現場總線網絡,某一個控制器可以與其他各種控制器之間進行互相通信或者控制器的資料資訊經由一個通信網絡與其它在網絡中互連的通信裝置之間可以實作通信。是以,MODBUS通信協定通過逐漸發展已經成為一種通用的工業通信标準。

      标準的MODBUS口是使用RS-232C相容串行接口,它定義了連接配接口的針腳、電纜、信号位、傳輸波特率、奇偶校驗等,控制器能直接或經由Modem組網。

控制器通信使用主/從技術,即僅主裝置能初始化傳輸(查詢),其它裝置(從裝置)根據主裝置查詢提供的資料做出響應。無論是主裝置查詢還是從裝置響應,每個MODBUS幀都包括位址域、功能域、資料域、錯誤檢測域。該協定分RTU和ASCII兩種傳輸模式,相對于ASC1I模式,RTU模式表達相同的資訊需要較少的位數,且在相同通訊速率下具有更大的資料流量,是以通常情況下,一般工業智能儀器儀表都是采用RTU模式。

      在RTU模式下,資訊幀以3.5個字元的靜态時間間隔為起始符和結束符,在資訊幀格式中均用T1-T2-T3-T4表示。每兩個字元之間發送或者接收的時間間隔不能超過1.5倍字元傳輸時間。如果兩個字元時間問隔超過了3.5倍的字元傳輸時間,協定就認為一幀資料已經接收,新的一幀資料傳輸開始。位址域用來寫入從裝置的位址。功能域用來寫入主裝置要求從裝置執行的功能代碼,如03或06。資料域用來寫入主裝置告之從裝置的一些額外的資訊,如連續的寄存器的起始位址、寄存器的數量等。CRC校驗是RTU模式下的錯誤校驗方式。資料幀中的資料采用十六進制數。如表1所示。

表1 RTU模式下的資訊幀格式 幀起始地| 址域功 | 能碼域 | 資料域 | CRC校驗域 | 結束 :—-| :——- |:——-|:———|:———–|:—— T1-T2-T3-T4|8bits|8bits|n * 8bits|16bits|T1-T2-T3-T4 T1-T2-T3-T4|1B|1B|nB|2B|T1-T2-T3-T4       根據MODBUS協定規定,不同功能碼對應資料域格式不盡相同,常用的功能碼有1、2、3、4、5、6、15和16,分别表示讀線圈、讀輸入狀态、讀保持寄存器、讀輸入寄存器、寫單個線圈、寫單個輸入狀态、寫多個線圈,寫多個保持寄存器。

3.3 水倉系統

      水倉系統由大水倉、蓄水池、應急水泵、變頻器水泵、放水閥門、明渠、暗渠、水舌組成;在水倉系統設定有管道流量傳感器、明渠水位傳感器、水舌溫度水位傳感器、水倉水位溫度傳感器、蓄水池水位溫度傳感器、管道壓力溫度傳感器。水倉系統的工作方式:首先打開放水閥門,水從大水倉通過放水閥門流入明渠,經過水舌流入暗渠,然後彙集于蓄水池,最後通過變頻器水泵把水從蓄水池抽入大水倉,完成整個循環。在使用過程中,需要注意蓄水池水位需要保持一定的水位,否則水泵中進入空氣,無法工作;同時也要注意蓄水池中的水不能溢出。

3.4 KJ402-F1礦用本安型水文檢測分站

      KJ402-F1 礦用本安型水文監測分站是一個資料監測控制分站,具有4 路模拟量采集和4 路數字量采集接口、1 路485 對上通訊接口、2 路對下通訊接口和一個液晶顯示屏。液晶顯示屏顯示分站挂接的傳感器采集到的各種資料。

      分站集電子技術、計算機技術與資料通信技術于一體,具有測量精度高、實時性強、運作穩定和自動化程度高等特點,其體積小、重量輕、安裝友善,能夠長期在無人值守的條件下自動對各類水文等進行監測與控制。

  • 分站具有與傳輸接口雙向通訊及工作狀态訓示和顯示功能。
  • 分站具有模拟量采集和數字量采集功能以及開關量控制功能。
  • 初始化參數通過上位機軟體設定。
  • 分站具有自診斷和故障訓示功能。
  • 分站具有外接備用電源

3.5 GLC30/50礦用磁漩渦流量傳感器

      GLC30/50 礦用磁旋渦流量傳感器(以下簡稱傳感器)是采用最先進磁旋渦數字檢測技術開發出的新型智能流量傳感器。該傳感器是将雙檢測抗震渦街傳感器和電磁傳感器技術結合為一體的流量測量儀表。傳感器采用先進的單片機技術和微功耗高新技術,具有以下特點:耐腐蝕性能好、結構簡單、使用壽命長、性能穩定,能識别流量與振動資料,消除所有幹擾信号,具有良好的抗震,抗幹擾能力,可耐 1g 振動(壓電式耐振≤0.2g),使計量性能穩定、可靠;下限流量低,量程比大,測量準确、精度高。

      GLC30/50 礦用磁旋渦流量傳感器是根據法拉第電磁感應原裡研制的,在表殼底部放置一個磁鋼産生強磁場,磁力線穿過管道,當媒體流過傳感器強磁場時,切割磁力線感應出脈動的磁動勢,用電極拾取此電信号,在一定的流速範圍内其頻率正比于流量。

管道流量采集實驗指導書

圖1磁漩渦流量傳感器原理圖

1—磁鋼 2—電極 3—表殼 4—電極壓緊螺絲

5—信号插頭 6—顯示儀 7—功能鍵 8—接地端子 9—信号輸出接線口

3.6 FD15直流穩壓電源

      FD15 專用直流穩壓采用先進的補償式技術設計制造,适應用于礦山、鄉鎮等地區電網電壓波動較大的工作環境,能自動保持輸出電壓的穩定,以保證用電裝置的正常運作。輸入電壓範圍寬,輸出電壓穩定。具有過流保護,短路保護,過壓保護,增強了電源的安全性與可靠性。

四、 實驗原理

4.1 發送幀

管道流量采集實驗指導書

圖2發送幀解析圖

  • 長度:長度是除去位址碼的幀的長度,最後以16進制儲存。
  • 屬性:00表示查詢單條資料,分站隻需要回複一條資料即可,回複的資料由站号和通道号指定
  • 站号:指定回複的分站裝置
  • 通道号:指定回複的傳感器測量值
  • 時間BCD碼:用4位二進制數來表示1位十進制數中的0~9這10個數位。是一種二進制的數字編碼形式,用二進制編碼的十進制代碼。通俗的說就是把十進制數字看作16進制數字,比如10進制的18轉換為16進制為12,但是使用BCD碼16進制還是18。
  • CRC校驗碼:在CRC計算時隻用8個資料位,起始位及停止位,如有奇偶校驗位也包括奇偶校驗位,都不參與CRC計算。

    CRC計算方法是:

    1、加載一值為0XFFFF的16位寄存器,此寄存器為CRC寄存器。

    2、把第一個8位二進制資料(即通訊資訊幀的第一個位元組)與16位的CRC寄存器的相異或,異或的結果仍存放于該CRC寄存器中。

    3、把CRC寄存器的内容右移一位,用0填補最高位,并檢測移出位是0還是1。

    4、如果移出位為零,則重複第三步(再次右移一位);如果移出位為1,CRC寄存器與0XA001進行異或。

    5、重複步驟3和4,直到右移8次,這樣整個8位資料全部進行了處理。

    6、重複步驟2和5,進行通訊資訊幀下一個位元組的處理。

    7、将該通訊資訊幀所有位元組按上述步驟計算完成後,得到的16位CRC寄存器的高、低位元組進行交換

    8、最後得到的CRC寄存器内容即為:CRC校驗碼。

4.2 接收幀

管道流量采集實驗指導書

圖3接收幀解析圖

  • 标志:FF表示高電平為1
  • 長度:長度是除去位址碼的幀的長度,最後以16進制儲存。
  • 屬性:發送幀的屬性碼加0X80
  • 站号:回複的分站裝置
  • 通道号:回複的傳感器測量值
  • 資料1:3個位元組
  • 資料2:3個位元組
  • 資料3:3個位元組
  • 随機位:兩次查詢的時間如果較短,那麼回複的内容可能完全相同,此時回複資料幀的接收會

    把兩個回複幀誤認為是一個回複幀,這樣就出現僞丢幀,是以,随機位解決這種情況,防止在短時間内回複的資料幀完全相同,而造成僞丢幀。

      資料有三個是因為分站裝置需要适配所有的傳感器,磁漩渦流量傳感器隻有一個資料,是以需要資料1即可,但是其他的傳感器比如溫度壓力傳感器需要2個資料,而明渠中的水位有三個資料(水位、泥位、溫度),是以資料位有三個,如果無資料,預設用0來補全。

五、 實驗步驟

5.1系統架構建構

首先建立一個基于對話框的空工程,不需要關于框和系統菜單。

管道流量采集實驗指導書

圖4工程預設圖

VS2015會自動生成基于工程名字的App和Dlg檔案。

管道流量采集實驗指導書

圖5工程自動生成檔案圖

接下來建立額外的7個對話框,對話框的名字和ID如表所示。

表2對話框和ID映射表

幀起始地 址域功
流量統計分析表 IDD_EXCEL
流量預測 IDD_FORECAST
曆史流量資料 IDD_HISTORY
原理講解 IDD_INTERPRET
檢視參數 IDD_LOOKDATA
設定參數 IDD_SETDATA
協定測試 IDD_TEXT

為添加的對話框綁定各自的類,右鍵對話框->【添加類】->【輸入類名】->【确定】。

管道流量采集實驗指導書

圖6建立的類

5.2外部插件導入

5.2.1序列槽插件導入

      系統中需要使用序列槽程式設計,是以需要使用到序列槽插件。首先在網際網路上下載下傳序列槽插件的ocx檔案,然後把ocx檔案放到系統盤的System32檔案夾下;最後使用管理者身份打開CMD,在CMD中切換到System32檔案夾下,運作指令:Regsvr32 序列槽插件的ocx名字.ocx。

      CMD會提示注冊成功,此時可以在VS2015中【工具】->【選擇工具箱】->【COM元件】->【浏覽】->找到序列槽插件的ocx檔案->【确定】。如果插件導入成功,可以在VS2015的工具箱中找到,或者可以在對話框中畫出一個電話類似的圖示。

5.2.2折線圖插件導入

      系統中畫折線圖需要用到TeeChart的一個插件。首先在網際網路上下載下傳TeeChart插件的ocx檔案,然後注冊插件,并導入到VS2015中;導入成功後,VS2015的工具箱中不會顯示插件,但是可以畫出一個折線圖的樣子,此時導入成功。

5.3對話框設計

其中對話框的控件和屬性如下:

5.3.1檢視參數

表3檢視參數控件表

類型 ID辨別符 屬性
對話框 IDD_LOOKDATA Caption:檢視參數;Style:Popup;System Menu:false;
按鈕 IDOK Caption:确定;
靜态文本框 IDC_STATIC Align Text:Left;Caption:伺服器IP位址:;
按鈕 IDCANCEL Caption:取消;
組合框 IDC_STATIC Caption:資料庫參數;
組合框 IDC_STATIC Caption:通信參數;
靜态文本框 IDC_STATIC Align Text:Left;Caption:伺服器端口号:;
靜态文本框 IDC_STATIC Align Text:Left;Caption:登陸使用者名:;
靜态文本框 IDC_STATIC Align Text:Left;Caption:登陸密碼:;
靜态文本框 IDC_STATIC Align Text:Left;Caption:連接配接資料庫名:;
靜态文本框 IDC_STATIC Align Text:Left;Caption:COM端口:;
靜态文本框 IDC_STATIC Align Text:Left;Caption:波特率:;
靜态文本框 IDC_STATIC Align Text:Left;Caption:校驗位:;
靜态文本框 IDC_STATIC Align Text:Left;Caption:資料位:;
靜态文本框 IDC_STATIC Align Text:Left;Caption:停止位:;
靜态文本框 IDC_STATIC Align Text:Left;Caption:自動重新整理時間:;
靜态文本框 IDC_L_IPADD Align Text:Center;Caption:;
靜态文本框 IDC_L_COM Align Text:Center;Caption:;
靜态文本框 IDC_L_PASSWORD Align Text:Center;Caption:;
靜态文本框 IDC_L_USERNAME Align Text:Center;Caption:;
靜态文本框 IDC_L_DATABASE Align Text:Center;Caption:;
靜态文本框 IDC_L_COMM Align Text:Center;Caption:;
靜态文本框 IDC_L_BOTELV Align Text:Center;Caption:;
靜态文本框 IDC_L_JIAOYAN Align Text:Center;Caption:;
靜态文本框 IDC_L_SHUJU Align Text:Center;Caption:;
靜态文本框 IDC_L_TINGZHI Align Text:Center;Caption:;
靜态文本框 IDC_L_TIME Align Text:Center;Caption:;
管道流量采集實驗指導書

圖7檢視參數效果圖

圖中紅框就是有各自ID的靜态文本框。

5.3.2曆史流量

表4曆史流量折線圖控件表

類型 ID辨別符 屬性
對話框 IDD_HISTORY Caption:曆史流量資料;Style:Popup;System Menu:false;
靜态文本框 IDC_STATIC Align Text:Left;Caption:選擇日期:;
時間 IDC_H_DATE Format:短日期;
折線圖 IDC_H_TCHART
按鈕 IDOK Caption:确定;
靜态文本框 IDC_H_TITLE Align Text:Center;Caption:;
按鈕 IDCANCEL Caption:取消;

表5曆史流量折線圖控件變量映射表

控件ID 類别 變量類型 變量名
IDC_DATAVIEW Value Cstring m_Dataview
IDC_H_DATE Control CDateTimeCtrl c_HDate
IDC_H_TCHART Control CTchart1 c_HTChart

折線圖插件設定:

輕按兩下插件會彈出設定對話框:

管道流量采集實驗指導書

圖8折線圖插件設定圖

      其中General調節檢視折線圖時滑鼠的樣式,Axis設定坐标系,Titles設定折線圖示題,第一行的Series菜單設定折線圖連線的樣式。

管道流量采集實驗指導書

圖9曆史流量對話框效果圖

5.3.3流量預測

表6流量預測控件表

類型 ID辨別符 屬性
對話框 IDD_FORECAST Caption:流量預測;Style:Popup;System Menu:false;
靜态文本框 IDC_STATIC Align Text:Left;Caption:預測結果:;
輸入框 IDC_F_RESULT Align Text:Left;
輸入框 IDC_F_REASON Align Text:Left;
按鈕 IDOK Caption:确定;
靜态文本框 IDC_STATIC Align Text:Left;Caption:預測理由:;
管道流量采集實驗指導書

圖10流量預測對話框效果圖

5.3.4設定參數

表7設定參數控件表

類型 ID辨別符 屬性
對話框 IDD_LOOKDATA Caption:檢視參數;Style:Popup;System Menu:false;
按鈕 IDOK Caption:确定;
靜态文本框 IDC_STATIC Align Text:Left;Caption:伺服器IP位址:;
按鈕 IDCANCEL Caption:取消;
組合框 IDC_STATIC Caption:資料庫參數;
組合框 IDC_STATIC Caption:通信參數;
靜态文本框 IDC_STATIC Align Text:Left;Caption:伺服器端口号:;
靜态文本框 IDC_STATIC Align Text:Left;Caption:登陸使用者名:;
靜态文本框 IDC_STATIC Align Text:Left;Caption:登陸密碼:;
靜态文本框 IDC_STATIC Align Text:Left;Caption:連接配接資料庫名:;
靜态文本框 IDC_STATIC Align Text:Left;Caption:COM端口:;
靜态文本框 IDC_STATIC Align Text:Left;Caption:波特率:;
靜态文本框 IDC_STATIC Align Text:Left;Caption:校驗位:;
靜态文本框 IDC_STATIC Align Text:Left;Caption:資料位:;
靜态文本框 IDC_STATIC Align Text:Left;Caption:停止位:;
靜态文本框 IDC_STATIC Align Text:Left;Caption:自動重新整理時間:;
IP位址輸入框 IDC_S_IPADD
輸入框 IDC_S_COM Align Text:Left;
輸入框 IDC_S_USERNAME Align Text:Left;
輸入框 IDC_S_PASSWORD Align Text:Left;Password:true;
輸入框 IDC_S_DATABASE Align Text:Left;
下拉清單 IDC_S_COMM Type:Dropdown;
下拉清單 IDC_S_BOTELV Type:Dropdown;
下拉清單 IDC_S_JIAO Type:Dropdown;
下拉清單 IDC_S_SHUJU Type:Dropdown;
下拉清單 IDC_S_TING Type:Dropdown;
輸入框 IDC_S_TIME Align Text:Left;
單選按鈕 IDC_S_HOUR Caption:小時(h);
單選按鈕 IDC_S_MINTE Caption:分鐘(m);
單選按鈕 IDC_S_SECEND Caption:秒(s);

表8設定參數控件變量映射表

控件ID 類别 變量類型 變量名
IDC_S_IPADD Value DWORD m_SetIpadd
IDC_S_COMM Control CComboBox c_Comm
IDC_S_BOTELV Control CComboBox c_Botelv
IDC_S_COM Value Cstring m_SetCom
IDC_S_USERNAME Value Cstring m_SetUsername
IDC_S_PASSWORD Value Cstring m_SetPassword
IDC_S_DATABASE Value Cstring m_SetDatabase
IDC_S_JIAO Control CComboBox c_Jiaoyan
IDC_S_SHUJU Control CComboBox c_Shuju
IDC_S_TING Control CComboBox c_Tingzhi
IDC_S_TIME Control CEdit c_Time
IDCANCEL Control CButton c_ButtonH
管道流量采集實驗指導書

圖11設定參數對話框效果圖

5.3.5統計表

表9統計表控件表

類型 ID辨別符 屬性
對話框 IDD_EXCEL Caption:流量統計分析表;Style:Popup;System Menu:false;
靜态文本框 IDC_E_TITLE Align Text:Center;
清單 IDC_E_LIST Alignment:Left;View:Report;
時間 IDC_E_DATE Format:短日期;
按鈕 IDOK Caption:确定;
靜态文本框 IDC_STATIC Align Text:Left;Caption:選擇日期:;
按鈕 IDCANCEL Caption:取消;

表10統計表控件變量映射表

控件ID 類别 變量類型 變量名
IDC_E_TITLE Value Cstring m_ETitle
IDC_E_LIST Control CListCtrl c_EList
IDC_E_DATE Control CDateTimeCtrl c_EDate
管道流量采集實驗指導書

圖12統計表對話框效果圖

5.3.6協定測試

表11協定測試控件表

類型 ID辨別符 屬性
對話框 IDD_TEXT Caption:協定測試;Style:Popup;System Menu:false;
靜态文本框 IDC_E_TITLE Align Text:Center;
輸入框 IDC_T_INPUT Align Text:Left;
時間 IDC_T_DATA Format:短日期;
按鈕 IDOK Caption:确定;
靜态文本框 IDC_STATIC Align Text:Left;Caption:(必須以空格分割);
按鈕 IDCANCEL Caption:取消;
靜态文本框 IDC_STATIC Align Text:Left;Caption:請輸入協定幀:;
靜态文本框 IDC_STATIC Align Text:Left;Caption:測試結果:;
時間 IDC_T_TIME Format:時間;
按鈕 IDC_BUTTON1 Caption:生成協定幀;

表12協定測試控件變量映射表

控件ID 類别 變量類型 變量名
IDC_DATAVIEW Value Cstring m_Dataview
IDC_T_DATA Control CDateTimeCtrl c_Data
IDC_T_TIME Control CDateTimeCtrl c_Time
管道流量采集實驗指導書

圖13協定測試對話框效果圖

5.3.7原理講解

表13協定測試控件表

類型 ID辨別符 屬性
對話框 IDD_INTERPRET Caption:原理講解;Style:Popup;System Menu:false;
圖檔 IDC_I_PIC
按鈕 IDC_I_LAST Caption:上一頁;
按鈕 IDC_I_NEXT Caption:下一頁;

表14協定測試控件變量映射表

控件ID 類别 變量類型 變量名
IDC_I_LAST Control CButton m_InterpretLast
IDC_I_NEXT Control CButton m_InterpretNext
管道流量采集實驗指導書

圖14協定測試對話框效果圖

5.3.8主對話框

表15主對話框控件表

類型 ID辨別符 屬性
對話框 IDD_DIA_DIALOG Caption:管道流量采集;Style:Popup;System Menu:true;
靜态文本框 IDC_DATAVIEW Align Text:Center;
靜态文本框 IDC_XIEYIZHEN Align Text:Left;
折線圖 IDC_TC_DATA
序列槽 IDC_MSCOMM1

表16主對話框控件變量映射表

控件ID 類别 變量類型 變量名
IDC_DATAVIEW Value Cstring m_Dataview
IDC_TC_DATA Control CTchart1 c_TChartData
IDC_MSCOMM1 Control CMscomm1 c_Comm
管道流量采集實驗指導書

圖15主對話框效果圖

5.4單例類

      在整個系統中,有些資料必須一直保持唯一,比如設定參數在系統運作的全部時間裡必須唯一,否則就會出錯,是以,需要為必須保持唯一性的資料使用單例類來調用,這樣就可以保證唯一性。單例類是單例模式的實作,單例模式是說當一個類中隻有一個執行個體化的對象時,這個類就是單例類。單例類的寫法很簡單,首先私有化類的構造方法,并且類中含有一個靜态的本類的私有執行個體化對象,然後建立一個靜态的公有方法來擷取此執行個體,這樣,每次擷取的執行個體對象,都是類的私有化的對象。

      在系統中資料庫、對話框、設定參數都需要唯一的調用,是以設定三個單例類來儲存資料DataConfig.h:

      注意,所有的代碼在了解的基礎上自行輸入,不要拷貝,否則會出錯,其中的省略号自行按照前面的補充完整。

#pragma
#include "Configdata.h"
class CDataConfig
{
public:
    static CDataConfig * GetCDataConfig() {
        static CDataConfig * m_CDataConfig;
        if (NULL == m_CDataConfig) {
            m_CDataConfig = new CDataConfig();
        }
        return m_CDataConfig;
    }
    ~CDataConfig();
private:
    CDataConfig();
    // 連接配接資料庫伺服器的IP位址
    CString m_IPAdress;
    //連接配接資料庫伺服器的端口号
    CString m_ComNum;
    // 連接配接資料庫的使用者名,預設為root
    CString m_Username;
    // 連接配接資料庫的密碼,預設為root
    CString m_Password;
    // 連接配接資料庫的資料庫名字
    CString m_Database;
    //COM端口
    CString m_Comm;
    //波特率
    CString m_Botelv;
    //校驗碼
    CString m_Jiaoyan;
    //資料位
    CString m_Shuju;
    //停止位
    CString m_Tingzhi;
    //時間
    CString m_Time;
public:
    // 擷取資料庫伺服器的IP位址
    CString getIpAddress();
    // 擷取資料庫伺服器端口号
    CString getComnum();
    // 擷取連接配接的資料庫名字
    CString getDatabase();
    // 擷取連接配接資料庫的密碼
    CString getPassword();
    // 擷取連接配接資料庫的使用者名
    CString getUsername();
    CString getComm();
    CString getBotelv();
    CString getJiaoyan();
    CString getShuju();
    CString getTingzhi();
    CString getTime();
    void setComm(CString m_Comm);
    void setBotelv(CString m_Botelv);
    void setJiaoyan(CString m_Jiaoyan);
    void setShuju(CString m_Shuju);
    void setTingzhi(CString m_Tingzhi);
    void setTime(CString m_Time);
    // 設定資料庫伺服器端口号
    void setComnum(CString m_ComNum);
    void setDatabase(CString m_Database);
    void setIpAddress(CString m_IpAddress);
    void setPassword(CString m_Password);
    void      

DataConfig.cpp:

#include "stdafx.h"
#include "DataConfig.h"
CDataConfig::CDataConfig()
    : m_IPAdress(_T(""))
    , m_ComNum(_T(""))
    , m_Username(_T(""))
    , m_Password(_T(""))
    , m_Database(_T(""))
    , m_Comm(_T(""))
    , m_Botelv(_T(""))
    , m_Jiaoyan(_T(""))
    , m_Shuju(_T(""))
    , m_Tingzhi(_T(""))
    , m_Time(_T(""))
{
}
CDataConfig::~CDataConfig()
{
}
// 擷取資料庫伺服器的IP位址
CString CDataConfig::getIpAddress()
{
    if (!this->m_IPAdress.IsEmpty()) {
        return this->m_IPAdress;
    }
    else
    {
        return NULL;
    }
}
// 擷取資料庫伺服器端口号
CString CDataConfig::getComnum()
{
    if (!this->m_ComNum.IsEmpty()) {
        return this->m_ComNum;
    }
    else {
        return 0;
    }
}
// 擷取連接配接的資料庫名字
CString CDataConfig::getDatabase()
{
    if (!this->m_Database.IsEmpty()) {
        return this->m_Database;
    }
    else {
        return NULL;
    }
}
// 擷取連接配接資料庫的密碼
CString CDataConfig::getPassword()
{
    if (!this->m_Password.IsEmpty()) {
        return this->m_Password;
    }
    else {
        return NULL;
    }
}
// 擷取連接配接資料庫的使用者名
CString CDataConfig::getUsername()
{
    if (!this->m_Username.IsEmpty()) {
        return this->m_Username;
    }
    else {
        return NULL;
    }
}
CString CDataConfig::getComm() {
    if (!this->m_Comm.IsEmpty()) {
        return this->m_Comm;
    }
    else {
        return NULL;
    }
}
CString CDataConfig::getBotelv() {
    if (!this->m_Botelv.IsEmpty()) {
        return this->m_Botelv;
    }
    else {
        return NULL;
    }
}
CString CDataConfig::getJiaoyan() {
    if (!this->m_Jiaoyan.IsEmpty()) {
        return this->m_Jiaoyan;
    }
    else {
        return NULL;
    }
}
CString CDataConfig::getShuju() {
    if (!this->m_Shuju.IsEmpty()) {
        return this->m_Shuju;
    }
    else {
        return NULL;
    }
}
CString CDataConfig::getTingzhi() {
    if (!this->m_Tingzhi.IsEmpty()) {
        return this->m_Tingzhi;
    }
    else {
        return NULL;
    }
}
CString CDataConfig::getTime() {
    if (!this->m_Time.IsEmpty()) {
        return this->m_Time;
    }
    else {
        return NULL;
    }
}
void CDataConfig::setComnum(CString m_ConNum) {
    this->m_ComNum = m_ConNum;
}
void CDataConfig::setDatabase(CString m_Database) {
    this->m_Database = m_Database;
}
void CDataConfig::setIpAddress(CString m_IpAddress) {
    this->m_IPAdress = m_IpAddress;
}
void CDataConfig::setPassword(CString m_Password) {
    this->m_Password = m_Password;
}
void CDataConfig::setUsername(CString m_Username) {
    this->m_Username = m_Username;
}
void CDataConfig::setComm(CString m_Comm) {
    this->m_Comm = m_Comm;
}
void CDataConfig::setBotelv(CString m_Botelv) {
    this->m_Botelv = m_Botelv;
}
void CDataConfig::setJiaoyan(CString m_Jiaoyan) {
    this->m_Jiaoyan = m_Jiaoyan;
}
void CDataConfig::setShuju(CString m_Shuju) {
    this->m_Shuju = m_Shuju;
}
void CDataConfig::setTingzhi(CString  m_Tingzhi) {
    this->m_Tingzhi = m_Tingzhi;
}
void CDataConfig::setTime(CString m_Time) {
    this->m_Time = m_Time;
}      

MysqlConnection.h

#pragma once
//頭檔案
#include "mysql.h"
#include "DataConfig.h"
#include "Configdata.h"
#include "TeeData.h"
class CMysqlConnection
private:
    CMysqlConnection();
    MYSQL m_mysql;
public:
    static CMysqlConnection * GetMysqlConn() {
        static CMysqlConnection * m_MysqlConn;
        if (NULL == m_MysqlConn) {
            m_MysqlConn = new CMysqlConnection();
        }
        return m_MysqlConn;
    }
    ~CMysqlConnection();
    BOOL setData(double m_FlowValue, CString time);
    CObArray * getData(SYSTEMTIME time);
    void      

MysqlConnection.cpp:

#include "stdafx.h"
#include "Single.h"
#include "MysqlConnection.h"
#include "管道流量采集Dlg.h"
CMysqlConnection::CMysqlConnection()
{
}
CMysqlConnection::~CMysqlConnection()
{
}
BOOL CMysqlConnection::setData(double m_FlowValue, CString time) {
    CString sql;
    CMysqlConnection * m_MysqlConnection = CMysqlConnection::GetMysqlConn();
    CString temp;
    temp.Format("%.3f", m_FlowValue);
    //INSERT INTO `data` (`time`, `value`) VALUES ('2018-5-4 12:51:52', '0.00');
    sql.Format("INSERT INTO `data` (`time`, `value`) VALUES ('%s', '%s');",time,temp);
    if (!mysql_query(&m_MysqlConnection->m_mysql, sql)) {
        return TRUE;
    }
    else {
        return FALSE;
    }
}
CObArray * CMysqlConnection::getData(SYSTEMTIME time) {
    CObArray * m_QueryData = new CObArray();
    CMysqlConnection * m_MysqlConnection = CMysqlConnection::GetMysqlConn();
    CString sql;
    MYSQL_RES * m_res;
    MYSQL_ROW m_row;
    sql.Format("SELECT * FROM `data` WHERE time BETWEEN '%2d-%d-%d' AND '%2d-%d-%d' ORDER BY time;",
        time.wYear, time.wMonth, time.wDay, time.wYear, time.wMonth, time.wDay + 1);
    mysql_query(&m_MysqlConnection->m_mysql, sql);
    m_res = mysql_store_result(&m_MysqlConnection->m_mysql);
    if (NULL != m_res) {
        if (0 != m_res->row_count) {
            while (m_row = mysql_fetch_row(m_res)) {
                m_QueryData->Add(new CTeeData(atof(m_row[1]), m_row[0]));
                //CString b = m_row[0];//時間
                //CString a = m_row[1];//值
            }
            return m_QueryData;
        }
        else
        {
            AfxMessageBox("資料庫沒有資料");
            return NULL;
        }
    }
    return NULL;
}
void CMysqlConnection::ConnectionMysql()
{
    CConfigdata * m_Configdata = new CConfigdata();
    m_Configdata->getConfigdata();
    CDataConfig * m_DataConfig = CDataConfig::GetCDataConfig();
    mysql_init(&this->m_mysql);
    //localhost:伺服器 root/123456為賬号密碼 managesystemdb為資料庫名 3306為端口    
    //if (!mysql_real_connect(&m_sqlCon, "localhost", "root", "123456", "managesystemdb", 3306, NULL, 0))
    if (!mysql_real_connect(&this->m_mysql,
        m_DataConfig->getIpAddress(),
        m_DataConfig->getUsername(),
        m_DataConfig->getPassword(),
        m_DataConfig->getDatabase(),
        atoi(m_DataConfig->getComnum()),
        NULL,
        0)
        ) {
        AfxMessageBox(mysql_error(&this->m_mysql));
        CSingle * m_Single = CSingle::GetSingle();
        if (m_Single->m_dlgSetdata->DoModal() == IDOK) {
            SetTimer(AfxGetMainWnd()->GetSafeHwnd(), 1, atoi(m_DataConfig->getTime()), NULL);
            //AfxMessageBox("開啟定時器");
        }
    }
    else {
        CString sql;
        AfxMessageBox("連接配接資料庫成功");
        mysql_query(&this->m_mysql, "SET NAMES 'utf-8'");
        //如果資料表不存在則重新建立
        sql.Format("CREATE TABLE If Not Exists `data` (`time` datetime NOT NULL,`value` double(5, 2) DEFAULT NULL,PRIMARY KEY(`time`)) ENGINE = InnoDB DEFAULT CHARSET = utf8; ");
        mysql_query(&this->m_mysql, sql);
        SetTimer(AfxGetMainWnd()->GetSafeHwnd(), 1, atoi(m_DataConfig->getTime()), NULL);
        //AfxMessageBox("定時器開始");
    }
    //mysql_query(&m_sqlCon, "SET NAMES 'GB2312'");//解決從資料庫中讀取資料後漢字亂碼顯示的問題  
}      

Single.h

#pragma once
//include
#include "DlgInterpret.h"
#include "DlgText.h"
#include "DlgForecast.h"
#include "DlgHistory.h"
#include "DlgExcel.h"
#include "DlgSetdata.h"
#include "DlgLookdata.h"
#include "Resource.h"
class CSingle
private:
    CSingle();
public:
    ~CSingle();
    // 擷取單例
    static CSingle* GetSingle() {
        static CSingle* m_Single;
        if (NULL == m_Single) {
            m_Single = new CSingle();
        }
        return      

Single.cpp:

#include "stdafx.h"
#include "Single.h"
CSingle::CSingle()
{
    if (NULL == this->m_dlgExcel) {
        this->m_dlgExcel = new CDlgExcel();
    }
    if (NULL == this->m_dlgForecast) {
        this->m_dlgForecast = new CDlgForecast();
    }
    if (NULL == this->m_dlgHistory) {
        this->m_dlgHistory = new CDlgHistory();
    }
    if (NULL == this->m_dlgInterpret) {
        this->m_dlgInterpret = new CDlgInterpret();
    }
    if (NULL == this->m_dlgText) {
        this->m_dlgText = new CDlgText();
    }
    if (NULL == this->m_dlgSetdata) {
        this->m_dlgSetdata = new CDlgSetdata();
    }
    if (NULL == this->m_dlgLookdata) {
        this->m_dlgLookdata = new      

5.5系統資料庫讀寫

ConfigData.h

#pragma once
//頭檔案
#include "DataConfig.h"
#include "DlgSetdata.h"
class CConfigdata
public:
    CConfigdata();
    ~CConfigdata();
    // 儲存資料到系統資料庫
    void setConfigdata();
    // 讀取系統資料庫資料到單例
    void      

ConfigData.cpp:

#include "stdafx.h"
#include "Configdata.h"
#include "MysqlConnection.h"
CConfigdata::CConfigdata()
{
}
CConfigdata::~CConfigdata()
{
}
/*
從系統資料庫讀取資料庫參數
包括:
IP:localhost
com:3306
username:root
password:root
database:flowdata
*/
// 儲存資料到系統資料庫
void CConfigdata::setConfigdata()
{
    CDataConfig * m_DataConfig = CDataConfig::GetCDataConfig();
    HKEY hKey;
    if (!RegOpenKeyEx(HKEY_CURRENT_USER,
        "SOFTWARE\\Flowtest", NULL, KEY_READ, &hKey)) {
        //如果在SOFTWARE下沒有Folwtest檔案夾那麼就需要建立檔案夾
        RegCreateKey(HKEY_CURRENT_USER, "Software\\Flowtest", &hKey);
        //AfxMessageBox("建立系統資料庫項");
    }
    RegSetValue(hKey,"IPAddress",
        REG_SZ,m_DataConfig->getIpAddress(),
        strlen(m_DataConfig->getIpAddress()));
    RegSetValue(hKey, "COM",
        REG_SZ, m_DataConfig->getComnum(),
        strlen(m_DataConfig->getComnum()));
    RegSetValue(hKey, "Username",
        REG_SZ, m_DataConfig->getUsername(),
        strlen(m_DataConfig->getUsername()));
    RegSetValue(hKey, "Password",
        REG_SZ, m_DataConfig->getPassword(),
        strlen(m_DataConfig->getPassword()));
    RegSetValue(hKey, "Database",
        REG_SZ, m_DataConfig->getDatabase(),
        strlen(m_DataConfig->getDatabase()));
    RegSetValue(hKey, "Comm",
        REG_SZ, m_DataConfig->getComm(),
        strlen(m_DataConfig->getComm()));
    RegSetValue(hKey, "Botelv",
        REG_SZ, m_DataConfig->getBotelv(),
        strlen(m_DataConfig->getBotelv()));
    RegSetValue(hKey, "Jiaoyan",
        REG_SZ, m_DataConfig->getJiaoyan(),
        strlen(m_DataConfig->getJiaoyan()));
    RegSetValue(hKey, "Shuju",
        REG_SZ, m_DataConfig->getShuju(),
        strlen(m_DataConfig->getShuju()));
    RegSetValue(hKey, "Tingzhi",
        REG_SZ, m_DataConfig->getTingzhi(),
        strlen(m_DataConfig->getTingzhi()));
    RegSetValue(hKey, "Time",
        REG_SZ, m_DataConfig->getTime(),
        strlen(m_DataConfig->getTime()));
    AfxMessageBox("系統資料庫寫入成功");
}
// 讀取系統資料庫資料到單例
void CConfigdata::getConfigdata()
{
    CDataConfig * m_DataConfig = CDataConfig::GetCDataConfig();
    HKEY hKey;
    char * temp;
    long a;
    if (ERROR_SUCCESS !=
        RegOpenKeyEx(HKEY_CURRENT_USER,
            "SOFTWARE\\Flowtest", NULL, KEY_READ, &hKey)) {
        //如果系統資料庫中沒有資料,那麼調用設定模态對話框提示輸入
        //同時建立系統資料庫
        CDlgSetdata m_dlgSetdata;
        if (m_dlgSetdata.DoModal() == IDOK) {
            this->setConfigdata();
            //AfxMessageBox("建立後從系統資料庫讀取到單例");
        }
    }
    else {
        //RegQueryValue(HKEY_CURRENT_USER,
        //"SOFTWARE\\ArwenSoft\\dataip", ipadd, &a);
        RegQueryValue(HKEY_CURRENT_USER,
            "SOFTWARE\\Flowtest\\IPAddress", NULL, &a);
        temp = new char[a];
        RegQueryValue(HKEY_CURRENT_USER,
            "SOFTWARE\\Flowtest\\IPAddress", temp, &a);
        m_DataConfig->setIpAddress(temp);
        delete temp;
        RegQueryValue(HKEY_CURRENT_USER,
            "SOFTWARE\\Flowtest\\COM", NULL, &a);
        temp = new char[a];
        RegQueryValue(HKEY_CURRENT_USER,
            "SOFTWARE\\Flowtest\\COM", temp, &a);
        m_DataConfig->setComnum(temp);
        delete temp;
        RegQueryValue(HKEY_CURRENT_USER,
            "SOFTWARE\\Flowtest\\Username", NULL, &a);
        temp = new char[a];
        RegQueryValue(HKEY_CURRENT_USER,
            "SOFTWARE\\Flowtest\\Username", temp, &a);
        m_DataConfig->setUsername(temp);
        delete temp;
        RegQueryValue(HKEY_CURRENT_USER,
            "SOFTWARE\\Flowtest\\Password", NULL, &a);
        temp = new char[a];
        RegQueryValue(HKEY_CURRENT_USER,
            "SOFTWARE\\Flowtest\\Password", temp, &a);
        m_DataConfig->setPassword(temp);
        delete temp;
        RegQueryValue(HKEY_CURRENT_USER,
            "SOFTWARE\\Flowtest\\Database", NULL, &a);
        temp = new char[a];
        RegQueryValue(HKEY_CURRENT_USER,
            "SOFTWARE\\Flowtest\\Database", temp, &a);
        m_DataConfig->setDatabase(temp);
        delete temp;
        RegQueryValue(HKEY_CURRENT_USER,
            "SOFTWARE\\Flowtest\\Comm", NULL, &a);
        temp = new char[a];
        RegQueryValue(HKEY_CURRENT_USER,
            "SOFTWARE\\Flowtest\\Comm", temp, &a);
        m_DataConfig->setComm(temp);
        delete temp;
        RegQueryValue(HKEY_CURRENT_USER,
            "SOFTWARE\\Flowtest\\Botelv", NULL, &a);
        temp = new char[a];
        RegQueryValue(HKEY_CURRENT_USER,
            "SOFTWARE\\Flowtest\\Botelv", temp, &a);
        m_DataConfig->setBotelv(temp);
        delete temp;
        RegQueryValue(HKEY_CURRENT_USER,
            "SOFTWARE\\Flowtest\\Jiaoyan", NULL, &a);
        temp = new char[a];
        RegQueryValue(HKEY_CURRENT_USER,
            "SOFTWARE\\Flowtest\\Jiaoyan", temp, &a);
        m_DataConfig->setJiaoyan(temp);
        delete temp;
        RegQueryValue(HKEY_CURRENT_USER,
            "SOFTWARE\\Flowtest\\Shuju", NULL, &a);
        temp = new char[a];
        RegQueryValue(HKEY_CURRENT_USER,
            "SOFTWARE\\Flowtest\\Shuju", temp, &a);
        m_DataConfig->setShuju(temp);
        delete temp;
        RegQueryValue(HKEY_CURRENT_USER,
            "SOFTWARE\\Flowtest\\Tingzhi", NULL, &a);
        temp = new char[a];
        RegQueryValue(HKEY_CURRENT_USER,
            "SOFTWARE\\Flowtest\\Tingzhi", temp, &a);
        m_DataConfig->setTingzhi(temp);
        delete temp;
        RegQueryValue(HKEY_CURRENT_USER,
            "SOFTWARE\\Flowtest\\Time", NULL, &a);
        temp = new char[a];
        RegQueryValue(HKEY_CURRENT_USER,
            "SOFTWARE\\Flowtest\\Time", temp, &a);
        m_DataConfig->setTime(temp);
        delete temp;
        AfxMessageBox("直接從系統資料庫讀取參數");
    }
}      

5.6折線圖、統計表、資料庫bean類

      Bean類是對應于資料表中一行資料的類,一個bean類的對象就是表中存儲的一行,在本系統中,資料處理,這是最小的機關

TeeData.h

#pragma
class CTeeData : public CObject
{
public:
    CTeeData();
    ~CTeeData();
    double m_Viewvalue;
    CString m_ViewData;
    CTeeData(double      

TeeData.cpp:

5.7對話框功能實作

5.7.1統計表

消息中重寫OnCtlColor方法:

// TODO:  在此更改 DC 的任何特性
CFont m_SetFont;switch (pWnd->GetDlgCtrlID()){case IDC_E_TITLE:
m_SetFont.CreatePointFont(400,"楷體");pDC->SelectObject(&m_SetFont);
pDC->SetTextColor(RGB(0, 255, 0));pDC->SetBkColor(RGB(103, 103, 103));break;
default:break;}      

重寫OnInitDialog方法:

// TODO:  在此添加額外的初始化
SYSTEMTIME m_System;GetLocalTime(&m_System);
this->c_EList.InsertColumn(0, "時間", LVCFMT_CENTER, 200);
this->c_EList.InsertColumn(1, "流量", LVCFMT_CENTER, 100);
this->c_EList.InsertColumn(2, "時間", LVCFMT_CENTER, 200);
this->c_EList.InsertColumn(3, "流量", LVCFMT_CENTER, 100);
this->c_EList.InsertColumn(4, "時間", LVCFMT_CENTER, 200);
this->c_EList.InsertColumn(5, "流量", LVCFMT_CENTER, 100);
this->c_EList.InsertColumn(6, "時間", LVCFMT_CENTER, 200);
this->c_EList.InsertColumn(7, "流量", LVCFMT_CENTER, 100);
this->c_EList.InsertColumn(8, "時間", LVCFMT_CENTER, 200);
this->c_EList.InsertColumn(9, "流量", LVCFMT_CENTER, 100);setExcel(m_System);      

增加參數寫入到統計表控件中的方法setExcel:

void CDlgExcel::setExcel(SYSTEMTIME m_Systime)
{CMysqlConnection * m_MysqlConnection = CMysqlConnection::GetMysqlConn();
CObArray * m_ExcelData = new CObArray();double flowsum = 0.0;//總流量數
double max = 0.0;//最大值double min = 0.0;//最小值int nItem = 0;//行數
int sum = 0;//總記錄數CTeeData * m_tmpTeedata;//一個資料元CString temp;
m_ExcelData = m_MysqlConnection->getData(m_Systime);if (m_ExcelData != NULL) {
this->c_EList.DeleteAllItems();
for (int i = 0; i < (m_ExcelData->GetSize() + 4) / 5; i++) {//添加一行
this->c_EList.InsertItem(nItem, "");for (int j = 0; j < 10; j++) {//添加一行中的一個元組資料
m_tmpTeedata = (CTeeData *)m_ExcelData->GetAt(sum);
flowsum += m_tmpTeedata->m_Viewvalue;
max=max>=m_tmpTeedata->m_Viewvalue?max:tmpTeedata->m_Viewvalue;
min=min<=m_tmpTeedata->m_Viewvalue?min:m_tmpTeedata->m_Viewvalue;
temp.Format("%.3f", m_tmpTeedata->m_Viewvalue);
this->c_EList.SetItemText(nItem, j, m_tmpTeedata->m_ViewData);//時間
this->c_EList.SetItemText(nItem, j + 1, temp);//值sum++;j++;
if (sum >= m_ExcelData->GetSize()) {    break;}}    nItem++;}//添加分析資料
this->c_EList.InsertItem(nItem, "");this->c_EList.SetItemText(nItem, 0, "最大值");
temp.Format("%.3f", max);this->c_EList.SetItemText(nItem, 1, temp);
this->c_EList.SetItemText(nItem, 2, "最小值");temp.Format("%.3f", min);
this->c_EList.SetItemText(nItem, 3, temp);this->c_EList.SetItemText(nItem, 4, "平均值");
temp.Format("%.6f", flowsum / m_ExcelData->GetSize());
this->c_EList.SetItemText(nItem, 5, temp);this->c_EList.SetItemText(nItem, 6, "總流量");
temp.Format("%.3f", flowsum);this->c_EList.SetItemText(nItem, 7, temp);
this->c_EList.SetItemText(nItem, 8, "總資料");temp.Format("%d", m_ExcelData->GetSize());
this->c_EList.SetItemText(nItem, 9, temp);
this->m_ETitle.Format("%2d-%d-%d的流量統計表", m_Systime.wYear, m_Systime.wMonth, m_Systime.wDay);GetDlgItem(IDC_E_TITLE)->SetWindowText(this->m_ETitle);}}      

添加統計表中确定按鈕的事件處理OnBnClickedEOk:

CTime m_ExcelTime;SYSTEMTIME m_tmpTime;this->c_EDate.GetTime(m_ExcelTime);
m_tmpTime.wYear = m_ExcelTime.GetYear();
m_tmpTime.wMonth = m_ExcelTime.GetMonth();
m_tmpTime.wDay = m_ExcelTime.GetDay();
m_tmpTime.wHour = m_ExcelTime.GetHour();
m_tmpTime.wMinute = m_ExcelTime.GetMinute();
m_tmpTime.wSecond = m_ExcelTime.GetSecond();setExcel(m_tmpTime);      

DlgExcel.h:

#pragma
#include "afxcmn.h"
#include "afxdtctl.h"
#include "MysqlConnection.h"
#include "TeeData.h"
// CDlgExcel 對話框
class CDlgExcel : public CDialogEx
{
    DECLARE_DYNAMIC(CDlgExcel)
public:
    CDlgExcel(CWnd* pParent = NULL);   // 标準構造函數
    virtual ~CDlgExcel();
// 對話框資料
#ifdef AFX_DESIGN_TIME
    enum { IDD = IDD_EXCEL };
#endif
protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支援
    DECLARE_MESSAGE_MAP()
public:
    // 統計表标題
    CString m_ETitle;
    // 清單
    CListCtrl c_EList;
    // 日期
    CDateTimeCtrl c_EDate;
    afx_msg void OnBnClickedEOk();
    virtual BOOL OnInitDialog();
    void      

DlgExcel.cpp:

// DlgExcel.cpp : 實作檔案
#include "stdafx.h"
#include "管道流量采集.h"
#include "DlgExcel.h"
#include "afxdialogex.h"
// CDlgExcel 對話框
IMPLEMENT_DYNAMIC(CDlgExcel, CDialogEx)
CDlgExcel::CDlgExcel(CWnd* pParent /*=NULL*/)
    : CDialogEx(IDD_EXCEL, pParent)
    , m_ETitle(_T(""))
{
}
CDlgExcel::~CDlgExcel()
{
}
void CDlgExcel::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
    DDX_Text(pDX, IDC_E_TITLE, m_ETitle);
    DDX_Control(pDX, IDC_E_LIST, c_EList);
    DDX_Control(pDX, IDC_E_DATE, c_EDate);
}
BEGIN_MESSAGE_MAP(CDlgExcel, CDialogEx)
    ON_BN_CLICKED(IDOK, &CDlgExcel::OnBnClickedEOk)
    ON_WM_CTLCOLOR()
END_MESSAGE_MAP()
// CDlgExcel 消息處理程式
void CDlgExcel::OnBnClickedEOk()
{
    // TODO: 在此添加控件通知處理程式代碼
    /*
    統計表子產品:
    在開始的時候查詢目前時間的資料
    然後顯示
    調用此方法知識擷取到選擇的日期
    另一個查詢的函數
    接收需要查詢的日期
    然後按照日期進行查詢
    第一次打開的時候以目前的日期為查詢日期
    查詢到的資料在繪制函數中進行繪制
    表格隻有兩項
    時間     流量值

    最後手動添加
    最大值
    最小值
    總量
    平均值
    超過檢測值的次數
    等等
    10列
    */
    CTime m_ExcelTime;
    SYSTEMTIME m_tmpTime;
    this->c_EDate.GetTime(m_ExcelTime);
    m_tmpTime.wYear = m_ExcelTime.GetYear();
    m_tmpTime.wMonth = m_ExcelTime.GetMonth();
    m_tmpTime.wDay = m_ExcelTime.GetDay();
    m_tmpTime.wHour = m_ExcelTime.GetHour();
    m_tmpTime.wMinute = m_ExcelTime.GetMinute();
    m_tmpTime.wSecond = m_ExcelTime.GetSecond();
    setExcel(m_tmpTime);
}
BOOL CDlgExcel::OnInitDialog()
{
    CDialogEx::OnInitDialog();
    // TODO:  在此添加額外的初始化
    SYSTEMTIME m_System;
    GetLocalTime(&m_System);
    this->c_EList.InsertColumn(0, "時間", LVCFMT_CENTER, 200);
    this->c_EList.InsertColumn(1, "流量", LVCFMT_CENTER, 100);
    this->c_EList.InsertColumn(2, "時間", LVCFMT_CENTER, 200);
    this->c_EList.InsertColumn(3, "流量", LVCFMT_CENTER, 100);
    this->c_EList.InsertColumn(4, "時間", LVCFMT_CENTER, 200);
    this->c_EList.InsertColumn(5, "流量", LVCFMT_CENTER, 100);
    this->c_EList.InsertColumn(6, "時間", LVCFMT_CENTER, 200);
    this->c_EList.InsertColumn(7, "流量", LVCFMT_CENTER, 100);
    this->c_EList.InsertColumn(8, "時間", LVCFMT_CENTER, 200);
    this->c_EList.InsertColumn(9, "流量", LVCFMT_CENTER, 100);
    setExcel(m_System);
    return TRUE;  // return TRUE unless you set the focus to a control
                  // 異常: OCX 屬性頁應傳回 FALSE
}
void CDlgExcel::setExcel(SYSTEMTIME m_Systime)
{
    CMysqlConnection * m_MysqlConnection = CMysqlConnection::GetMysqlConn();
    CObArray * m_ExcelData = new CObArray();
    double flowsum = 0.0;//總流量數
    double max = 0.0;//最大值
    double min = 0.0;//最小值
    int nItem = 0;//行數
    int sum = 0;//總記錄數
    CTeeData * m_tmpTeedata;//一個資料元
    CString temp;
    m_ExcelData = m_MysqlConnection->getData(m_Systime);
    if (m_ExcelData != NULL) {
        this->c_EList.DeleteAllItems();
        for (int i = 0; i < (m_ExcelData->GetSize() + 4) / 5; i++) {
            //添加一行
            this->c_EList.InsertItem(nItem, "");
            for (int j = 0; j < 10; j++) {
                //添加一行中的一個元組資料
                m_tmpTeedata = (CTeeData *)m_ExcelData->GetAt(sum);
                flowsum += m_tmpTeedata->m_Viewvalue;
                max = max >= m_tmpTeedata->m_Viewvalue ? max : m_tmpTeedata->m_Viewvalue;
                min = min <= m_tmpTeedata->m_Viewvalue ? min : m_tmpTeedata->m_Viewvalue;
                temp.Format("%.3f", m_tmpTeedata->m_Viewvalue);
                this->c_EList.SetItemText(nItem, j, m_tmpTeedata->m_ViewData);//時間
                this->c_EList.SetItemText(nItem, j + 1, temp);//值
                sum++;
                j++;
                if (sum >= m_ExcelData->GetSize()) {
                    break;
                }
            }
            nItem++;
        }
        //添加分析資料
        this->c_EList.InsertItem(nItem, "");
        this->c_EList.SetItemText(nItem, 0, "最大值");
        temp.Format("%.3f", max);
        this->c_EList.SetItemText(nItem, 1, temp);
        this->c_EList.SetItemText(nItem, 2, "最小值");
        temp.Format("%.3f", min);
        this->c_EList.SetItemText(nItem, 3, temp);
        this->c_EList.SetItemText(nItem, 4, "平均值");
        temp.Format("%.6f", flowsum / m_ExcelData->GetSize());
        this->c_EList.SetItemText(nItem, 5, temp);
        this->c_EList.SetItemText(nItem, 6, "總流量");
        temp.Format("%.3f", flowsum);
        this->c_EList.SetItemText(nItem, 7, temp);
        this->c_EList.SetItemText(nItem, 8, "總資料");
        temp.Format("%d", m_ExcelData->GetSize());
        this->c_EList.SetItemText(nItem, 9, temp);
        this->m_ETitle.Format("%2d-%d-%d的流量統計表", m_Systime.wYear, m_Systime.wMonth, m_Systime.wDay);
        GetDlgItem(IDC_E_TITLE)->SetWindowText(this->m_ETitle);
    }
}
HBRUSH CDlgExcel::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
    HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor);
    // TODO:  在此更改 DC 的任何特性
    CFont m_SetFont;
    switch (pWnd->GetDlgCtrlID())
    {
    case IDC_E_TITLE:
        m_SetFont.CreatePointFont(400,"楷體");
        pDC->SelectObject(&m_SetFont);
        pDC->SetTextColor(RGB(0, 255, 0));
        pDC->SetBkColor(RGB(103, 103, 103));
        break;
    default:
        break;
    }
    // TODO:  如果預設的不是所需畫筆,則傳回另一個畫筆
    return      

5.7.2流量預測

添加流量預測儲存按鈕的事件處理方法OnBnClickedOk:

CString m_result;CString m_reason;char temp[255];CString t;CString strPath;CFile file;
GetDlgItemText(IDC_F_RESULT, m_result);GetDlgItemText(IDC_F_REASON, m_reason);
SHGetSpecialFolderPath(0, temp, CSIDL_DESKTOPDIRECTORY, 0);t.Format(temp);
t += "\\流量預測分析";m_result += "\r\n";m_result += m_reason;
CFileDialog saveDlg(FALSE,"txt",t,OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT, "文本文檔(*.txt)", this);
if (saveDlg.DoModal() == IDOK) {strPath = saveDlg.GetPathName();
file.Open(strPath, CFile::modeCreate | CFile::modeWrite);//str為CString類型 
file.Write(m_result.GetBuffer(),m_result.GetLength()*sizeof(TCHAR));
file.Flush();file.Close();AfxMessageBox("儲存成功");}
else {AfxMessageBox("沒有傳入路徑");}      

DlgForecast.h:

#pragma
// CDlgForecast 對話框
class CDlgForecast : public CDialogEx
{
    DECLARE_DYNAMIC(CDlgForecast)
public:
    CDlgForecast(CWnd* pParent = NULL);   // 标準構造函數
    virtual ~CDlgForecast();
// 對話框資料
#ifdef AFX_DESIGN_TIME
    enum { IDD = IDD_FORECAST };
#endif
protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支援
    DECLARE_MESSAGE_MAP()
public:
    afx_msg void OnBnClickedOk();
};      

DlgForecast.cpp:

#include "stdafx.h"
#include "管道流量采集.h"
#include "DlgForecast.h"
#include "afxdialogex.h"
// CDlgForecast 對話框
IMPLEMENT_DYNAMIC(CDlgForecast, CDialogEx)
CDlgForecast::CDlgForecast(CWnd* pParent /*=NULL*/)
    : CDialogEx(IDD_FORECAST, pParent)
{
}
CDlgForecast::~CDlgForecast()
{
}
void CDlgForecast::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CDlgForecast, CDialogEx)
    ON_BN_CLICKED(IDOK, &CDlgForecast::OnBnClickedOk)
END_MESSAGE_MAP()
void CDlgForecast::OnBnClickedOk()
{
    // TODO: 在此添加控件通知處理程式代碼
    CString m_result;
    CString m_reason;
    char temp[255];
    CString t;
    CString strPath;
    CFile file;
    GetDlgItemText(IDC_F_RESULT, m_result);
    GetDlgItemText(IDC_F_REASON, m_reason);
    SHGetSpecialFolderPath(0, temp, CSIDL_DESKTOPDIRECTORY, 0);
    t.Format(temp);
    t += "\\流量預測分析";
    m_result += "\r\n";
    m_result += m_reason;
    CFileDialog saveDlg(FALSE, "txt", t, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, "文本文檔(*.txt)", this);
    if (saveDlg.DoModal() == IDOK) {
        strPath = saveDlg.GetPathName();
        file.Open(strPath, CFile::modeCreate | CFile::modeWrite);
        file.Write(m_result.GetBuffer(), m_result.GetLength() * sizeof(TCHAR));//str為CString類型 
        file.Flush();
        file.Close();
        AfxMessageBox("儲存成功");
    }
    else {
        AfxMessageBox("沒有傳入路徑");
    }
    //CDialogEx::OnOK();      

5.7.3曆史流量折線圖

重寫OnCtlColor方法:

CFont m_SetFont;switch (pWnd->GetDlgCtrlID()){case IDC_H_TITLE:
m_SetFont.CreatePointFont(400, "楷體");pDC->SelectObject(&m_SetFont);
pDC->SetTextColor(RGB(0, 255, 0));pDC->SetBkColor(RGB(103, 103, 103));break;
default:break;}      

重寫OnInitDialog,使用目前日期作為查詢條件并顯示:

SYSTEMTIME m_Systime;GetLocalTime(&m_Systime);setTeeChart(m_Systime);      

增加資料顯示到折線圖插件的方法:

void CDlgHistory::setTeeChart(SYSTEMTIME m_Systime)
{CObArray * m_Viewdatas = new CObArray();
CMysqlConnection * m_MysqlConnection = CMysqlConnection::GetMysqlConn();
CTeeData * m_OneData;CSeries viewdata = this->c_HTChart.Series(0);CString temp;
temp.Format("%2d-%d-%d的流量資料折線圖", m_Systime.wYear, m_Systime.wMonth, m_Systime.wDay);
GetDlgItem(IDC_H_TITLE)->SetWindowText(temp);
m_Viewdatas =  m_MysqlConnection->getData(m_Systime);viewdata.Clear();
if (NULL != m_Viewdatas) {for (int i = 0; i < m_Viewdatas->GetSize(); i++) {
m_OneData = (CTeeData *)m_Viewdatas->GetAt(i);
viewdata.Add(m_OneData->m_Viewvalue,m_OneData->m_ViewData, NULL);}}}      

添加确定按鈕的事件處理方法OnBnClickedOk,當使用者重寫選擇日期後确定,此方法就會被調用。

CTime m_tmpTime;SYSTEMTIME m_Datetime;this->c_HDate.GetTime(m_tmpTime);
m_Datetime.wYear = m_tmpTime.GetYear();m_Datetime.wMonth = m_tmpTime.GetMonth();
m_Datetime.wDay = m_tmpTime.GetDay();m_Datetime.wHour = m_tmpTime.GetHour();
m_Datetime.wMinute = m_tmpTime.GetMinute();
m_Datetime.wSecond = m_tmpTime.GetSecond();setTeeChart(m_Datetime);      

DlgHistory.h:

#pragma
#include "afxdtctl.h"
#include "tchart1.h"
#include "TeeData.h"
#include "CSeries.h"
// CDlgHistory 對話框
class CDlgHistory : public CDialogEx
{
    DECLARE_DYNAMIC(CDlgHistory)
public:
    CDlgHistory(CWnd* pParent = NULL);   // 标準構造函數
    virtual ~CDlgHistory();
// 對話框資料
#ifdef AFX_DESIGN_TIME
    enum { IDD = IDD_HISTORY };
#endif
protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支援
    DECLARE_MESSAGE_MAP()
public:
    CDateTimeCtrl c_HDate;
    CTchart1 c_HTChart;
    virtual BOOL OnInitDialog();
    afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);
    void setTeeChart(SYSTEMTIME m_Systime);
    afx_msg void      

DlgHistory.cpp:

// DlgHistory.cpp : 實作檔案
#include "stdafx.h"
#include "管道流量采集.h"
#include "DlgHistory.h"
#include "afxdialogex.h"
#include "MysqlConnection.h"
// CDlgHistory 對話框
IMPLEMENT_DYNAMIC(CDlgHistory, CDialogEx)
CDlgHistory::CDlgHistory(CWnd* pParent /*=NULL*/)
    : CDialogEx(IDD_HISTORY, pParent)
{
}
CDlgHistory::~CDlgHistory()
{
}
void CDlgHistory::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
    DDX_Control(pDX, IDC_H_DATE, c_HDate);
    DDX_Control(pDX, IDC_H_TCHART, c_HTChart);
}
BEGIN_MESSAGE_MAP(CDlgHistory, CDialogEx)
    ON_WM_CTLCOLOR()
    ON_BN_CLICKED(IDOK, &CDlgHistory::OnBnClickedOk)
END_MESSAGE_MAP()
// CDlgHistory 消息處理程式
BOOL CDlgHistory::OnInitDialog()
{
    CDialogEx::OnInitDialog();
    // TODO:  在此添加額外的初始化
    SYSTEMTIME m_Systime;
    GetLocalTime(&m_Systime);
    setTeeChart(m_Systime);
    return TRUE;  // return TRUE unless you set the focus to a control
                  // 異常: OCX 屬性頁應傳回 FALSE
}
HBRUSH CDlgHistory::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
    HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor);
    // TODO:  在此更改 DC 的任何特性
    CFont m_SetFont;
    switch (pWnd->GetDlgCtrlID())
    {
    case IDC_H_TITLE:
        m_SetFont.CreatePointFont(400, "楷體");
        pDC->SelectObject(&m_SetFont);
        pDC->SetTextColor(RGB(0, 255, 0));
        pDC->SetBkColor(RGB(103, 103, 103));
        break;
    default:
        break;
    }
    // TODO:  如果預設的不是所需畫筆,則傳回另一個畫筆
    return hbr;
}
void CDlgHistory::setTeeChart(SYSTEMTIME m_Systime)
{
    CObArray * m_Viewdatas = new CObArray();
    CMysqlConnection * m_MysqlConnection = CMysqlConnection::GetMysqlConn();
    CTeeData * m_OneData;
    CSeries viewdata = this->c_HTChart.Series(0);
    CString temp;
    temp.Format("%2d-%d-%d的流量資料折線圖",m_Systime.wYear,m_Systime.wMonth,m_Systime.wDay);
    GetDlgItem(IDC_H_TITLE)->SetWindowText(temp);
    m_Viewdatas =  m_MysqlConnection->getData(m_Systime);
    viewdata.Clear();
    if (NULL != m_Viewdatas) {
        for (int i = 0; i < m_Viewdatas->GetSize(); i++) {
            m_OneData = (CTeeData *)m_Viewdatas->GetAt(i);
            viewdata.Add(m_OneData->m_Viewvalue, m_OneData->m_ViewData, NULL);
        }
    }   
}
void CDlgHistory::OnBnClickedOk()
{
    // TODO: 在此添加控件通知處理程式代碼
    CTime m_tmpTime;
    SYSTEMTIME m_Datetime;
    this->c_HDate.GetTime(m_tmpTime);
    m_Datetime.wYear = m_tmpTime.GetYear();
    m_Datetime.wMonth = m_tmpTime.GetMonth();
    m_Datetime.wDay = m_tmpTime.GetDay();
    m_Datetime.wHour = m_tmpTime.GetHour();
    m_Datetime.wMinute = m_tmpTime.GetMinute();
    m_Datetime.wSecond = m_tmpTime.GetSecond();
    setTeeChart(m_Datetime);
}      

5.7.4原理講解

重寫OnInitDialog方法:

this->m_BmpId.Add(IDB_BITMAP1);this->m_BmpId.Add(IDB_BITMAP2);
this->m_BmpId.Add(IDB_BITMAP3);this->m_BmpId.Add(IDB_BITMAP4);
this->m_BmpId.Add(IDB_BITMAP5);this->m_BmpId.Add(IDB_BITMAP6);      

重寫OnPaint方法:

//如果是第一張圖檔,設定上一頁按鈕不可用
if (0 == this->m_BmpFlag) {m_InterpretLast.EnableWindow(0);}
else if (0 != this->m_BmpFlag && !m_InterpretLast.IsWindowEnabled()) {
m_InterpretLast.EnableWindow(1);}
//如果是最後一張圖檔,設定下一頁按鈕不可用
if (this->m_BmpFlag == this->m_BmpId.GetSize() - 1) {m_InterpretNext.EnableWindow(0);}
else if (this->m_BmpFlag != this->m_BmpId.GetSize() - 1 &&
!m_InterpretNext.IsWindowEnabled()) {m_InterpretNext.EnableWindow(1);}
ShowPic(this->m_BmpId.GetAt(this->m_BmpFlag));      

增加圖檔自适應方法ShowPic:

CBitmap bitmap; CStatic * p;BITMAP bmpInfo;
CDC dcMemory;   CDC * pDC;  CBitmap * pOldBitmap;CRect rect;int nX, nY;
//加載指定位圖資源 Bmp圖檔ID  
bitmap.LoadBitmap(m_PicID);//擷取對話框上的句柄 圖檔控件ID  
p = (CStatic *)GetDlgItem(IDC_I_PIC);//設定靜态控件視窗風格為位圖居中顯示   
p->ModifyStyle(0xf, SS_BITMAP | SS_CENTERIMAGE);//将圖檔設定到Picture控件上  
p->SetBitmap(bitmap);bitmap.GetBitmap(&bmpInfo);
pDC = GetDlgItem(IDC_I_PIC)->GetDC();dcMemory.CreateCompatibleDC(pDC);
pOldBitmap = dcMemory.SelectObject(&bitmap);p->GetClientRect(&rect);
nX = rect.left + (rect.Width() - bmpInfo.bmWidth) / 2;
nY = rect.top + (rect.Height() - bmpInfo.bmHeight) / 2;
pDC->SetStretchBltMode(COLORONCOLOR);
pDC->StretchBlt(0, 0, rect.Width(), rect.Height(),&dcMemory, 0, 0, bmpInfo.bmWidth, bmpInfo.bmHeight, SRCCOPY);dcMemory.SelectObject(pOldBitmap);ReleaseDC(pDC);      

增加上一頁按鈕的事件處理方法OnBnClickedILast:

this->m_BmpFlag--;if (this->m_BmpFlag < 0) {this->m_BmpFlag = 0;}
CDlgInterpret::OnPaint();      

增加下一頁按鈕的事件處理方法OnBnClickedINext

this->m_BmpFlag++;  if (this->m_BmpFlag >= this->m_BmpId.GetSize()) {
this->m_BmpFlag = this->m_BmpId.GetSize() - 1;} CDlgInterpret::OnPaint();      

DlgInterpret.h:

#pragma
#include "afxwin.h"
// CDlgInterpret 對話框
class CDlgInterpret : public CDialogEx
{
    DECLARE_DYNAMIC(CDlgInterpret)
public:
    CDlgInterpret(CWnd* pParent = NULL);   // 标準構造函數
    virtual ~CDlgInterpret();
// 對話框資料
#ifdef AFX_DESIGN_TIME
    enum { IDD = IDD_INTERPRET };
#endif
protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支援
    DECLARE_MESSAGE_MAP()
public:
    void ShowPic(int m_PicID);
    virtual BOOL OnInitDialog();
    afx_msg void OnPaint();
    CButton m_InterpretLast;
    CButton m_InterpretNext;
    CArray<int, int> m_BmpId;
    int m_BmpFlag;
    afx_msg void OnBnClickedINext();
    afx_msg void      

DlgInterpret.cpp:

// DlgInterpret.cpp : 實作檔案
#include "stdafx.h"
#include "管道流量采集.h"
#include "DlgInterpret.h"
#include "afxdialogex.h"
// CDlgInterpret 對話框
IMPLEMENT_DYNAMIC(CDlgInterpret, CDialogEx)
CDlgInterpret::CDlgInterpret(CWnd* pParent /*=NULL*/)
    : CDialogEx(IDD_INTERPRET, pParent)
    , m_BmpFlag(0)
{
}
CDlgInterpret::~CDlgInterpret()
{
}
void CDlgInterpret::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
    DDX_Control(pDX, IDC_I_LAST, m_InterpretLast);
    DDX_Control(pDX, IDC_I_NEXT, m_InterpretNext);
}
BEGIN_MESSAGE_MAP(CDlgInterpret, CDialogEx)
    ON_WM_PAINT()
    ON_BN_CLICKED(IDC_I_NEXT, &CDlgInterpret::OnBnClickedINext)
    ON_BN_CLICKED(IDC_I_LAST, &CDlgInterpret::OnBnClickedILast)
END_MESSAGE_MAP()
// CDlgInterpret 消息處理程式
void CDlgInterpret::ShowPic(int m_PicID)
{
    CBitmap bitmap;
    CStatic * p;
    BITMAP bmpInfo;
    CDC dcMemory;
    CDC * pDC;
    CBitmap * pOldBitmap;
    CRect rect;
    int nX, nY;
    //加載指定位圖資源 Bmp圖檔ID  
    bitmap.LoadBitmap(m_PicID);
    //擷取對話框上的句柄 圖檔控件ID  
    p = (CStatic *)GetDlgItem(IDC_I_PIC);
    //設定靜态控件視窗風格為位圖居中顯示   
    p->ModifyStyle(0xf, SS_BITMAP | SS_CENTERIMAGE);
    //将圖檔設定到Picture控件上  
    p->SetBitmap(bitmap);
    bitmap.GetBitmap(&bmpInfo);
    pDC = GetDlgItem(IDC_I_PIC)->GetDC();
    dcMemory.CreateCompatibleDC(pDC);
    pOldBitmap = dcMemory.SelectObject(&bitmap);
    p->GetClientRect(&rect);
    nX = rect.left + (rect.Width() - bmpInfo.bmWidth) / 2;
    nY = rect.top + (rect.Height() - bmpInfo.bmHeight) / 2;
    pDC->SetStretchBltMode(COLORONCOLOR);
    pDC->StretchBlt(0, 0, rect.Width(), rect.Height(), 
        &dcMemory, 0, 0, bmpInfo.bmWidth, bmpInfo.bmHeight, SRCCOPY);
    dcMemory.SelectObject(pOldBitmap);
    ReleaseDC(pDC);
}
BOOL CDlgInterpret::OnInitDialog()
{
    CDialogEx::OnInitDialog();
    // TODO:  在此添加額外的初始化
    this->m_BmpId.Add(IDB_BITMAP1);
    this->m_BmpId.Add(IDB_BITMAP2);
    this->m_BmpId.Add(IDB_BITMAP3);
    this->m_BmpId.Add(IDB_BITMAP4);
    this->m_BmpId.Add(IDB_BITMAP5);
    this->m_BmpId.Add(IDB_BITMAP6);
    return TRUE;  // return TRUE unless you set the focus to a control
                  // 異常: OCX 屬性頁應傳回 FALSE
}
void CDlgInterpret::OnPaint()
{
    CPaintDC dc(this); // device context for painting
                       // TODO: 在此處添加消息處理程式代碼
                       // 不為繪圖消息調用 CDialogEx::OnPaint()
    //如果是第一張圖檔,設定上一頁按鈕不可用
    if (0 == this->m_BmpFlag) {
        m_InterpretLast.EnableWindow(0);
    }
    else if (0 != this->m_BmpFlag && !m_InterpretLast.IsWindowEnabled()) {
        m_InterpretLast.EnableWindow(1);
    }
    //如果是最後一張圖檔,設定下一頁按鈕不可用
    if (this->m_BmpFlag == this->m_BmpId.GetSize() - 1) {
        m_InterpretNext.EnableWindow(0);
    }
    else if (this->m_BmpFlag != this->m_BmpId.GetSize() - 1 &&
        !m_InterpretNext.IsWindowEnabled()) {
        m_InterpretNext.EnableWindow(1);
    }
    ShowPic(this->m_BmpId.GetAt(this->m_BmpFlag));
}
void CDlgInterpret::OnBnClickedINext()
{
    // TODO: 在此添加控件通知處理程式代碼
    this->m_BmpFlag++;
    if (this->m_BmpFlag >= this->m_BmpId.GetSize()) {
        this->m_BmpFlag = this->m_BmpId.GetSize() - 1;
    }
    CDlgInterpret::OnPaint();
}
void CDlgInterpret::OnBnClickedILast()
{
    // TODO: 在此添加控件通知處理程式代碼
    this->m_BmpFlag--;
    if (this->m_BmpFlag < 0) {
        this->m_BmpFlag = 0;
    }
    CDlgInterpret::OnPaint();
}      

5.7.5檢視參數

重寫OnInitDialog方法:

CString temp;CConfigdata * m_Configdata = new CConfigdata();
m_Configdata->getConfigdata();
CDataConfig * m_DataConfig = CDataConfig::GetCDataConfig();
SetDlgItemText(IDC_L_IPADD,m_DataConfig->getIpAddress());
SetDlgItemText(IDC_L_COM, m_DataConfig->getComnum());
SetDlgItemText(IDC_L_USERNAME, m_DataConfig->getUsername());
SetDlgItemText(IDC_L_PASSWORD, m_DataConfig->getPassword());
SetDlgItemText(IDC_L_DATABASE, m_DataConfig->getDatabase());temp = "COM";
temp += m_DataConfig->getComm();SetDlgItemText(IDC_L_COMM, temp);
SetDlgItemText(IDC_L_BOTELV, m_DataConfig->getBotelv());
SetDlgItemText(IDC_L_JIAOYAN, m_DataConfig->getJiaoyan());
SetDlgItemText(IDC_L_SHUJU, m_DataConfig->getShuju());
SetDlgItemText(IDC_L_TINGZHI, m_DataConfig->getTingzhi());
temp = m_DataConfig->getTime();long tt = atol(temp);tt /= 1000;
if (tt <= 60) {temp.Format("%d", tt);temp += "秒";}if (tt > 60 && tt <= 3600) {
temp.Format("%d", tt / 60);temp += "分鐘";}if (tt > 3600) {   temp.Format("%d", (tt / 60) / 60);
temp += "小時";}SetDlgItemText(IDC_L_TIME, temp);UpdateData(FALSE);      

DlgLookdata.h:

#pragma
#include "DataConfig.h"
#include "Configdata.h"
// CDlgLookdata 對話框
class CDlgLookdata : public CDialogEx
{
    DECLARE_DYNAMIC(CDlgLookdata)
public:
    CDlgLookdata(CWnd* pParent = NULL);   // 标準構造函數
    virtual ~CDlgLookdata();
// 對話框資料
#ifdef AFX_DESIGN_TIME
    enum { IDD = IDD_LOOKDATA };
#endif
protected:
    DECLARE_MESSAGE_MAP()
public:
    virtual BOOL OnInitDialog();
};      

DlgLookdata.cpp:

// DlgLookdata.cpp : 實作檔案
#include "stdafx.h"
#include "管道流量采集.h"
#include "DlgLookdata.h"
#include "afxdialogex.h"
// CDlgLookdata 對話框
IMPLEMENT_DYNAMIC(CDlgLookdata, CDialogEx)
CDlgLookdata::CDlgLookdata(CWnd* pParent /*=NULL*/)
    : CDialogEx(IDD_LOOKDATA, pParent)
{
}
CDlgLookdata::~CDlgLookdata()
{
}
BEGIN_MESSAGE_MAP(CDlgLookdata, CDialogEx)
END_MESSAGE_MAP()
// CDlgLookdata 消息處理程式
BOOL CDlgLookdata::OnInitDialog()
{
    CDialogEx::OnInitDialog();
    // TODO:  在此添加額外的初始化
    CString temp;
    CConfigdata * m_Configdata = new CConfigdata();
    m_Configdata->getConfigdata();
    CDataConfig * m_DataConfig = CDataConfig::GetCDataConfig();
    SetDlgItemText(IDC_L_IPADD,m_DataConfig->getIpAddress());
    SetDlgItemText(IDC_L_COM, m_DataConfig->getComnum());
    SetDlgItemText(IDC_L_USERNAME, m_DataConfig->getUsername());
    SetDlgItemText(IDC_L_PASSWORD, m_DataConfig->getPassword());
    SetDlgItemText(IDC_L_DATABASE, m_DataConfig->getDatabase());
    temp = "COM";
    temp += m_DataConfig->getComm();
    SetDlgItemText(IDC_L_COMM, temp);
    SetDlgItemText(IDC_L_BOTELV, m_DataConfig->getBotelv());
    SetDlgItemText(IDC_L_JIAOYAN, m_DataConfig->getJiaoyan());
    SetDlgItemText(IDC_L_SHUJU, m_DataConfig->getShuju());
    SetDlgItemText(IDC_L_TINGZHI, m_DataConfig->getTingzhi());
    temp = m_DataConfig->getTime();
    long tt = atol(temp);
    tt /= 1000;
    if (tt <= 60) {
        temp.Format("%d", tt);
        temp += "秒";
    }
    if (tt > 60 && tt <= 3600) {
        temp.Format("%d", tt / 60);
        temp += "分鐘";
    }
    if (tt > 3600) {
        temp.Format("%d", (tt / 60) / 60);
        temp += "小時";
    }
    SetDlgItemText(IDC_L_TIME, temp);
    UpdateData(FALSE);
    return TRUE;  // return TRUE unless you set the focus to a control
                  // 異常: OCX 屬性頁應傳回 FALSE      

5.7.6設定參數

重寫OnInitDialog方法,設定參數的預設參數:

//初始化下拉選擇框
SetDlgItemText(IDC_S_IPADD, "127.0.0.1");SetDlgItemText(IDC_S_COM, "3305");
SetDlgItemText(IDC_S_USERNAME, "root"); SetDlgItemText(IDC_S_PASSWORD, "root");
SetDlgItemText(IDC_S_DATABASE, "flowdata"); this->c_Comm.ResetContent();
this->c_Comm.AddString("COM1");
…….
this->c_Comm.AddString("COM8");this->c_Comm.SetCurSel(2);//預設為COM3
this->c_Botelv.ResetContent();this->c_Botelv.AddString("300");
……
this->c_Botelv.AddString("38400");this->c_Botelv.SetCurSel(2);//預設1200
this->c_Jiaoyan.ResetContent();this->c_Jiaoyan.AddString("無");
this->c_Jiaoyan.AddString("奇校驗");this->c_Jiaoyan.AddString("偶校驗");
this->c_Jiaoyan.SetCurSel(0);//預設無校驗this->c_Shuju.ResetContent();
this->c_Shuju.AddString("8");this->c_Shuju.AddString("7");this->c_Shuju.AddString("6");
this->c_Shuju.SetCurSel(0);//預設8個資料位this->c_Tingzhi.ResetContent();
this->c_Tingzhi.AddString("1");this->c_Tingzhi.AddString("2");
this->c_Tingzhi.SetCurSel(0);//預設1個停止位SetDlgItemText(IDC_S_TIME, "30");
CButton * radioS = (CButton *)GetDlgItem(IDC_S_SECEND);radioS->SetCheck(1);      

重寫PreTranslateMessage方法,此方法可以讓使用者通過Tab鍵來選擇下一個:

if ((pMsg->message == WM_KEYDOWN) && (VK_TAB == (int)pMsg->wParam)) {
CWnd *mwnd = GetFocus();if (NULL != mwnd) {
if (mwnd == GetDlgItem(IDC_S_IPADD)) {GetDlgItem(IDC_S_COM)->SetFocus();
return TRUE;}else if (mwnd == GetDlgItem(IDC_S_COM)) {
GetDlgItem(IDC_S_USERNAME)->SetFocus();return      

增加确定按鈕的事件處理方法OnBnClickedOk:

CString temp;CDataConfig * m_DataConfig = CDataConfig::GetCDataConfig();
GetDlgItemText(IDC_S_COM, temp);    m_DataConfig->setComnum(temp);
GetDlgItemText(IDC_S_IPADD, temp);m_DataConfig->setIpAddress(temp);
GetDlgItemText(IDC_S_USERNAME, this->m_SetUsername);
m_DataConfig->setUsername(this->m_SetUsername);
GetDlgItemText(IDC_S_PASSWORD, this->m_SetPassword);
m_DataConfig->setPassword(this->m_SetPassword);
GetDlgItemText(IDC_S_DATABASE, this->m_SetDatabase);
m_DataConfig->setDatabase(this->m_SetDatabase);
//沒有COM0
switch (this->c_Comm.GetCurSel()) {case 0:temp = "1";break;case 1:temp = "2";break;
case 2:temp = "3";break;case 3:temp = "4";break;case 4:temp = "5";break;
case 5:temp = "6";break;case 6:temp = "7";break;case 7:temp = "8";break;    default:break;}
m_DataConfig->setComm(temp);GetDlgItemText(IDC_S_BOTELV, temp);
m_DataConfig->setBotelv(temp);switch (this->c_Jiaoyan.GetCurSel())
{case 0:temp = "n";break;   case 1:temp = "1";break;case 2:temp = "2";break;
default:temp = "n";break;}m_DataConfig->setJiaoyan(temp);
GetDlgItemText(IDC_S_SHUJU, temp);m_DataConfig->setShuju(temp);
GetDlgItemText(IDC_S_TING, temp);   m_DataConfig->setTingzhi(temp);
GetDlgItemText(IDC_S_TIME, temp);   long tt;tt = atol(temp);CButton * pTemp = NULL;
pTemp = (CButton * )GetDlgItem(IDC_S_HOUR);if (pTemp->GetCheck()) {
tt = tt * 60 * 60 * 1000;}pTemp = (CButton *)GetDlgItem(IDC_S_MINTE);
if (pTemp->GetCheck()) {tt = tt * 60 * 1000;}
pTemp = (CButton *)GetDlgItem(IDC_S_SECEND);if (pTemp->GetCheck()) {
tt = tt * 1000;}temp.Format("%d", tt);m_DataConfig->setTime(temp);
CConfigdata m_Configdata;m_Configdata.setConfigdata();
SetTimer(1, atoi(m_DataConfig->getTime()), NULL);CDialogEx::OnOK();      

DlgSetdata.h:

#pragma
//頭檔案
#include "afxwin.h"
#include "Configdata.h"
// CDlgSetdata 對話框
class CDlgSetdata : public CDialogEx
{
    DECLARE_DYNAMIC(CDlgSetdata)
    CDlgSetdata(CWnd* pParent = NULL);   // 标準構造函數
public:
    virtual ~CDlgSetdata();
// 對話框資料
#ifdef AFX_DESIGN_TIME
    enum { IDD = IDD_SETDATA };
#endif
protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支援
    DECLARE_MESSAGE_MAP()
public:
    // IP位址
    DWORD m_SetIpadd;
    // 端口号
    CString m_SetCom;
    // 使用者名
    CString m_SetUsername;
    // 密碼
    CString m_SetPassword;
    // 資料庫名
    CString m_SetDatabase;
    afx_msg void OnBnClickedOk();
    virtual BOOL PreTranslateMessage(MSG* pMsg);
    virtual      

DlgSetdata.cpp:

// DlgSetdata.cpp : 實作檔案
#include "stdafx.h"
#include "管道流量采集.h"
#include "DlgSetdata.h"
#include "afxdialogex.h"
// CDlgSetdata 對話框
IMPLEMENT_DYNAMIC(CDlgSetdata, CDialogEx)
CDlgSetdata::CDlgSetdata(CWnd* pParent /*=NULL*/)
    : CDialogEx(IDD_SETDATA, pParent)
    , m_SetIpadd(0)
    , m_SetUsername(_T(""))
    , m_SetPassword(_T(""))
    , m_SetDatabase(_T(""))
{
}
CDlgSetdata::~CDlgSetdata()
{
}
void CDlgSetdata::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
    DDX_IPAddress(pDX, IDC_S_IPADD, m_SetIpadd);
    DDX_Text(pDX, IDC_S_COM, m_SetCom);
    DDX_Text(pDX, IDC_S_USERNAME, m_SetUsername);
    DDX_Text(pDX, IDC_S_PASSWORD, m_SetPassword);
    DDX_Text(pDX, IDC_S_DATABASE, m_SetDatabase);
    DDX_Control(pDX, IDC_S_COMM, c_Comm);
    DDX_Control(pDX, IDC_S_BOTELV, c_Botelv);
    DDX_Control(pDX, IDC_S_JIAO, c_Jiaoyan);
    DDX_Control(pDX, IDC_S_SHUJU, c_Shuju);
    DDX_Control(pDX, IDC_S_TING, c_Tingzhi);
    DDX_Control(pDX, IDC_S_TIME, c_Time);
    DDX_Control(pDX, IDCANCEL, c_ButtonH);
}
BEGIN_MESSAGE_MAP(CDlgSetdata, CDialogEx)
    ON_BN_CLICKED(IDOK, &CDlgSetdata::OnBnClickedOk)
END_MESSAGE_MAP()
// CDlgSetdata 消息處理程式
void CDlgSetdata::OnBnClickedOk()
{
    // TODO: 在此添加控件通知處理程式代碼
    CString temp;
    CDataConfig * m_DataConfig = CDataConfig::GetCDataConfig();
    GetDlgItemText(IDC_S_COM, temp);
    m_DataConfig->setComnum(temp);
    GetDlgItemText(IDC_S_IPADD, temp);
    m_DataConfig->setIpAddress(temp);
    GetDlgItemText(IDC_S_USERNAME, this->m_SetUsername);
    m_DataConfig->setUsername(this->m_SetUsername);
    GetDlgItemText(IDC_S_PASSWORD, this->m_SetPassword);
    m_DataConfig->setPassword(this->m_SetPassword);
    GetDlgItemText(IDC_S_DATABASE, this->m_SetDatabase);
    m_DataConfig->setDatabase(this->m_SetDatabase);
    switch (this->c_Comm.GetCurSel()) {
    case 0:
        temp = "1";
        break;
    case 1:
        temp = "2";
        break;
    case 2:
        temp = "3";
        break;
    case 3:
        temp = "4";
        break;
    case 4:
        temp = "5";
        break;
    case 5:
        temp = "6";
        break;
    case 6:
        temp = "7";
        break;
    case 7:
        temp = "8";
        break;
    default:
        break;
    }
    m_DataConfig->setComm(temp);
    GetDlgItemText(IDC_S_BOTELV, temp);
    m_DataConfig->setBotelv(temp);
    switch (this->c_Jiaoyan.GetCurSel())
    {
    case 0:
        temp = "n";
        break;
    case 1:
        temp = "1";
        break;
    case 2:
        temp = "2";
        break;
    default:
        temp = "n";
        break;
    }
    m_DataConfig->setJiaoyan(temp);
    GetDlgItemText(IDC_S_SHUJU, temp);
    m_DataConfig->setShuju(temp);
    GetDlgItemText(IDC_S_TING, temp);
    m_DataConfig->setTingzhi(temp);
    GetDlgItemText(IDC_S_TIME, temp);
    long tt;
    tt = atol(temp);
    CButton * pTemp = NULL;
    pTemp = (CButton * )GetDlgItem(IDC_S_HOUR);
    if (pTemp->GetCheck()) {
        tt = tt * 60 * 60 * 1000;
    }
    pTemp = (CButton *)GetDlgItem(IDC_S_MINTE);
    if (pTemp->GetCheck()) {
        tt = tt * 60 * 1000;
    }
    pTemp = (CButton *)GetDlgItem(IDC_S_SECEND);
    if (pTemp->GetCheck()) {
        tt = tt * 1000;
    }
    temp.Format("%d", tt);
    m_DataConfig->setTime(temp);
    CConfigdata m_Configdata;
    m_Configdata.setConfigdata();
    SetTimer(1, atoi(m_DataConfig->getTime()), NULL);
    //AfxMessageBox("定時器開始");
    CDialogEx::OnOK();
}
BOOL CDlgSetdata::PreTranslateMessage(MSG* pMsg)
{
    // TODO: 在此添加專用代碼和/或調用基類
    if ((pMsg->message == WM_KEYDOWN) && (VK_TAB == (int)pMsg->wParam)) {
        CWnd *mwnd = GetFocus();
        if (NULL != mwnd) {
            if (mwnd == GetDlgItem(IDC_S_IPADD)) {
                GetDlgItem(IDC_S_COM)->SetFocus();
                return TRUE;
            }
            else if (mwnd == GetDlgItem(IDC_S_COM)) {
                GetDlgItem(IDC_S_USERNAME)->SetFocus();
                return TRUE;
            }
            else if (mwnd == GetDlgItem(IDC_S_USERNAME)) {
                GetDlgItem(IDC_S_PASSWORD)->SetFocus();
                return TRUE;
            }
            else if (mwnd == GetDlgItem(IDC_S_PASSWORD)) {
                GetDlgItem(IDC_S_DATABASE)->SetFocus();
                return TRUE;
            }
            else if (mwnd == GetDlgItem(IDC_S_DATABASE)) {
                GetDlgItem(IDOK)->SetFocus();
                return TRUE;
            }
            else if (mwnd == GetDlgItem(IDOK)) {
                GetDlgItem(IDCANCEL)->SetFocus();
                return TRUE;
            }
            else if (mwnd == GetDlgItem(IDCANCEL)) {
                GetDlgItem(IDC_S_IPADD)->SetFocus();
                return TRUE;
            }
        }
    }
    return CDialogEx::PreTranslateMessage(pMsg);
}
BOOL CDlgSetdata::OnInitDialog()
{
    CDialogEx::OnInitDialog();
    // TODO:  在此添加額外的初始化
    //初始化下拉選擇框
    SetDlgItemText(IDC_S_IPADD, "127.0.0.1");
    SetDlgItemText(IDC_S_COM, "3305");
    SetDlgItemText(IDC_S_USERNAME, "root");
    SetDlgItemText(IDC_S_PASSWORD, "root");
    SetDlgItemText(IDC_S_DATABASE, "flowdata");
    this->c_Comm.ResetContent();
    this->c_Comm.AddString("COM1");
    this->c_Comm.AddString("COM2");
    this->c_Comm.AddString("COM3");
    this->c_Comm.AddString("COM4");
    this->c_Comm.AddString("COM5");
    this->c_Comm.AddString("COM6");
    this->c_Comm.AddString("COM7");
    this->c_Comm.AddString("COM8");
    this->c_Comm.SetCurSel(2);//預設為COM3
    this->c_Botelv.ResetContent();
    this->c_Botelv.AddString("300");
    this->c_Botelv.AddString("600");
    this->c_Botelv.AddString("1200");
    this->c_Botelv.AddString("2400");
    this->c_Botelv.AddString("3600");
    this->c_Botelv.AddString("4800");
    this->c_Botelv.AddString("9600");
    this->c_Botelv.AddString("19200");
    this->c_Botelv.AddString("38400");
    this->c_Botelv.SetCurSel(2);//預設1200
    this->c_Jiaoyan.ResetContent();
    this->c_Jiaoyan.AddString("無");
    this->c_Jiaoyan.AddString("奇校驗");
    this->c_Jiaoyan.AddString("偶校驗");
    this->c_Jiaoyan.SetCurSel(0);//預設無校驗
    this->c_Shuju.ResetContent();
    this->c_Shuju.AddString("8");
    this->c_Shuju.AddString("7");
    this->c_Shuju.AddString("6");
    this->c_Shuju.SetCurSel(0);//預設8個資料位
    this->c_Tingzhi.ResetContent();
    this->c_Tingzhi.AddString("1");
    this->c_Tingzhi.AddString("2");
    this->c_Tingzhi.SetCurSel(0);//預設1個停止位
    SetDlgItemText(IDC_S_TIME, "30");
    CButton * radioS = (CButton *)GetDlgItem(IDC_S_SECEND);
    radioS->SetCheck(1);
    return TRUE;  // return TRUE unless you set the focus to a control
                  // 異常: OCX 屬性頁應傳回 FALSE      

5.7.7協定測試

添加CRC校驗碼的計算方法,頭檔案:

#include      

實作檔案:

#include "stdafx.h"#include "crc.h"
static const uint8_t aucCRCHi[] = {
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
    0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
    0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
    0x00, 0xC1, 0x81, 0x40};
static const uint8_t aucCRCLo[] = {
    0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7,
    0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E,
    0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9,
    0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC,
    0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
    0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32,
    0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D,
    0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38,
    0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF,
    0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
    0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1,
    0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4,
    0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB,
    0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA,
    0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
    0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0,
    0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97,
    0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E,
    0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89,
    0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
    0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83,
    0x41, 0x81, 0x80, 0x40};
uint16_t CRC16( uint8_t * pucFrame, uint16_t usLen )
{uint8_t ucCRCHi = 0xFF;uint8_t ucCRCLo = 0xFF;int iIndex;
while( usLen-- ){iIndex = ucCRCLo ^ *( pucFrame++ );
ucCRCLo = ( uint8_t )( ucCRCHi ^ aucCRCHi[iIndex] );ucCRCHi = aucCRCLo[iIndex];}
return ( uint16_t )( ucCRCLo << 8      

自動生成協定幀的按鈕事件處理方法OnBnClickedButton1:

CString result;CTime tmpTime;SYSTEMTIME systim;uint8_t len;uint8_t prop;
uint8_t station;uint8_t pass;uint8_t timey;uint8_t timem;   uint8_t timed;
uint8_t timeh;uint8_t timemin;uint8_t times;uint16_t crc_result;CString temp;
len = 0X0C;prop = 0X00;station = 0X02;pass = 0X02;result = "自動生成的協定幀\n";
result += "EB 90 0C 00 02 02 ";this->c_Data.GetTime(tmpTime);
timey = tmpTime.GetYear()%100;  temp.Format("%02d", timey);result += temp;result += " ";
timey = strtol(temp, NULL, 16);
…….
uint8_t crc_mess[] = { len, prop, station, pass, timey, timem, timed, timeh, timemin, times };
crc_result = CRC16((uint8_t*)crc_mess, 10);temp.Format("%04X", crc_result);
result += temp;result.Insert(result.GetLength() - 2, " ");
SetDlgItemText(IDC_T_RESULT, result);      

确定按鈕的事件處理方法OnBnClickedOk:

CString m_input;    CString m_result = "測試結果:";GetDlgItemText(IDC_T_INPUT, m_input);
if (m_input.GetLength() < 41) {m_result += "幀總長度不夠";}
else {uint16_t address;CString addrtemp;addrtemp += m_input.GetAt(0);
addrtemp += m_input.GetAt(1);addrtemp += m_input.GetAt(3);
addrtemp += m_input.GetAt(4);address = strtol(addrtemp, NULL, 16);if (0xEB90 != address) {
m_result += "\n前四位位址碼為EB 90";}else {m_result += "\n位址碼測試通過";}
uint8_t len;CString lentemp;lentemp += m_input.GetAt(6);
lentemp += m_input.GetAt(7);len = strtol(lentemp, NULL, 16);
if ((m_input.GetLength() - 17) / 2 != len) {m_result += "\t長度計算錯誤,正确的是:";
lentemp.Format("%02X", (m_input.GetLength() - 17) / 2);m_result += lentemp; }
else {m_result += "\t長度測試通過";}
uint8_t prop;   CString proptemp;proptemp += m_input.GetAt(9);
proptemp += m_input.GetAt(10);prop = strtol(proptemp, NULL, 16);
if (0 != prop) {m_result += "\n屬性碼錯誤,正确的為:00";}
else {m_result += "\n屬性碼測試通過";}uint8_t station;CString stationtemp;
stationtemp += m_input.GetAt(12);stationtemp += m_input.GetAt(13);
station = strtol(stationtemp, NULL, 16);
if (0x02 != station) {m_result += "\t站号錯誤,正确為:02";}
else {m_result += "\t站号測試通過";}
uint8_t pass;   CString passtemp;passtemp += m_input.GetAt(15);
passtemp += m_input.GetAt(16);pass = strtol(passtemp, NULL, 16);
if (0x02 != pass) {m_result += "\n通道号錯誤,正确為:02";}
else {m_result += "\n通道号測試通過";}
uint8_t timey;uint8_t timem;uint8_t timed;uint8_t timeh;uint8_t timemin;
uint8_t times;CString timetemp = "";timetemp += m_input.GetAt(18);
timetemp += m_input.GetAt(19);timey = strtol(timetemp, NULL, 16);
timetemp = "";timetemp += m_input.GetAt(21);
timetemp += m_input.GetAt(22);timem = strtol(timetemp, NULL, 16);
timetemp = "";timetemp += m_input.GetAt(24);timetemp += m_input.GetAt(25);
timed = strtol(timetemp, NULL, 16);timetemp = "";timetemp += m_input.GetAt(27);
timetemp += m_input.GetAt(28);timeh = strtol(timetemp, NULL, 16);timetemp = "";
timetemp += m_input.GetAt(30);timetemp += m_input.GetAt(31);
timemin = strtol(timetemp, NULL, 16);timetemp = "";
timetemp += m_input.GetAt(33);timetemp += m_input.GetAt(34);
times = strtol(timetemp, NULL, 16);uint16_t crc_y;timetemp = "";
timetemp += m_input.GetAt(36);timetemp += m_input.GetAt(37);
timetemp += m_input.GetAt(39);timetemp += m_input.GetAt(40);
crc_y = strtol(timetemp, NULL, 16);
uint8_t crc_mess[]={len,prop,station,pass, timey, timem, timed, timeh, timemin, times };
uint16_t crc_result = CRC16((uint8_t*)crc_mess, 10);
if (crc_result != crc_y) {CString t;m_result += "\t校驗碼錯誤,正确為:";
t.Format("%04X", crc_result);   t.Insert(t.GetLength() - 2, " ");m_result += t;}
else {m_result += "\t校驗碼測試通過";}}SetDlgItemText(IDC_T_RESULT, m_result);      

DlgText.h

#pragma
#include "afxdtctl.h"
// CDlgText 對話框
class CDlgText : public CDialogEx
{
    DECLARE_DYNAMIC(CDlgText)
public:
    CDlgText(CWnd* pParent = NULL);   // 标準構造函數
    virtual ~CDlgText();
// 對話框資料
#ifdef AFX_DESIGN_TIME
    enum { IDD = IDD_TEXT };
#endif
protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支援
    DECLARE_MESSAGE_MAP()
public:
    afx_msg void OnBnClickedOk();
    afx_msg void      

DlgText.cpp:

// DlgText.cpp : 實作檔案
#include "stdafx.h"
#include "管道流量采集.h"
#include "DlgText.h"
#include "afxdialogex.h"
#include "stdio.h"
#include "stdint.h"
#include "crc.h"
// CDlgText 對話框
IMPLEMENT_DYNAMIC(CDlgText, CDialogEx)
CDlgText::CDlgText(CWnd* pParent /*=NULL*/)
    : CDialogEx(IDD_TEXT, pParent)
{
}
CDlgText::~CDlgText()
{
}
void CDlgText::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
    DDX_Control(pDX, IDC_T_DATA, c_Data);
    DDX_Control(pDX, IDC_T_TIME, c_Time);
}
BEGIN_MESSAGE_MAP(CDlgText, CDialogEx)
    ON_BN_CLICKED(IDOK, &CDlgText::OnBnClickedOk)
    ON_BN_CLICKED(IDC_BUTTON1, &CDlgText::OnBnClickedButton1)
END_MESSAGE_MAP()
// CDlgText 消息處理程式
void CDlgText::OnBnClickedOk()
{
    // TODO: 在此添加控件通知處理程式代碼
    CString m_input;
    CString m_result = "測試結果:";
    GetDlgItemText(IDC_T_INPUT, m_input);
    if (m_input.GetLength() < 41) {
        m_result += "幀總長度不夠";
    }
    else {
        uint16_t address;
        CString addrtemp;
        addrtemp += m_input.GetAt(0);
        addrtemp += m_input.GetAt(1);
        addrtemp += m_input.GetAt(3);
        addrtemp += m_input.GetAt(4);
        address = strtol(addrtemp, NULL, 16);
        if (0xEB90 != address) {
            m_result += "\n前四位位址碼為EB 90";
        }
        else {
            m_result += "\n位址碼測試通過";
        }
        uint8_t len;
        CString lentemp;
        lentemp += m_input.GetAt(6);
        lentemp += m_input.GetAt(7);
        len = strtol(lentemp, NULL, 16);
        if ((m_input.GetLength() - 17) / 2 != len) {
            m_result += "\t長度計算錯誤,正确的是:";
            lentemp.Format("%02X", (m_input.GetLength() - 17) / 2);
            m_result += lentemp;
        }
        else {
            m_result += "\t長度測試通過";
        }
        uint8_t prop;
        CString proptemp;
        proptemp += m_input.GetAt(9);
        proptemp += m_input.GetAt(10);
        prop = strtol(proptemp, NULL, 16);
        if (0 != prop) {
            m_result += "\n屬性碼錯誤,正确的為:00";
        }
        else {
            m_result += "\n屬性碼測試通過";
        }
        uint8_t station;
        CString stationtemp;
        stationtemp += m_input.GetAt(12);
        stationtemp += m_input.GetAt(13);
        station = strtol(stationtemp, NULL, 16);
        if (0x02 != station) {
            m_result += "\t站号錯誤,正确為:02";
        }
        else {
            m_result += "\t站号測試通過";
        }
        uint8_t pass;
        CString passtemp;
        passtemp += m_input.GetAt(15);
        passtemp += m_input.GetAt(16);
        pass = strtol(passtemp, NULL, 16);
        if (0x02 != pass) {
            m_result += "\n通道号錯誤,正确為:02";
        }
        else {
            m_result += "\n通道号測試通過";
        }
        uint8_t timey;
        uint8_t timem;
        uint8_t timed;
        uint8_t timeh;
        uint8_t timemin;
        uint8_t times;
        CString timetemp = "";
        timetemp += m_input.GetAt(18);
        timetemp += m_input.GetAt(19);
        timey = strtol(timetemp, NULL, 16);
        timetemp = "";
        timetemp += m_input.GetAt(21);
        timetemp += m_input.GetAt(22);
        timem = strtol(timetemp, NULL, 16);
        timetemp = "";
        timetemp += m_input.GetAt(24);
        timetemp += m_input.GetAt(25);
        timed = strtol(timetemp, NULL, 16);
        timetemp = "";
        timetemp += m_input.GetAt(27);
        timetemp += m_input.GetAt(28);
        timeh = strtol(timetemp, NULL, 16);
        timetemp = "";
        timetemp += m_input.GetAt(30);
        timetemp += m_input.GetAt(31);
        timemin = strtol(timetemp, NULL, 16);
        timetemp = "";
        timetemp += m_input.GetAt(33);
        timetemp += m_input.GetAt(34);
        times = strtol(timetemp, NULL, 16);
        uint16_t crc_y;
        timetemp = "";
        timetemp += m_input.GetAt(36);
        timetemp += m_input.GetAt(37);
        timetemp += m_input.GetAt(39);
        timetemp += m_input.GetAt(40);
        crc_y = strtol(timetemp, NULL, 16);
        //EB90 0C 00 02 02 180512162835 C1CF
        uint8_t crc_mess[] = { len, prop, station, pass, timey, timem, timed, timeh, timemin, times };
        uint16_t crc_result = CRC16((uint8_t*)crc_mess, 10);
        if (crc_result != crc_y) {
            CString t;
            m_result += "\t校驗碼錯誤,正确為:";
            t.Format("%04X", crc_result);
            t.Insert(t.GetLength() - 2, " ");
            m_result += t;
        }
        else {
            m_result += "\t校驗碼測試通過";
        }
    }
    SetDlgItemText(IDC_T_RESULT, m_result);
    //CDialogEx::OnOK();
}
void CDlgText::OnBnClickedButton1()
{
    // TODO: 在此添加控件通知處理程式代碼
    CString result;
    CTime tmpTime;
    SYSTEMTIME systim;
    uint8_t len;
    uint8_t prop;
    uint8_t station;
    uint8_t pass;
    uint8_t timey;
    uint8_t timem;
    uint8_t timed;
    uint8_t timeh;
    uint8_t timemin;
    uint8_t times;
    uint16_t crc_result;
    CString temp;
    len = 0X0C;
    prop = 0X00;
    station = 0X02;
    pass = 0X02;
    result = "自動生成的協定幀\n";
    result += "EB 90 0C 00 02 02 ";
    this->c_Data.GetTime(tmpTime);
    timey = tmpTime.GetYear()%100;
    temp.Format("%02d", timey);
    result += temp;
    result += " ";
    timey = strtol(temp, NULL, 16);
    timem = tmpTime.GetMonth();
    temp.Format("%02d", timem);
    result += temp;
    result += " ";
    timem = strtol(temp, NULL, 16);
    timed = tmpTime.GetDay();
    temp.Format("%02d", timed);
    result += temp;
    result += " ";
    timed = strtol(temp, NULL, 16);
    this->c_Time.GetTime(tmpTime);
    timeh = tmpTime.GetHour();
    temp.Format("%02d", timeh);
    result += temp;
    result += " ";
    timeh = strtol(temp, NULL, 16);
    timemin = tmpTime.GetMinute();
    temp.Format("%02d", timemin);
    result += temp;
    result += " ";
    timemin = strtol(temp, NULL, 16);
    times = tmpTime.GetSecond();
    temp.Format("%02d", times);
    result += temp;
    result += " ";
    times = strtol(temp, NULL, 16);
    uint8_t crc_mess[] = { len, prop, station, pass, timey, timem, timed, timeh, timemin, times };
    crc_result = CRC16((uint8_t*)crc_mess, 10);
    temp.Format("%04X", crc_result);
    result += temp;
    result.Insert(result.GetLength() - 2, " ");
    SetDlgItemText(IDC_T_RESULT, result);      

5.7.8主對話框(實時流量)

首先為主對話框添加菜單欄:

管道流量采集實驗指導書

圖16增加資源示意圖

管道流量采集實驗指導書

圖17菜單分布圖

圖18快捷鍵鍵位圖 把菜單和快捷鍵和主對話框綁定,重寫OnInitDialog方法:

ShowWindow(SW_MAXIMIZE);    CMenu menu;menu.LoadMenu(IDR_MENU);
SetMenu(&menu);//添加快捷鍵//加載資源清單
m_Haccel = LoadAccelerators(theApp.m_hInstance, (LPCTSTR)IDR_ACCELERATOR);
CMysqlConnection * m_MysqlConnectin = CMysqlConnection::GetMysqlConn();
m_MysqlConnectin->ConnectionMysql();//設定序列槽參數setComm();//設定折線圖資料      

為菜單添加事件處理方法,在主對話框屬性中選擇事件添加COMMAND處理方法:

void C管道流量采集Dlg::OnExcel()
{// TODO: 在此添加指令處理程式代碼//統計分析表對話框
CSingle *single = CSingle::GetSingle();single->m_dlgExcel->DoModal();}      

其餘類似,確定所有的菜單都添加了事件處理方法。

重寫OnCancel方法,在此方法中添加連接配接關閉的方法:

if (this->c_Comm.get_PortOpen()) {this->c_Comm.put_PortOpen(FALSE);
AfxMessageBox("序列槽關閉成功");}
else {AfxMessageBox("序列槽關閉失敗,請重試");}      

重寫OnCtlColor方法:

CFont m_SetFont;switch (pWnd->GetDlgCtrlID())
{case IDC_STATIC_DATAVIEW:pDC->SetTextColor(RGB(255, 0, 0));break;
case IDC_STATIC_MS:pDC->SetTextColor(RGB(255, 0, 0));break;
case IDC_DATAVIEW:m_SetFont.CreatePointFont(400, _T("TimesNewRoman"));
pDC->SelectObject(&m_SetFont);pDC->SetTextColor(RGB(0, 255, 0));
pDC->SetBkColor(RGB(103, 103, 103));break;
case IDC_XIEYIZHEN:m_SetFont.CreatePointFont(200, _T("TimesNewRoman"));
pDC->SelectObject(&m_SetFont);pDC->SetTextColor(RGB(0, 0, 255));
pDC->SetBkColor(RGB(0, 255, 0));break;default:break;}      

增加打開序列槽的方法setComm:

CDataConfig * m_DataConfig = CDataConfig::GetCDataConfig();
CString temp;temp += m_DataConfig->getBotelv(); temp += ",";
temp += m_DataConfig->getJiaoyan(); temp += ",";    temp += m_DataConfig->getShuju();
temp += ",";    temp += m_DataConfig->getTingzhi();
this->c_Comm.put_CommPort(atoi(m_DataConfig->getComm()));
this->c_Comm.put_InBufferSize(1024);this->c_Comm.put_OutBufferSize(1024);
this->c_Comm.put_InputLen(0);this->c_Comm.put_InputMode(1);
this->c_Comm.put_RThreshold(1);this->c_Comm.put_Settings(temp);
if (!this->c_Comm.get_PortOpen()) {this->c_Comm.put_PortOpen(TRUE);
AfxMessageBox("序列槽打開成功");this->c_Comm.put_InBufferCount(0);}
else {AfxMessageBox("序列槽打開失敗,請重試");}      

增加資料顯示到實時流量折線圖的方法setTChartData:

CTeeData * m_Onedata;CString temp;
CString tt;CSeries viewdata= CSeries)this->c_TChartData.Series(0);
tt = "實時流量:";temp.Format("%.3f", this->m_Dataview);
tt += temp;tt += "  m3/s";GetDlgItem(IDC_DATAVIEW)->SetWindowText(tt);
viewdata.Clear();   for (int i = 0; i < this->m_ViewDatas->GetSize(); i++) {
m_Onedata = (CTeeData *)this->m_ViewDatas->GetAt(i);
viewdata.Add(m_Onedata->m_Viewvalue, m_Onedata->m_ViewData, NULL);}      

增加字元串轉16進制數的方法String2Hex:

int C管道流量采集Dlg::String2Hex(CString str, CByteArray& senddata)
{int hexdata, lowhexdata;int hexdatalen = 0;int len = str.GetLength();senddata.SetSize(len / 2);
for (int i = 0; i<len;){char lstr, hstr = str[i];if (hstr == ' '){i++;continue;}i++;if (i >= len)break;
lstr = str[i];hexdata = ConvertHexChar(hstr);lowhexdata = ConvertHexChar(lstr);
if ((hexdata == 16) || (lowhexdata == 16))break;
else    hexdata = hexdata * 16 + lowhexdata;i++;senddata[hexdatalen] = (char)hexdata;
hexdatalen++;}senddata.SetSize(hexdatalen);return      

增加序列槽資料幀格式化方法:

char C管道流量采集Dlg::ConvertHexChar(char ch)
{if ((ch >= '0') && (ch <= '9'))return ch - 0x30;else if ((ch >= 'A') && (ch <= 'F'))
return ch - 'A' + 10;else if ((ch >= 'a') && (ch <= 'f'))return ch - 'a' + 10;else return (-1);}      

增加16進制轉10進制的方法:

int C管道流量采集Dlg::HexToDem(CString str)
{int dem = 0;for (int i = 0; i<str.GetLength(); i++){dem = dem * 16;
if ((str[i] <= '9') && (str[i] >= '0'))        //0~9之間的字元dem += str[i] - '0';
else if ((str[i] <= 'F') && (str[i] >= 'A'))   //A~F之間的字元dem += str[i] - 'A' + 10;
else if ((str[i] <= 'f') && (str[i] >= 'a'))   //a~f之間的字元dem += str[i] - 'a' + 10;
else    return -1;                          //出錯時傳回-1}return dem;}      

增加序列槽資料接收的事件處理方法OnCommMscomm1:

VARIANT variant_inp;COleSafeArray safearray_inp;LONG len, k;
BYTE rxdata[2048]; //設定BYTE數組 An 8-bit integerthat is not signed.
CString strtemp = "";CString resultmess = "";BYTE bt;
if (this->c_Comm.get_CommEvent() == 2) //事件值為2表示接收緩沖區内有字元
{variant_inp = this->c_Comm.get_Input(); //讀緩沖區
safearray_inp = variant_inp; //VARIANT型變量轉換為ColeSafeArray型變量
len = safearray_inp.GetOneDimSize(); //得到有效資料長度for (k = 0; k<len; k++)
safearray_inp.GetElement(&k, rxdata + k);//轉換為BYTE型數組
for (k = 0; k<len; k++) //将數組轉換為Cstring型變量{bt = *(char*)(rxdata + k); //字元型
strtemp.Format("%02X", bt);resultmess += strtemp;   strtemp = "";}}
this->message += resultmess;    this->c_Comm.put_InBufferCount(0);
this->timerflag++;if(this->timerflag == 3)SetTimer(2, 300, NULL);      

增加定時器時間到的處理方法,在屬性的消息中重寫WM_TIMER的處理方法OnTimer。

CString temp;
CMysqlConnection * m_MysqlConnection = CMysqlConnection::GetMysqlConn();
CString send;CString strtemp;CString tmp;SYSTEMTIME m_Systm;//添加發送資料
//在接收資料裡處理//添加到資料庫等等
CByteArray hexdata;uint8_t addressh;uint8_t addressl;uint8_t len;uint8_t prop;
uint8_t station;uint8_t pass;uint8_t timey;uint8_t timem;uint8_t timed;uint8_t timeh;
uint8_t timemin;uint8_t times;uint16_t crc_result;uint8_t crc_y[10];
CString xieyizhentemp = "";CString ttt = "";CString xieyizhen = "";switch (nIDEvent) {
case 1:temp = "";   send = "";GetLocalTime(&m_Systm);this->m_Datatime = m_Systm;
addressh = strtol("EB", NULL, 16);addressl = strtol("90", NULL, 16);
len = strtol("0C", NULL, 16);prop = strtol("00", NULL, 16);
station = strtol("02", NULL, 16);pass = strtol("02", NULL, 16);
tmp.Format("%d", m_Systm.wYear % 100);timey = strtol(tmp, NULL, 16);
tmp.Format("%d", m_Systm.wMonth);   timem = strtol(tmp, NULL, 16);
tmp.Format("%d", m_Systm.wDay);timed = strtol(tmp, NULL, 16);
tmp.Format("%d", m_Systm.wHour);timeh = strtol(tmp, NULL, 16);
tmp.Format("%d", m_Systm.wMinute);timemin = strtol(tmp, NULL, 16);
tmp.Format("%d", m_Systm.wSecond);times = strtol(tmp, NULL, 16);
crc_y[0] = len;crc_y[1] = prop;crc_y[2] = station;crc_y[3] = pass;crc_y[4] = timey;
crc_y[5] = timem;crc_y[6] = timed;crc_y[7] = timeh;crc_y[8] = timemin;
crc_y[9] = times;   crc_result = CRC16((uint8_t*)crc_y, 10);
temp.Format("%02X, addressh);send += temp;temp.Format("%02X, addressl);
send += temp;temp.Format("%02X, len);send += temp;temp.Format("%02X, prop);
send += temp;temp.Format("%02X, station);send += temp;
temp.Format("%02X, pass);send += temp;temp.Format("%02X, timey);
send += temp;temp.Format("%02X, timem);send += temp;
temp.Format("%02X, timed);send += temp;temp.Format("%02X, timeh);
send += temp;temp.Format("%02X, timemin);send += temp;
temp.Format("%02X, times);send += temp;temp.Format("%04X", crc_result);
send += temp;send.Insert(send.GetLength() - 2, " ");    xieyizhen = "發送:";
xieyizhen += send;SetDlgItemText(IDC_XIEYIZHEN, xieyizhen);
String2Hex(send, hexdata);this->c_Comm.put_Output(COleVariant(hexdata));break;
case 2:if (this->message.GetLength() == 38 && this->timerflag == 3 && KillTimer(2)) {
xieyizhentemp = this->message;for (int i = 2; i < xieyizhentemp.GetLength(); i += 3) {
xieyizhentemp.Insert(i, " ");}
GetDlgItemText(IDC_XIEYIZHEN, ttt);ttt += "\n傳回:";ttt += xieyizhentemp;
SetDlgItemText(IDC_XIEYIZHEN, ttt);
this->timerflag = 0;strtemp += this->message.GetAt(14);
strtemp += this->message.GetAt(15);strtemp += this->message.GetAt(16);
strtemp += this->message.GetAt(17);strtemp += this->message.GetAt(18);
strtemp += this->message.GetAt(19);this->m_Dataview = HexToDem(strtemp) / 1000.0;
strtemp.Format("%d:%d:%d",this->m_Datatime.wHour,his->m_Datatime.wMinute,this->m_Datatime.wSecond);CTeeData * m_Onedata = new CTeeData(this->m_Dataview, strtemp);
this->m_ViewDatas->Add(m_Onedata);setTChartData();
strtemp.Format("%2d-%d-%d %d:%d:%d",this->m_Datatime.wYear,this->m_Datatime.wMonth,this->m_Datatime.wDay,this->m_Datatime.wHour,this->m_Datatime.wMinute,this->m_Datatime.wSecond);if (m_MysqlConnection->setData(this->m_Dataview, strtemp)) {
this->message = "";}else    {AfxMessageBox("加入資料庫失敗");return;}  }break;efault:break;}      

對話框實作大小自适應,在自适應中控件的大小需要對應的改變。

首先增加自使用的頭檔案easysize.h:

#ifndef __EASYSIZE_H_#define __EASYSIZE_H_#define ES_BORDER 0xffffffff
#define ES_KEEPSIZE 0xfffffffe#define ES_HCENTER 0x00000001
#define ES_VCENTER 0x00000002#define DECLARE_EASYSIZE \void __ES__RepositionControls(BOOL bInit);\void __ES__CalcBottomRight(CWnd *pThis, BOOL bBottom, int &bottomright, int &topleft, UINT id, UINT br, int es_br, CRect &rect, int clientbottomright);#define INIT_EASYSIZE __ES__RepositionControls(TRUE); __ES__RepositionControls(FALSE)#define UPDATE_EASYSIZE if(GetWindow(GW_CHILD)!=NULL) __ES__RepositionControls(FALSE)#define EASYSIZE_MINSIZE(mx,my,s,r) if(r->right-r->left < mx) { if((s == WMSZ_BOTTOMLEFT)||(s == WMSZ_LEFT)||(s == WMSZ_TOPLEFT)) r->left = r->right-mx; else r->right = r->left+mx; } if(r->bottom-r->top < my) { if((s == WMSZ_TOP)||(s == WMSZ_TOPLEFT)||(s == WMSZ_TOPRIGHT)) r->top = r->bottom-my; else r->bottom = r->top+my; }#define BEGIN_EASYSIZE_MAP(class) \void class::__ES__CalcBottomRight(CWnd *pThis, BOOL bBottom, int &bottomright, int &topleft, UINT id, UINT br, int es_br, CRect &rect, int clientbottomright) {\if(br==ES_BORDER) bottomright = clientbottomright-es_br;\else if(br==ES_KEEPSIZE) bottomright = topleft+es_br;\else { CRect rect2;\pThis->GetDlgItem(br)->GetWindowRect(rect2); pThis->ScreenToClient(rect2);\bottomright = (bBottom?rect2.top:rect2.left) - es_br;}}\void class::__ES__RepositionControls(BOOL bInit) { CRect rect,rect2,client; GetClientRect(client);#define END_EASYSIZE_MAP Invalidate(); UpdateWindow(); }#define EASYSIZE(id,l,t,r,b,o) \static int id##_es_l, id##_es_t, id##_es_r, id##_es_b;\if(bInit) {\GetDlgItem(id)->GetWindowRect(rect); ScreenToClient(rect);\if(o & ES_HCENTER) id##_es_l = rect.Width()/2; else {\if(l==ES_BORDER) id##_es_l = rect.left; else if(l==ES_KEEPSIZE) id##_es_l = rect.Width(); else {\GetDlgItem(l)->GetWindowRect(rect2); ScreenToClient(rect2);\id##_es_l = rect.left-rect2.right;}}\if(o & ES_VCENTER) id##_es_t = rect.Height()/2; else {\if(t==ES_BORDER) id##_es_t = rect.top; else if(t==ES_KEEPSIZE) id##_es_t = rect.Height(); else {\GetDlgItem(t)->GetWindowRect(rect2); ScreenToClient(rect2);\id##_es_t = rect.top-rect2.bottom;}}\if(o & ES_HCENTER) id##_es_r = rect.Width(); else { if(r==ES_BORDER) id##_es_r = client.right-rect.right; else if(r==ES_KEEPSIZE) id##_es_r = rect.Width(); else {\GetDlgItem(r)->GetWindowRect(rect2); ScreenToClient(rect2);\id##_es_r = rect2.left-rect.right;}}\if(o & ES_VCENTER) id##_es_b = rect.Height(); else { if(b==ES_BORDER) id##_es_b = client.bottom-rect.bottom; else if(b==ES_KEEPSIZE) id##_es_b = rect.Height(); else {\GetDlgItem(b)->GetWindowRect(rect2); ScreenToClient(rect2);\id##_es_b = rect2.top-rect.bottom;}}\} else {\int left,top,right,bottom; BOOL bR = FALSE,bB = FALSE;\if(o & ES_HCENTER) { int _a,_b;\if(l==ES_BORDER) _a = client.left; else { GetDlgItem(l)->GetWindowRect(rect2); ScreenToClient(rect2); _a = rect2.right; }\if(r==ES_BORDER) _b = client.right; else { GetDlgItem(r)->GetWindowRect(rect2); ScreenToClient(rect2); _b = rect2.left; }\left = _a+((_b-_a)/2-id##_es_l); right = left + id##_es_r;} else {\if(l==ES_BORDER) left = id##_es_l;\else if(l==ES_KEEPSIZE) { __ES__CalcBottomRight(this,FALSE,right,left,id,r,id##_es_r,rect,client.right); left = right-id##_es_l;\} else { GetDlgItem(l)->GetWindowRect(rect2); ScreenToClient(rect2); left = rect2.right + id##_es_l; }\if(l != ES_KEEPSIZE) __ES__CalcBottomRight(this,FALSE,right,left,id,r,id##_es_r,rect,client.right);}\if(o & ES_VCENTER) { int _a,_b;\if(t==ES_BORDER) _a = client.top; else { GetDlgItem(t)->GetWindowRect(rect2); ScreenToClient(rect2); _a = rect2.bottom; }\
if(b==ES_BORDER) _b = client.bottom; else { GetDlgItem(b)->GetWindowRect(rect2); ScreenToClient(rect2); _b = rect2.top; }\top = _a+((_b-_a)/2-id##_es_t); bottom = top + id##_es_b;} else {\if(t==ES_BORDER) top = id##_es_t;\else if(t==ES_KEEPSIZE) { __ES__CalcBottomRight(this,TRUE,bottom,top,id,b,id##_es_b,rect,client.bottom); top = bottom-id##_es_t;\} else { GetDlgItem(t)->GetWindowRect(rect2); ScreenToClient(rect2); top = rect2.bottom + id##_es_t; }\if(t != ES_KEEPSIZE) __ES__CalcBottomRight(this,TRUE,bottom,top,id,b,id##_es_b,rect,client.bottom);}\GetDlgItem(id)->MoveWindow(left,top,right-left,bottom-top,FALSE);\}#endif //__EASYSIZE_H_      

然後重寫OnSize方法:

UPDATE_EASYSIZE;      

在主對話框的cpp檔案中最後部分添加控件映射:

BEGIN_EASYSIZE_MAP(C管道流量采集Dlg)
    EASYSIZE(IDC_TC_DATA, ES_BORDER, IDC_XIEYIZHEN, ES_BORDER, ES_BORDER, 0)
    EASYSIZE(IDC_XIEYIZHEN, ES_BORDER, IDC_DATAVIEW, ES_BORDER, IDC_TC_DATA,0)
    EASYSIZE(IDC_DATAVIEW, ES_BORDER, ES_BORDER, ES_BORDER, IDC_XIEYIZHEN, 0)      

在初始化方法中添加INIT_EASYSIZE;,在類的聲明中最開始添加DECLARE_EASYSIZE。

管道流量采集.h:

// 管道流量采集.h : PROJECT_NAME 應用程式的主頭檔案
#pragma
#ifndef __AFXWIN_H__
    #error
#endif
#include "resource.h"       // 主符号
// C管道流量采集App: 
// 有關此類的實作,請參閱 管道流量采集.cpp
//
class C管道流量采集App : public CWinApp
{
public:
    C管道流量采集App();
// 重寫
public:
    virtual BOOL InitInstance();
// 實作
    DECLARE_MESSAGE_MAP()
};
extern      

管道流量采集.cpp:

// 管道流量采集.cpp : 定義應用程式的類行為。
#include "stdafx.h"
#include "管道流量采集.h"
#include "管道流量采集Dlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// C管道流量采集App
BEGIN_MESSAGE_MAP(C管道流量采集App, CWinApp)
    ON_COMMAND(ID_HELP, &CWinApp::OnHelp)
END_MESSAGE_MAP()
// C管道流量采集App 構造
C管道流量采集App::C管道流量采集App()
{
    // 支援重新啟動管理器
    m_dwRestartManagerSupportFlags = AFX_RESTART_MANAGER_SUPPORT_RESTART;
    // TODO: 在此處添加構造代碼,
    // 将所有重要的初始化放置在 InitInstance 中
}
// 唯一的一個 C管道流量采集App 對象
C管道流量采集App theApp;
// C管道流量采集App 初始化
BOOL C管道流量采集App::InitInstance()
{
    // 如果一個運作在 Windows XP 上的應用程式清單指定要
    // 使用 ComCtl32.dll 版本 6 或更高版本來啟用可視化方式,
    //則需要 InitCommonControlsEx()。  否則,将無法建立視窗。
    INITCOMMONCONTROLSEX InitCtrls;
    InitCtrls.dwSize = sizeof(InitCtrls);
    // 将它設定為包括所有要在應用程式中使用的
    // 公共控件類。
    InitCtrls.dwICC = ICC_WIN95_CLASSES;
    InitCommonControlsEx(&InitCtrls);
    OleInitialize(NULL);
    AfxEnableControlContainer();
    CWinApp::InitInstance();
    AfxEnableControlContainer();
    // 建立 shell 管理器,以防對話框包含
    // 任何 shell 樹視圖控件或 shell 清單視圖控件。
    CShellManager *pShellManager = new CShellManager;
    // 激活“Windows Native”視覺管理器,以便在 MFC 控件中啟用主題
CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows));
    // 标準初始化
    // 如果未使用這些功能并希望減小
    // 最終可執行檔案的大小,則應移除下列
    // 不需要的特定初始化例程
    // 更改用于存儲設定的系統資料庫項
    // TODO: 應适當修改該字元串,
    // 例如修改為公司或組織名
    SetRegistryKey(_T("應用程式向導生成的本地應用程式"));
    C管道流量采集Dlg dlg;
    m_pMainWnd = &dlg;
    INT_PTR nResponse = dlg.DoModal();
    if (nResponse == IDOK)
    {
        // TODO: 在此放置處理何時用
        //  “确定”來關閉對話框的代碼
    }
    else if (nResponse == IDCANCEL)
    {
        // TODO: 在此放置處理何時用
        //  “取消”來關閉對話框的代碼
    }
    else if (nResponse == -1)
    {
        TRACE(traceAppMsg, 0, "警告: 對話框建立失敗,應用程式将意外終止。\n");
        TRACE(traceAppMsg, 0, "警告: 如果您在對話框上使用 MFC 控件,則無法 #define _AFX_NO_MFC_CONTROLS_IN_DIALOGS。\n");
    }
    // 删除上面建立的 shell 管理器。
    if (pShellManager != NULL)
    {
        delete pShellManager;
    }
#ifndef _AFXDLL
    ControlBarCleanUp();
#endif
    // 由于對話框已關閉,是以将傳回 FALSE 以便退出應用程式,
    //  而不是啟動應用程式的消息泵。
    return FALSE;
}      

5.8資料庫額外操作

      首先在網際網路上下載下傳32位的資料庫檔案,如果本機系統是32的,那麼可以不用下載下傳,如果實在找不到下載下傳的位址,可以到32位的資料庫安裝目錄中拷貝檔案:

管道流量采集實驗指導書

圖19資料庫32連接配接檔案圖

【項目】->【屬性】->【配置屬性】->【正常屬性】->【字元集】->【多位元組字元集】

【配置屬性】->【C/C++】->【正常】->【附加包含目錄】->【C:\Program Files\MySQL\MySQL Server 5.7\include;%(AdditionalIncludeDirectories)】

【連結器】->【正常】->【附加庫目錄】->【C:\Program Files\MySQL\MySQL Server 5.7\lib;%(AdditionalLibraryDirectories)】

【連結器】->【輸入】->【附加依賴項】->【libmysql32.lib;%(AdditionalDependencies)】

然後把libmysql32.dll重命名為libmysql.dll并且放到Debug目錄下。

5.9常見錯誤

預編譯無法使用或這打開**預編譯檔案:

【項目】->【屬性】->【配置屬性】->【C/C++】->【預編譯頭】->【預編譯頭】,如果原來是使用改成建立,原來是建立改成使用。

*.dll檔案無法加載:

管道流量采集實驗指導書

圖20錯誤解決設定圖

第一次編譯時間會比較長,無法打開的dll檔案會從網際網路上下載下傳,是以必須聯網。

5.10替換标題欄圖示

      MFC預設的标題欄圖示替換首先需要找到自己需要替換的ico檔案,然後類似導入圖檔一樣導入到工程中,其ID為IDI_ICON1,并且把ico檔案放到res檔案夾下,然後打開resource.hz增加:

#define      

最後在主對話框的構造方法中添加:

m_hIcon = AfxGetApp()->LoadIcon(IDI_ICON1);      

5.11打包

      在前面的操作都沒有問題,且debug調試全部通過後,即可進入這個操作。

首先切換到Release模式。

管道流量采集實驗指導書

圖21切換模式圖

      然後重寫設定第8部分的所有操作,操作成功後重新生成解決方案,當Release中調試通過後,到網際網路上下載下傳打包模闆。

管道流量采集實驗指導書

圖22打包模闆詳細資訊

      把打包模闆安裝好後,在工程的解決方案視圖中右鍵整個解決方案->【添加】->【建立項目】。

管道流量采集實驗指導書

圖23建立安裝包工程圖

此時整個解決方案中有兩個項目:

管道流量采集實驗指導書

圖24解決方案圖

右鍵安裝包項目->【Add】->【項目輸出】->【主輸出】,其次:

管道流量采集實驗指導書

圖25添加子產品圖

添加所有32位的檔案。

右鍵安裝包項目->【View】->【檔案系統】,然後添加Release檔案夾中除去exe檔案的所有檔案。

管道流量采集實驗指導書

圖26安裝封包件系統圖

      其中Pipe Line.ico是應用程式安裝成功後快捷方式的圖示,也需要導入;msiexec.exe是32位系統中解除安裝程式的,以及折線圖和序列槽的ocx檔案,這些檔案都是安裝目錄中的檔案。User’s Desktop是安裝包安裝成功後在使用者桌面的快捷方式,首先建立一個主輸出的快捷方式和一個解除安裝程式的快捷方式,然後重命名為自己需要的名字,設定主輸出的icon為添加的ico圖示;修改解除安裝程式的快捷方式的Arguments的屬性值為/x {D1AB7D8F-BCD0-4F41-857B-549373B3EDE5},大括号中的數字在安裝包的屬性的ProductCode中的數值。同樣在開始菜單中拷貝這兩個檔案。

右鍵整個解決方案->【批生成】。

管道流量采集實驗指導書

圖27批生成配置圖

選中圖中的兩個勾,選擇重新生成。如果一切順利将會在輸出視窗顯示。

管道流量采集實驗指導書

圖28安裝包生成成功圖

此時,安裝封包件在工程檔案下安裝封包件夾的Release檔案夾下。

管道流量采集實驗指導書

圖29安裝包位置圖

六、 總結