WTL是一個好東東.它開發的程序都很短小精悍.對開發WIN32的應用有很好的優點.它不用MFC開發.但可以高速產生窗體和控件.
以文本方式查看主題
-??
溫馨小筑
??(http://www.learnsky.com/bbs/index.asp)
--??
電腦編程
??(http://www.learnsky.com/bbs/list.asp?boardid=6)
----??
WTL簡單介紹
??(http://www.learnsky.com/bbs/dispbbs.asp?boardid=6&id=407)
|
WTL簡單介紹
vcmfc
? ? ? 在ATL出現的時候,一些部分COM的編程人員開始認為開發COM運用是一種快樂,由于使用它非常方便地開發小規模的COM組件,但好景不長,現實的COM組件是包羅相當廣泛的,特別當它們準備使用包裝我窗體控件,發現ATL提供了相當的稀少。因此Microsoft推出了半成品與沒有技術支持的WTL,這也是WTL誕生的原因。
? ? ? 非常多初次接觸WTL都問“WTL這三個字母代表什么呢?”:WTL全稱為Windows Template Library,構架于ATL之上,採用C++模板技術來包裝大部窗體控制,并給出一個與MFC類似的應用框架。
? ? ? ?他們緊跟著問“那我怎樣得到它呢?”:因為WTL是Microsoft推出的,在Microsoft的PlatForm SDK中就有,下面是部分畫面:
或者能過下面鏈接下載:
http://msdn.microsoft.com/msdn-files/027/001/586/wtl31.exe
? ? ? 跟著問題又來了,“我該怎樣使用它們呢?”:在你安裝完了WTL SDK之后,在安裝文件夾中有一個AtlApp60.Awx的向導文件,將它復制到你安裝Visual C++的文件夾:Microsoft Visual Studio//common//mesdev98//bin//ide//文件夾下(實在不行使用Windows的搜索文件查找.awx),這是,在VC的應用程序向導里就有跟MFC類似的WTL應用程序向導。
? ? ? 假設你是MFC的使用者,你可能會再問“WTL與MFC在包裝窗體控制有哪些不同呢?”:我僅僅能用下面表格回答你:
Feature
|
MFC
|
WTL
|
Stand-alone library
|
Yes
|
No (built on ATL)
|
AppWizard support
|
Yes
|
Yes
|
Clazard support
|
Yes
|
No
|
Officially supported by Microsoft
|
Yes
|
No (Supported by volunteers inside MS)
|
Support for OLE Documents
|
Yes
|
No
|
Support for Views
|
Yes
|
Yes
|
Support for Documents
|
Yes
|
No
|
Basic Win32 & Common Control Wrappers
|
Yes
|
Yes
|
Advanced Common Control Wrappers (Flat scrollbar, IP Address, Pager Control, etc.)
|
No
|
Yes
|
Command Bar support (including bitmapped context menus)
|
No (MFC does provide dialog bars)
|
Yes
|
CString
|
Yes
|
Yes
|
GDI wrappers
|
Yes
|
Yes
|
Helper classes (CRect, Cpoint, etc.)
|
Yes
|
Yes
|
Property Sheets/Wizards
|
Yes
|
Yes
|
SDI, MDI support
|
Yes
|
Yes
|
Multi-SDI support
|
No
|
Yes
|
MRU Support
|
Yes
|
Yes
|
Docking Windows/Bars
|
Yes
|
No
|
Splitters
|
Yes
|
Yes
|
DDX
|
Yes
|
Yes (not as extensive as MFC)
|
Printing/Print Preview
|
Yes
|
Yes
|
Scrollable Views
|
Yes
|
Yes
|
Custom Draw/Owner Draw Wrapper
|
No
|
Yes
|
Message/Command Routing
|
Yes
|
Yes
|
Common Dialogs
|
Yes
|
Yes
|
HTML Views
|
Yes
|
Yes
|
Single Instance Applications
|
No
|
No
|
UI Updating
|
Yes
|
Yes
|
Template-based
|
No
|
Yes
|
Size of a statically linked do-nothing SDI application with toolbar, status bar, and menu
|
228KB +
MSVCRT.DLL (288KB)
|
24k (with /OPT:NOWIN98)
(+ MSVCRT.DLL if you use CString)
|
Size of a dynamically linked do-nothing SDI application with toolbar, status bar, and menu
|
24KB +
MFC42.DLL (972KB) +
MSVCRT.DLL (288KB)
|
N/A
|
Runtime Dependencies
|
CRT (+ MFC42.DLL, if dynamically linked)
|
None (CRT if you use CString)
|
? ? ? ?最后再說兩句。因為WTL不是Microsoft的正式產品,因此得不到Microsoft的技術支持,盡管有不少民間技術團體的支持,但這還不夠;關于WTL的技術文章相當的少,并且WTL使用C++的Template技術,這是一種相對較新的技術,無法與MFC混合使用,使用它須要又一次學習它,以致于相當少的人使用它。
?
|
--??作者:admin
--??公布時間:2005-1-11 2:11:00
--??
什么是WTL????? 選擇自 dairyman000 的 Blog??
keyword?? WTL ATL COM?
出處???
http://www.idevresource.com/com/library/bytesize/wtl.asp
?
簡單介紹
WTL 在開發人員之間的悄悄傳播已經超過一年了, 傳聞它是基于ATL的,并在微軟內部使用.這理所當然的引起了ATL開發人員社區的主意.這些人從ATL1.1開始,就一直為ATL控件書寫UI代碼,可是他們發現,他們的所寫的代碼經常就是純的Win32 GDI代碼.我告訴您, WTL并沒有多大不同.
是不是讓人失望? 不,由于ATL僅僅是對COM進行了簡單的封裝,這也是ATL的強大之處. 是的,寫ATL您必須通曉COM. 您在ATL上額外花費的功夫跟您學習COM所作的努力比起來,簡直微不足道.這跟那些須要把主要精力花費在學習類庫本身,忽略COM的庫是全然不同的.
WTL與此相似.您須要懂得Win32窗體技術和GDI.僅僅要您懂得,學習WTL就似清風撫面,再簡單只是了.假設您不懂 這些,那么您最好使用VB來寫UI代碼.
WTL有什么?
它給各種類型的應用程序提供了一個主要的框架.注意,盡管您沒有MFC那樣的文檔/視結構,可是您有視(views). 在WTL有大量的代碼讓您來管理視,并且增加您自己的代碼也非常easy.??WTL有AppWizard,能夠讓您生成SDI, MDI 和多線程SDI程序多線程SDI跟IE或Windows Explorer非常像.它看起來是打開了多個程序實例,實際上這些窗體都是屬于一個進程的).
另外,您的程序能夠是基于對話框的,也能夠是基于視的.視能夠是基于CWindowImpl的,也能夠是基于控件,甚至是IE里的一個HTML頁.您能夠選擇您的程序是否須要一個rebar, command bar (CE-like), toolbar 和/或status bar.另外,您的程序能夠主持ActiveX控件,以及成為一個COMserver.
這里有幾個關于視的選項. WTL提供splitter窗體類(這樣在一個視里您能夠有兩個窗體)和scroll窗體類(這樣您的窗體能夠比它顯示的"視"小). WTL也有個相似MFC的UpDateUI的東西,可是它們不是非常一樣 - 基本的差別是您須要把須要更新的項用宏映射標注出來,然后您在您的類里增加運行UpdateUI的代碼. DDX/DDV在WTL也支持,相同相似MFC,但有不同. 您必須加一個宏映射來實現DoDataExchange,然后增加調用它的代碼.
如今WTL也有GDI類了.然而,HDC的封裝類就像CWindow一樣,僅僅進行了非常easy的封裝 - 它差點兒沒有增加不論什么新的功能.只是,在WTL,你能夠得到播放meta文件和OpenGL支持. 最有價值的我猜應該是打印機DC的那些繼承類 - WTL有打印機支持,甚至打印預覽. 當然也有GDI對象的封裝. 諸如畫筆,畫刷,區域等.
WTL對全部的Win32 (和W2K) 通用對話框進行了封裝.相同雖然簡單,可是它的確使請求字體或者文件變的很的簡單.
合成了舊的AtlControls.h,新加了一些封裝類. 這些封裝類封裝了W2K控件,以及一些不屬于Win32的"控件",像Command Bar, bitmap button, hyperlink 和 wait cursor.
WTL 終于把消息分離帶入了ATL! 一些新的MSG映射宏將消息分離,調用您類里的消息處理函數.消息處理函數的參數的值是從消息分離得到的.唯一令人頭痛的是,您須要查看頭文件以確定函數參數的意義.
最后,WTL另一些有用類.最重要的是CString. 不錯,它是從MFC克隆得到的(copy on write),具有(在我知道的范圍內)MFC版本號的全部方法.還有查找文件的API的封裝類,以及CRect, CSize and CPoint.
總結
假設您打算寫一個Win32 界面程序,我建議您在考慮MFC之前,先試試WTL.使用WTL來寫您的代碼, 程序將變得小巧些,也更有效率些.使用WTL, 您還將得到ATL支持COM優點.而MFC沒有對COM的支持.
您能夠在2000年一月份的平臺SDK中找到WTL.在MSI選項頁的Source Code section下.
作者Blog:
http://blog.csdn.net/dairyman000/
|
--??作者:admin
--??公布時間:2005-1-11 2:11:00
--??
WTL
體系結構
緒論
?????
WTL
終于來了
,
并且提供了我所希望的功能
.
我在
WTL Bytesize
(
譯文
)的文章列出
WTL
主要特征
.
在本文中
,
我將描寫敘述一下
WTL
的體系結構
,
同一時候我會給出一些簡單的樣例來演示怎樣使用它的那些特征
.
希望可以對您有所幫助
.
WTL
應用程序的類型
???? WTL有好幾種應用程序類型,供您在AppWizard選取.
?
????下表對這些應用程序進行了描寫敘述. 這樣的彈性構成了WTL體系結構的一部分.
應用程序類型
|
描寫敘述
|
SDI Application
|
單文本界面 – 僅僅有一個窗體
|
Multiple Threads SDI
|
單個進程擁有一個或多個窗體
|
MDI Application
|
多文本界面 – 在框架內,您能夠有零個或多個子窗體
|
Dialog Based
|
基于對話框模版
|
????你可能還是首次聽說多線程SDI應用程序,可是不用操心,它的概念非常easy理解.一個多線程SDI程序啟動后它會有一個窗體, 窗體顯示了一個文檔. 當你想要程序要再創建一個文檔時,問題就出現了--SDI程序僅僅能顯示一個文檔.為了解決問題,多線程SDI創建了還有一個SDI窗體.看起來是一個新的實例在執行,實際上它只是是原來的進程創建了一個新的窗體,并把它依附到進程的一個新線程. IE的新建窗體就是這樣做的.
????除了多線程SDI,全部這些應用程序都能夠作為COMserver, 而且應用程序向導(AppWizard)為此提供了一個選項.另外應用程序向導還能夠讓你指定該程序是否主持ActiveX控件.令人費解的是,不同的程序類型,選取"Host ActiveX Controls"的地方不同.除對話框應用程序外的其它類型在第一頁上選取,而對話框類型卻放到第二頁.
????第二頁的其它選項,對對話框程序以外的類型都是可用的.它們讓你指定程序是否須要工具條(toolbar),狀態條(status bar)和視窗體(View Window).
????假設選取了"Toolbar"選項,你能夠通過"Rebar"選擇是否將工具條放入IE Rebar控件中. 假設你選取了Rebar, 你就能夠通過框架窗體(frame window)的成員m_hWndToolBar(后邊會有具體的描寫敘述)來訪問它.你能夠依照你的意愿,在里邊增加其它的工具條. 選取了"Rebar"后, 你能夠決定是否選取"Command Bar". Command bar非常像CE的command bar控件.僅僅是WTL是用一個類來實現,而在CE, command bar是一個系統窗體類(system window class). Command bar非常實用,它能夠把窗體也增加到工具條中去. 假設你選取了這個選項, 工具條和菜單都將被當做toolbar來實現.這使菜單項也能夠有關聯的圖標,而且當你移動鼠標到一個菜單項上時,該菜單項會被置成高亮.從Office 97以來, Office軟件的菜單都具有上述特征.
????第二頁還有指定程序是否使用視的選項(多半你想要使用), 同一時候你能夠決定這些視怎樣實現. 下表列出了全部可選的視.
視
|
描寫敘述
|
Generic Window
|
一個簡單的窗體. 此類窗體同意程序猿編寫WM_PAINT消息的處理函數. 適用于須要直接進行paint的文檔.
|
Form
|
這類視具有一個對話框模版.適用于帶ActiveX 控件的窗體. 應用程序來操作這些控件.
|
List Box
|
這個視是個list box.它最簡單的形式意味著能夠通過調用AddString() 方法來加入字符串.
|
Edit
|
這個視是個edit control. 本質上,它提供了一個像Notepad一樣的程序.
|
List View
|
這個視是個list view 通用控件.用這個控件來顯示相關的項(比方, 控制面板是一個Explorer主持的List View, 全部的項都是控制面板applet).
|
Tree View
|
這個視是個tree view 通用控件. 這個適用于具有層次關系的數據,比方,能夠用它來顯示數據庫的schema. 頂層分支為表和存儲過程,次級的分支為表中的字段.
|
Rich Edit
|
這個視是個rich edit 控件,像WordPad.
|
HTML Page
|
這個視主持了一個IE Web Browser 控件. 它把主持的一個web page當成一個視.
|
????本文的樣例須要一個對話框模版,同一時候還須要菜單,因此Form view是個理想的選擇.
|
--??作者:admin
--??公布時間:2005-1-11 2:14:00
--??
WTL體系結構
程序線程
????跟ATL一樣,WTL程序也須要一個
_Module
全局變量來保存全局數據,方便應用級代碼訪問.在WTL中,這個變量是
CAppModule
或
CServerAppModule
的實例,后者在程序同一時候作為一個COMserver時用到.每一個應用程序具有一個或者多個UI線程.WTL使用兩種方式來管理這些線程.
????假設應用程序僅僅有一個UI線程(除了多線程SDI以外,其它程序類型默認僅僅有一個UI線程),線程調用全局函數
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;
}
????線程的消息循環包括在
CMessageLoop
內部.函數創建了一個
CMessageLoop
實例, 把它放入全局的消息循環映射(message loop map)數組. 以線程ID為索引,線程中執行的其它的代碼能夠訪問到這個實例. 消息循環對象包括了message filter和idle handler. 執行在這個UI線程的UI元件(UI element)能夠有它自己的idle handler,在線程的消息隊列為空時執行
【
譯注:通過
CMessageLoop::AddIdleHandler()
把這個UI元件增加到
CMessageLoop
的idle handler 數組中
】
.
?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;
}
????能夠看到,這個函數推動著消息隊列. 沒有消息時, 執行注冊到線程的idle hander. 假設在隊列中檢測到消息,把它取出來,傳給每一個message filter. 假設消息沒有被這些函數處理,它將依照通常的方式,發送到目標窗體.
????假設程序有超過一個的UI線程,能夠用WTL的線程管理器,多線程SDI就是這樣做的. 主線程作為一個管理者線程,它會為每一個新窗體創建一個新的新線程. 主要流程例如以下:
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);
????}
}
那些線程句柄放在一個數組中. 線程通過
AddThread()
增加到數組(同一時候啟動線程),?
RemoveThread()
從數組移走. wait語句在兩種情況下會被打斷: 線程死亡(將線程從數組中移出) 或線程收到了
WM_USER
消息(一個線程在一個新線程里新建了一個窗體). 線程管理者為程序中的一個類,因此能夠在循環中增加自己的message handler, 比方,當程序有不止一種窗體類型時. 創建一個新的窗體非常easy,僅僅需在隨意一個窗體中調用:
:
:PostThreadMessage(_Module.m_dwMainThreadID, WM_USER, 0, 0L);
這個循環會一直執行下去,直到全部的UI線程都關閉了. UI線程具有一個thread procedure,它跟單UI線程的Run()方法一樣.只是,因為線程管理者使用了
MsgWaitForMultipleObjects()
, 這意味者最多僅僅能有
MAXIMUM_WAIT_OBJECTS
-1個UI線程,這也意味著最多僅僅能創建63個窗體.?
框架
????WTL實際上是兩類窗體: 框架窗體和視圖窗體. 正如名字所暗示的那樣, 框架窗體為窗體提供標題欄(caption bar)和邊框,你的代碼用它來處理工具條(tool bar)和菜單項命令.你看到的程序窗體實際上是視圖窗體, 視圖覆蓋了框架窗體的客戶區.客戶區是指框架窗體沒有被諸如狀態條,工具條之類的修飾部件所遮擋的部分.
????線程會創建主框架窗體的一個實例,創建視圖的工作由主框架窗體的
WM_CREATE
消息處理函數完畢. 對于SDI程序來說,這個過程非常easy. 把視圖類的一個實例作為主框架類的一個成員,調用視圖類的
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的工具條和一個狀態條. 函數的第一行創建了一個command bar實例,然后對它進行初始化,在當中增加框架窗體的菜單和工具條位圖. 這段代碼先將菜單取出,把全部的下拉菜單轉換為工具條button,并將菜單保存在一個變量中,以備后用. 給人的感覺是菜單是由工具條實現的-那我們就把它叫做工具條菜單(menu toolbar)吧. 然后Command Bar將程序工具條的圖標裝入image list 并將它們的ID保存在數組中. 當點擊工具條菜單的button時,commandbar會找到相應的子菜單,創建一個彈出菜單. Command bar將子菜單項的ID和它保存的ID進行比較,這些ID跟image list中的工具條button圖標是相關聯的. 假設比較成功, 則將關聯的圖標加到菜單項上去. 這意味著同樣ID的菜單項和工具條button具有同樣的圖標.
接下來, 創建工具條并把它關聯到commandbar, 然后創建狀態條和視圖.能夠看到視圖的
HWND
存放在框架窗體的
m_hWndClient
變量中. 這個窗體句柄在框架窗體的
WM_SIZE
?handler中會用到.當框架窗體改變大小時,它告知視圖改變自身,于此同一時候也要考慮狀態條和command bar.?
在下來的三行(從調用
UIAddToolBar()
開始) 用來顯示在執行時會改變狀態的UI項(UI item).文章后面還會重提這個話題. 最后,訪問消息循環(message loop), 你應該還記得該消息循環存放在一全局數組中.
?GetMessageLoop()
?取得當前線程的消息循環,增加框架窗體的message filter和idle handler, 分別默認是
PreTranslateMessage()
和
OnIdle()
.
框架窗體繼承于下面類:
class CMainFrame :?
????public CFrameWindowImpl<CMainFrame>,?
????public CUpdateUI<CMainFrame>,?
????public CMessageFilter,?
????public CIdleHandler
后兩個抽象類宣稱了框架窗體類實現了
PreTranslateMessage()
和
OnIdle()
. 從
CUpdateUI<>
繼承表示框架類支持UI update map.
|
--??作者:admin
--??公布時間:2005-1-11 2:15:00
--??
WTL體系結構
視圖
視圖窗體看起來顯得非常easy:
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);
????????
//TOD Add your drawing code here
????????return 0;
????}
};
上面是一個SDI程序的視圖類. 多線程SDI和MDI的視圖類在本質上也跟這個一樣,但他們沒有
PreTranslateMessage()
方法. SDI程序就是使用這個函數,趕在框架類處理消息之前把消息抓住.?
PreTranslateMessage()
在SDI的框架類中的實現是,直接將消息轉發給視圖類.?
這里顯示的視圖實際上沒有做什么工作.你應該自己在
OnPaint()
函數中增加畫出文檔內容的代碼.假設須要支持輸入,如鼠標的點擊和鍵盤的按鍵,你應該增加對應消息處理函數到類和映射中. 能夠看到這個窗體是從
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
的處理函數,由于它已被
CScrollWindowImpl<>
處理.依據滾動欄的位置,
CScrollWindowImpl<>
畫出視圖相相應的部分. 取而代之的是,在你的類里實現
DoPaint()
,在這里你須要畫出整個視圖.假設你想指定滾動的范圍,大小或起點,你須要加上處理
WM_CREATE
消息的函數,把這些初始化代碼放到里邊.
正如我先前所提到的,框架窗體會改變視圖窗體的大小,以使它客戶區未被狀態條和工具條覆蓋的部分為視圖所填充. 在大多數情況下,這樣就夠了.可是當你想要一個具有Windows Explorer樣子的程序時,該怎么辦呢? Windows Explorer的窗體包括了一個tree view 和一個list view,還有兩者之間的切割條. WTL的解決方式非常easy:使用splitter窗體!
為此你須要改變一下框架窗體,讓它創建splitter窗體的一個實例作為它的視圖. 比如, 在你的框架類里有例如以下的數據成員:
CSplitterWindow m_view;
CTreeViewCtrl m_tree;
CListViewCtrl m_list;
你能夠在
OnCreate()
創建一個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窗體如同一個視圖,將框架窗體作為它的父窗體. 在這段代碼里,我將框架窗體客戶區的實際大小傳給了splitter窗體. 我也能夠在這里使用?
rcDefault
,由于一旦框架窗體創建完畢,框架窗體就會轉發
WM_SIZE
消息給splitter. 這樣splitter能夠立即改變自身的大小來填充框架. 然而,當我準備使用不帶參數的
SetSplitterPos()
,把切割條設置于窗體中線時,出現了問題.Splitter窗體使用它的大小來決定中線的位置,由于
rcDefault
告訴窗體它的大小是0(因此中線的位置也是0),從而意味著切割條將出如今z最左邊,將左窗體隱藏了起來.
創建了splitter窗體后,你須要創建那些你想要切割的窗體了.它們將作為splitter窗體的子窗體被創建.最后你將這些子窗體通過
SetSplitterPanes()
加到splitter窗體中去,并確定切割條的位置所在.
UI Update
菜單項能夠被設置為有效或無效,能夠帶check記號或著像radiobutton一樣,在一組菜單項中同一時候有且僅僅有一個能被check.此外,菜單項還能夠帶圖標和文字. 全部的這些狀態都能夠在執行時依據程序中的某個值進行改變.工具條在某種程度上能夠看做是菜單的易見形態,由于它們的button能夠個別地,或者作為一組的一部分被置成有效或無效,推入推出. UI update機制同意你指定哪些UI元件(UI element)的狀態能夠在執行時改變. WTL使用例如以下的UI update映射來實現這一功能:
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()
這個樣例指出三個菜單項在執行時有一個狀態須要顯示,當中的一個, ID_FILE_SAVERESULTS,另一個工具條button跟它相關聯. WTL通過建立一個數組來保存這些信息.為此你須要完畢雙方面的工作:
首先是UI元件的狀態. 假設是菜單項, 你能夠使用
UIEnable()
使能該菜單項,?
UISetCheck()
設置check記號,?
UISetText()
改變菜單的文字.假設是工具條button,那么你使用
UIEnable()
使能該button,?
UISetCheck()
或者
UISetRadio()
決定button是推入還是推出.下邊的代碼依據是否有文本被選中,來使能Cut菜單項和工具條button:
BOOL bSelected = GetSelected();
UIEnable(ID_EDIT_CUT, bSelected);
你能夠把這種代碼放入對應處理函數中(如一個菜單項的狀態依賴于另一個菜單項的動作,將它放入后者的處理函數中),或者放入
OnIdle()
方法,通過檢查某個類變量來決定元件的狀態.
其次是確定各個UI元件是否都被更新了,為此你須要調用
CUpdateUI<>
的某個
方法將UI元件增加到列表中.主菜單已被自己主動增加,可是其它的不論什么菜單和全部的工具條必須分別通過調用
UIAddMenuBar()
和
UIAddToolBar()
手動增加.
其它另一堆事情要注意. 首先,設置了工具條的狀態后,使用
UIUpdateToolBar()
以使工具條狀態更新. 對于菜單,你不需如此,由于子菜單是動態生成的
.
UIUpdateMenuBar()
這種方法也存在,可是它的作用是把菜單恢復到初始狀態,假設你改變過某些項的文字,
調用
UIUpdateMenuBar()
的結果可能不是你所期望的(由于菜單項的文字會變成老的).?
雖然另一個方法
UISetRadio()
,可是還沒有一個把幾個菜單項或者工具條button當做radiobutton組(也就是說,有一個并且僅僅有一個被選中)的機制.假設你希望得到這樣效果,你必須自己編碼,只是它并不難.
|
--??作者:admin
--??公布時間:2005-1-11 2:16:00
--??
WTL體系結構
對話框
ATL的對話框支持一向非常好,對此WTL新增了通用對話框的封裝. 本質上是為對話框增加了輸入驗證和回調函數. 比方, 你想在用戶改變年Open對話框中的目錄時有所動作,那么你應該從
CFileDialogImpl<>
繼承一個類,實現
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<>
調用
OnFolderChange()
.該函數使用基類的
GetFolderPath()
,來取得新路徑.
控件
WTL為全部的Win32和通用控件提供了封裝類,包含Windows 2000新增加的. 盡管僅僅是簡單的包裝,可是它們使這些控件更加easy訪問.譬如,你能記清楚從List View讀出當前選定項的文字的消息和須要傳的參數嗎?(實際上, 你須要發送兩個消息, 一個是得到選定項的索引,還有一個是讀出它的文字.) WTL的作者為你完畢了這些煩人的工作, 提供了一個簡單的封裝函數供你使用.
使用這些控件類有兩種方法. 假設你的對話框里有一個控件, 你能夠將控件的
HWND
依附到一個封裝對象,使用封裝類的方法來訪問控件.這樣的方法簡化了你讀寫控件數據和處理
notification
消息的代碼.?
另外的使用方法是把這些類加到你的視圖類的繼承層次中去:
class CMyView : public CWindowImpl<CMyView, CListBox>
這表示
CWindowImpl<>
是
從
CListBox
繼承而來,因此創建的窗體將是一個list box (由于窗體類的名字是通過調用?
CListBox::GetWndClassName()
得到的). 另外, ATL的窗體機制會子類化這個窗體,將發給它的消息路由到你的消息映射中去. 它保留了老的窗體函數,這樣,你沒有處理的消息將由老的窗體函數來處理.當你的視圖類從控件類繼承時,WTL就會使用這一技術.
在notification消息和子類化這個主題上,有一點非常值得指出,那就是當某事件發生時,絕大多數窗體控件都會發送notification消息給它們的父窗體.讓你窗體來處理這些
notification
消息要比子類化一個已存在控件窗體(或子類化一個已存在的類,然后建立一個實例),從而在控件之前取得消息好得多. 譬如, 你想處理button的click事件,你所須要做的僅僅是處理
BN_CLICKED
?
notification
.它將由button發送給你的窗體類.另外的一種方法是從
CContainedWindow<>
子類化BUTTON窗體來處理
click
消息.?
我之所以說這個是由于一個知名的ATL鼓吹者給我一份代碼里就是這么做的.他的代碼取得一個簡單的button
click
事件所花的時間是別人的3到4倍,由于他子類化了button控件,而不是簡單的處理
BN_CLICKED
?
notification
.
WTL還提供了一些新的控件,在win32中沒有對等者. 你已經看到過一個 -- command bar, 實際上還有其它一些非常實用類:
?
類??
|
描寫敘述
|
CBitmapButton
|
這是一個用位圖替代標題的button.你能夠提供一個image list,里邊包括button在正常狀態,失效, 推入和鼠標落在button上的圖表.
|
CHyperLink
|
讓你建立一個static控件,它代表一個hyperlink,這樣當用戶點擊它時,默認的web瀏覽器打開該鏈接.
|
CWaitCursor
|
這只是是在它的構造函數中把鼠標圖標改成等待狀態,而在析構函數中還原.
|
CCheckListViewCtrl
|
在每一項邊上都有一個check box的list box.
|
CMultiPaneStatusBarCtrl
|
具有多個pane的狀態條
|
?
|