青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

道。道。道

安全特性不等于安全的特性

   :: 首頁 :: 聯(lián)系 :: 聚合  :: 管理

常用鏈接

搜索

  •  

最新評論

緒論

???? WTL 最終來了 , 而且 提供了我所希望的功能 . 我在 WTL Bytesize (譯文)的文章列出 WTL 主要特征 . 在本文中 , 我將描述一下 WTL 的體系結構 , 同時我會給出一些簡單的例子來演示如何使用它的那些特征 . 希望能夠?qū)δ?span lang="zh-cn">所幫助 . ?

WTL 應用程序的類型

???? WTL 有好幾種應用程序類型 , 供您在 AppWizard 選取 .



???
下表對這些應用程序進行了描述
. 這種彈性構成了 WTL 體系結構的一部分 .

應用程序類型 描述
SDI Application 單文本界面 只有一個窗口
Multiple Threads SDI 單個進程擁有一個或多個窗口
MDI Application 多文本界面 在框架內(nèi) , 您可以有零個或多個子窗口
Dialog Based 基于對話框模版

??? 你可能還是首次聽說多線程SDI應用程序,但是不用擔心,它的概念很容易理解.一個多線程SDI程序啟動后它會有一個窗口, 窗口顯示了一個文檔. 當你想要程序要再創(chuàng)建一個文檔時,問題就出現(xiàn)了--SDI程序只能顯示一個文檔.為了解決這個問題,多線程SDI創(chuàng)建了另一個SDI窗口.看起來是一個新的實例在運行,實際上它不過是原來的進程創(chuàng)建了一個新的窗口,并把它依附到進程的一個新線程. IE的新建窗口就是這樣做的. ?

??? 除了多線程SDI,所有這些應用程序都可以作為COM服務器, 并且應用程序向?qū)?AppWizard)為此提供了一個選項.另外應用程序向?qū)н€可以讓你指定該程序是否主持ActiveX控件.令人費解的是,不同的程序類型,選取"Host ActiveX Controls"的地方不同.除對話框應用程序外的其他類型在第一頁上選取,而對話框類型卻放到第二頁. ?

??? 第二頁的其他選項,對對話框程序以外的類型都是可用的.它們讓你指定程序是否需要工具條(toolbar),狀態(tài)條(status bar)和視窗口(View Window).



??? 如果選取了"Toolbar"選項,你可以通過"Rebar"選擇是否將工具條放入IE Rebar控件中. 如果你選取了Rebar, 你就可以通過框架窗口(frame window)的成員m_hWndToolBar(后邊會有詳細的描述)來訪問它.你可以按照你的意愿,在里邊加入其他的工具條. 選取了"Rebar"后, 你可以決定是否選取"Command Bar".
Command bar很像CE的command bar控件.只是WTL是用一個類來實現(xiàn),而在CE, command bar是一個系統(tǒng)窗口類(system window class). Command bar非常有用,它能夠把窗口也加入到工具條中去. 如果你選取了這個選項, 工具條和菜單都將被當做toolbar來實現(xiàn).這使菜單項也可以有關聯(lián)的圖標,并且當你移動鼠標到一個菜單項上時,該菜單項會被置成高亮.從Office 97以來, Office軟件的菜單都具有上述特征. ?

??? 第二頁還有指定程序是否使用視的選項(多半你想要使用), 同時你可以決定這些視如何實現(xiàn). 下表列出了所有可選的視. ?

描述
Generic Window 一個簡單的窗口 . 此類窗口允許程序員編寫 WM_PAINT 消息的處理函數(shù) . 適用于需要直接進行 paint 的文檔 .
Form 這類視具有一個對話框模版 . 適用于帶 ActiveX 控件的窗口 . 應用程序來操作這些控件 .
List Box 這個視是個 list box. 它最簡單的形式意味著可以通過調(diào)用 AddString() 方法來添加字符串 .
Edit 這個視是個 edit control. 本質(zhì)上 , 它提供了一個像 Notepad 一樣的程序 .
List View 這個視是個 list view 通用控件 . 用這個控件來顯示相關的項 ( 比如 , 控制面板是一個 Explorer 主持的 List View, 所有的項都是控制面板 applet).
Tree View 這個視是個 tree view 通用控件 . 這個適用于具有層次關系的數(shù)據(jù) , 比如 , 可以用它來顯示數(shù)據(jù)庫的 schema. 頂層分支為表和存儲過程 , 次級的分支為表中的字段 .
Rich Edit 這個視是個 rich edit 控件 , WordPad.
HTML Page 這個視主持了一個 IE Web Browser 控件 . 它把主持的一個 web page 當成一個視 .

