(VC+MFC網絡聊天工具)詳細設計(共48頁)_第1頁
(VC+MFC網絡聊天工具)詳細設計(共48頁)_第2頁
(VC+MFC網絡聊天工具)詳細設計(共48頁)_第3頁
(VC+MFC網絡聊天工具)詳細設計(共48頁)_第4頁
(VC+MFC網絡聊天工具)詳細設計(共48頁)_第5頁
已閱讀5頁,還剩43頁未讀 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

1、精選優(yōu)質文檔-傾情為你奉上第2章系統(tǒng)分析及開發(fā)技術說明2.1節(jié)需求分析2.1.1節(jié)功能需求分析功能需求發(fā)送基本聊天信息傳輸音視頻數據傳輸文件白板共享屏幕保持連接發(fā)送文本信息發(fā)送圖片信息圖2.1功能需求說明圖(1)用戶端的基本聊天信息發(fā)送,這些基本聊天信息包括文本和圖片。文本和圖片聊天是聊天軟件最基礎的功能。用戶通過輸入IP來查找用戶,并申請加為好友,在對方同意加為好友后,在線用戶列表就會更新用戶,把加入的用戶添加到用戶列表中。這樣,兩個用戶之前就可以實現通信了。在信息傳輸中,預計利用TCP/IP協(xié)議中的UDP協(xié)議,這是面向無連接的協(xié)議,但發(fā)送速度快,用于聊天信息傳輸用適合。(2)用戶端的音視頻

2、數據傳輸,這是本設計的擴展功能。用戶可以正常通信后,就可以選擇是否進行語音或視頻聊天。本功能也將采用UDP協(xié)議,UDP協(xié)議可能會丟失數據,但對于音視頻聊天需要傳輸大量數據但又允許丟失少量數據的情況下,UDP的快速發(fā)送信息的特點就得到很好的體現。(3)用戶端文件傳輸的功能,用戶之間可以斷點續(xù)傳文件。在傳文件之前,首先創(chuàng)建一信息文件,記錄文件傳送的一些信息,并根據傳輸的數據量實時修改。如果沒有傳完,下次就可以繼續(xù)打開這個信息文件,接著上次的進度傳輸。因為文件傳輸入要求數據不能出錯,因此此模塊采用TCP協(xié)議。(4)用戶端之間白板和共享屏幕的功能,這個功能有些類似視頻的傳輸,因些并不是很難,可以在視頻

3、傳輸的功能上加以修改。(5)用戶之間后臺的連接,每個用戶隔指定時間會向用戶列表中的每一用戶發(fā)送消息,查看用戶是否在線,如果不在線,就更新用戶列表,刪除用戶。2.1.2節(jié)數據需求分析(1)客戶端之間聊天信息。在控件上顯示時格式化,更易于用戶的查看自己發(fā)送或接收到的信息。(2)在線用戶列表信息。服務器端存放在適當的空間中,在發(fā)送給客戶端時,對信息列表進行格式化,便于客戶端提取信息。(3)客戶端向服務器端發(fā)送的確認在線信息。包括客戶端剛剛啟動時的初始化信息和在使用過程中的確認在線信息。(4)其它程序內部可能需要設計的數據結構體。2.1.3節(jié)性能需求分析(1)可靠性高,能在由于系統(tǒng)問題或其它原因產生錯

4、誤后,作出相對應處理,比如網絡初始化失敗、服務器不在線等,可以提示用戶安全退出本程序,在出現不可知的錯誤以后,可以盡量安全的退出程序。在程序的設計過程中,要求能盡可能多的設想到用戶使用過程中可能發(fā)生的事件,并能在判斷事件后做出相應的處理,使程序具有較高的容錯性能。(2)宜操作性,程序簡單易懂,容易上手使用。設計界面是,簡化界面的復雜性,模擬QQ等現有即時通訊工具的界面,使用戶能很容易看懂并使用。(3)開發(fā)文檔易理解,保證以后自己二次開發(fā)或他人接手開發(fā)時,能夠清晰的理解整個系統(tǒng)的設計思路和實現細節(jié)。(4)模塊化設計此軟件的功能,不同的模塊實現不同的功能,使得軟件易于以后的維護與擴展,在以后可以更

5、好的完善本軟件的功能,更方便于在工作中的應用。2.1.4節(jié)運行需求分析(1)用戶界面程序較小,啟動速度快,無啟動界面。在本地局域網中使用,所以無需進行用戶登錄,無需認證界面,啟動后的應用界面要清爽,設計要簡單明了,要具有較高的易用性。(2)故障處理在遇到可預知的故障與情況時,能提示用戶并自動退出;在遇到不可預知的故障時能安全退出。2.4節(jié)Winsock網絡編程Windows Sockets是從Berkeley Sockets擴展而來的,其在繼承Berkeley Sockets的基礎上,又進行了新的擴充。這些擴充主要是提供了一些異步函數,并增加了符合WINDOWS消息驅動特性的網絡事件異步選擇機

