Win32 SDK封閉例項——普通的Windows程式(翻譯) (轉)
普通的
這個程式使用類封裝了Windows 。
- Controller-- 視窗過程和之間的橋樑。
- View-- Windows程式的輸出封裝。
- Canvas-- 封裝了不同的裝置描述符和事件,你可以去使用它們。
- Model-- 工作者,你的程式的大腦。從不處理視窗。
Controller * pCtrl = WinGetLong 你可以呼叫
Controller * pCtrl = reinterpret_cast 讓我們從WinMain開始,我們建立一個視窗類及我們的程式的最頂層視窗。我在兩個類中封裝了這些動作:WinClass和WinMaker。如果在那我們的程式已經執行了一個例項,WinClass可以告訴我們。當這樣的事發生時,我們的例子,將簡單的啟用程式先前的例項後結束。當你只想讓你的程式在同一時間執行一個例項時,你應該這樣做。
一旦頂層視窗被成功的建立,我們開始訊息迴圈。在這時我們透過呼叫TranslateMessage來處理。這是因為我們的程式的選單條目可以使用Alt+鍵的組合來訪問。
另外這個程式有趣的是我們不能使用很長的字串去命名我們的資源——我們使用數字標識。即使是API呼叫的字串,象視窗型別名或標題,我們都存貯在字串資源中,透過識別符號來訪問。你們的Windows開發環境中多數有一個資源編輯器讓你去建立圖示,選單,及字串資源,給它們分配適當的數字識別符號。這些識別符號的符號名存貯在一個引審了的頭中——我們程式去呼叫它re.h。
常量,ID_MAIN是為例項的主程式引入的圖示 (在同一資源中有一大一小),主選單,及視窗型別句的字串。ID_CAPTION是視窗標題字串。
int WINAPI WinMain (HINSTANCE hInst, HINSTANCE hPrevInst, char * cmdParam, int cmdShow) { _set_new_handler (& NewHandler); // 使用異常幫助你的程式 // 防止異常事件 try { // 建立頂層視窗類 TopWinClass topWinClass (ID_MAIN, hInst, MainWndProc); // 正在執行這個程式的例項嗎? HWND hwndOther = topWinClass.GetRunningWindow (); if (hwndOther != 0) { ::SetForegroundWindow (hwndOther); if (::IsIconic (hwndOther)) ::ShowWindow (hwndOther, SW_RESTORE); return 0; } topWinClass.Register (); // 建立頂層視窗 ResString caption (hInst, ID_CAPTION); TopWinMaker topWin (topWinClass, caption); topWin.Create (); topWin.Show (cmdShow); // 主訊息迴圈 MSG msg; int status; while ((status = ::GetMessage (&msg, 0, 0, 0)) != 0) { if (status == -1) return -1; ::TranslateMessage (&msg); ::DispatchMessage (&msg); } return msg.wParam; } catch ( WinException e ) { char buf [50]; wsprintf (buf, "%s, Error %d", e.GetMessage (), e.GetError ()); ::MessageBox (0, buf, "Exception", MB_ICONEXCLAMATION | MB_OK); } catch (...) { ::MessageBox (0, "Unknown", "Exception", MB_ICONEXCLAMATION | MB_OK); } return 0; } 我倘若有一個方法的例子可以不考慮預設。例如,SetBgSylor可以改變預設的視窗的客戶區的背景色。方法SetResIcons從資源中裝入適當的圖示,並把它們附在視窗類上。這些圖示將在當時顯示在主視窗和Windows的工作列中。
TopWinClass來由於WinClass的方法的使用。它同樣分配選單到頂層視窗類中。
class WinSimpleClass { public: WinSimpleClass (char const * name, HINSTANCE hInst) : _name (name), _hInstance (hInst) {} WinSimpleClass (int resId, HINSTANCE hInst); char const * GetName () const { return _name.c_str (); } HINSTANCE GetInstance () const { return _hInstance; } HWND GetRunningWindow (); protected: HINSTANCE _hInstance; std::string _name; }; WinSimpleClass::WinSimpleClass (int resId, HINSTANCE hInst) : _hInstance (hInst) { ResString resStr (hInst, resId); _name = resStr; } HWND WinSimpleClass::GetRunningWindow () { HWND hwnd = ::FindWindow (GetName (), 0); if (::IsWindow (hwnd)) { HWND hwndPopup = ::GetLastActivePopup (hwnd); if (::IsWindow (hwndPopup)) hwnd = hwndPopup; } else hwnd = 0; return hwnd; } class WinClass: public WinSimpleClass { public: WinClass (char const * className, HINSTANCE hInst, WNDPROC wndProc); WinClass (int resId, HINSTANCE hInst, WNDPROC wndProc); void SetBgSysColor (int sysColor) { _class.hbrBackground = reinterpret_cast class TopWinClass: public WinClass { public: TopWinClass (int resId, HINSTANCE hInst, WNDPROC wndProc); }; TopWinClass::TopWinClass (int resId, HINSTANCE hInst, WNDPROC wndProc) : WinClass (resId, hInst, wndProc) { SetResIcons (resId); _class.lpszMenuName = MAKEINTRESOURCE (resId); } WinMaker類的工作非常像WinClass。它的構造提供了切合實際的預設值,可以透過呼叫細節方法去覆蓋。一旦任何事都設定了,你呼叫Create方法去建立一個視窗,及呼叫Show方法去顯示它。注意,在呼叫Create的瞬間,你的視窗過程被WM_CREATE訊息呼叫。
頂層視窗使用TopWinMaker類建立,提供了適當的風格和標題。
class WinMaker { public: WinMaker (WinClass & winClass); operator HWND () { return _hwnd; } void AddCaption (char const * caption) { _windowName = caption; } void AddSysMenu () { _style |= WS_SYSMENU; } void AddVScrollBar () { _style |= WS_VSCROLL; } void AddHScrollBar () { _style |= WS_HSCROLL; } void Create (); void Show (int nCmdShow = SW_SHOWNORMAL); protected: WinClass & _class; HWND _hwnd; D _exStyle; // 擴充套件視窗風格 char const * _windowName; // 指向視窗名字的指標p DWORD _style; // 視窗風格 int _x; // 視窗的水平位置 int _y; // 視窗的升起位置 int _width; // 視窗寬 int _height; // 視窗高 HWND _hWndParent; // 父視窗或所有者的控制程式碼 HMENU _hMenu; // 選單的控制程式碼,或子視窗的識別符號 void * _data; // 指向視窗創造資料 }; WinMaker::WinMaker (WinClass & winClass) : _hwnd (0), _class (winClass), _exStyle (0), // 擴充套件視窗風格 _windowName (0), // 指向視窗的名字 _style (WS_OVERLAPPED), // 視窗風格 _x (CW_USEDEFAULT), // 視窗的水平位置 _y (0), // 視窗的升起位置 _width (CW_USEDEFAULT), // 視窗寬 _height (0), // 視窗高 _hWndParent (0), // 父視窗或所用者的控制程式碼 _hMenu (0), // 指向選單,或子視窗的識別符號 _data (0) // 指向視窗創造資料 { } void WinMaker::Create () { _hwnd = ::CreateWindowEx ( _exStyle, _class.GetName (), _windowName, _style, _x, _y, _width, _height, _hWndParent, _hMenu, _class.GetInstance (), _data); if (_hwnd == 0) throw WinException ("Internal error: Window Creation Failed."); } void WinMaker::Show (int nCmdShow) { ::ShowWindow (_hwnd, nCmdShow); ::UpdateWindow (_hwnd); } // 製造頂層重疊帶標題的視窗 TopWinMaker::TopWinMaker ((WinClass & winClass, char const * caption) : WinMaker (winClass) { _style = WS_OVERLAPPEDWINDOW | WS_VISIBLE; _windowName = caption; } ResString類是對你的應用程式的字串資源中貯存的字串的簡單的封裝。
// exception類:貯存訊息和錯誤程式碼 class WinException { public: WinException (char* msg) : _err (::GetLastError()), _msg(msg) {} DWORD GetError() const { return _err; } char const * GetMessage () const { return _msg; } private: DWORD _err; char * _msg; }; // :丟擲異常 int NewHandler (size_t size) { throw WinException ( "Out of memory" ); return 0; } class ResString { enum { MAX_RESSTRING = 255 }; public: ResString (HINSTANCE hInst, int resId); operator char const * () { return _buf; } private: char _buf [MAX_RESSTRING + 1]; }; ResString::ResString (HINSTANCE hInst, int resId) { if (!::LoadString (hInst, resId, _buf, MAX_RESSTRING + 1)) throw WinException ("Load String failed"); } 如果,這常常發生,你的應用程式只有一個最頂層的視窗,你可以在它的控制中立即插入model。這單一化的資源管理,這是以控制元件器與model的緊密聯絡的。在大的專案中應該避免這樣的聯接——首選在控制器裡使用一個指向model的指標。
更多的controller方法為了它們操作的利益需要一個指向視窗的控制程式碼。這個控制程式碼是每一個視窗訊息透過的控制程式碼,但它只是一次性的簡單的貯存它到controller物件裡,隨時都可以使用它。記住——在視窗例項(因為視窗的控制程式碼)和controller物件之間有一對一的通訊。
class Controller { public: Controller(HWND hwnd, CREATESTRUCT * pCreate); ~Controller (); void Size (int x, int y); void Paint (); void Command (int cmd); private: HWND _hwnd; Model _model; View _view; }; 視窗過程被給定訊息指定的視窗呼叫的。這個控制程式碼是獨一無二的一個協調視窗例項的內部視窗資料。它發生時,我們可以訪問這些資料結構,及使用它去貯存一些例項指定的資料。這是典型的的訪問結構的途徑。順便,這個結構的GWL_USERDATA成員是所有視窗允許給出的。包含訊息框,對話方塊及平滑按鈕。
template 視窗過程首先被WM_CREATE訊息呼叫。在那時我們建立了控制器物件並初始化了帶有視窗控制程式碼的它,且透過呼叫CREATESTRUCT指定了資料結構。一旦我們有了控制器,我們貯存指向在當前hwnd的標籤下相應的內部視窗的資料結構。在下次視窗過程被呼叫,帶有一個不同與WM_CREATE的訊息,我們只要簡單的取回指向我們控制器的指標,使用hwnd。
這個支援是容易的。視窗過程解釋訊息引數及呼叫控制器的適當模組。
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { Controller * pCtrl = WinGetLong Controller::Controller (HWND hwnd, CREATESTRUCT * pCreate) :_hwnd (hwnd), _model ("Generic") { } Controller::~Controller () { ::PostQuitMessage(0); } void Controller::Size (int cx, int cy) { _view.SetSize (cx, cy); } void Controller::Paint () { // prepare the canvas and let View do the rest PaintCanvas canvas (_hwnd); _view.Paint (canvas, _model); // Notice: The destructor of PaintCanvas called automatically! } 我們的選單僅僅包含三個條目,它們的標識id為IDM_EXIT,IDM_HELP和IDM_ABOUT。響應IDM_ABOUT時對話方塊被顯示,它也是利用資源編輯器建立的,給定的標識id為IDD_ABOUT。它的對話方塊過程是AboutDlgProc。
最後,為了顯示一個對話方塊我們需指定應用程式例項的控制程式碼。標準的途徑是利用應用程式的hwnd訪問內部視窗資料結構取回它。
// 選單命令處理 void Controller::Command (int cmd) { switch (cmd) { case IDM_EXIT: ::SendMessage (_hwnd, WM_CLOSE, 0, 0L); break; case IDM_HELP: ::MessageBox (_hwnd, "Go figure!", "Generic", MB_ICONINFORMATION | MB_OK); break; case IDM_ABOUT: { // 透過HWND取得例項控制程式碼 HINSTANCE hInst = WinGetLong 圖形輸出到視窗是透過適當的Canvas物件的方法完成的。倘若,我們列印的文字是原型是從客戶範圍的邊緣繪製一個10個象素的垂直行。
class View { public: void SetSize (int cxNew, int cyNew) { _cx = cxNew; _cy = cyNew; } void Paint (Canvas & canvas, Model & model); protected: int _cx; int _cy; }; void View::Paint (Canvas & canvas, Model & model) { canvas.Text (12, 1, model.GetText(), model.GetLen()); canvas.Line (10, 0, 10, _cy); } class Canvas { public: operator HDC () { return _hdc; } void Line ( int x1, int y1, int x2, int y2 ) { ::MoveToEx (_hdc, x1, y1, 0); ::Lo (_hdc, x2, y2); } void Text (int x, int y, char const * buf, int cBuf) { ::TextOut ( _hdc, x, y, buf, cBuf ); } void Char (int x, int y, char c) { ::TextOut (_hdc, x, y, & c, 1); } protected: // 保護建構函式:你不能建造 // 一個Canvas物件,但你可 // 以從它的來源構造物件。 Canvas (HDC hdc): _hdc (hdc) {} HDC _hdc; }; // canvas的具體的例項。 // 在WM_PAINT訊息後建立這個物件。 class PaintCanvas: public Canvas { public: // Constructor obtains the DC PaintCanvas (HWND hwnd) : Canvas (::BeginPaint (hwnd, & _paint)), _hwnd (hwnd) {} // 解構函式釋放DC ~PaintCanvas () { ::EndPaint(_hwnd, & _paint); } protected: PAINTSTRUCT _paint; HWND _hwnd; };
讓我們一起看一下WinClass類。它封裝了被WNDCLASSEX呼叫的視窗定義結構,為它的所有欄位提供了合理的預設值。它來源於一個WinSimpleClass模板類,你可以使用去封裝一些固定的視窗型別(象按鈕,列表視)
一旦視窗類在被註冊,你可以建立任意個你想要的這個類的視窗。他們將,當然,他們同享這個類註冊的過程。稍後我們將可以瞭解在過程內視窗的不同例項的區別。
在我們開始下一步前,這有一個小的類。WinException丟擲任何時刻的Windows API的失敗。它需取回的Windows錯誤程式碼。(順便,使用FormatMessage很容易的轉換錯誤程式碼到字串。)
Controller是一個特別的視窗例項的強健的系統。它建立了視窗,貯存了它,並在最後銷燬了它。在它的控制內你可以放置一些對特定視窗例項的描述資訊。在通常,器有一個視(透過在視窗的表面繪製進行互動)並且它有權使用model。它相當於你的應用程式的大腦(在這,MVC或Model-View-Controller透過Smalltalk程式師被呼叫)。
視窗過程是一個視窗應用程式的主器。你不能在你的程式視窗中呼叫它!每當某件有意義的事件發生,Windows傳送條訊息給你的程式。這條訊息被你的視窗過程傳遞。你可以處理它,或傳遞它到預設的視窗過程。
每當Windows呼叫我們的視窗過程時,我們應該首先找回它的控制物件。記住,在這可能幾個視窗共享相同的視窗過程,我們應該為每個視窗分別控制。當我們被呼叫後怎麼樣知道去使用哪個控制?我們透過找出視窗的控制程式碼。在這個控制程式碼裡我們貯存了指向這個特定視窗的控制器,使用Win[Set/Get]Long技巧。
在這個簡單的例子中了少許的控制器方法。建構函式為稍後的使用不得不記住視窗的控制程式碼,解構函式不得不傳送離開訊息,Size方法傳遞它的引數到View,等等,我們將討論關於描繪視窗。目前,注意到控制器準備與View去一起描繪。
當選擇了選單條目之一時,產生WM_COMMAND訊息視窗過程被呼叫。適當的控制方法當足於命命令id分配命令。當你利用你的資源編輯器建立了你的選單時,你為每個選單條目選取了這些標識id。它們被貯存在適當的標頭檔案裡(可能在resource.h裡) ,不得不被包含到控制器的原始檔中。
視物件通常貯存客戶範圍的尺寸。它們隨著控制器過程的WM_SIZE訊息。首先WM_SIZE訊息是在視窗創造期間和WM_PAINT訊息前傳送的,因此我們可以在描繪呼叫時安全的呈現已知客戶範圍的尺寸。
canvas物件封裝了Windows所謂的裝置描述符。我們的Canvas非常的簡單,我們只要知道怎樣列印文字和繪製行,但你的Canvas可以有很多的方法去做創造性的事情。我們將在下一個指南里告訴關於Canvas的更多。
你建造的canvas用來響應WM_PAINT訊息到特定種類。它們透過呼叫BeginPaint獲得裝置描述符並透過呼叫EndPaint來釋放。PAINTSTRUCT包含關於哪部分使用者範圍應該被寫的附加資訊,上當我們忽視這種詳細資料,但如果你嚴肅的關注,你應該學習關於它的更多。
CopyRight by VCROAD ©2000-2001 All Right Reserve
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-992125/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 透過SDK函式實現WIN32應用程式的唯一例項。 (轉)函式Win32
- div前後翻轉效果程式碼例項
- [翻譯]返回導向程式設計例項入門程式設計
- 設計模式例項講解 - 開放封閉設計模式
- 圖片正反面翻轉效果程式碼例項
- CSS 例項之翻轉圖片CSS
- WPF中嵌入普通Win32程式的方法Win32
- [非專業翻譯] Mapster - 配置例項
- 閉包程式碼例項演示
- 樹形半封閉程式碼表中的“其他”項
- 原生javascript對ajax的封裝程式碼例項JavaScript封裝
- win32 單例項程式執行-無視窗程式也可Win32單例
- javascript字串操作程式碼封裝程式碼例項JavaScript字串封裝
- Win32 SDK登錄檔操作——RegQueryValueEx (轉)Win32
- javascript閉包簡單程式碼例項JavaScript
- css3實現的div上下左右翻轉效果程式碼例項CSSS3
- JavaScript封裝的id選擇器程式碼例項JavaScript封裝
- javascript獲取元素封裝程式碼例項JavaScript封裝
- 原生ajax()函式封裝程式碼例項函式封裝
- [轉][翻譯]深入理解Win32結構化異常處理(三)Win32
- [轉][翻譯]深入理解Win32結構化異常處理(一)Win32
- [轉]BDB例項程式碼
- Win32 SDK登錄檔操作——RegOpenKey (轉)Win32Go
- Win32 SDK登錄檔操作——RegCloseKey (轉)Win32GC
- Win32 SDK登錄檔操作——RegCreateKey (轉)Win32GC
- javascript閉包的應用簡單程式碼例項JavaScript
- (譯)win32asm例項-1 (轉)Win32ASM
- (譯)win32asm例項-3 (轉)Win32ASM
- 2 Day DBA-管理Oracle例項-關於例項的啟動和關閉-關於例項關閉Oracle
- 使用普通檔案建立ASM例項ASM
- javascript閉包的理解和例項JavaScript
- Win32 SDK登錄檔操作函式——RegQueryValue (轉)Win32函式
- 使用Delphi,SDK編寫Windows簡單程式 (轉)Windows
- 百度機器翻譯SDK實驗
- javascript關閉當前視窗例項程式碼JavaScript
- 多翻譯引擎的程式
- [翻譯] 在JavaScript中使用weakmaps實現私有例項成員JavaScript
- [翻譯]程式設計師需要掌握的6項相關技能程式設計師