??? 本文的例子需要一個對話框模版 , 同時還需要菜單 , 因此 Form view 是個理想的選擇 .

程序線程

??? 跟ATL一樣,WTL程序也需要一個_Module全局變量來保存全局數(shù)據(jù),方便應用級代碼訪問.在WTL中,這個變量是CAppModuleCServerAppModule的實例,后者在程序同時作為一個COM服務器時用到.每個應用程序具有一個或者多個UI線程.WTL使用兩種方式來管理這些線程.

??? 如果應用程序只有一個UI線程(除了多線程SDI以外,其他程序類型默認只有一個UI線程),線程調(diào)用全局函數(shù)run():

int Run(LPTSTR /*lpstrCmdLine*/ = NULL, int nCmdShow = SW_SHOWDEFAULT)
{
??? CMessageLoop theLoop;
??? _Module.AddMessageLoop(&theLoop);
??? CMainFrame wndMain;
??? if (wndMain.CreateEx() == NULL)
??? {
??????? ATLTRACE(_T("Main window creation failed!\n"));
??????? return 0;
??? }
??? wndMain.ShowWindow(nCmdShow);
??? int nRet = theLoop.Run();
??? _Module.RemoveMessageLoop();
??? return nRet;
}

??? 線程的消息循環(huán)包含在CMessageLoop內(nèi)部.函數(shù)創(chuàng)建了一個CMessageLoop實例, 把它放入全局的消息循環(huán)映射(message loop map)數(shù)組. 以線程ID為索引,線程中運行的其他的代碼可以訪問到這個實例. 消息循環(huán)對象包含了message filter和idle handler. 運行在這個UI線程的UI元件(UI element)可以有它自己的idle handler,在線程的消息隊列為空時運行譯注:通過CMessageLoop::AddIdleHandler()把這個UI元件加入到CMessageLoop的idle handler 數(shù)組中. CMessageLoop::Run()包含了UI線程的主消息映射(main message map).下邊是它的偽代碼:

MSG m_msg;
int CMessageLoop::Run()
{
??? for (;;)
??? {
??????? while (!::PeekMessage(&m_msg, NULL, 0, 0, PM_NOREMOVE))
??????????? DoIdleHandlers();
??????? bRet = ::GetMessage(&m_msg, NULL, 0, 0);
??????? if(bRet == -1)
??????????? continue;
??????? else if(!bRet)
??????????? break;
??????? if (!DoMessageFilters(&m_msg))
??????? {
??????????? ::TranslateMessage(&m_msg);
??????????? ::DispatchMessage(&m_msg);
??????? }
??? }
??? return (int)m_msg.wParam;
}


??? 可以看到,這個函數(shù)推動著消息隊列. 沒有消息時, 運行注冊到線程的idle hander. 如果在隊列中檢測到消息,把它取出來,傳給每個message filter. 如果消息沒有被這些函數(shù)處理,它將按照通常的方式,發(fā)送到目標窗口.

??? 如果程序有超過一個的UI線程,可以用WTL的線程管理器,多線程SDI就是這樣做的. 主線程作為一個管理者線程,它會為每個新窗口創(chuàng)建一個新的線程. 主要流程如下:

int nRet = m_dwCount;
DWORD dwRet;
while(m_dwCount > 0)
{
??? dwRet = ::MsgWaitForMultipleObjects(m_dwCount, m_arrThreadHandles,
??????? FALSE, INFINITE, QS_ALLINPUT);
??? if(dwRet >= WAIT_OBJECT_0 && dwRet <= (WAIT_OBJECT_0 + m_dwCount - 1))
??????? RemoveThread(dwRet - WAIT_OBJECT_0);
??? else if(dwRet == (WAIT_OBJECT_0 + m_dwCount))
??? {
??????? ::GetMessage(&msg, NULL, 0, 0);
??????? if(msg.message == WM_USER)
??????????? AddThread(_T(""), SW_SHOWNORMAL);
??? }
}


