WTL介绍
来源:互联网 发布:c语言转义字符有哪些 编辑:程序博客网 时间:2024/06/07 07:05
WTL是一个好东东.它开发的程序都非常短小精悍.对开发WIN32的应用有非常好的好处.它不用MFC开发.但能够快速产生窗口和控件. 以文本方式查看主题 在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 + 24k (with /OPT:NOWIN98) Size of a dynamically linked do-nothing SDI application with toolbar, status bar, and menu 24KB + N/A Runtime Dependencies CRT (+ MFC42.DLL, if dynamically linked) None (CRT if you use CString) 最后再说两句。由于WTL不是Microsoft的正式产品,因此得不到Microsoft的技术支持,虽然有不少民间技术团体的支持,但这还不够;关于WTL的技术文章相当的少,而且WTL使用C++的Template技术,这是一种相对较新的技术,无法与MFC混合使用,使用它需要重新学习它,以致于相当少的人使用它。 什么是WTL? 选择自 dairyman000 的 Blog 是不是让人失望? 不,因为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) 通用对话框进行了封装.同样尽管简单,但是它的确使请求字体或者文件变的非常的简单. WTL 最终把消息分离带入了ATL! 一些新的MSG映射宏将消息分离,调用您类里的消息处理函数.消息处理函数的参数的值是从消息分离得到的.唯一令人头痛的是,您需要查看头文件以确定函数参数的意义. 最后,WTL还有一些实用类.最重要的是CString. 不错,它是从MFC克隆得到的(copy on write),具有(在我知道的范围内)MFC版本的所有方法.还有查找文件的API的封装类,以及CRect, CSize and CPoint. 总结 如果您打算写一个Win32 界面程序,我建议您在考虑MFC之前,先试试WTL.使用WTL来写您的代码, 程序将变得小巧些,也更有效率些.使用WTL, 您还将得到ATL支持COM好处.而MFC没有对COM的支持. WTL体系结构 绪论 WTL最终来了,而且提供了我所希望的功能.我在WTL Bytesize(译文)的文章列出WTL主要特征.在本文中,我将描述一下WTL的体系结构,同时我会给出一些简单的例子来演示如何使用它的那些特征.希望能够对您有所帮助. WTL应用程序的类型 WTL有好几种应用程序类型,供您在AppWizard选取. 下表对这些应用程序进行了描述. 这种弹性构成了WTL体系结构的一部分. 你可能还是首次听说多线程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软件的菜单都具有上述特征. 第二页还有指定程序是否使用视的选项(多半你想要使用), 同时你可以决定这些视如何实现. 下表列出了所有可选的视. 本文的例子需要一个对话框模版,同时还需要菜单,因此Form view是个理想的选择. 程序线程 跟ATL一样,WTL程序也需要一个_Module全局变量来保存全局数据,方便应用级代码访问.在WTL中,这个变量是CAppModule或CServerAppModule的实例,后者在程序同时作为一个COM服务器时用到.每个应用程序具有一个或者多个UI线程.WTL使用两种方式来管理这些线程. int Run(LPTSTR /*lpstrCmdLine*/ = NULL, int nCmdShow = SW_SHOWDEFAULT) 线程的消息循环包含在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).下边是它的伪代码: WTL体系结构 视图 视图窗口看起来显得很简单: class CMyView : public CWindowImpl<CMyView> class CMyView : public CScrollWindowImpl<CMyView> BEGIN_UPDATE_UI_MAP(CMainFrame) 首先是UI元件的状态. 如果是菜单项, 你可以使用UIEnable()使能该菜单项, UISetCheck()设置check记号, UISetText()改变菜单的文字.如果是工具条按钮,那么你使用UIEnable()使能该按钮, UISetCheck()或者UISetRadio()决定按钮是推入还是推出.下边的代码根据是否有文本被选中,来使能Cut菜单项和工具条按钮: WTL体系结构 对话框 class CMyFileDialog : public CFileDialogImpl<CMyFileDialog> 当文件夹的路径改变时,CFileDialogImpl<>调用OnFolderChange().该函数使用基类的GetFolderPath(),来取得新路径. WTL简介
关键词: WTL
- 温馨小筑 (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
MSVCRT.DLL (288KB)
(+ MSVCRT.DLL if you use CString)
MFC42.DLL (972KB) +
MSVCRT.DLL (288KB)
-- 作者:admin
-- 发布时间:2005-1-11 2:11:00
--
关键字 WTL ATL COM
出处 http://www.idevresource.com/com/library/bytesize/wtl.asp
简介
WTL 在开发者之间的悄悄传播已经超过一年了, 传闻它是基于ATL的,并在微软内部使用.这理所当然的引起了ATL开发者社区的主意.这些人从ATL1.1开始,就一直为ATL控件书写UI代码,但是他们发现,他们的所写的代码常常就是纯的Win32 GDI代码.我告诉您, WTL并没有多大不同.
合成了旧的AtlControls.h,新加了一些封装类. 这些封装类封装了W2K控件,以及一些不属于Win32的"控件",像Command Bar, bitmap button, hyperlink 和 wait cursor.
您可以在2000年一月份的平台SDK中找到WTL.在MSI选项页的Source Code section下.
作者Blog:http://blog.csdn.net/dairyman000/
-- 作者:admin
-- 发布时间:2005-1-11 2:11:00
--
-- 作者:admin
-- 发布时间:2005-1-11 2:14:00
-- WTL体系结构
如果应用程序只有一个UI线程(除了多线程SDI以外,其他程序类型默认只有一个UI线程),线程调用全局函数run():
{
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;
}
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
--
{
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<>,同时把消息链给它:
{
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 centreRECT 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映射来实现这一功能:
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通过建立一个数组来保存这些信息.为此你需要完成两方面的工作:
BOOL bSelected = GetSelected();
UIEnable(ID_EDIT_CUT, bSelected);
你可以把这样的代码放入相应处理函数中(如一个菜单项的状态依赖于另一个菜单项的动作,将它放入后者的处理函数中),或者放入OnIdle()方法,通过检查某个类变量来决定元件的状态.
其次是确定各个UI元件是否都被更新了,为此你需要调用CUpdateUI<>的某个方法将UI元件加入到列表中.主菜单已被自动加入,但是其他的任何菜单和所有的工具条必须分别通过调用UIAddMenuBar()和UIAddToolBar()手动加入.
其他还有一堆事情要注意. 首先,设置了工具条的状态后,使用UIUpdateToolBar()以使工具条状态更新. 对于菜单,你不需如此,因为子菜单是动态生成的.UIUpdateMenuBar()这个方法也存在,但是它的作用是把菜单恢复到初始状态,如果你改变过某些项的文字,调用UIUpdateMenuBar()的结果可能不是你所期望的(因为菜单项的文字会变成老的).
尽管还有一个方法UISetRadio(),但是还没有一个把几个菜单项或者工具条按钮当做radio按钮组(也就是说,有一个而且只有一个被选中)的机制.如果你希望得到这样效果,你必须自己编码,不过它并不难.
-- 作者:admin
-- 发布时间:2005-1-11 2:16:00
--
ATL的对话框支持一向很好,对此WTL新增了通用对话框的封装. 本质上是为对话框加入了输入验证和回调函数. 比如, 你想在用户改变年Open对话框中的文件夹时有所动作,那么你应该从CFileDialogImpl<>继承一个类,实现OnFolderChange():
{
public:
CMyFileDialog(BOOL b)
: CFileDialogImpl<CMyFileDialog>(b) { }
void OnFolderChange(LPOFNOTIFY lpon)
{
char strFolder[MAX_PATH];
if (GetFolderPath(strFolder, sizeof(strFolder)) > 0)
{
MessageBox(strFolder);
}
}
};
控件
WTL为所有的Win32和通用控件提供了封装类,包括Windows 2000新加入的. 虽然只是简单的包装,但是它们使这些控件更加容易访问.譬如,你能记清楚从List View读出当前选定项的文字的消息和需要传的参数吗?(实际上, 你需要发送两个消息, 一个是得到选定项的索引,另一个是读出它的文字.) WTL的作者为你完成了这些烦人的工作, 提供了一个简单的封装函数供你使用.
使用这些控件类有两种方法. 如果你的对话框里有一个控件, 你可以将控件的HWND依附到一个封装对象,使用封装类的方法来访问控件.这种方法简化了你读写控件数据和处理notification消息的代码.
另外的用法是把这些类加到你的视图类的继承层次中去:
class CMyView : public CWindowImpl<CMyView, CListBox>
这表示CWindowImpl<>是从CListBox继承而来,因此创建的窗口将是一个list box (因为窗口类的名字是通过调用
CListBox::GetWndClassName()得到的). 另外, ATL的窗口机制会子类化这个窗口,将发给它的消息路由到你的消息映射中去. 它保留了老的窗口函数,这样,你没有处理的消息将由老的窗口函数来处理.当你的视图类从控件类继承时,WTL就会使用这一技术.
在notification消息和子类化这个主题上,有一点很值得指出,那就是当某事件发生时,绝大多数窗口控件都会发送notification消息给它们的父窗口.让你窗口来处理这些notification消息要比子类化一个已存在控件窗口(或子类化一个已存在的类,然后建立一个实例),从而在控件之前取得消息好得多. 譬如, 你想处理按钮的click事件,你所需要做的只是处理BN_CLICKED notification.它将由按钮发送给你的窗口类.另外的一种方法是从CContainedWindow<>子类化BUTTON窗口来处理click消息.
我之所以说这个是因为一个知名的ATL鼓吹者给我一份代码里就是这么做的.他的代码取得一个简单的按钮click事件所花的时间是别人的3到4倍,因为他子类化了按钮控件,而不是简单的处理BN_CLICKED notification.
WTL还提供了一些新的控件,在win32中没有对等者. 你已经看到过一个 -- command bar, 实际上还有其他一些非常有用类:
- WTL介绍
- WTL介绍
- WTL介绍
- WTL 详细介绍
- WTL学习之旅(二) WTL介绍
- WTL:介绍,例子和想法
- WTL 具体介绍,及基础知识
- WTL.CDC.DrawText参数介绍
- WTL
- WTL
- WTL
- WTL
- WTL
- WTL
- WTL
- WTL
- wTL
- WTL
- java线程典例
- 2011年应关注的5项Web技术 jQuery移动版入选
- Techcrunch:将会成为2011年主流的七大IT技术
- div+css
- CDib类继承基类Object
- WTL介绍
- 要下载东西,一个积分都没有
- ADO
- 郁闷
- 怎样把自己培养成一个能保护自己的黑客
- Sql Server 常用函数
- 关于C++从属名称
- 误删资料恢复
- ASP.NET——邮件发送