In-depth analysis of MFC document view structure (project practice)
K_eckel: http://www.mscenter.edu.cn/blog/k_eckel
Document View Architecture is the essence of the MFC, and one of the specific implementation frameworks of the OBServer mode, and Document / View Architecture provides a good data hierarchical and expression level decoupling by separating data and its representation However, although we can easily get a MFC program framework that supports Document / View Architecture, the complexity of Document / View Architecture itself, plus a series of code generated by VC enough to make us dazzling, in the cloud fog Can not be self-extricted. In addition, we have not learned the learning and development of MFC Programming through the learning and experience of Windows SDK Programming, but also a pile of code.
Document / View Architecture,
Hou Jie
Mr.'s "in-depth and shallow MFC" book has indeed been analyzed and studied. There are also many further articles on the basis of Mr. Houjie, but personal feelings have a little defect (only k_eckel " : Too much in-depth, these analysis and research will eventually be positioned to the window of Windows SDK, the complex unordered macro provided by Document / View Architecture support in the MFC, etc. For learners without Windows SDK Programming experience and experience And the learners who are not very familiar with MFC are not very annoying, one is more complicated in a very complicated issue. My point is that this process is necessary, but it is not necessary for everyone, or not everyone must study in early study and most of the project development. I have always been a lot to learn to drag my points, I think I will have MFC (
Hou Jie
Mr. has a photo of this group in the book in "deep-in-depth MFC", here is not to be sure, but I still think that light level learning cost is important, easy to get started, easy to accept is a technology success or valuable A great decisive factor. Therefore, it is necessary to provide a lightweight learning process that is necessary for learning. This series follows such a concept, and analyzes the Document / View Architecture in the MFC (you can also call it deep), try to Will be the theoretical research of Document / View Architecture (
Hou Jie
Many of the books in the book) and the actual project development combine, and finally provide a simple but comprehensive Document / View Architecture project development (mainly interface frame design and development) for reference.
1 Essential Basics Overview
1.1 MFC Document View Structure Program Structure Total
When we use the MFC AppWizard to generate an MFC program, choose all the default settings (of course, Multiple Documents, this article is based primarily based on Multiple Documents, for SINGLE Document, only simple representation, many similarities the latter and the former But the former is more complicated and is more common.), Suppose your program name is A, you will get CMAINFRAME, CCHildFrame, Caboutdlg, Cadoc, Caview, CaApp 6 classes (Single Document only one cchildframe class, the rest) with). The specific meaning of these classes will be given later, here to first give a MFC support document view structural program (hereinafter referred to as app) main components: u An app (corresponding class CAAPP) can include multiple document template, But MFC AppWizard (whether SDI or MDI) is just a default. But in actual development, a document template is not enough, you need to add yourself (exemplified by the later actual project example). This structure is implemented by CDOCManager * m_pdocmanager in the MFC CWINAPP, and our CAAPP is inheriting the CWINAPP class provided from the MFC.
u CDOCManager class has a pointer chain table cptrlist m_templatelist to maintain these document templates. These document templates are in CaApp :: InitInstance () through AddDDOCTemplate (PDOCTemplate).
u CDOCTemplate has 3 member variables, which holds Document, View, Frame's CRUNTIMECLASS pointer, and hold member variables m_nidResource, which is used to specify the menu resource used when this document is displayed. These 4 data are specified in the constructor of CDOCTemplate in CaApp :: InitInstance (). Have a pointer (m_pdoctemplate) that refers to CDOCTemplate in Document.
u One document can have multiple views, maintained by member variables in Document Cptrlist M_ViewList.
u cframeWnd has a member variable CView * m_pactiveView points to the current active view.
u CVIEW has a member variable cDocument * m_pdocument pointing to the Document related to the view.
[Note]: 1mfc SDI / MDI program By default, a document template is generated by default, and this document template add to its document template's list, because this is the MFC default, this document template will be inserted into the document template The first position, and the MFC is also determined by the specific location of this document template. By default, this document template will be enabled when we click File (Open) / File (New).
In addition to Mr. Houjie in "In-depth analysis of the above-in-depth MFC, we should also (largely more important) to master the following information about MFC SDI / MDI:
u Documentation Essent: Document is used to save data and process information about data, and a document is opened whenever the MFC SDI / MDI response file (open) / file (new) is opened. Documents can have multiple views. The relationship between documents and views can be understood: The document is an object that is viewed by the view. u View Essential: View in Windows is a window, which is a visual rectangular area. The view is used to represent the data of the document. However, each view must be attached to a frame (MAINFRAME, MDI is ChildFrame). Of course you can go to create a view yourself and to display it.
u Frame The nature: The frame is actually also a Windows window. But on the frame, you can place the menu, toolbar, and status bar, etc. The view is placed on the client area of the frame. Therefore, the window we see in the MFC actually works together with the Frame and View.
u At a moment, there is only one active document, framework, and view, namely the current document, frame, view.
1.2 Interpuna between MFC SDI / MDI
The most used in the actual project development is interviews between various classes. He has made a summary in the network and books on the network, and the author is used in actual development.
Access Object Access Location Access Implement Application App An any location 1 AFXGetApp (); 2 In the file you want to use: Extern CaApp THEAPP, then use the global THEAPP variable. Main frame window 1AFXGETMAINWND (); 2afxgetApp () -> m_pmainwnd; view frame class getActiveView (); // GetFirstViewPosition () in // Current Activity ViewPosition (); // You can get all view getNextView (); document document class GetDocument (); GetFirstDocPosition (); // This document template corresponds to all documents getNextDoc (); frame class getActiveDocument (); // Current Active Writing Sub-frame class (MDI) Main framework class 1mdiGetActive ();
2GetActiveFrame (); view class getParentFrame (); Document template document class GetDoCtemplate (); getFirstDoCtemplatePosition (); getNextDoCtemplate ();
Description: 1) The above given the method, the following simple processing may also be performed in the actual access, such as type conversion, loop traversal, etc.
2) There may be no interviews in all possible locations, but can be obtained through their combination.
2 Documents, view, and framework
The core in the MFC SDI / MDI is the association between the document, the view, and the framework, forming an organic operational whole. The MFC provides a default association relationship, but it is often necessary to dynamically perform the association between the actual project development.
2.1 Association between documents and views
Using the MFC AppWizard claiming the MFC SDI / MDI program, there is a code in the initInstance () method of the App class (assuming the Project name is TEST):
U SDI
CSingleDocTemplate * pDocTemplate; pDocTemplate = new CSingleDocTemplate (IDR_MAINFRAME, RUNTIME_CLASS (CTestDoc), RUNTIME_CLASS (CMainFrame), // main SDI frame window RUNTIME_CLASS (CTestView)); AddDocTemplate (pDocTemplate); u MDI in
CMultiDocTemplate * pDocTemplate; pDocTemplate = new CMultiDocTemplate (IDR_TESTTYPE, RUNTIME_CLASS (CTestDoc), RUNTIME_CLASS (CChildFrame), // custom MDI child frame RUNTIME_CLASS (CTestView)); AddDocTemplate (pDocTemplate);
Here, the text is associated with the constructor of CDOCTemplate (CSINGLECTEMPLATE in SDI), the text, the view, and the frame (in SDI, in the SDI, in the MDI, in the MDI, and the self-frame) are formed, and one is formed.
Manual implementation of literals
In the actual project development, only the literal and views generated by MFC AppWizard are not enough, so we need to master this association manual. The association of manual literal and view can have the following two implementations:
l Imitation MFC AppWizard implementation, use cdoctemplate constructor: on the above
In the analysis we can see constructor through CDOCTemplate (CSINGEDEDEMPLATE in SDI). We can get the association of documents, view, and frameworks for the CMULTIDEMPLATE in MDI. It can therefore be associated by simulating this manner. The specific implementation method is as follows:
1) Create a new document, view, and framework, the method is to use the Insert MFC Class in the VC.
achieve. Note that the framework class selects cmdichildWnd as the base class, the document class selects cDocument as the base class, and the view class can select CView or its subclasses or the like as the base class as needed.
2) Add menu resources for the framework, add new vegetables to the VC resource window MENU menu
Single, of course, the default menu can be modified by copying the VC.
3) Add the following similar code in the initInstance () of the App class:
CMultiDocTemplate * m_pDocTemplate; m_pDocTemplate = new CMultiDocTemplate (IDR_TESTTYPE, // read your new menu resource ID RUNTIME_CLASS (CTestDoc), // read your new document class RUNTIME_CLASS (CChildFrame), // read your new frame class RUNTIME_CLASS (CTestView)); / / Change to your newly built view category adddddhemplate (m_pdoctemplate); 4) In order to record this document template, you can add a cmultidEcTemplate in the App class *
Type variables to maintain this document template.
l The above gives the document, view, and framework, but the constructor is given.
Sometimes we don't want to create a new document template, we just want to provide different results showing the same data, or add a new view to the same document and provide a switch between them. I have given such an implementation in the article "Single document multi-view implementation of VC project development". Another possibility is that we are not a program supported by a document view structure, and you want to add a document to the view, better business logic and a separation of the representation. So we give the second view and document association: We use the CCReateContext class to do the association between them, the specific implementation is:
m_panotherview = new canotherview (); // New a new view, can be changed to your newly built view
/ / Get a existing document, you can be your new document
CDocument * m_pdoc = ((cframewnd *) m_pmainwnd) -> getActiveDocument ();
// Document and View Association
CcreateContext context;
CONTEXT.M_PCURRENTDOC = M_PDOC;
// Create a view
Uint m_idforanotherview = afx_idw_pane_first 1; // Create a view of the ID number, you can set it yourself
CRECT RECT;
M_Panotherview-> Create (Null, Null, WS_CHILD, RECT, M_PMAINWND, M_IDFORANOTHERVIEW, & Context);
l When the framework and view are associated, see the frame and view associated part.
2.2 Association of framework and view
In the first partial analysis, we know that the framework and view are actually a Windows window, but the framework provides resources such as menus, title bar, status bar, while the view is just a rectangular area. The views in the MFC program determine that most of the time is attached to a framework (the sub-frame window in the SDI in the MAINFRAME and MDI), which can be understood that the framework is equivalent to a window container (of course it is also a Windows window), and the view It is exactly the content of the customer area placed within the frame.
The association of the frame and view can also be implemented by imitation MFC AppWizard, using CDOCTemplate constructor implementation, that is, the same relationship between documents and views in 2.1, this is no longer given here, see the detailed implementation of the above.
With the above analysis, we don't need a new document template in many times, we just need to display a new window (MDI program), for example, when we manage the MIS system interface, the frequent situation is user Click on a menu option to pop up a handling window. To display a new window, we can open a document implementation by the method I have in the "VC Multi-Document User Interface Design" (by cdoCTemplate's openDocumentfile () method to create a set of documents, view And the framework system. The above has been analyzed, we see a combination of the MFC's window, we do not have to provide the entire system of documents, views, frameworks, we only need the combination of frames and views to display the display. This is to be achieved by two steps: the first step is associated with the view and framework, the second step shows the frame (that is, a Windows window display). The specific implementation of the frame and view is given below: cchildframe * pfrm = new cchildframe (); // Framework can be your newly created or custom frame class
CcreateContext context;
Context.m_pnewviewclass = runtime_class (cdemoview); // View can be a view you want to display
PFRM-> LoadFrame (idR_test2type, ws_child | ws_overlappedwindow, this, & context); // Menu resources you can modify
PFRM-> showwindow (sw_show); // Display Window
PFRM-> InitialUpdateFrame (NULL, TRUE); // Call the view of the onInitialUpdate () and framework of the framework (), you can set the title of the window here
Of course, you can add the links and documents here, the specific implementation is to add the following code:
CONTEXT.M_PCURRENTDOC = m_pdoc; // m_pdoc is the document object you want to associate
3 code instance
This section will be used as an example in design and development of an universal MDI project interface, and the above analysis is attached.
3.1 Scenario Description
A common interface logic is: User opens a system, displaying basic menus, used for users' login, logout, and user management (of course, this can also be implemented by a user login dialog). When the user logs in correctly, the functional operation interface of the system will pop up a handling operation interface (not a dialog) when the user clicks on a menu item (corresponding to one or more business logic). Each functional operating interface can be coordinated within a framework, which maximizes, minimizes or off.
3.2 Code Implementation
Next, the above mentioned scenarios will be given a detailed implementation of the techniques mentioned above.
Step 1: Create a new MFC project, named Demo, choose not to support the Document / View Architecture support (second step to remove the default checkbox). This system generates 5 classes for you by default: CDemoApp, CMAINFRAME, CCHILDFRAME, CABOUTDLG, CDEMOVIEW. The meaning of each class has been analyzed, not Luo Wei. In addition, the system also provides two default menus: IDR_DEMOTYPE and IDR_MAINFRAME, the "file" of idR_mainframe is named "Start" (it seems to be more professional, there is nothing, it is Demo), then this menu item The submenu is changed to "Login", "Logout", and use the default child and change the ID number of the first two to: "id_login" and "id_logout". Copy (CTRL C) Paste (CTRL V), get a menu resource named IDR_MAINFRAME1, delete the original IDR_DEMOTYPE menu (note first saved name), and then change the name of IDR_MAINFRAME1 to IDR_Demotype. Add a menu item "Feature" for IDR_Demotype, add two submenu items "Business Logic One" and "Business Logic II", ID number: ID_FUNC_ONE and ID_FUNC_TWO. Step 2: Add two variables to cdemoApp, save menu resources:
HMENU M_HOPMENU;
HMENU M_HINITMENU;
And add code to Bool CDemoApp :: InitInstance ():
m_hinitmenu = :: loadmenu (hinst, makeintresource (idR_mainframe);
m_hopmenu = :: loadmenu (hinst, makeintresource (idr_demotype);
To display the effect, add the code in Bool CDemoApp :: InitInstance ():
Pframe-> setWindowText ("Wuhan University Computer College - Not Logged in");
m_ncmdshow = sw_showmaximized;
Pframe-> showwindow (m_ncmdshow); //
Pframe-> UpdateWindow ();
Add a response function for the menu item "Log in" (using class wizard, select CDemoApp)
Void CDemoApp :: ONLogin ()
{
// Todo: add your command handler code here
SetMenu (AFXGetApp () -> m_pmainwnd-> m_hwnd, m_hopmenu);
AFXGetApp () -> m_pmainwnd-> setWindowText ("Wuhan University Computer College - Logged in");
}
In the sameby, add a response function for the menu item "Logout":
Void cdemoApp :: ONLOGOUT ()
{
// Todo: add your command handler code here
IF ((cmainframe *) AFXGETMAINWND ()) -> m_pfunconeframe! = null)
(CMAINFRAME *) AFXGETMAINWND ()) -> m_pfunconeframe-> sendMessage (wm_close); if ((cMAINFRAME *) AFXGETMAINWND ()) -> m_pfunctwoframe! = NULL)
((CMAINFRAME *) AFXGETMAINWND ()) -> m_pfunctwoframe-> sendMessage (WM_CLOSE);
SetMenu (AFXGetApp () -> m_pmainwnd-> m_hwnd, m_hinitmenu);
AFXGetApp () -> m_pmainwnd-> setWindowText ("Wuhan University Computer College - Not Logged in");
}
This enables the function of login and logout (of course, there may be a dialog box that verifies user permissions and legitimacy, here is omitted), and the transition of the user's operation menu is implemented. Note: The front two lines of code in ONLOGOUT are to be added, and the definitions and functions of m_pfunconeframe and m_pfunctWoframe are defined later when logging out. See later definitions.
Step 3: Add a new sub-frame class CDemOFrame whose base class is cmdichildwnd. Add a two new view class CFunconeView and CFUNCTWOVIEW class, the former base class is CVIEW, the latter is CFormView. Of course, in order to add a CFUNCTWOVIEW class, you need to be insert a dialog resource, and change the ID to IDD_FUNC_TWO_DLG, the property style is modified to "Child" (default is Popup). This is selected when new CFUNCTWOVIEW is created is IDD_FUNC_TWO_DLG. Note Change CDemOFrame's constructor to public (default is protected).
STEP 4: Add two member variables to CMAINFRAME to record the window corresponding to each business logic, add: Add:
CDemoFrame * m_pfunconeframe;
CDemoframe * m_pfunctwoframe;
And in CMAINFRAME :: CMAINFRAME ():
CMAINFRAME :: CMAINFRAME ()
{
// Todo: Add Member Initialization Code Here
m_pfunconeframe = NULL;
m_pfunctwoframe = null;
}
Step 5: Add a response function for "Business Logic One": CMIANFRAME:
Void CMAINFRAME :: onfuncone ()
{
// Todo: add your command handler code here
IF (m_pfunconeframe! = NULL)
{
m_pfunconeframe-> mdiactivate ();
Return;
}
m_pfunconeframe = new cdemoframe ();
CcreateContext context;
Context.m_pnewviewclass = runtime_class (cfunconeView);
M_pfunconeframe-> loadingframe (idR_mainframe, ws_maximize | ws_overlappedwindow, this, & context);
m_pfunconeframe-> setWindowText ("Business Logic One");
M_pfunconeframe-> showwindow (sw_showmaximized); m_pfunconeframe-> initialupdateframe (null, true);
}
Also, add a response function for "Business Logic 2":
Void cmainframe :: onfunctwo ()
{
// Todo: add your command handler code here
IF (m_pfunctwoframe! = null)
{
m_pfunctwoframe-> mdiactivate ();
Return;
}
m_pfunctwoframe = new cdemoframe ();
CcreateContext context;
Context.m_pnewviewclass = runtime_class (cfunctWoView);
M_pfunctWoframe-> LoadFrame (idR_mainframe, ws_maximize | ws_overlappedwindow, this, & context);
m_pfunctwoframe-> setWindowText ("Business Logic 2");
m_pfunctwoframe-> showwindow (sw_showmaximized);
m_pfunctWoframe-> InitialUpdateFrame (null, true);
}
In this way, the above-mentioned demand scenarios are basically done, but it needs to be described:
1) The appropriate header file needs to be added in the appropriate place, that is, the header file that is to include the header of INCLUDE.
2) The above is actually a common interface operation template for MIS management system. You can make corresponding modifications in actual project development (mainly to achieve corresponding business logic, etc.);
3) The default main frame window provided here is relatively simple (default). To add a background, please refer to the author's "VC-Main Framework window drawing background" Add a suitable background;
4) In the above example, it is to generate the MFC Document / View Architecture, if there is already a default program that supports the MFC Document / View Architecture, simulate the implementation above the above.
5) The above can use the CchildFrame class generated by the MFC AppWizard instead of the CDemOframe class, but it is recommended to create a new framework class, business logic one, and business logic 2 can use different framework classes to imitate implementation.
Of course, you can need to add a document to the view to achieve the loose coupling of business logic and performance layers, and add document view structure support for CFUNCONEVIEW.
STEP 6: Add a document class CDEMODOC, base class as cdecument, change CDEMODOC's constructor to public (default to protected), to demonstrate, add functions to CDEMODOC GetData ():
CString cdemodoc :: getData ()
{
Return "Hello World";
}
Step 7: Add a function for the CFunconeView: GetDocument:
CDEMODOC * cfunconeview :: getDocument ()
{
Return (CDEMOC *) m_pdocument;
}
And modify the onDraw function:
Void cfunconeview :: OnDraw (CDC * PDC) {
// cdocument * pdoc = getDocument ();
// Todo: Add Draw Code Here
CDEMODOC * PDOC = getDocument ();
PDC-> Textout (50, 50, pdoc-> getdata ());
}
Step 8: Associate CDEMODOC and CFUNCTWOVIEW: Modify Void CMAINFRAME :: onfuncone () function is:
Void CMAINFRAME :: onfuncone ()
{
// Todo: add your command handler code here
IF (m_pfunconeframe! = NULL)
{
m_pfunconeframe-> mdiactivate ();
Return;
}
m_pfunconeframe = new cdemoframe ();
CDEMODOC * m_pdoc = new cdemodoc ();
CcreateContext context;
Context.m_pnewviewclass = runtime_class (cfunconeView);
CONTEXT.M_PCURRENTDOC = M_PDOC;
M_pfunconeframe-> loadingframe (idR_mainframe, ws_maximize | ws_overlappedwindow, this, & context);
m_pfunconeframe-> setWindowText ("Business Logic One");
m_pfunconeframe-> showwindow (sw_showmaximized);
m_pfunconeframe-> initialUpdateframe (null, true);
}
At this point, the entire process is completed. It should be noted:
1) The appropriate header file needs to be added in the appropriate place, that is, the header file that is to include the header of INCLUDE.
2) If it is a program that already has a document view support, the above documentation can use the documentation provided in the system;
The above is provided with a simple and universal interface operation, you can refer to implementation, such as adding more views, implementing your business logic, etc.
3) This article provides the entire code for implementation, please refer to.