6、制5。Windows Sockets由兩部分組成:開發(fā)組件和運行組件。開發(fā)組件:Windows Sockets 實現文檔、應用程序接口(API)引入庫和一些頭文件。運行組件:Windows Sockets 應用程序接口的動態(tài)鏈接庫(WINSOCK.DLL)。2.4.1節(jié)Socket套接字(Socket)最初是由加利福尼亞大學Berkeley分校為UNIX操作系統(tǒng)開發(fā)的網絡通信接口,隨著UNIX操作系統(tǒng)的廣泛使用,套接字成為當前最流行的網絡通信應用程序接口之一7。90年代初,由Sun Microsystems,JSB Corporation,FTP software,Microdyne和Micr

7、osoft等幾家公司共同制定了一套標準,即Windows Sockets規(guī)范。Windows Sockets API是Microsoft Windows的網絡程序設計接口,它在繼承了Berkeley Sockets主要特征的基礎上,又對它進行了重要擴充。這些擴充主要是提供了一些異步函數,并增加了符合Windows消息驅動特性的網絡事件異步選擇機制。這些擴充有利于應用程序開發(fā)者編制符合Windows編程模式的軟件,它使在Windows下開發(fā)高性能的網絡通信程序成為可能。Socket實際上是指一個通信端點,借助于它,用戶所開發(fā)的Socket應用程序,可以通過網絡與其它Socket應用程序進行通信。

8、近年來,隨著計算機網絡與Windows 95的流行,許多用戶所開發(fā)的應用程序需要實現網絡間的數據通信。2.4.2節(jié)開發(fā)Windows Sockets網絡通信程序的軟、硬件環(huán)境所采用的操作系統(tǒng)軟件可以是Windows 95,2000,XP,也可以是Windows NT,因為它們都支持Windows Sockets API,在以下的介紹中,我們將以在Windows XP環(huán)境下的開發(fā)為例。 所采用的編程語言一般可選目前較流行使用的可視化和采用面向對象技術的Microsoft Visual C+ 6.0。Visual C+ 6.0可在Windows XP或Windows NT環(huán)境下運行,其開發(fā)系統(tǒng)增加

9、了全面集成的基于Windows 的開發(fā)工具以及一個基于傳統(tǒng)C/C+開發(fā)過程的“可視化”用戶界面驅動模型。Visual C+ 6.0中的Microsoft基類(MFC,即Microsoft Foundation Class)庫是一系列C+類,其中封裝著為Microsoft Windows操作系統(tǒng)系列編寫應用程序的各種功能 。在有關套接字方面,Visual C+ 6.0對原來的Windows Sockets庫函數進行了一系列封裝,繼而產生了CSocket 、CSocketFile等類,它們封裝著有關Socket的各種功能8。 所采用的網絡通信協(xié)議一般是TCP / IP。Windows XP和Win

10、dows NT都帶有該協(xié)議。但是,所開發(fā)的網絡通信應用程序并不能直接與TCP / IP核心打交道,而是與網絡應用編程界面Windows Sockets API打交道。Windows Sockets API則可直接與TCP/IP核心進行溝通。TCP / IP核心協(xié)議連同網絡物理介質(如網卡)一起,都是提供網絡應用程序間相互通信的設施。2.4.3節(jié)CSocket類編程模型使用CSocket對象涉及CArchive和CSocketFile 類對象。以下介紹的針對字節(jié)流型套接字的操作步驟中,只有第三步對于客戶方和服務方操作是不同的,其他步驟都相同13。 (1)構造一個CSocket對象。 (2)使用這

11、個對象的Create()成員函數產生一個socket對象。在客戶方程序中,除非需要數據報套接字,Create()函數一般情況下應該使用默認參數。而對于服務方程序,必須在調用Create時指定一個端口。需要注意的是,Carchive類對象不能與數據報(UDP)套接字一起工作,因此對于數據報套接字,CAsyncSocket和CSocket 的使用方法是一樣的。 (3)如果是客戶方套接字,則調用CAsyncSocket Connect()函數與服務方套接字連接;如果是服務方套接字,則調用CAsyncSocketListen()開始監(jiān)聽來自客戶方的連接請求,收到連接請求后,調用CAsyncSocket

12、Accept()函數接受請求,建立連接。請注意Accept()成員函數需要一個新的并且為空的CSocket對象作為它的參數,解釋同上。 (4)產生一個CSocketFile對象,并把它與CSocket 對象關聯(lián)起來。(5)為接收和發(fā)送數據各產生一個CArchive 對象,把它們與CSocketFile對象關聯(lián)起來。切記CArchive是不能和數據報套接字一起工作的。 (6)使用CArchive對象的Read()、Write()等函數在客戶與服務方傳送數據。(7)通訊完畢后,銷毀CArchive、CSocketFile和CSocket對象。2.4.4節(jié)用VC6.0進行Windows Socket