那些線程句柄放在一個數(shù)組中. 線程通過AddThread()加入到數(shù)組(同時啟動線程), RemoveThread()從數(shù)組移走. wait語句在兩種情況下會被打斷: 線程死亡(將線程從數(shù)組中移出) 或線程收到了WM_USER消息(一個線程在一個新線程里新建了一個窗口). 線程管理者為程序中的一個類,因此可以在循環(huán)中加入自己的message handler, 比如,當程序有不止一種窗口類型時. 創(chuàng)建一個新的窗口非常簡單,只需在任意一個窗口中調(diào)用:

::PostThreadMessage(_Module.m_dwMainThreadID, WM_USER, 0, 0L);

這個循環(huán)會一直運行下去,直到所有的UI線程都關閉了. UI線程具有一個thread procedure,它跟單UI線程的Run()方法一樣.不過,由于線程管理者使用了MsgWaitForMultipleObjects(), 這意味者最多只能有MAXIMUM_WAIT_OBJECTS-1個UI線程,這也意味著最多只能創(chuàng)建63個窗口.

框架

??? WTL實際上是兩類窗口: 框架窗口和視圖窗口. 正如名字所暗示的那樣, 框架窗口為窗口提供標題欄(caption bar)和邊框,你的代碼用它來處理工具條(tool bar)和菜單項命令.你看到的程序窗口實際上是視圖窗口, 視圖覆蓋了框架窗口的客戶區(qū).客戶區(qū)是指框架窗口沒有被諸如狀態(tài)條,工具條之類的修飾部件所遮擋的部分.

??? 線程會創(chuàng)建主框架窗口的一個實例,創(chuàng)建視圖的工作由主框架窗口的WM_CREATE消息處理函數(shù)完成. 對于SDI程序來說,這個過程很簡單. 把視圖類的一個實例作為主框架類的一個成員,調(diào)用視圖類的Create()方法即可.MDI程序稍微有些不同, MDI主框架窗口通過CMDIFrameWindowImpl<>::CreateMDIClient()建立一個名為MDICLIENT的窗口. 這個客戶窗口將CMDIChildWindowImpl<>窗口當做它的子窗口,子窗口有一個視圖.這也反映了這么一個事實,MDI程序可以具有零個或者多個子窗口,每個都有邊框和標題欄.

框架窗口的OnCreate()很有意思,讓我看看:

LRESULT OnCreate(UINT, WPARAM, LPARAM, BOOL&)
{
??? // create command bar window
??? HWND hWndCmdBar = m_CmdBar.Create(m_hWnd, rcDefault,
??????? NULL, ATL_SIMPLE_CMDBAR_PANE_STYLE);
??? // attach menu
??? m_CmdBar.AttachMenu(GetMenu());
??? // load command bar images
??? m_CmdBar.LoadImages(IDR_MAINFRAME);
??? // remove old menu
??? SetMenu(NULL);
??? HWND hWndToolBar = CreateSimpleToolBarCtrl(m_hWnd, IDR_MAINFRAME,
??????? FALSE, ATL_SIMPLE_TOOLBAR_PANE_STYLE);
??? CreateSimpleReBar(ATL_SIMPLE_REBAR_NOBORDER_STYLE);
??? AddSimpleReBarBand(hWndCmdBar);
??? AddSimpleReBarBand(hWndToolBar, NULL, TRUE);
??? CreateSimpleStatusBar();
??? m_hWndClient = m_view.Create(m_hWnd, rcDefault, NULL,
??????? WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
??????? WS_EX_CLIENTEDGE);
??? UIAddToolBar(hWndToolBar);
??? UISetCheck(ID_VIEW_TOOLBAR, 1);
??? UISetCheck(ID_VIEW_STATUS_BAR, 1);
??? CMessageLoop* pLoop = _Module.GetMessageLoop();
??? pLoop->AddMessageFilter(this);
??? pLoop->AddIdleHandler(this);
??? return 0;
}

