CodeMax 语法编辑控件封装与WTL MDI应用开发

本文旨在介绍如何使用CodeMax语法编辑控件的封装类,并在Windows Template Library (WTL)环境下开发多文档界面(MDI)应用程序。在开发过程中,发现需要解释演示应用程序本身的内容,因此决定撰写一篇关于CodeMax封装类的文章,并扩展一些在编写MDI应用程序时发现的内容。

示例代码结构

如果曾经使用过WTL向导,可能会熟悉它将应用程序的所有代码都塞进一组头文件的做法。尽管喜欢将组件放入单一的头文件中以简化集成,但并不喜欢以这种方式设置应用程序代码。因此,首先将代码分割成相应的源文件和头文件。这样做使得实现更加清晰,并且在看来,它更易于阅读和编辑。

不幸的是,这样做破坏了使用Visual C++提供的“添加Windows消息处理程序”向导的机会。但也选择了使用WTL实现的“扩展”消息映射(BEGIN_MSG_MAP_EX等),这与上述向导也不兼容。因此,最终它无论如何都是无用的。

CodeMax封装类

包含的封装类几乎封装了CodeMax提供的所有内容。说“几乎”,是因为还没有实现一个中心方式来更新CodeMax控件的设置(当运行示例时,会明白意思)。

所有类都在cmaxwtl.h文件中定义,所有类都在cmax命名空间中声明。

  • CodeMaxLibrary:封装所有基本的CodeMax库调用,包括注册和注销。
  • CodeMaxControl:封装CodeMax控件本身。
  • CodeMaxControlNotifications:基类,允许处理来自CodeMax控件的通知消息(反射或非反射)。
  • CodeMaxControlCommands:基类,处理标准CodeMax命令(剪切、复制、粘贴等)。
  • UndoBlock:简单的撤销助手,允许将一系列可撤销命令组合为一个。

如何使用封装

首先,需要声明一个CodeMaxLibrary对象的实例并初始化它。

CodeMaxLibrary cmaxlib; if (!cmaxlib.Initialize()) { ATLTRACE(_T("CodeMax initialization failed!\n")); return 0; }

虽然可以在任何地方执行此操作,但最好尽早进行,以避免后续的麻烦。建议在WinMain函数或向导为声明的Run函数中执行此操作。

接下来,需要修改“视图”或客户端窗口,并从CodeMaxControl类派生它。

class CCodeMaxWTLSampleView : public CWindowImpl { public: // Superclass the CodeMax control DECLARE_WND_SUPERCLASS(NULL, CodeMaxControl::GetWndClassName()) };

还包含了CodeMaxControlNotifications类,允许处理CodeMax控件的通知消息。这个类可以作为视图或主框架的基础。在示例中,将其用于视图,但使用它在应用程序的主框架中可能有一些很好的理由。如果决定在应用程序的主框架中使用它,请确保将所有子窗口的消息转发到主框架。在MDI应用程序的情况下,在MDI子的消息映射中放置一个调用FORWARD_NOTIFICATIONS()可以做到这一点。

反射

在MFC中,不需要真正担心反射消息。一个人所需要做的就是子类化一个窗口或控件,它所有的通知消息就会为反射回来。在WTL中,情况并非如此,实际上必须将消息从父窗口反射回其子窗口。幸运的是,这并不难,因为ATL为提供了一个快速简单的方法来做这件事。所要做的就是记得在父窗口的消息映射中添加REFLECT_NOTIFICATIONS()。这个宏的美妙之处在于,它允许在定义它的类中处理窗口的所有内容。

class CChildFrame : public CMDIChildWindowImpl { BEGIN_MSG_MAP_EX(CChildFrame) // Notification handlers REFLECT_NOTIFICATIONS() END_MSG_MAP() };

消息更改

ATL和WTL为以窗口为中心的编程提供的最强大的概念之一是消息更改。这允许将已经灵活的消息处理方案划分为更小、更易于管理的部分。这使能够提供CodeMaxControlCommands类,它处理所有Windows的标准命令消息。为剪切和粘贴以及撤销/重做等命令提供了基本处理。

为了从这个类中获益,可以从它派生视图,或者像通知处理程序类一样,从主框架窗口派生。正如可能已经猜到的,这并不是所需要做的全部。还必须确保命令消息从主框架传递到视图。请记住,如果使用的是MDI界面,消息必须首先通过子框架才能到达视图。

以下宏将使这成为可能(两者都在atlframe.h中定义):

  • CHAIN_MDI_CHILD_COMMANDS():在主框架的消息映射中,它简单地将控制权传递给活动MDI子窗口。
  • CHAIN_CLIENT_COMMANDS():它从主框架接管控制权,然后将其传递给子的客户端控件(即视图)。
class CMainFrame : public CMDIFrameWindowImpl, public CUpdateUI, public CMessageFilter, public CIdleHandler { BEGIN_MSG_MAP_EX(CMainFrame) // Chained Message maps CHAIN_MDI_CHILD_COMMANDS() other chains... END_MSG_MAP() }; class CChildFrame : public CMDIChildWindowImpl { BEGIN_MSG_MAP_EX(CChildFrame) // Chained Message maps CHAIN_CLIENT_COMMANDS() other chains... END_MSG_MAP() }; class CCodeMaxWTLSampleView : public CWindowImpl, public CodeMaxControlNotifications, public CodeMaxControlCommands { public: // Superclass the CodeMax control DECLARE_WND_SUPERCLASS(NULL, CodeMaxControl::GetWndClassName()) // View's message map BEGIN_MSG_MAP_EX(CCodeMaxWTLSampleView) // Chained Message maps CHAIN_MSG_MAP_ALT(CodeMaxControlNotifications, CMAX_REFLECTED_NOTIFY_CODE_HANDLERS) CHAIN_MSG_MAP_ALT(CodeMaxControlCommands, CMAX_BASIC_COMMAND_ID_HANDLERS) END_MSG_MAP() };
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485