为WTL设计一个“文档-视图”模型

上传人:仙*** 文档编号:162099254 上传时间:2022-10-17 格式:DOC 页数:23 大小:167KB
收藏 版权申诉 举报 下载
为WTL设计一个“文档-视图”模型_第1页
第1页 / 共23页
为WTL设计一个“文档-视图”模型_第2页
第2页 / 共23页
为WTL设计一个“文档-视图”模型_第3页
第3页 / 共23页
资源描述:

《为WTL设计一个“文档-视图”模型》由会员分享,可在线阅读,更多相关《为WTL设计一个“文档-视图”模型(23页珍藏版)》请在装配图网上搜索。

1、为WTL设计一个“文档-视图”模型作者:戴霖bill.dai前言21- 编译期虚函数调用 & 嵌入类32- 文档类43- 视图类54- 文档模板类65- 文档模板管理器类66- 上下文信息CCREATECONTEXT67- 改造你的代码78- 模型的工作流程109- 实现代码1110- 后记22前言WTL(Windows Template Library,Windows模板库)提供了比MFC库更加精减的代码框架,这其中就省略了对MFC“文档-视图”模型的支持。而“文档-视图”模型的核心思想将数据和其表示分开,在开发大型软件时颇为有用。那如何既能保留WTL精减方便的优点,又能拥有MFC“文档-视

2、图”模型的精髓呢?本文将探讨一种方法,在为WTL引入“文档-视图”模型的同时,让其接口尽可能地接近于MFC,从而方便实际应用。我们将构建四个主要的类来实现“文档-视图”模型的行为,分别是文档类、视图类、文档模板类和文档模板管理器类。四部分的关系如下图:记录并管理一个或多个文档模板文档模板管理器文档模板文档视图记录并管理一个或多个文档;创建文档,同时负责创建所对应的视图(包括视图依附的框架);打开文档负责保存数据;若数据有改变则更新所有关联的视图负责与用户交流,响应用户的操作;若用户的操作修改了数据则通知文档类由于WTL是构建在ATL基础之上的,所以其代码风格迥异于MFC,包含了大量的C+模板类

3、代码。即使你能毫不费力地读懂它们,但是下面的代码仍然可能让你一头雾水:Class CMyWin : public CWindowImpl;这样做是合法的,虽然CMyWin类只是被部分定义,但是类名CMyWin已经被列入了C+的递归继承列表,是可以使用的。可是为什么要这样做呢?目的何在?这里蕴含了两个概念,一是编译期间的虚函数调用机制,二是嵌入类。1- 编译期虚函数调用 & 嵌入类如果你想了解它们如何工作,请看下面的例子;如果你已经有了很好的ATL基础,那么可以直接跳过本章。例子:template class Baseprotected:void SayHello()cout Hello Bas

4、e; public: void Print() T* ptr = static_cast(this); / 这里我们称之为编译期虚函数调用 ptr-SayHello(); ; class Deriver1 : public Base/*空类*/; class Deriver2 : public Baseprotected:void SayHello()cout Hello Deriver2; ; main() Deriver1 d1; Deriver2 d2; d1.Print(); / 显示Hello Base d2.Print(); / 显示Hello Deriver2这句代码static

5、_cast(this) 就是窍门所在。它在函数调用时将指向Base类型的指针this转换为指向派生类Deriver1或Deriver2的指针。因为模板代码是在编译期间生成的,所以只要编译器生成正确的继承列表,这种转换就是安全的。因为在这个例子里this只能是指向Deriver 1或Deriver 2类型的对象,不会是其他的东西。这很像C+的多态性,只是Print()方法不是虚函数。要解释这是如何工作的,首先看看对每个Print()函数的调用,在d1.Print()语句里,对象Base被指派为Deriver1,所以代码被解释成:void Base:Print() Deriver1* ptr =

6、static_cast(this); ptr-SayHello();由于Deriver1没有重载SayHello(),所以查看基类Base,Base有SayHello(),所以Base的SayHello()被调用。再看d2.Print()语句,这一次对象被指派为Deriver2类型,Print()被解释成:void Base:Print() Deriver2* ptr = static_cast(this); ptr-SayHello();这一次,Deriver2含有SayHello()方法,所以Deriver2的SayHello()方法被调用。这种技术的好处在于: 不需要使用指向对象的指针。