??? 這是從一個SDI程序拿來的一段代碼,該程序有一個基于command bar的工具條和一個狀態(tài)條. 函數(shù)的第一行創(chuàng)建了一個command bar實例,然后對它進行初始化,在其中加入框架窗口的菜單和工具條位圖. 這段代碼先將菜單取出,把所有的下拉菜單轉(zhuǎn)換為工具條按鈕,并將菜單保存在一個變量中,以備后用. 給人的感覺是菜單是由工具條實現(xiàn)的-那我們就把它叫做工具條菜單(menu toolbar)吧. 然后Command Bar將程序工具條的圖標裝入image list 并將它們的ID保存在數(shù)組中. 當點擊工具條菜單的按鈕時,commandbar會找到對應的子菜單,創(chuàng)建一個彈出菜單. Command bar將子菜單項的ID和它保存的ID進行比較,這些ID跟image list中的工具條按鈕圖標是相關聯(lián)的. 如果比較成功, 則將關聯(lián)的圖標加到菜單項上去. 這意味著相同ID的菜單項和工具條按鈕具有相同的圖標.

接下來, 創(chuàng)建工具條并把它關聯(lián)到commandbar, 然后創(chuàng)建狀態(tài)條和視圖.可以看到視圖的HWND存放在框架窗口的m_hWndClient變量中. 這個窗口句柄在框架窗口的WM_SIZE handler中會用到.當框架窗口改變大小時,它告知視圖改變自身,于此同時也要考慮狀態(tài)條和command bar.

在下來的三行(從調(diào)用UIAddToolBar()開始) 用來顯示在運行時會改變狀態(tài)的UI項(UI item).文章后面還會重提這個話題. 最后,訪問消息循環(huán)(message loop), 你應該還記得該消息循環(huán)存放在一全局數(shù)組中.GetMessageLoop() 取得當前線程的消息循環(huán),加入框架窗口的message filter和idle handler, 分別默認是PreTranslateMessage()OnIdle().

框架窗口繼承于以下類:

class CMainFrame :
??? public CFrameWindowImpl<CMainFrame>,
??? public CUpdateUI<CMainFrame>,
??? public CMessageFilter,
??? public CIdleHandler


后兩個抽象類宣稱了框架窗口類實現(xiàn)了PreTranslateMessage()OnIdle(). 從CUpdateUI<>繼承表示框架類支持UI update map.

視圖

視圖窗口看起來顯得很簡單:

class CMyView : public CWindowImpl<CMyView>
{
public:
??? DECLARE_WND_CLASS(NULL)
??? BOOL PreTranslateMessage(MSG* pMsg)
??? {
??? ??? pMsg;
??????? return FALSE;
??? }
??? BEGIN_MSG_MAP(CMyView)
??????? MESSAGE_HANDLER(WM_PAINT, OnPaint)
??? END_MSG_MAP()
??? LRESULT OnPaint(UINT, WPARAM, LPARAM, BOOL&)
??? {
??????? CPaintDC dc(m_hWnd);
??????? //TODO: Add your drawing code here
??????? return 0;
??? }
};


上面一個SDI程序的視圖類. 多線程SDI和MDI的視圖類在本質(zhì)上也跟這個一樣,但他們沒有PreTranslateMessage()方法. SDI程序就是使用這個函數(shù),趕在框架類處理消息之前把消息抓住. PreTranslateMessage()在SDI的框架類中的實現(xiàn)是直接消息轉(zhuǎn)發(fā)給視圖類.

這里顯示的視圖實際上沒有做什么工作.你應該自己OnPaint()函數(shù)中加入畫出文檔內(nèi)容的代碼.如果要支持輸入,如鼠標的點擊和鍵盤的按鍵,你應該加入相應消息處理函數(shù)到類和映射中. 可以看這個窗口是從CWindowImpl<>繼承下來的,如果你想讓它基于一個Win32控件的話,就應該從定義在AtlCtrls.h文件某個WTL類繼承.

如果想在基于CWindowImpl<>的類里加上滾動條,那么你應該把基類換成CScrollWindowImpl<>,同時把消息鏈給它:

class CMyView : public CScrollWindowImpl<CMyView>
{
public:
??? typedef CScrollWindowImpl<CMyView> parent;
??? BEGIN_MSG_MAP(CMyView)
??????? CHAIN_MSG_MAP(parent)
??? END_MSG_MAP()
??? void DoPaint(CDCHandle dc)
??? {
??? }
}