13、s程序開發(fā)的技術要點(1)同常規(guī)編程一樣,無論服務器方還是客戶方應用程序都要進行所謂的初始化處理,這部分工作仍可采用消息驅動機制來先期完成。 (2)一般情況下,網絡通信程序是某應用程序中的一模塊。在單獨調試網絡通信程序時,要盡量與采用該通信模塊的其它應用程序開發(fā)者約定好,統(tǒng)一采用一種界面形式,即單文檔界面SDI、多文檔界面MDI和基于對話框界面中的一種(這在使用AppWizard形成項目Project文件時有提示),盡管這并非必須,但可使通信模塊在移植到所需的應用程序時省時省力,因為Visual C+ 6.0這種可視化語言在給我們提供方便的同時,也給我們帶來某些不便,譬如所形成的項目文件中的許

14、多相關文件與所采用的界面形式密切聯(lián)系,許多消息驅動功能,隨所采用的界面形式不同而各異。 當然,也可將通信模塊函數化,并形成一個動態(tài)連接庫文件(DLL文件),供主程序調用。 (3)以通信程序作為其中一個模塊的應用程序往往不是在等待數據發(fā)送或接收完之后再做其它工作,因而在主程序中要采用多線程(Multithreaded)技術。即將數據的發(fā)或收,放在一個具有一定優(yōu)先級(一般宜取較高優(yōu)先級)的輔助線程中,在數據發(fā)或收期間,主程序仍可進行其它工作,譬如利用上一個周期收到的數據繪制曲線 。Visual C+ 6.0中的MFC提供了許多有關啟動線程、管理線程、同步化線程、終止線程等功能函數14。(4)在許多

15、情況下,要求通信模塊應實時地收、發(fā)數據。譬如調用之的主程序以0.5秒為一周期,在這段時間內 ,要進行如下工作:接收數據,利用收到的數據進行運算,將運算結果發(fā)送到其它計算機節(jié)點,周而復始。我們在充分利用Windows Sockets的基于消息的網絡事件異步選擇機制,用消息來驅動數據的發(fā)送和接收的基礎上,結合使用其他措施,如將數據的收和發(fā)放在高優(yōu)先級線程,在軟件設計上,安排好時序,盡量避免在同一時間內,雙方都在向對方發(fā)送大量數據的情況發(fā)生,保證網絡要有足夠的帶寬等,成功地實現了數據傳輸的實時性2。第3章詳細設計本章將從各個方面介紹本系統(tǒng)的設計。先從基本框架的設計出發(fā),然后逐步介紹好友管理、聊天模塊

16、、聊天室模塊、傳送文件模塊、共享屏幕模塊、白板模塊、音、視頻模塊和調試模塊,所以本章是本論文的重點。3.1節(jié)基本框架設計本節(jié)內容將介紹除各個功能模塊外的設計,包括界面上的處理、保持好友在線列表等的處理。有些內容可能并不屬性框架設計,但這些內容也不具有單獨使用一節(jié)來介紹的必要,所以把這些內容也一并放到這些節(jié)來介紹。這也是為了區(qū)分設計周圍的處理與各個功能模塊的處理。3.1.1節(jié)宏和數據結構的定義程序中用到了很多宏和數據結構,這些宏和數據結構在多個模塊中都有用到,因此程序中專門新建一個頭文件Global.h,此頭文件里是程序中很到的宏和數據結構的定義1。在StdAfx.h文件包含Global.h,在

17、程序其他地方都可以使用Global.h中的宏和定義的數據結構。這樣處理還有一個好處,如果需要修改某些宏的值,可以直接在Global.h中修改,而不用到處去找宏的定義,方便和快捷。3.1.2節(jié)程序配置文件程序中很多信息需要保存,比如用戶名和熱鍵,因些程序用到了配置文件,默認的配置文件名為conf.ini。程序用讀取和寫入配置文件系列函數來管理此配置文件。3.1.3節(jié)主界面初始化用過QQ的人都知道,QQ主面板總是處于其他程序的上面,而且QQ在任務欄沒有圖標,而是把圖標放到了托盤區(qū),另外,我們還可以按Ctrl+Alt+Z默認的快捷鍵隱藏和顯示QQ主面板。不但QQ是這樣處理的,很多聊天軟件都采用此種處

18、理方式。本設計也不例外,同樣也要達到這樣的目的。下面從各個方面來說明本設計的處理方式:(1)不在任務欄顯示圖標CDialog dlgParent;dlgParent.Create( IDD_DIALOG_BG );dlgParent.ShowWindow( SW_HIDE );CInstantMessagingDlg dlg( &dlgParent );m_pMainWnd = &dlg;ModifyStyleEx( WS_EX_APPWINDOW, 0 );上面代碼就達到了程序主界面不在任務顯示的目的。首先,我們創(chuàng)建一個對話框,并隱藏此對放框,然后把這個對話框作為主界面對話框

