1. 主要內容
從本節開始介紹windows開發實現記事本程式的邏輯實現部分。本節的主要內容有以下3點:
1. 主視窗定義 —— 主要介紹記事本主介面視窗對應的視窗類別及實現方案
2. RichEdit控制項的選用及初始化 —— 記事本程式中編輯控制項的選擇及使用
3. 整個程式ICON的選擇。—— 程式ICON設定
2. 實際開發
2.1 主視窗實現
在上一篇介紹介面的實現中只是給出了運行介面的效果,但是當時那個介面程式不能響應任何的windows訊息,因為當時的視窗在建立時將視窗對應的過程處理函數設定為NULL。現在,我們需要將相應的過程處理函數添加上使得這個記事本應用程式可以響應我們發出的一系類操作指令。為此,本文在開發時,單獨設計了一個用於儲存主介面視窗的類CMainWnd。這個類定義了整個視窗的過程處理函數Main_Porc。在Main_Proc中可以對傳入的任何訊息進行處理(包括初始化視窗訊息,視窗中其他控制項的訊息,關閉視窗訊息等等)。以windows 內建記事本為例,如圖1所示
圖1 windows主視窗訊息效應地區
如上圖所示,在windows記事本主介面中,需要響應紅色矩形地區內的菜單控制項的各類訊息、響應黃色矩形地區內系統按鈕的相關訊息,以及相應編輯控制項Edit中的訊息。對於主視窗中的各類控制項的訊息,windows會以WM_COMMAND訊息進行傳輸,這也是整個程式的核心處理地區。系統按鈕關閉的訊息則是WM_CLOSE。視窗初始化訊息WM_INITDIALOG則是構建對話方塊視窗前發出的初始化訊息。為了能夠響應上述各類訊息,需要在CMainWnd中添加對於這幾類訊息的響應函數,因此整個CMainWnd的基本實現形式如下:
標頭檔聲明:
/************************************************************************//* file : CMainWnd.h * author : Huagang Li * date : 2014-8-30 15:29:42 * blogs : http://www.cnblogs.com/lhglihuagang/ * tips : 主視窗實作類別, 實現視窗的過程函數,訊息響應函數等 *//************************************************************************/#ifndef _MAIN_WND_H#define _MAIN_WND_H#include <Windows.h>//////////////////////////////////////////////////////////////////////////// CMainWnd 主視窗類,提供class CMainWnd{public: static BOOL WINAPI Main_Proc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); static BOOL Main_OnInitDialog(HWND hWnd, HWND hWndFocus, LPARAM lParam); static void Main_OnCommand(HWND hWnd, int id, HWND hWndCtl, LPARAM lParam); static void Main_OnClose(HWND hWnd);private: static HWND hMainWnd; // 主視窗控制代碼};#endif
CMainWnd具體定義:
#include "MainWnd.h"include <WindowsX.h>//////////////////////////////////////////////////////////////////////////// static data membersHWND CMainWnd::hMainWnd = NULL;//////////////////////////////////////////////////////////////////////////// static function members// 主視窗的過程函數,根據訊息類型處理各類訊息BOOL WINAPI CMainWnd::Main_Proc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ){ switch (uMsg) { HANDLE_MSG(hWnd, WM_INITDIALOG, Main_OnInitDialog); HANDLE_MSG(hWnd, WM_COMMAND, Main_OnCommand); HANDLE_MSG(hWnd, WM_CLOSE, Main_OnClose); }</span><span style="color: #0000ff">return</span><span style="color: #000000"> FALSE;}BOOL CMainWnd::Main_OnInitDialog( HWND hWnd, HWND hWndFocus, LPARAM lParam ){ return TRUE;}// id為具體空間的ID號,可以在resource中定義有意義的控制項ID,如“開啟檔案”可以設定// 為ID_FILE_OPENvoid CMainWnd::Main_OnCommand( HWND hWnd, int id, HWND hWndCtl, LPARAM lParam ){ switch (id) { // }}void CMainWnd::Main_OnClose( HWND hWnd ){ ::EndDialog(hWnd, NULL);}
在定義了CMainWnd後,在main函數處的DialogBox處添加主視窗的過程處理函數
::DialogBox(hInstance, MAKEINTRESOURCE(IDD_MAIN), NULL, CMainWnd::Main_Proc);
完成上述步驟運行後,就可以看到啟動後的主介面可以響應視窗上系統按鈕“關閉”,但是對於菜單控制項的訊息,因為訊息響應此還是函數中數什麼都沒有做,因此還是不會進行任何處理。
2.2 RichEdit控制項的選用
對於一個記事本程式來說,主介面上核心地區還是編輯地區。但是當前記事本程式中還沒有選擇任何編輯控制項。通過觀察現有windows控制項列表可以看出,適合編輯控制項的有Edit Control以及Rich Edit2.0 Control。對於這兩種編輯控制項,Edit Control較為簡單,但是響應的功能也較少。Rich Edit2.0 Control實現起來較為複雜,但是對應的功能也多了不少(例如可以改變字型顏色,字型大小等等)。本文希望能夠實現一個功能較強的記事本,因此選擇了Rich Edit2.0 Control進行後續開發。插入了Rich Edit2.0 Control後,主介面視窗對應的資源檢視如圖2所示:
圖2 IDD_MAIN中插入Rich Edit2.0 Control
上述步驟運行後,本以為可以看到帶有編輯介面的記事本程式,可是實際上程式運行後沒有任何效果,甚至主介面都不能正常啟動了。百度後發現,對於richedit啟動失敗的方法都是針對MFC程式來說的,需要添加初始化函數AfxInitRichEdit2。但是現在使用windows API 開發,並沒有AfxInitRichEdit2這個函數,只能另尋他路了。終於在一篇博文中http://blog.csdn.net/dijkstar/article/details/7953816提到,原來上面那個初始化函數中主要是載入RichEdit依賴的dll,那麼整個問題就豁然開朗了,我們只需要在主視窗啟動前手動的載入這個dll就可以了。因此在主函數的DialogBox前添加了依據載入dll的操作如下:
::LoadLibrary(T("riched20.dll"));
MAIN的properties中:
此時再運行程式時,可以正常啟動記事本了,且能夠在richedit中進行編輯,效果如圖3所示:
圖3 手動載入Riched20.dll後出現主介面視窗
在啟動主介面後,可以正常進行編輯。貌似這個控制項可以正常工作了。但在實際測試時,發現了以下幾個問題:
1. 介面運行後RichEdit邊框稜角過於分明
處理方法: Richedit控制項的properties -> Boarder –> Flase
2.輸入Enter 不能換行(手動輸入時一直在同一行編輯)
處理方法: Richedit控制項的properties -> Multiline–> True
Richedit控制項的properties -> Want Return–> True
3. 沒有捲軸(橫向以及縱向的)
這個在主介面屬性上,IDD
處理方法: IDD_MAIN-> properties -> Horizontal Scrollbar–> True
IDD_MAIN –> properties -> Vertical Scrollbar–> True
4. 不能隨視窗大小伸縮
在對視窗進行伸縮時,RichEdit控制項的大小還是保持原來的大小,如圖4所示:
圖4 主介面大小變化時RichEdit控制項大小不變
這個問題其實很好理解,因為伸縮主介面視窗時,windows將發送WM_SIZE訊息通知視窗。這個過程類似於windows對主介面視窗說“hi, 你的大小已經變了,你根據改變後的大小變一下”。現在我們的主視窗過程處理函數中並沒有針對WM_SIZE訊息對RichEdit進行特殊處理,因此主介面下面的RichEdit一直保持自己原來的大小,才會出現上面的情況。那麼具體的解決方案為:在InitDialog中添加RichEdit大小自適應功能,同時針對WM_SIZE訊息,添加Main_OnSize函數來處理這種獨立的控制項。具體的代碼實現如下:
void CMainWnd::Main_OnSize( HWND hWnd, UINT state, int cx, int cy ){ RECT stRect; ::GetClientRect(hWnd, &stRect); // 擷取視窗客戶區大小</span><span style="color: #008000">//</span><span style="color: #008000"> 將RichEdit大小調整為客戶區大小</span> ::MoveWindow(::GetDlgItem(hWnd, IDC_RICHEDIT), stRect.left, stRect.top, stRect.right-stRect.left, stRect.bottom-stRect.top, TRUE);}
這裡只是在CMainWnd中添加了對於WM_SIZE的訊息響應函數,要讓RichEdit響應這個訊息,還需要在Main_Proc中添加相應過程
HANDLE_MSG(hWnd, WM_SIZE, Main_OnSize);
這樣,RichEdit也就可以跟著主視窗大小自由伸縮了。上述過程處理函數中,主要調用了三個基本的API介面。
1. GetClientRect,這個API用於擷取客戶區大小,RichEdit伸縮的大小就是這個大小值
2. GetDlgItem 擷取視窗下某一個控制項的控制代碼,例如GetDlgItem(hWnd, IDC_RICHEDIT),就可以獲得主視窗下RichEdit控制項對應的控制代碼。
3. MoveWindow。它的第一個參數就是需要進行位置大小變化的視窗控制代碼。我們這裡將2中的RichEdit控制代碼傳入,後面的參數分別是矩形地區的left點,top點,width值以及height值。最後一個參數用來表示大小改變後要不要重繪視窗。注意,這裡選擇了TRUE。如果選擇FALSE,會出現以下這種情況:當將視窗變小後,在進行變大操作,RichEdit並沒有立即適應變大後的地區,還是保留在原來變小的地區。效果如圖5所示:
圖5 MoveWindows中參數repaint設定為FALSE後潛在問題
基於此,我們在用MoveWindow改變視窗大小時,最好使得repaint為TRUE,保證即時改變。
2.3 主程式ICON設計
在上述截圖中可以看出,主介面的左上方ICON一直是windows內建的ICON。為了與windows內建記事本做到類似,直接到網上找了一個類似的JPG表徵圖轉為ICO,然後設定了程式的ICON。具體的表徵圖設定方法請參考http://www.cnblogs.com/lhglihuagang/p/3927283.html
在表徵圖設定後,可以運行程式查看下最新的效果,如圖6所示
圖6 設定程式表徵圖後的結果
最後,對話方塊視窗的標題Dialog實在顯得有些另類,這雷根據windows內建記事本的標題“無標題 - 記事本”,將這個值進行了相應的修改,具體為IDD_MAIN-> properties -> Caption –> 無標題 - 記事本最後,對話方塊.
3. 運行結果
在添加了CMainWnd以及RichEdit後,整個程式的運行後效果如下圖7所示:
圖7 本節程式改動後的效果
4. 結論
1. 使用RichEdit控制項時,需要手動載入riched20.dll,否則程式運行後沒有任何介面效果
2. RichEdit換行、捲軸、邊框都可以通過properties中相應欄位進行設定
3. 需要在CMainWnd中添加WM_SIZE訊息響應函數,保證RichEdit自由伸縮。
5. 參考連結
[1] http://blog.csdn.net/dijkstar/article/details/7953816
[2] http://www.cnblogs.com/lhglihuagang/p/3927283.html
[3] http://msdn.microsoft.com/en-us/library/ms633534(VS.85).aspx
6. 說明
這將是一個系列博文,後面會繼續補充邏輯功能的開發的步驟。希望能與更多博友交流。 如果你覺得這篇文章還可以,請點贊,哈哈~~
聲明:未作說明,則本文為年糕原創。 注意:轉載須保留全文,如需修改請 聯絡作者。