基類保證窗口具滾動條,并提供滾動條消息的默認處理.視圖類不再有WM_PAINT的處理函數(shù),因為它CScrollWindowImpl<>處理.根據(jù)滾動條的位置,CScrollWindowImpl<>畫出視圖相對應的部分. 取而代之在你的類里實現(xiàn)DoPaint(),在這里你需要畫出個視圖.如果你指定滾動的范圍,大小或起點,你需要加上處理WM_CREATE消息的函數(shù),把這些初始化代碼放到里邊.

正如我先前提到的,框架窗口會改變視圖窗口的大小,以使它客戶區(qū)未被狀態(tài)條和工具條覆蓋的部分為視圖所填充. 在大多數(shù)情況下,這樣就夠了.但是當你想要一個具有Windows Explorer樣子的程序時,該怎么辦呢? Windows Explorer的窗口包含了一個tree view 和一個list view,還有兩者之間的分割條. WTL的解決方案很簡單:使用splitter窗口!

為此你需要改變一下框架窗口,讓它創(chuàng)建splitter窗口的一個實例作為它的視圖. 例如, 在你的框架類里有如下的數(shù)據(jù)成員:

CSplitterWindow m_view;
CTreeViewCtrl m_tree;
CListViewCtrl m_list;


你可以在OnCreate()創(chuàng)建一個splitter窗口:

// get the frame client rect, so that we set the splitter initial size
// and we can get the splitter bar in the centre

RECT rect;
GetClientRect(&rect);
m_hWndClient = m_view.Create(m_hWnd, rect,
??? NULL, WS_CHILD | WS_VISIBLE);
m_tree.Create(m_view, rcDefault, NULL,
??? WS_CHILD | WS_VISIBLE | TVS_HASBUTTONS | TVS_HASLINES | TVS_LINESATROOT,
??? WS_EX_CLIENTEDGE);
m_list.Create(m_view, rcDefault,
??? NULL, WS_CHILD | WS_VISIBLE | LVS_REPORT, WS_EX_CLIENTEDGE);
m_view.SetSplitterPanes(m_tree, m_list);
m_view.SetSplitterPos();


Splitter窗口如同一個視圖,將框架窗口作為它的父窗口. 在這段代碼里,我將框架窗口客戶區(qū)的實際大小傳給splitter窗口. 我可以在這里使用 rcDefault,因為一旦框架窗口創(chuàng)建完成,框架窗口會轉(zhuǎn)發(fā)WM_SIZE消息給splitter. 這樣splitter可以馬上改變自身的大小來填充框架. 然而,當我準備使用不參數(shù)的SetSplitterPos(),把分割條設置于窗口中線時,出現(xiàn)了問題.Splitter窗口使用它的大小來決定中線的位置,由于rcDefault告訴窗口它的大小是0(因此中線的位置也是0),從而意味著分割條將出現(xiàn)在z最左邊,左窗口隱藏了起來.

創(chuàng)建了splitter窗口后,你需要創(chuàng)建那些你想要分割的窗口.它們將作為splitter窗口的窗口被創(chuàng)建.最后你將這些子窗口通過SetSplitterPanes()加到splitter窗口中去,并確定分割條的位置所在.

UI Update

菜單項可以被設置為有效或無效,可以check記號或著像radio按鈕一樣,一組菜單項中同時有且只有一個能被check.此外,菜單項還可以帶圖標和文字. 所有的這些狀態(tài)都可以在運行時根據(jù)程序中的某個值進行改變.工具條在某種程度上可以看做是菜單的易見形態(tài),因為它們的按鈕可以個別地,或者作為一組的一部被置成有效或無效,推入推出. UI update機制允許你指定哪些UI元件(UI element)的狀態(tài)可以在運行時改變. WTL使用如下的UI update映射來實現(xiàn)這一功能:


BEGIN_UPDATE_UI_MAP(CMainFrame)
??? UPDATE_ELEMENT(ID_FILE_SAVERESULTS, UPDUI_MENUPOPUP | UPDUI_TOOLBAR)
??? UPDATE_ELEMENT(ID_VIEW_TOOLBAR, UPDUI_MENUPOPUP)
??? UPDATE_ELEMENT(ID_VIEW_STATUS_BAR, UPDUI_MENUPOPUP)
END_UPDATE_UI_MAP()