7、 不需要虚函数表,节省内存。 因为没有虚函数表,所以运行时不会发生调用了空指针指向的虚函数的错误。 所有的函数调用在编译时确定,而非C+虚函数机制使用的动态联编,这有利于编译程序对代码的优化。 读到这里你应该可以明白什么是编译期间的虚函数调用机制,那么嵌入类又是什么呢?其实这是ATL引入的一个概念,或者叫作“另一种继承机制”更合适。上例中,编译期的虚函数调用机制能够让Base类安全地操纵其派生类的指针,就好像Base类被直接“嵌入”到了其派生类中。而在传统的继承方法中,只能够在派生类中去操纵基类。所以,我们不妨将嵌入类理解成WTL/ATL的继承机制吧。明白了这样写代码的原因和工作原理之后,可以

8、接着往下看了。2- 文档类文档是用来保存数据以及关于数据的处理的,每当SDI/MDI应用程序响应File(Open)/ File(New)命令的时候都会打开文档。一个文档可以拥有多个视图。文档和视图的关系可以这样理解:文档是被视图观察的对象。在数据发生改变时,文档负责通知所有与其关联的视图更新其显示。为实现该目的,文档需要维护一份包含所有关联视图的引用列表,这通常用指针数组来实现。在MFC中,你的所有文档类都继承自CDocument基类。我们模仿这一概念,根据WTL继承机制将构造一个嵌入类CDocument,它是你所有文档类的基类。我们还将构建一个CDocument的基类CDocumentBa

9、se,它是一个非模板类,而且是一个空类。为什么呢?因为CDocument类型中的T有无数种可能,除CDocument之外的其他类不知道T是什么(如后面还要构建的视图类),它们将如何操纵文档类呢?只需建立一个CDocumentBase类型的指针,它可以指向任何一个文档类,是不是方便了?class CDocumentBase;template class CDocument : public CDocumentBase;3- 视图类视图在Windows中就是一个窗口(模型中的视图需要依附在一个框架上才能显示为我们看到的窗口),是用来表示文档的数据的。每个视图都对应于一个特定的文档,它拥有一个指向其

10、关联文档的指针以便操作数据对象,并且在数据改动后通知其它与同一文档相关联的视图更新其显示。我们同样根据WTL继承机制将视图类设计成嵌入类。/ 视图的基类,请让你的视图类TUser_View继承它template class CView : public TDoc_ViewTDoc_View是什么?它就是“文档-视图”模型中的“视图”。你的视图类继承它以后,也具备了与一个文档类关联的属性。TDoc_View定义为CViewBase,为此我们还需要一个CViewBase类。构建CViewBase类的其中一个目的与CDocumentBase相同,不过它可不是一个空类,它是所有视图的抽象基类。由于一个

11、视图是对应于一个特定文档的,所以其模板参数必然是文档类。/ 所有视图的抽象基类template class CViewBase此外,CViewBase还将负责记录当前处于活动状态的视图。4- 文档模板类文档模板类是整个模型的核心部分,不过它非常适合用C+类模板来编程实现(MFC中使用了CRuntimeClass类型,繁琐很多)。文档模板的职责是创建一个文档及其对应的视图(包括视图依附的子窗口窗口)。它必须拥有文档、视图和框架这三个对象的信息。一个文档模板可创建多个文档。每一个文档模板对象由文档模板管理器负责记录并管理。另外,模仿MFC中的概念,文档模板类还应该持有特定文档所对应的资源ID(菜单

12、、工具栏和其它资源)。所以,文档模板类是一个拥有4个模板参数的类模板:/ 所有文档模板的抽象基类class CDocTemplateBase;/ 文档模板类template class CDocTemplate : public CDocTemplateBase5- 文档模板管理器类在MFC中,文档模板管理器的功能是在CWinApp类中提供的,而WTL没有该类。怎么办呢?我们决定在MainFrame中提供该功能。为什么呢?因为MainFrame位于窗口体系的顶层,且每一个应用程序只有一个MainFrame。当然,如果你正在做一个SDI应用程序,那么文档模板管理器就是不必要的。文档模板管理器的职

13、责是记录并管理应用程序的所有文档模板,这通常用指针数组来实现。由于我们将在MainFrame中提供该功能,所以CDocManager文档模板管理器将被设计成嵌入类(嵌入到MainFrame中去),其模板参数为MainFrame。template class CDocManager6- 上下文信息CCreateContext上下文信息是一个struct,在创建文档的过程中负责记录该文档及其所对应的文档模板和视图的相关信息,与MFC中的功能一样,那就仿着MFC中的写吧:template struct CCreateContextTDoc* m_pCurrentDoc;TView* m_pCurre