19、的父窗口,然后在主界面對話框的初始化函數中修改其風格,去掉WS_EX_APPWINDOW風格。這樣,主界面就不會出現在任務了3。(2)將主界面放在最上層將程序放到頂層,很多程序都有這功能,比如金山詞霸等,實現起來其實很簡單,只用一條語句就可以達到目的:SetWindowPos( &wndTopMost, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE );第一個參數就是將程序放到所有非頂層窗口的頂層,如果有多個程序都是頂層窗口,那么他們誰在上面,就要看當前誰是激活的窗口。最后一個參數,是用位或組后起來的,從字面意思上我們就能理解到這是不移動不改變大小的意思,忽略

20、了當中的4個參數6。(3)熱鍵的處理設計中默認的熱鍵是Ctrl+Alt+Z,當然程序允許用戶自己定義熱鍵,自定義的熱鍵將保存在conf.ini文件中。熱鍵的功能可以隱藏、顯示主界面,有消息到達時,按熱鍵也可以打開聊天對話框。:RegisterHotKey( m_hWnd, IDHOTKEY, m_wModifiers, m_wVirtualKeyCode );使用全局函數RegisterHotKey可以注冊熱鍵,如果注冊的熱鍵沒有被其他程序占用,那么注冊成功。注冊成功后,如果按熱鍵,那么程序就會接受到WM_HOTKEY消息,因此我們還需要自己處理WM_HOTKEY消息12:void OnHot

21、key( WPARAM wParam, LPARAM lParam );BEGIN_MESSAGE_MAP(CInstantMessagingDlg, CDialog)ON_MESSAGE( WM_HOTKEY, OnHotkey )/AFX_MSG_MAPEND_MESSAGE_MAP()在消息映射中,我們用OnHotkey()函數來處理WM_HOTKEY消息。void CInstantMessagingDlg:OnHotkey( WPARAM wParam, LPARAM lParam )if( this->IsWindowVisible() )ShowWindow( SW_HIDE

22、 );elseShowWindow( SW_SHOW );:SetForegroundWindow( m_hWnd );在OnHotkey()函數中判斷主界面是否是可見的,如果是可見的那么隱藏起來,否則顯示,并且把主界面設為前景窗口。(4)最小化和關閉按鈕的處理我們希望單擊程序右上角的最小化按鈕時,程序隱藏起來,而單擊關閉按鈕時,程序會提示是否退出,而不會悄無聲息的退出。void CInstantMessagingDlg:OnSysCommand(UINT nID, LPARAM lParam)if( nID = SC_MINIMIZE )this->ShowWindow( SW_HID

23、E);elseCDialog:OnSysCommand(nID, lParam);void CInstantMessagingDlg:OnCancel() if( IDOK = MessageBox( "要退出嗎?", "退出", MB_OKCANCEL | MB_ICONINFORMATION | MB_DEFBUTTON2 ) )DestroyWindow();在程序中處理OnSysCommand()函數和OnCancel ()函數就實現了我們要的功能。(5)托盤圖標的顯示至此,程序已不在任務欄顯示圖標,已是最頂層窗口,而且也已有熱鍵功能,但是還沒有

24、實現托盤圖標的顯示。實現托盤圖標的代碼如下:NOTIFYICONDATAm_nid;HICON hIcon= AfxGetApp()->LoadIcon( STATE_ONLINE );m_nid.hIcon= hIcon;m_nid.hWnd= m_hWnd;m_nid.cbSize= sizeof( NOTIFYICONDATA );m_nid.uCallbackMessage= WM_SHELLNOTIFY;m_nid.uFlags= NIF_ICON | NIF_MESSAGE | NIF_TIP;m_nid.uID= IDR_MENU1;sprintf( m_nid.szTip

25、, "即時聊天軟件" );Shell_NotifyIcon( NIM_ADD, &m_nid );這樣我們就在托盤區(qū)顯示了STATE_ONLINE的圖標,把鼠標移動到圖標上一會,還會出現“即時聊天軟件”的提示框。如果你們對圖標有單擊和雙擊等操作,程序會收到WM_SHELLNOTIFY消息,因此,我們還必須處理WM_SHELLNOTIFY消息。void OnShellNotifyProc( WPARAM wParam, LPARAM lParam );BEGIN_MESSAGE_MAP(CInstantMessagingDlg, CDialog)/AFX_MSG_MA

26、P(CInstantMessagingDlg)ON_MESSAGE( WM_SHELLNOTIFY, OnShellNotifyProc )/AFX_MSG_MAPEND_MESSAGE_MAP()void CInstantMessagingDlg:OnShellNotifyProc( WPARAM wParam, LPARAM lParam )if( lParam = WM_LBUTTONDBLCLK )else if( lParam = WM_RBUTTONUP )與熱鍵處理一樣,OnShellNotifyProc()函數響應我們對圖標的操作,其中l(wèi)Param參數表示消息號,在本設計中只處