這個例子指出三個菜單項在運行時有一個狀態(tài)需要顯示,其中的一個, ID_FILE_SAVERESULTS,有一個工具條按鈕跟它相關聯(lián). WTL通過建立一個數(shù)組來保存這些信息.為此你需要完成兩方面的工作:

首先是UI元件的狀態(tài). 如果是菜單項, 你可以使用UIEnable()使能該菜單項, UISetCheck()設置check記號, UISetText()改變菜單的文字.如果是工具條按鈕,那么你使用UIEnable()使能該按鈕, UISetCheck()或者UISetRadio()決定按鈕是推入還是推出.下邊的代碼根據(jù)是否有文本被選中,來使能Cut菜單項和工具條按鈕:

BOOL bSelected = GetSelected();
UIEnable(ID_EDIT_CUT, bSelected);


你可以把這樣的代碼放入相應處理函數(shù)中(如一個菜單項的狀態(tài)依賴于另一個菜單項的動作,將它放入后者的處理函數(shù)中),或者放入OnIdle()方法,通過檢查某個類變量來決定元件的狀態(tài).

其次是確定各個UI元件是否都被更新了,為此你需要調(diào)用CUpdateUI<>的某個方法UI元件加入到列表中.主菜單已自動加入,但是其他的任何菜單和所有的工具條必須分別通過調(diào)用UIAddMenuBar()UIAddToolBar()手動加入.

其他還有一堆事情要注意. 首先,設置了工具條的狀態(tài)后,使用UIUpdateToolBar()以使工具條狀態(tài)更新. 對于菜單,你不需如此,因為子菜單是動態(tài)生成的.UIUpdateMenuBar()這個方法也存在,但是它的作用是把菜單恢復到初始狀態(tài),如果你改變過某些項的文字,調(diào)用UIUpdateMenuBar()的結果可能不是你所期望的(因為菜單項的文字會變成的).

盡管還有一個方法UISetRadio(),但是沒有一個把幾個菜單項或者工具條按鈕當做radio按鈕組(也就是說,有一個而且只有一個被選中)的機制.如果你希望得到這樣效果,你必須自己編碼,不過它并不難.

對話框

ATL的對話框支持一向很好,對此WTL新增了通用對話框的封裝. 本質(zhì)上是為對話框加入了輸入驗證和回調(diào)函數(shù). 比如, 你想用戶改變年Open對話框中的文件夾時有所動作,那么你應該從CFileDialogImpl<>繼承一個類,實現(xiàn)OnFolderChange():

class CMyFileDialog : public CFileDialogImpl<CMyFileDialog>
{
public:
??? CMyFileDialog(BOOL b)
??????? : CFileDialogImpl<CMyFileDialog>(b) { }
??? void OnFolderChange(LPOFNOTIFY lpon)
??? {
??????? char strFolder[MAX_PATH];
??????? if (GetFolderPath(strFolder, sizeof(strFolder)) > 0)
??????? {
??????????? MessageBox(strFolder);
??????? }
??? }
};

當文件夾的路徑改變時,CFileDialogImpl<>調(diào)用OnFolderChange().該函數(shù)使用基類的GetFolderPath(),來取得新路徑.

控件

WTL為所有的Win32和通用控件提供了封裝類,包括Windows 2000新加入的. 雖然只是簡單的包裝,但是它們使這些控件更加容易訪問.譬如,你能記清楚從List View讀出當前選定項的文字的消息和需要傳的參數(shù)嗎?(實際上, 你需要發(fā)送兩個消息, 一個是得到選定項的索引,另一個是讀出它的文字.) WTL的作者為你完成了這些煩人的工作, 提供了一個簡單的封裝函數(shù)供你使用.

使用這些控件類有兩種方法. 如果你的對話框里有一個控件, 你可以將控件的HWND依附到一個封裝對象,使用封裝類的方法來訪問控件.這種方法簡化了你讀寫控件數(shù)據(jù)和處理notification消息的代碼.

另外的用法是把這些類加到你的視圖類的繼承層次中去:

class CMyView : public CWindowImpl<CMyView, CListBox>