14、ntView;CDocTemplateBase* m_pNewDocTemplate;7- 改造你的代码假设你已经(我们把SDI看成是MDI的特殊情况),并且你的程序只有1个文档模板(多文档模板只需增加类似代码即可)。下面以我最近写的一个“语法高亮显示编辑器”为例,介绍代码改造过程。该编辑器由WTL 7.5的向导生成了一个MDI应用程序框架,默认视图选用了RichEdit。最初包含下面4个类:CAboutDlg,CChildFrame,CMainFrame和CSHLEditorView。首先,为程序增加一个文档类CSHLEditDoc,作如下声明:class CSHLEditorDoc: pu

15、blic CDocumentpublic:CSHLEditorDoc(void);CSHLEditorDoc(void);protected:CStringm_data;/ 必须实现的方法,CDocument需要调用它们public:/ 创建新文档时调用,返回FALSE表示失败BOOLOnNewDocument();/ 保存文档时调用,返回FALSE表示失败BOOLOnSaveDocument(LPCTSTR lpszPathName); / 打开文档时调用,返回FALSE表示失败BOOLOnOpenDocument(LPCTSTR lpszPathName); ;/ 这就是前面提过的TDoc

16、_Viewtypedef CViewBase CSHLEditorDocView;接着修改视图类CSHLEditorView。改变如下(注意深灰色背景的文字,那就是你要添加或改变的部分):typedef CWindowImpl CRichEditView;typedef CView CViewModel;class CSHLEditorView : public CRichEditView,public CViewModelpublic:DECLARE_WND_SUPERCLASS(NULL, RichEditCtrl:GetWndClassName()BOOL PreTranslateMes

17、sage(MSG* pMsg);BEGIN_MSG_MAP(CSHLEditorView)MSG_WM_CREATE(OnCreate)CHAIN_MSG_MAP(CViewModel)END_MSG_MAP()/ 必须实现的方法virtual void OnFinalMessage(HWND hWnd);/ 对应的文档类内容发生改变时调用(如:读取了某个文件后更新显示)void OnUpdate(CSHLEditorDocView *pSender, LPARAM Hint, LPVOID pHint);public:HWND Create(HWND hWndParent, CCreateC

18、ontext * pContext);HWND CSHLEditorView:Create(HWND hWndParent, CCreateContext * pContext)/ 设置与该视图关联的文档SetDocument(pContext-m_pCurrentDoc);/ 将该视图添加到关联文档的视图列表里pContext-m_pCurrentDoc-AddView(this); return CWindowImpl:Create(hWndParent, NULL, 0, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN

19、| WS_HSCROLL | WS_VSCROLL | ES_AUTOHSCROLL | ES_AUTOVSCROLL | ES_MULTILINE | ES_NOHIDESEL | ES_SAVESEL, WS_EX_CLIENTEDGE, (UINT)0, pContext);void CSHLEditorView:OnFinalMessage(HWND hWnd)m_pDocument-RemoveView(this);return;void CSHLEditorView:OnUpdate(CSHLEditorDocView *pSender, LPARAM Hint, LPVOID p

20、Hint)return;视图类改造完成后,接下来是框架类。先看CChildFrame:LRESULT CChildFrame:OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)LPCREATESTRUCT lpcs = (LPCREATESTRUCT)lParam;LPMDICREATESTRUCT lpms = (LPMDICREATESTRUCT)lpcs-lpCreateParams;CCreateContext * pContext =(CCreateContext *)lpms-lPara

21、m;_ASSERTE(pContext-m_pCurrentView = NULL);pContext-m_pCurrentView = &m_view;m_hWndClient = m_view.Create(m_hWnd, pContext);bHandled = FALSE;return 0;然后再把你的MainFrame改变如下:Class CMainFrame : public CMDIFrameWindowImpl,public CUpdateUI,public CMessageFilter, public CIdleHandler,public CDocManagerpublic

22、:CDocTemplate m_DocTemplate;LRESULT CMainFrame:OnCreate()AddDocTemplate(&m_DocTemplate);return 0;做好了如上改变后,下面我们开始分析一下模型的工作流程。8- 模型的工作流程模型的工作起点通常位于MainFrame的OnFileNew() 消息响应函数中,那里有默认的新建子窗口的过程:CChildFrame* pChild = new CChildFrame;pChild-CreateEx(m_hWndClient);将它们改为:/ 创建一个新文档GetDocTemplate(0)-CreateNew