27、理左鍵雙擊(顯示主界面)和右鍵單擊(彈出菜單)。在托盤添加圖標,退出程序前,如果沒有從托盤刪除圖標,那么托盤區(qū)的圖標會一直保留下來,直到鼠標移過托盤區(qū)引起托盤區(qū)的重繪,這當然不是我們所希望的結果。void CInstantMessagingDlg:OnDestroy() / 刪除在托盤建立的圖標:Shell_NotifyIcon( NIM_DELETE, &m_nid );CDialog:OnDestroy();以上代碼在程序退出時調用,從托盤從刪除圖標。(6)只允許運行唯一實例這點與QQ不同,在一臺機子上可以運行多個QQ,但本程序只允許運行一個實例。只允許運行一個實例,有多種方法,本

28、設計采用的是創(chuàng)建命名事件的方法:HANDLE hEvent = :CreateEvent( NULL, FALSE, FALSE, "InstantMessaging" );if( hEvent )if( ERROR_ALREADY_EXISTS = GetLastError() )return FALSE;事件與普通變量不一樣,普通變量只在運行的當前程序中有效,而事件在整個系統(tǒng)中都有效。當首次運行程序時,會創(chuàng)建一個名為“InstantMessaging”的事件,這個事件在系統(tǒng)范圍內有效,當再次運行程序時,程序會嘗試著創(chuàng)建同名的事件,因為之前已經創(chuàng)建了這個事件,因此系統(tǒng)會返

29、回之前創(chuàng)建事件的句柄,但GetLastError()會返回ERROR_ALREADY_EXISTS,表明需創(chuàng)建的事件之前已經創(chuàng)建,為了保證只允許一個實例,這個實例就不再允許運行,直接返回,退出程序。3.1.3節(jié)主界面布局程序主界面如下:圖3.1主界面左上角顯示的是自己的頭像、狀態(tài)和昵稱;右上角的列表框是查找IP輸入框,下面是添加按鈕;在下面一點的列表框是自己的址列表框,顯示了自己的所有IP;主界面中央是用戶列表框;最下面是4個功能按鈕。用戶列表框是一列一列的顯示添加的好友,最左邊是好友的頭像;中部上邊是好友的昵稱,下面是好友的IP;右下角是刪除好友按鈕和攝像頭按鈕,當然好友必須有攝像頭才會顯示

30、攝像頭按鈕。有兩種方式添加聯(lián)系人:(1)在右上解的查找IP輸入框里輸入IP,然后單擊下面的添加按鈕。也可以從IP輸入框里選擇以前加過的好友IP。程序允許保存10個最近聯(lián)系人的IP,當新添加聯(lián)系人時,如果已保存了10個聯(lián)系人的IP,程序會按照時間的先后順序覆蓋之前的IP。在列表框展開下拉列表后,可以按DELETE鍵刪除選定的IP。(2)選定一個自己的IP,然后單擊“網段”按鈕。此功能可以向選定IP的IP段發(fā)送添加請求的消息,這相當于批量添加好友的功能。在主界面任何地點單擊左鍵不放開,可以拖動程序;單擊右鍵,會彈出菜單,用戶選中相應的菜單項,可以執(zhí)行相應的功能;在任何地點雙擊左鍵,可以打開“個人設

31、置”對話框,如下:圖3.2設置對話框最后一項“允許別人直接將我加為聯(lián)系”的意思是別人添加我為好友時,不會彈出請求對話框而直接加為好友。單擊保存后,此對話框里的內容會保存到config.ini配置文件中。運行程序后,會從config.ini讀取用戶信息,并在主界面中作相應的設置。在主界面,添加、聊天室、傳送文件、共享屏幕和白板按鈕都是自繪按鈕,可以顯示圖片,有提示能力,當鼠標移動到其上一會兒后,會彈出提示框,而且這些按鈕都具有XP風格,既鼠標滑過時會顯示不同的狀態(tài)。用戶列表框也是自繪的,普通的列表控件無法顯示我們所需的信息。自繪按鈕和自繪列表框會作為一個單獨的模塊來介紹,這兒就不作過多的介紹。3

32、.1.4節(jié)自繪按鈕VC+6.0自帶的按鈕控件不具有XP風格,而且也不能顯示圖像,作為一款好的軟件,應該有個好的界面。在程序的主界面上,主要的按鈕都采用了自繪按鈕,而不使用自帶的按鈕控件。AdvButton.h和AdvButton.cpp是自繪按鈕類的頭文件和實現文件。在自繪按鈕類中定義了如下成員變量:intm_nState;/ 按鈕的狀態(tài)CBitmapm_bmpNormal;/ 正常圖標CBitmapm_bmpHover;/ 焦點圖標CBitmapm_bmpDown;/ 按下圖標CBitmapm_bmpDisable;/ 無效圖標CToolTipCtrlm_pToolTipCtrl;/ 提示類