這表示CWindowImpl<>CListBox繼承而來,因此創(chuàng)建的窗口將是一個list box (因為窗口類的名字是通過調(diào)用
CListBox::GetWndClassName()得到). 另外, ATL的窗口機制會子類化這個窗口,將發(fā)給它的消息路由到你的消息映射中去. 它保留了老的窗口函數(shù),這樣,你沒有處理的消息將由老的窗口函數(shù)來處理.當你的視圖類從控件類繼承時,WTL就會使用這一技術.

在notification消息和子類化這個主題上,有一點很值得指出,那就是當事件發(fā)生時,絕大多數(shù)窗口控件都會發(fā)送notification消息給它們的父窗口.讓你窗口來處理這些notification消息要比子類化一個已存在控件窗口(或子類化一個已存在的類,然后建立一個實例),從而在控件之前取得消息好得多. 譬如, 你想處理按鈕的click事件,你所需要做的只是處理BN_CLICKEDnotification.它將由按鈕發(fā)送給你的窗口類.另外的一種方法是從CContainedWindow<>子類化BUTTON窗口來處理click消息.

之所以說這個是因為一個知名的ATL鼓吹者給我一份代碼里就是這么做的.他的代碼取得一個簡單的按鈕click事件所花的時間是別人的3到4倍,因為他子類化了按鈕控件,而不是簡單的處理BN_CLICKEDnotification.

WTL還提供了一些新的控件,在win32中沒有對等者. 你已經(jīng)看到過一個 -- command bar, 實際上還有其他一些非常有用類:

?? 描述
CBitmapButton 這是一個用位圖替代標題的按鈕.你可以提供一個image list,里邊包含按鈕在正常狀態(tài),失效, 推入和鼠標落在按鈕上的圖表.
CHyperLink 讓你建立一個static控件,它代表一個hyperlink,這樣當用戶點擊它時,默認的web瀏覽器打開該鏈接.
CWaitCursor 這不過是在它的構造函數(shù)中把鼠標圖標改成等待狀態(tài),而在析構函數(shù)中還原.
CCheckListViewCtrl 在每一項邊上都有一個check box的list box.
CMultiPaneStatusBarCtrl 具有多個pane的狀態(tài)條

?