23、Document();该语句将调用第一个文档模板来创建一个新的文档。我们来看一下该方法:TDoc* CreateNewDocument()TDoc* pDoc = new TDoc;AddDocument(pDoc);TFrame* pFrame = CreateNewFrame(pDoc);if(!pDoc-OnNewDocument()/ 如果创建新文档不成功,则销毁框架窗口pFrame-DestroyWindow();RemoveDocument(pDoc);delete pDoc;return NULL;return pDoc;先创建一个新文档对象,由文档模板把它记录下来,然后创建视图

24、(包括视图依附的子窗口),接着调用该文档对象的OnNewDocument()方法,去完成整个文档的创建并显示出来。如果创建失败了则做一些收尾工作,否则返回新建的文档对象指针。创建视图时调用了CreateNewFrame()方法,我们也来看一下:TFrame* CreateNewFrame(TDoc* pDoc)CCreateContext context;context.m_pCurrentDoc = pDoc;context.m_pNewDocTemplate = this;TFrame:GetWndClassInfo().m_uCommonResourceID = nID;TFrame*

25、pFrame = new TFrame;pFrame-CreateEx(m_hWndClient, NULL, NULL, 0, 0, &context);return pFrame;首先,我们用一个上下文结构记录当前的创建过程保存当前创建的文档及其对应的文档模板。接着将资源ID分配给将要创建的子窗口。然后该上下文结构被传递给子窗口的创建函数。现在回头去看CChildFrame的OnCreate()消息响应函数,前3条语句先取出该上下文结构,再用它保存将要创建的视图于是,该上下文结构便保存了一份完整的“文档-视图”映射关系。接下来它又被传递给视图类CSHLEditView的Create方法,C

26、reate方法依次设置了“视图的关联文档”和“文档的关联视图”,之后再创建CSHLEditView视图并显示出来。至此,一个完整的“文档-视图”模型便建立了起来。9- 实现代码以下是该方案的完整实现代码,你可以将它保存到一个C+头文件中(我给它命名为“Doc-View Model for WTL.h”),然后在你的“stdafx.h”文件中包含它(建议将它置为最后一个包含文件)。#pragma once#defineHINT_UPDATE_ALL_DOCUMENTS-1#defineHINT_DOCUMENT_MODIFIED-2/ 超前声明:所有文档模板的基类class CDocTempla

27、teBase;/ 上下文信息template struct CCreateContextTDoc* m_pCurrentDoc;TView* m_pCurrentView;CDocTemplateBase* m_pNewDocTemplate;CCreateContext() memset(this, 0, sizeof(*this);/ 用于“单文档-多视图”模型的构造函数template CCreateContext(CCreateContext * pContext) m_pCurrentDoc = pContext-m_pCurrentDoc;m_pNewDocTemplate = p

28、Context-m_pNewDocTemplate;/ 所有视图的抽象基类template class CViewBase public:static CViewBase* GetActiveView();/ 返回当前活动的视图,使用时请转换:static_cast(GetActiveView()protected:TUser_Doc*m_pDocument;/ 视图所对应的文档指针static CViewBase* m_pActiveView;/ 指向当前活动视图的指针public:virtual void Update(CViewBase* pSender, LPARAM lHint,LP

29、VOID pHint) = 0;/ lHint与pHint目前没多少用处,留着以后扩展模型用吧TUser_Doc* GetDocument()return m_pDocument;void SetDocument(TUser_Doc* pDoc)m_pDocument = pDoc;/ 更新关联文档模板的所有文档void UpdateAllDocs()CDocTemplateBase* pDocTemplate = m_pDocument-GetDocTemplate();int ndocs = pDocTemplate-GetNumDocs();for(int j = 0; j ndocs;

30、 j+)TUser_Doc *pDoc= static_cast(pDocTemplate-GetDocument(j);if(pDoc)pDoc-UpdateAllViews(this, HINT_UPDATE_ALL_DOCUMENTS);/ 截获窗口激活消息,记录活动视图,你需要在自己的视图类加上CHAIN_MSG_MAP(CView)/ 这里若采用WTL风格的消息映射(BEGIN_MSG_MAP_EX)会导致编译错误,不知何故BEGIN_MSG_MAP(CViewBase)MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus)END_MSG_MAP()LRES

31、ULT OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)HWND hwndOldFocus = (HWND)wParam;m_pActiveView = this;bHandled = FALSE;return 0;template CViewBase* CViewBase:m_pActiveView = NULL;template CViewBase* CViewBase:GetActiveView()return CViewBase:m_pActiveView;/ 视图的基类,请让你的视图类继承它temp

32、late class CView : public TDoc_Viewpublic:virtual void Update(TDoc_View* pSender, LPARAM lHint, LPVOID pHint)TUser_View* pT = static_cast(this);pT-OnUpdate(pSender, lHint, pHint);HWND GetParentFrame()TUser_View* pT = static_cast(this);HWND hWnd = pT-GetParent();while(!(GetWindowLong(hWnd, GWL_EXSTYL

33、E) & WS_EX_MDICHILD)hWnd = :GetParent(hWnd);return hWnd;typedef CView CView1;BEGIN_MSG_MAP(CView1)CHAIN_MSG_MAP(TDoc_View)END_MSG_MAP();/ 所有文档的基类class CDocumentBase;/ 文档类template class CDocument : public CDocumentBasepublic:CDocument()m_bModified = FALSE;void UpdateAllViews(CViewBase * pSender, LPAR

34、AM lHint = 0, LPVOID pHint = NULL)int count = m_aViews.GetSize();for(int i = 0; i count; i+)CViewBase * pView = m_aViewsi;if(pView != (CViewBase *)pSender)pView-Update(pSender, lHint, pHint);CViewBase* AddView(CViewBase* pView)pView-SetDocument(static_cast(this);CViewBase* pV = static_castCViewBase*

35、(pView);m_aViews.Add(pV);return pView;void RemoveView(CViewBase* pView)int count = m_aViews.GetSize();for(int i = 0; i SetDocument(NULL);break;int GetNumViews() constreturn m_aViews.GetSize();CViewBase* GetView(const int pos)_ASSERTE(pos m_aViews.GetSize();return m_aViewspos;BOOL IsModified()return

36、m_bModified;void SetModifiedFlag(BOOL bModified = TRUE)m_bModified = bModified;CDocTemplateBase* GetDocTemplate()return m_pDocTemplate;/ 保存文档,返回NULL表示保存失败,请在你的文档类中实现BOOL OnSaveDocument(LPCTSTR lpszPathName)BOOL SaveDocument()TUser_Doc* pDoc = static_cast(this);if(pDoc-IsModified()/ 文档已被修改CString pat

37、hName;/ sFilter请直接用LPCTSTR类型,如果用CString会丢掉0字符,导致运行不正常LPCTSTR sFilter = _T(文本文件(*.txt)0*.txt0所有文件(*.*)0*.*0);/ 定制保存文件对话框,如果是Win2000/XP,则显示新样式对话框CFileDialog dlgSaveFile(FALSE, _T(txt), NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, sFilter, GetActiveWindow();dlgSaveFile.m_ofn.lStructSize = (GetVersion(

38、) OnSaveDocument(pathName)/ 如果文档未能成功保存MessageBox(NULL, 保存文档失败!, _T(警告), MB_OK | MB_ICONWARNING);return FALSE;pDoc-SetModifiedFlag(FALSE);/ 保存成功,取消修改标志break;else/ 用户取消了文件对话框break;/ for/ ifreturn TRUE;protected:CSimpleArrayCViewBase*m_aViews;BOOLm_bModified;public:CDocTemplateBase*m_pDocTemplate;/ 文档模

39、板的抽象基类class CDocTemplateBasepublic:virtual int GetNumDocs() const = 0;virtual CDocumentBase* Document(int pos) = 0;/ 返回第pos个文档/ 创建一个新文档,返回NULL表示创建失败,在你的文档类中实现BOOL OnNewDocument()virtual CDocumentBase* CreateNewDocument() = 0;/ 打开一个文档,返回NULL表示打开失败,请在你的文档类中实现BOOL OnOpenDocument(LPCTSTR lpszPathName)vi

40、rtual CDocumentBase* OpenDocument(BOOL bMakeVisible = TRUE) = 0;/ 文档模板类template class CDocTemplate : public CDocTemplateBaseprivate:CSimpleArraym_aDocuments;public:HWNDm_hWndClient;CDocTemplate()int ndocs = GetNumDocs();for(int i = 0; i ndocs; i+)delete m_aDocumentsi;m_aDocuments.RemoveAll();TFrame*

41、 CreateNewFrame(TDoc* pDoc)CCreateContext context;context.m_pCurrentDoc = pDoc;context.m_pNewDocTemplate = this;TFrame:GetWndClassInfo().m_uCommonResourceID = nID;TFrame* pFrame = new TFrame;pFrame-CreateEx(m_hWndClient, NULL, NULL, 0, 0, &context);return pFrame;TDoc* CreateNewDocument()TDoc* pDoc =

42、 new TDoc;AddDocument(pDoc);TFrame* pFrame = CreateNewFrame(pDoc);if(!pDoc-OnNewDocument()/ 如果创建新文档不成功,则销毁框架窗口pFrame-DestroyWindow();RemoveDocument(pDoc);delete pDoc;MessageBox(NULL, 创建新文档失败!, _T(警告), MB_OK | MB_ICONWARNING);return NULL;return pDoc;TDoc* OpenDocument(BOOL bMakeVisible = TRUE)TDoc *p

43、Doc = new TDoc;AddDocument(pDoc);LPCTSTR sFilter = _T(文本文件(*.txt)0*.txt0所有文件(*.*)0*.*0);CFileDialog dlgOpenFile(TRUE, _T(txt), NULL, OFN_OVERWRITEPROMPT,sFilter, GetActiveWindow();dlgOpenFile.m_ofn.lStructSize = (GetVersion() OnOpenDocument(pathName)/ 如果文档未能成功打开RemoveDocument(pDoc);delete pDoc;pDoc

44、= NULL;MessageBox(NULL, 打开文档失败!, _T(警告), MB_OK | MB_ICONWARNING);else/ 打开文档后,创建窗口将其显示出来TFrame* pFrame = CreateNewFrame(pDoc);pDoc-UpdateAllViews(NULL);pDoc-SetModifiedFlag(FALSE);break;else/ 用户取消了文件对话框break; / forreturn pDoc;CDocumentBase* Document(int pos)return m_aDocumentspos;virtual void AddDocu

45、ment(TDoc* pDoc)pDoc-m_pDocTemplate = this;m_aDocuments.Add(pDoc);virtual TDoc* RemoveDocument(TDoc* pDoc)int ndocs = GetNumDocs();for(int i = 0; i ndocs; i+)if(m_aDocumentsi = pDoc)m_aDocuments.RemoveAt(i);break;return pDoc;int GetNumDocs() constreturn m_aDocuments.GetSize();/ 文档模板管理器,管理所有的文档模板temp

46、late class CDocManagerpublic:template int AddDocTemplate(TDocTemplate* pDocTemplate)_ASSERTE(pDocTemplate != NULL);pDocTemplate-m_hWndClient = static_cast(this)-m_hWndClient;CDocTemplateBase* pDocBase = static_cast(pDocTemplate);m_aTemplates.Add(pDocBase);return m_aTemplates.GetSize() - 1;int GetNum

47、Templates() constreturn m_aTemplates.GetSize();CDocTemplateBase* GetDocTemplate(const int pos)_ASSERTE(pos m_aTemplates.GetSize();return m_aTemplatespos;protected:CSimpleArray m_aTemplates;10- 后记感谢我的朋友Gabriel Kniznik,他是一个思维缜密的人,帮助我解决了一些技术问题,并鼓励我将文章发表出去,与大家共享知识。插几句题外话,我最近在做“语法高亮显示编辑器”时深刻地体会到WTL确实很精巧而

48、且强大,如Win32编程般贴近底层,又具有MFC的易读性,但是相关文档实在是太少了,很多时候我是参考了MFC库,再放到WTL中看看能否行得通,还好目前WTL提供了大部分MFC拥有的类。我还尝试了在WTL中直接使用MFC库,但是#include编译器会报错。经过多次修改afx.h,现在我可以在WTL中正常使用CFile,CStudioFile,CMemFile等类,这些都是MFC有而WTL没有的。另外我也可以使用MFC版的CString,它比WTL的版本功能要强一些。对WTL与MFC结合有兴趣的朋友可以共同探讨一下。如此结合以后,WTL功能更加完善,辅以STL + Boost库,再加上本文所拓展的“文档-视图”模型,WTL应该可以在绝大部分项目中取代MFC了。第 23 页 共 23 页

展开阅读全文
温馨提示:
1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
2: 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
3.本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
关于我们 - 网站声明 - 网站地图 - 资源地图 - 友情链接 - 网站客服 - 联系我们

copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!