WTL簡介

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)


 

 --  作者:admin
--  發佈時間:2005-1-11 2:08:00

--  WTL簡介

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  
關鍵字   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有大量的代碼讓您來管理視,而且加入您自己的代碼也很容易.  WTL有AppWizard,可以讓您生成SDI, MDI 和多線程SDI程序多線程SDI跟IE或Windows Explorer很像.它看起來是打開了多個程序實例,實際上這些窗口都是屬於一個進程的).

另外,您的程序可以是基於對話框的,也可以是基於視的.視可以是基於CWindowImpl的,也可以是基於控件,甚至是IE裏的一個HTML頁.您可以選擇您的程序是否需要一個rebar, command bar (CE-like), toolbar 和/或status bar.另外,您的程序可以主持ActiveX控件,以及成爲一個COM服務器.

這裏有幾個關於視的選項. WTL提供splitter窗口類(這樣在一個視裏您可以有兩個窗口)和scroll窗口類(這樣您的窗口可以比它顯示的"視"小). WTL也有個類似MFC的UpDateUI的東西,但是它們不是很一樣 - 主要的區別是您需要把需要更新的項用宏映射標註出來,然後您在您的類里加入執行UpdateUI的代碼. DDX/DDV在WTL也支持,同樣類似MFC,但有不同. 您必須加一個宏映射來實現DoDataExchange,然後加入調用它的代碼.

現在WTL也有GDI類了.然而,HDC的封裝類就像CWindow一樣,只進行了很簡單的封裝 - 它幾乎沒有加入任何新的功能.不過,在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應用程序,但是不用擔心,它的概念很容易理解.一個多線程SDI程序啓動後它會有一個窗口, 窗口顯示了一個文檔. 當你想要程序要再創建一個文檔時,問題就出現了--SDI程序只能顯示一個文檔.爲了解決這個問題,多線程SDI創建了另一個SDI窗口.看起來是一個新的實例在運行,實際上它不過是原來的進程創建了一個新的窗口,並把它依附到進程的一個新線程. IE的新建窗口就是這樣做的.

    除了多線程SDI,所有這些應用程序都可以作爲COM服務器, 並且應用程序嚮導(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中,這個變量是CAppModuleCServerAppModule的實例,後者在程序同時作爲一個COM服務器時用到.每個應用程序具有一個或者多個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, 比如,當程序有不止一種窗口類型時. 創建一個新的窗口非常簡單,只需在任意一個窗口中調用:

::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程序來說,這個過程很簡單. 把視圖類的一個實例作爲主框架類的一個成員,調用視圖類的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實例,然後對它進行初始化,在其中加入框架窗口的菜單和工具條位圖. 這段代碼先將菜單取出,把所有的下拉菜單轉換爲工具條按鈕,並將菜單保存在一個變量中,以備後用. 給人的感覺是菜單是由工具條實現的-那我們就把它叫做工具條菜單(menu toolbar)吧. 然後Command Bar將程序工具條的圖標裝入image list 並將它們的ID保存在數組中. 當點擊工具條菜單的按鈕時,commandbar會找到對應的子菜單,創建一個彈出菜單. Command bar將子菜單項的ID和它保存的ID進行比較,這些ID跟image list中的工具條按鈕圖標是相關聯的. 如果比較成功, 則將關聯的圖標加到菜單項上去. 這意味着相同ID的菜單項和工具條按鈕具有相同的圖標.

接下來, 創建工具條並把它關聯到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體系結構

視圖

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

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的解決方案很簡單:使用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記號或着像radio按鈕一樣,在一組菜單項中同時有且只有一個能被check.此外,菜單項還可以帶圖標和文字. 所有的這些狀態都可以在運行時根據程序中的某個值進行改變.工具條在某種程度上可以看做是菜單的易見形態,因爲它們的按鈕可以個別地,或者作爲一組的一部分被置成有效或無效,推入推出. 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,還有一個工具條按鈕跟它相關聯. WTL通過建立一個數組來保存這些信息.爲此你需要完成兩方面的工作:

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

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


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

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

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

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

發佈了14 篇原創文章 · 獲贊 6 · 訪問量 16萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章