posted on 2007-01-18 09:49 獨孤九劍 閱讀(1536) 評論(0)  編輯 收藏 引用 所屬分類: C/C++/STL/ATL/WTL
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            最新热久久免费视频| 91久久精品国产91久久性色tv| 日韩视频一区二区三区在线播放免费观看 | 亚洲精品之草原avav久久| 久久午夜电影| 在线观看亚洲a| 亚洲国产成人久久综合一区| 久久视频一区二区| 亚洲激情女人| 91久久精品日日躁夜夜躁国产| 欧美高清在线| 亚洲午夜精品一区二区三区他趣| 99热在线精品观看| 国产精品亚洲综合一区在线观看| 久久av在线看| 久久天堂精品| 夜色激情一区二区| 亚洲一区二区成人在线观看| 国产乱码精品| 欧美激情视频一区二区三区免费| 欧美福利影院| 欧美呦呦网站| 欧美风情在线| 欧美一级日韩一级| 女人天堂亚洲aⅴ在线观看| 日韩天天综合| 亚洲欧美在线aaa| 在线日韩欧美| 亚洲视频一二三| 亚洲国产欧美一区二区三区久久| 免费短视频成人日韩| 欧美国产三区| 久久久久在线| 欧美色一级片| 亚洲第一区中文99精品| 国产精品久久久久国产a级| 久久精品中文字幕一区| 欧美日韩你懂的| 免费一区视频| 国产精品亚洲成人| 亚洲国产精品嫩草影院| 国产日韩精品入口| 99pao成人国产永久免费视频| 国产夜色精品一区二区av| 亚洲国产成人av在线| 国产欧美在线观看一区| 亚洲国产视频直播| 国产亚洲在线| 亚洲愉拍自拍另类高清精品| 日韩视频免费看| 久久精品道一区二区三区| 午夜精品久久| 欧美日韩 国产精品| 欧美sm视频| 狠狠色香婷婷久久亚洲精品| 亚洲少妇在线| 亚洲一区二区黄色| 欧美巨乳在线观看| 亚洲成色777777女色窝| 国内精品久久久久久久果冻传媒| 亚洲一区二区毛片| 亚洲欧美另类中文字幕| 欧美日韩妖精视频| 亚洲精品一级| 亚洲网站啪啪| 欧美日韩精品免费| 亚洲美女黄色| 在线亚洲精品福利网址导航| 欧美日本精品| 99re6热只有精品免费观看| 一本久久a久久免费精品不卡| 欧美成人午夜影院| 91久久极品少妇xxxxⅹ软件| 亚洲人体偷拍| 欧美日韩精品一本二本三本| 亚洲欧洲精品一区二区| 日韩一级网站| 欧美三区在线| 香蕉av777xxx色综合一区| 亚洲欧美日韩成人| 国产精品视频导航| 性做久久久久久久免费看| 欧美一区二区三区的| 国产欧美日韩视频在线观看 | 欧美一级专区| 国语自产在线不卡| 久久久久久婷| 欧美成人一区在线| 9久re热视频在线精品| 欧美日韩无遮挡| 在线亚洲一区二区| 久久精品视频免费| 亚洲高清资源| 国产精品成人播放| 欧美一区亚洲| 亚洲黄色成人| 欧美一区视频| 亚洲国产女人aaa毛片在线| 欧美日韩网址| 久久国产精品久久w女人spa| 亚洲国产日韩欧美一区二区三区| 亚洲色无码播放| 黄色亚洲免费| 欧美日韩亚洲91| 久久aⅴ国产欧美74aaa| 亚洲人成毛片在线播放女女| 西瓜成人精品人成网站| 亚洲国产一区二区三区高清| 欧美日精品一区视频| 久久久99国产精品免费| 亚洲欧洲日产国产综合网| 性欧美xxxx视频在线观看| 亚洲欧洲日本国产| 国产欧美激情| 欧美乱在线观看| 久久精品国产一区二区三区| 99精品国产99久久久久久福利| 久久精品一区二区| 一区二区三区视频观看| 亚洲国产日韩欧美在线99| 国产精品高潮呻吟久久av无限| 久久久久久久91| 先锋影音国产精品| a4yy欧美一区二区三区| 欧美激情免费观看| 久久久久久久999精品视频| 亚洲午夜电影网| 亚洲人成在线免费观看| 激情综合视频| 国内精品国语自产拍在线观看| 欧美先锋影音| 欧美日韩一区免费| 欧美成人精品不卡视频在线观看| 欧美一区亚洲| 欧美一区二区三区视频免费| 亚洲天堂男人| 这里是久久伊人| 一级日韩一区在线观看| 亚洲精品在线免费| 亚洲国产欧美日韩精品| 亚洲第一级黄色片| 欧美.日韩.国产.一区.二区| 久久人人超碰| 美女精品在线| 美女主播精品视频一二三四| 久久久久国产精品人| 久久久99爱| 久久米奇亚洲| 久久久亚洲午夜电影| 久久精品2019中文字幕| 久久精品一区四区| 久久深夜福利免费观看| 久久精品夜夜夜夜久久| 久久久国产视频91| 老司机午夜精品视频在线观看| 久久久激情视频| 麻豆精品在线观看| 欧美二区乱c少妇| 欧美福利电影网| 亚洲国产精品一区制服丝袜 | 久久人体大胆视频| 你懂的亚洲视频| 亚洲黄网站黄| 中文国产成人精品久久一| 亚洲欧美日韩国产成人| 性一交一乱一区二区洋洋av| 久久久久久久激情视频| 久久亚洲高清| 欧美经典一区二区| 国产精品视频专区| 狠狠色丁香婷婷综合| 亚洲区欧美区| 欧美亚洲一区三区| 欧美成人官网二区| 日韩视频欧美视频| 欧美怡红院视频| 你懂的成人av| 国产精品欧美一区二区三区奶水 | 国产欧美一区二区视频| 亚洲电影av在线| 在线一区视频| 久热精品视频在线| 亚洲日本中文字幕| 欧美伊人影院| 欧美日韩国产三级| 激情av一区二区| 亚洲视频一区二区| 开心色5月久久精品| 亚洲精品美女91| 久久国产黑丝| 国产精品伦理| 亚洲精品在线一区二区| 久久精品男女| 国产精品99久久久久久宅男| 久久婷婷国产麻豆91天堂| 国产精品日韩在线播放| 亚洲精品日韩在线| 久久久亚洲成人| 91久久精品久久国产性色也91 | 红桃视频一区|