33、m_nState表示當前按鈕的狀態(tài),可以為宏:NORMAL,HOVER,DOWN,DISABLE,分別表示按鈕正常狀態(tài)、處于焦點狀態(tài)、按下狀態(tài)、無效狀態(tài),這4個宏的定義在實現文件。4個CBitmap的變量分別存儲4種狀態(tài)下的圖像。m_pToolTipCtrl是提示工具控件類,既是鼠標在其上時,會彈出提示窗口。要實現按鈕自繪,必須更新按鈕的風格為自繪,可以在按鈕的屬性中更改,也可以使用代碼更改。重載PreSubclassWindow(),在這個函數中更改按鈕風格并初始化m_pToolTipCtrl。void CAdvButton:PreSubclassWindow() ModifyStyle(

34、0, BS_OWNERDRAW );CButton:PreSubclassWindow();m_pToolTipCtrl.Create( this, TTS_ALWAYSTIP );m_pToolTipCtrl.SetDelayTime( 100 );CString strText;GetWindowText( strText );m_pToolTipCtrl.AddTool( this, strText ); VC+6.0中的ClassWizard不能為我們添加鼠標離開的消息,只能為我們添加鼠標移動、單擊等消息,我們得自己為自繪按鈕添加上鼠標離開的消息。TRACKMOUSEEVENT tme

35、;tme.cbSize = sizeof( TRACKMOUSEEVENT );tme.hwndTrack = m_hWnd;tme.dwFlags = TME_LEAVE;:_TrackMouseEvent( &tme );以上代碼告訴系統(tǒng),當鼠標離開m_hWnd窗口時,向這個窗口發(fā)送一條WM_MOUSELEAVE消息。下面的處理方式與熱鍵和托盤通知消息的處理方式一樣,自定義這個消息處理函數就行了。自繪按鈕必須重載DrawItem()函數,在DrawItem()函數中根據m_nState的值可以貼上不同的圖,表示按鈕的一不同狀態(tài)。void CAdvButton:DrawItem(LP

36、DRAWITEMSTRUCT lpDrawItemStruct) if( lpDrawItemStruct->itemState & ODS_DISABLED )m_nState = DISABLE;switch( m_nState )case NORMAL:DrawNORMAL();break;case HOVER:DrawHOVER();break;case DOWN:DrawDOWN();break;case DISABLE:DrawDISABLE();break;default:break;DrawNORMAL() 、DrawHOVER ()、DrawDOWN() 、Dr

37、awDISABLE()分別畫按鈕的4種狀態(tài)。當鼠標滑過或單擊按鈕時,更改m_nState的值,然后調用Invalidate(),強制按鈕重繪。要使按鈕無效,必須調用EnableWindow( FALSE )函數來更改按鈕的狀態(tài),我們也就無法更改m_nState的值。lpDrawItemStruct->itemState的值表示了當前按鈕的狀態(tài),可以檢測lpDrawItemStruct->itemState,如果按鈕是無效狀態(tài),則設置m_nState為DISABLE,否則不作改變。在畫按鈕的狀態(tài)時,使用到了TransparentBlt()函數,這個函數可以貼透明位圖。在Transpa

38、rentBlt()最后一個參數中指定掩碼色,貼圖時掩碼色就不會貼出來。要使用此函數,必須導入 msimg32.dll,在程序使用如下語句導入:#pragma comment( lib, "C:Program FilesMicrosoft VisualStudioVC98LibMSIMG32.LIB" )3.1.5節(jié)自繪好友列表框普通的列表控件無法滿足程序的要求,程序要求好友列表框可以顯示好友的頭像、好友昵稱、好友IP和刪除、攝像頭按鈕。FriendsListCtrl.h和FriendsListCtrl.cpp是自繪列表框的頭文件和實現文件。定義的成員變量如下:CInstan

39、tMessagingDlg*m_pMainDlg;/ 主對話框CImageListm_imageList;/ 頭像圖像列表intm_nCamera;/ 攝像頭激活的序號intm_nDelIcon;/ 刪除按鈕激活的序號intm_nCurSel;/ 當前選中用戶序號與自繪按鈕類似,在PreSubclassWindow()函數中更改列表框的風格為自繪:void CFriendsListCtrl:PreSubclassWindow() ModifyStyle( 0, LVS_OWNERDRAWFIXED );CListCtrl:PreSubclassWindow();重載MeasureItem()函

40、數更改列表框每一項的高度:void CFriendsListCtrl:MeasureItem( LPMEASUREITEMSTRUCT lpMeasureItemStruct )lpMeasureItemStruct->itemHeight = DEFAULT_FRIENDSLIST_HEIGHT;宏DEFAULT_FRIENDSLIST_HEIGHT在Global.h文件定義,表示好友列表框每項的高度。列表框中的鼠標離開消息與自繪按鈕的實現是同一個原理,這兒就不再贅述。在向好友列表框中添加好友時,主對話框調用好友列表框的AddUser()函數,參數為USER結構體,這個參數作為列表項的

41、額外數據,這樣重繪的時候再讀取出這個額外數據就可以得到這一項的用戶信息。鼠標在好友列表框上移動時,判斷鼠標是否在刪除或攝像頭(如果有攝像頭)按鈕范圍內,如果在,就設置m_nDelIcon或m_nCamera為當前項的序號,否則就設置m_nCurSel為當前項的序號。用戶雙擊鼠標時,調用主對框的相應函數,并把項的序號傳給此函數。如果是單擊,先判斷m_nDelIcon、m_nCamera值,如果不為-1,則選中了刪除或攝像頭按鈕,調主對框相應函數執(zhí)行相應操作。在DrawItem()函數中,先得到額外的附加數據,既是添加項時作為參數傳遞的USER類型的變量,然后再根據m_nCurSel、m_nDel

42、Icon和m_nCamera的值自繪。在自繪時,為了防止閃爍,程序用到了雙緩沖技術。雙緩沖技術,就是先創(chuàng)建一個與目標設備兼容的內存設備上下文,在內存設置上下文中畫圖或進行其他處理,操作完成了,再一并把內存設備上下文的內容貼到目標設備上,這樣就可以有效的防止閃爍。3.2節(jié)好友管理好友管理包括添加好友、刪除好友以及與好友保持連接。3.2.1節(jié)添加好友添加好友的兩種方式4.1節(jié)已經介紹過了,這一節(jié)介紹的是具體的實現。首先然主對話框定義監(jiān)聽Socket并初始化:CListeningSocket*m_pLisSocket;m_pLisSocket = new CListeningSocket( this

43、 );m_pLisSocket->Create( DEFAULT_PORT, SOCK_DGRAM );在添加按鈕的響應函數中先判斷IP地址是否合法,是否是自己的IP,是否已經添加此好友。如果可以添加此好友,則向此好友發(fā)起請求加為好友的請求:/ 定義數據包DATAPACKET dataPacket;dataPmand = REQUEST_ADD;/ 設置請求的用戶結構USER user;user.bHasCamera= m_bCamera;user.nFace= m_wFace;memcpy( user.strName, m_strNickName.GetBuffer( MAXNICKN

44、AMELENGTH + 1 ), MAXNICKNAMELENGTH + 1 );m_strNickName.ReleaseBuffer();/ 分配空間UINT uDataLength = sizeof( DATAPACKET ) + sizeof( USER );BYTE *pSendData = new BYTE uDataLength ;memcpy( pSendData, &dataPacket, sizeof( DATAPACKET ) );memcpy( pSendData + sizeof( DATAPACKET ), &user, sizeof( USER )

45、 );/ 發(fā)送請求m_pLisSocket->SendTo( pSendData, uDataLength, DEFAULT_PORT, strFriendIP );delete pSendData;以上代碼中的宏都可以在Global.h頭文件中找到。向好友發(fā)起請求的數據中,還包括自己的USER數據。向對方發(fā)起請求后,對方的m_pLisSocket就會調用OnReceive()函數,程序中重載了CListeningSocket類的OnReceive()函數,在OnReceive()中調用主對對話框的OnListeningReceive()函數來接收網絡數據。在OnListeningRec

46、eive()函數中,根據DATAPACKET的command值來進行相應的處理,這兒是添加為好友的請法度,先得到發(fā)起請求的USER,再調用AddRequest()函數做相應處理。在AddRequest()函數中,先進行相應的判斷,如果具備加為好友的條件,根據是否允許直接加為好友的值是否彈出提示對話框。如果拒絕加為好友,則向發(fā)送者發(fā)送拒絕的消息。否則先把發(fā)起者的USER信息加入到好友列表中,再向請求者發(fā)送允許加為好友的消息,消息中包括自己的USER信息。請求者收到對方的拒絕消息,會彈出對話框提示對方拒絕加為好友;如果收到的是允許加為好友的消息,則再得到一同發(fā)送過來的USER信息,再加入到列表中。

47、在InstantMessaging.h頭文件中定了如下變量:CArray< USER, USER >m_arrFriends;/ 好友列表此數組保存的是已連接的好友,添加好友時會向這個變量里添加USER信息,并把USER添加到好友列表框中。請求者添加好友流程圖如下:添加好友對方是否允許將好友添加到數組和列表框中彈出提示框TF圖3.3添加好友流程圖好友收到請求的流程圖如下:收到請求是否允許將好友添加到數組和列表框中并發(fā)送允許消息發(fā)送拒絕消息TF圖3.4好友收到請求流程圖3.2.2節(jié)刪除好友刪除好友比較簡單,在服務器端向要刪除的好友發(fā)送命令為OFFLINE的消息,然后從好友數組和好友列

48、表框中刪除此好友。在客戶端接受到OFFLINE的網絡消息時,得到發(fā)送此消息的IP,然后從好友數據和好友列表框中刪除與此IP相等的好友。另外,當用戶改變自己的狀態(tài)為下線狀態(tài)或關閉程序時,會調用SendOffLineMessage()函數向所有好友發(fā)送下線消息,并刪除所有的好友。3.2.3節(jié)與好友保持連接此功能用到了定時器,間隔一定時間向所有好友發(fā)起請求保持連接的消息,并把發(fā)送過此消息的好友添加到一個臨時好友列表中。好友收到請求保持連接的消息后,會發(fā)送回應保持連接的消息。程序收到回應保持連接的消息后,會從臨時好友列表中刪除對應的好友。在下一次定時器到的時候,程序檢查臨時好友列表,在臨時好友列表中的

49、好友都是沒有回應的的好友,這些好友可能是因為程序不正常關閉而未向其他好友發(fā)送下線通知,程序就可以將這些好友刪除。在程序初始化時設置一定時器:SetTimer( TIMER_CONNECT, DEFAULT_REFRESH_TIME, NULL );在OnTimer()函數中進行如下處理:/ 保持接連if( TIMER_CONNECT = nIDEvent )/ 刪除沒有回應的聯(lián)系人for( int nIndex = 0; nIndex < m_arrFriends.GetSize(); nIndex+ )USER userDel = m_arrFriends.GetAt( nIndex

50、);if( m_strlstKeepConnent.Find( userDel.strIP ) )m_listCtrlFriends.DeleteUser( nIndex );m_arrFriends.RemoveAt( nIndex );nIndex-;m_strlstKeepConnent.RemoveAll();/ 分別發(fā)送保持連接的消息,將發(fā)送過的IP加入到m_strlstKeepConnentfor( nIndex = 0; nIndex < m_arrFriends.GetSize(); nIndex+ )USER user = m_arrFriends.GetAt( nIn

51、dex );DATAPACKET dataPacket;dataPmand = REQUEST_KEEPCONNECT;/ 分配空間UINT uDataLength = sizeof( DATAPACKET );BYTE *pSendData = new BYTE uDataLength ;memcpy( pSendData, &dataPacket, sizeof( DATAPACKET ) );m_pLisSocket->SendTo( pSendData, uDataLength, DEFAULT_PORT, user.strIP );delete pSendData;m_

52、strlstKeepConnent.AddTail( user.strIP );3.3節(jié)聊天模塊聊天包括文字聊和圖片聊天,本系統(tǒng)用到了Microsoft Rich Textbox Control 6.0控件,此控件支持RTF(Rich Text Format)格式的內容,包括不同顏色、不同字體字號的文本和圖片。要使用此控件,系統(tǒng)中必須注冊了此控件,如果未注冊此控件,那么打開聊天對話框時程序會死掉。為了解決這個問題,本設計在程序中檢查系統(tǒng)是否注冊過richtx32.ocx控件,如果沒有注冊,程序會先注冊,代碼如下:HKEY hKey;if( RegOpenKeyEx( HKEY_CLASSES_

53、ROOT, "RICHTEXT.RichtextCtrlCLSID", 0, KEY_READ, &hKey ) != ERROR_SUCCESS ) HINSTANCE hLib = LoadLibrary( "RICHTX32.OCX" );/ 控件不存在if( !hLib )MessageBox( "RICHTX32.OCX控件未找到" );else/獲取注冊函數DllRegisterServer地址FARPROC lpDllEntryPoint;lpDllEntryPoint = GetProcAddress( hLi

54、b, "DllRegisterServer" );/ 注冊richtx32.ocx控件lpDllEntryPoint();聊天對話框如下:圖3.5聊天對話框聊天對話框用的Socket是主對話框的m_pLisSocket,當要發(fā)送消息時,調用主對話框的SendPreChatMessage()函數,主對話框接收到聊天消息時調用聊天對話框的ReceiveMessage()函數。聊天對話框中定的發(fā)送和接收富文本框變量為:CRichTextm_rtReceived;CRichTextm_rtSend;發(fā)送消息的主要代碼如下:void CChatDlg:OnSend() CTime t

55、ime = CTime:GetCurrentTime();CString strTime = time.Format( "%H:%M:%S" );CString strSend = m_rtSend.GetTextRTF();/ 發(fā)送聊天消息m_pMainDlg->SendPreChatMessage( m_userChat, strTime, strSend );單擊“發(fā)送”按鈕或CTRL+ENTER鍵,程序會調用OnSend()函數,首先得到發(fā)送的時間和發(fā)送的內容,得到的是RTF格式的內容,因此strSend中還包括了文字的格式和圖片信息。然后調用主對話框的Sen

56、dPreChatMessage()函數向m_userChat好友發(fā)送聊天消息。接收到的消息主要代碼如下:void CChatDlg:ReceiveMessage( LPCSTR szTime, LPCSTR szMessage )CString strText;strText.Format( "%s(%s) %srn ", m_userChat.strName,m_userChat.strIP,szTime );/ 設置接收框m_rtReceived.SetSelStart( m_rtReceived.GetTextRTF().GetLength() );m_rtReceived.S

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論