In-depth understanding of the text / view structure in the MFC
Li Zeyu Jin Gang Xiong Huan Jiang Army
(Huazhong University of Technology Image Identification and Artificial Intelligence Research Institute)
Visual C 5.0 is favored by the user-friendly and user interface. However, in the current version of the current Microsoft Basic Class. 4. There are approximately 200 classes, thousands of functions, and Microsoft has hidden some technical details so that people have become very difficult in learning MFC.
The AppWizard of the MFC can generate three types of applications: Based on the dialog, single document application (SDI), and multi-document applications (MDI). The structure of the top two is simpler, this article is no longer sentenced. The author intends to start the document / view structure in the MFC, analyze some functions, and resolve some of the common problems in the MDI application process.
(1) Learn about document / view structure
The MFC application model has been a considerable development for many years. There is a period of time, it is just a simple model using the application object and the main window object. In this model, the application's data is maintained in the frame window class in the frame window class in this model, and the data is submitted by the display in the client area of the Frame Window. With the advent of MFC2.0, an application structure is new ---- The MFC document / view structure has appeared. In this configuration, the CFRAMEWND heavy task is delegated to several different classes, and the data storage and display are implemented. In general, applications with document / view structures should consist at least by the following objects:
. The application is a CWINAPP derived object that acts as a container for all applications. The application is allocated all the subprograms to it along the message mapping network. . The frame window is a CFRMewnd derived object. . The document is a cdocument derived object that stores the application's data and supplies this information to the rest of the application. . Windows are CVIEW derived objects, which is aligned with their parent framework window subscriber areas. The window accepts the user's input to the application and displays the associated document data.
Typically, the application data exists in the frame window in the simple model. In document / view, the data is moved into independent data objects called Document. Of course, the document is not necessarily text, and the document is an abstract term for the data set you can use. The user input processing and graphics output functions turn from the frame window. A separate window completely masked the client area of the frame window, which means that even if the programmer directly draws the client area of the frame window, the view still masks the painting and does not have any information on the screen. So the output must pass the view. The frame window is just a view container.
The CDocument class provides support for documentation and archiving and provides applications to control their data. The MDI application can handle multiple types of documents, each type of document with a associated document template object. The document object resides behind the scene and provides information displayed by the view object. The document has at least one associated view. A view can only be associated with a document.
In document / view, the object of object is managed by the document template, which is a CDOCTemplate derived object, establishes and maintains frame windows, documents, and views.
The MFC calls the command handler to respond to events that occur in the application. The priority sent by the command is:
Active View -> Frame Window -> Document -> Applications -> Default WindowsProc
In summary, in document / view, documentation and view are separated, namely: document is used to save data, while the view is used to display this data. Document templates maintain Kansai between them. This document / view structure is particularly useful when developing large software items.
(2) Learn about the relationship between various classes related to the document / view structure.
In the document / depending application, the CWINAPP object has and controls the document template, the latter generates documents, frame windows, and windows. This interrelation is shown in Figure (1): From the user's point of view, "view" is actually a normal window. Like other Widnows applications, people can change its size, move it, or close it at any time. If viewed from a programmer, it is actually an object that is generated from the CVIEW class from the MFC class library. Document objects are used to save data, while the viewing object is used to display data, and allow data to be edited. The document class for SDI or MDI is derived from the CDocument class, which can have one or more view classes, and these viewing classes are ultimately derived from the CView class. Applications only one document object associated with it, the CView :: getDocument function it contains allows the application to be associated with the document in the view, accordingly, the application can perform document class member functions and public data members. access. If the view object accepts a message, it means that the user enters new data in editing control. At this time, the document object must be notified to perform corresponding updates to its internal data.
If the document data changes, all views must be notified so that they can be updated accordingly. This feature can be done by cdocument :: updateAllViews function. When the function is called, the CView :: onupdate function of the derived view class is triggered. Typically onupdate functions To access documents, read document data, and then update the data member or control to reflect the changes in documents. In addition, you can use the onupdate function to make the partial client area of the view to trigger the CView :: overdraw function, and use document data to re-draw the window.
In the MDI application, you can handle multiple document types, multiple document templates, each template, and multiple documents, each document can be displayed. For management, the last level often retains the next level of pointer list. as shown in picture 2:
Explain as follows:
(1), each application class (CWINAPP derived class) is retained and maintained a pointer list of all document templates, which is a linked table structure. The application dynamically assigns a cmultidoctemplate object for each document type to be supported.
CMULTIDOCTEMPLATE (Uint NidResource,
Cruntimeclass * pdocclass,
Cruntimeclass * pframeclass,
CruntimeClass * pViewClass;
And passed each CMULTIDEMPLATE object to CWINAPP :: addDoCtemplate in the application class CWINAPP :: InitInstance member function. This function adds a document template to the application available in the document template. The function is:
Void AddDDOCTemplate (CDOCTemplate * Ptemplate);
The application can use CWINAPP :: GetFirstDoCTemPstion to get the location of the first document template for the application, use this value to call the CWINAPP :: GetNextDocTemplate function, get the first CDOCTemplate object pointer. The function is as follows:
Position getfirstdoctemplate () const;
CDOCTemplate * GetNextDocTemplate (Position & Pos) Const;
The second function returns a document template identified by the POS. Position is an MFC defined value for iteration or object pointer retrieval. Through these two functions, the application can traverse the entire document template list. If the retrieved document template is the last one in the template list, the POS parameter is set to NULL. (2), a document template can have multiple documents, each of which retains and maintains a pointer list of all corresponding documents. The application can use the CDOCTemplate :: getFirstDocposition function to get the location of the first document in the document collection associated with the document template, and use the position value as the parameters of CDOCTemplate :: GetNextDoc to repeat the list of documents related to the template. The function is:
VIAUAL POSITION GETFIRSTDOCPSITION () Const = 0;
Visual CDocument * getNextdoc (Position & RPOS) const = 0;
If the list is empty, the RPOS is set to NULL.
(3) In the document, you can call CDocument :: getDocTemplate to get pointers to this document template. The function is as follows:
CDOCTEMPLATE * GETDOCTEMPLATE () Const;
If the document does not belong to the document template management, the return value is NULL.
(4), one document can have multiple views. Each document retains and maintains a list of all relevant views. CDocument :: AddView The view is connected to the document, and the view is added to the list of documents, and the document pointer will point to this document. When there is file / new, file / open, windows / new or window / split commands to connect a newly created object to the document, the MFC will automatically call the function, the framework will document through the document / depending structure. And look up. Of course, programmers can call this function according to their needs.
Virtual position getfirstviewPosition () const;
Virtual cviw * getnextview (position & rposition) COSNT;
The application can call CDocument :: getFirstViewPosition Returns the location of the first view in the list of views connected to the document, and calls cdocument :: getNextView to return to the specified location, and place the rpositon's value as the next one. The position value of the view. If the last looks found in the list, RPSITION is set to NULL.
The MFC calls the ONCHANGEVIEWLIST function when a view is added or deleted on the document. If the deleted view is the last look of the document, the document is deleted.
(5) A document can be available. In the view, call CView :: getDocument to get a pointer to a document that points to a view. The function is as follows:
CDocument * getDocument () const;
Returns NULL if the view is not in any document.
(6), the MDI frame window can get the CDocument pointer connected to the current activity by calling CFrameWnd :: getActiveDocument. The function is as follows:
Virtual cdocument * getActiveDocument ();
(7), by calling CFrameWnd :: getActiveView, you can get a pointer to the activity view connected to the CFRAMEWND Framework window. If it is called by the CMDIFrameWnd Framework window, return NULL. The MDI Framework window can first call MDiGetActive to find the MDI sub-window of the active MDI and find the activity of the sub-window. The function is as follows: virtual cdocument * getActiveDocument ();
(8), the MDI frame window can get a pointer to the MDI Frame Window window by calling CFrameWnd :: GetActiveFrame.
(9), cmdichildwnd calls GetMDIFrame to get the MDI frame window (CMDIFrameWnd).
(10) CWINAPP calls AFXGETMAINWND to get the pointer to the active main window to the application.
The following segment is to use CDOCTemplate, CDocument, and CVIEW to traverse the entire document template, documentation, and viewing.
CMYAPP * PMYAPP = (CMYAPP *) AFXGetApp ();
Position P = PMYAPP-> getFirstDoCtemplatePosition ();
while (! p = NULL) {CDocTemplate * pDocTemplate = pMyApp-> GetNextDocTemplate (p); POSITION p1 = pDocTemplate-> GetFirstDocPosition (); while (! p1 = NULL) {CDocument * pDocument = pDocTemplate-> GetNextDoc (p1); POSITION P2 = pDocument-> getfirstviewPosition (); while (p2! = Null) {cView * pView = pDocument-> getnextview (p2);}}}
(Figure 4), traversing the entire document template, documentation and view
Anywhere in the application, the programmer can call AFXGetApp () to get the object pointer to the application. Since this paper focuses on documentation / depending on the relationship, the relationship between the frame window is not fully, the reader can check the corresponding document.
(3) Understanding CWINAP :: OnFileNew, CWINAPP: ONFILEOPEN and Window / New program flow. (1), cwinapp :: onfilenew and cwinapp :: onfileopen functions simple processes.
In the cwinapp :: onfile / new or cwinapp :: onfileopen function, the core operation is the cdoctemplate :: OpenDocument function. Its function prototype is:
Virtual cdocument * cdoctemplate :: OpenDocumentFile (lpctstr lpszpathname, bool bmakevisible = true) = 0;
Figure (4) The flow of the function is the process of the function, and the brief introduction is as follows:
(1), the cdoctemplate :: CreateNewDocument function creates a new document, which is related to the document template, and joins the document pointer list of the document template through the function cdocument :: AddDocument. At this point, the constructor of the document class is executed, and the program can be initialized here.
(2), the function cdockplate :: CreateNewFrame Calls the constructor of the MDI sub-window class (cmdichildwnd) to generate the MDI sub-window object. Then call cmdichildwnd :: PrecreateWindow. Then, generate a ccreateContext object (CCReateContext is a structure used by the MFC framework, which links components constituting the document and the viewing.), Will be described in detail.) And pass the object value to the cmdichildwnd :: oncreateclient function . MFC calls this function, creates one or more CVIEW objects with the information provided by the CCReateContext object. At this time, the constructor of each view is sequentially called. (3), then, it is judged whether or not the LPSZPATHNAME is empty. Divided into two cases:
(a) If it is empty, it indicates that you want to create a new document: call the SetDefaultTITLE function to load the default title of the document, and display it in the title bar of the document; then execute cdocument :: OnNewDocument. This function calls DeleteContents to ensure that the document is empty, then set up a new document to clean. This function can be overloaded.
(b), otherwise, indicate that you want to open an existing document: call cdocument :: onopendocument Open the specified file; execute DeleteContext, ensure that the document is empty; call CObject :: serialize to read the contents of the file. (The programmer can perform file read operations here. Of course, you can also read files in cdocument :: onoPendocument). Then set the document to clean; finally, call CDOCTemplate :: SetPathName and add the file name to the list of recent files.
(4) Call the CDOCTemplate :: InitialUpdateFrame function, enable the ONInitialUpdate calls in the frame window. The main view of the frame window (the sub-window ID is equal to the view of AFX_IDW_Pane_First) is activated. Programmers can initialize the objects here.
(2) The program process of the window / new command
When there is a sub-window on the main frame window, select the window / new command to generate the image of the active sub-window. They have the same document template, the same document. The process is as follows:
The process of executing Window / New is similar to file / new process. Different, File / New requires a new document, and Window / New is a document that got existing MDI sub-windows. Therefore, the views of the previously existing viewing and NEW will be viewed in this document, which are displayed in the contents of the document. When calling the cDocument :: UpdateAllViews function, they (depending on) onupdate functions will be activated. At this point, in the field of view of the document, more than one view (the specific number is determined by the number of times the number of times the window execution) is performed. The reader can use the code tracking program in FIG. 3).
(4) Discussion on several situations
Abu, the author analyzes the relationship between document / depending on the MFC, here, the author will discuss the specific situation:
(1) How to choose a document template according to your own requirements, and the appropriate views and documents.
In the usual MDI application, there is only one document template, and the programmer can only open a type of document. Therefore, programmers can call File / New or File / Open to create or open documents, as for the relationship between documents, view, and frame windows, the document template is controlled behind the scenes, and does not need to operate the document template. However, if the application needs to handle multiple types of documents, and when to open what documentation requires programmers to manually control, at this time, the programmer must program the document template. For example, the author needs to process two file types of AVI and BMP. The data storage format of AVI and BMP is different, and the same data structure cannot be used, so it is not appropriate to store their data into one document. At the same time, since AVI is an image sequence, BMP is only an image, and their display is definitely different, that is, it is different. Based on this, the author decided to establish two sets of document templates, two sets of frame windows, two sets of documents, and two sets of views, respectively, and data storage and display of AVI and BMP. The program can process AVI and BMP according to the file name selected by the user. Specific steps are as follows:
(Step 1) Increase the document template member variable in the derived class of the application class (CWINAPP) to operate the document template.
Class C3dlcsapp: Public CWINAPP
{. . . . . .
PUBLIC:
CMULTIDEMPLATE * M_PAVIDOCTEMPLATE;
CMULTIDEMPLATE * M_PBMPDOCTEMPLATE;
}
(Step 2), add menu response in the main frame:
Void CMAINFRAME :: onfileopen () {
CFiledialog My (TRUE);
IF (my.domodal () == idok) {
CSTRING FILENAME = my.getpathname (); cstring fileext = my.getfileext ();
IF ((FileExt == "AVI") || (FileExt == "Avi")) {
CMYAPP * PMYAPP = (CMYAPP *) AFXGetApp (); cmultidoCtemplate * pavidoCtemplate = PMYAPP-> m_PavidOcTemplate; pavidOctemplate-> OpenDocumentFile (filename);
}
Else IF ((FileExt == "BMP") || (FileExt == "BMP")) {
CMYAPP * p3dlcsapp = (cmyapp *) AFXGetApp ();
CMULTIDEMPLATE * PDATDOCTEMPLATE = PMYAPP-> m_pbmpdoctemplate;
PDATDOCTEMPLATE-> OpenDocumentFile (filename);
}
Else {
AFXMessageBox ("Yor SELECT A File Not Supported!");
Return;
}
}
}
The author enters the subscript of the user as a branch condition. If it is an AVI file, you will get the document template for the AVI file, then call the cdoctemplate :: OpenUpdateFrame (lpszfilename) function Open this document. As previously analyzed, this function will generate a new document, a new framework, create a view in CmdichildWnd :: OnCreateClient, and finally send initialization messages in all the views in the frame to display it on the screen. If it is a BMP file, the operation is similar. Of course, programmers can also implement this operation anywhere in the program: Application object pointer is obtained through the full-class function AFXGetApp, thereby obtaining the corresponding document template pointer. Since the application generated by AppWizard will default CWINAPP :: ONFileNew, a new empty window is displayed on the main frame when the program begins to execute. If you want to remove this empty window, you only need to overrupt the cwinapp :: ONFileNew function, you can't want any code, you can. (2) Splitting window and document / view structure
A document can have multiple views, and the cut window is a method representing more than a view. The cut window is expressed by class csplitterwnd. For Window, the CSPLitterWnd object is a real window that fully occupies the customer area of the frame window, and the window occupies the window area of the cutoff window. Separation windows do not participate in the command transfer mechanism, (in the window) The window is logically connected directly to its frame window.
Separation windows can be divided into dynamics and static. The former is more simple, this article only discusses the latter. The steps to create a cut window are as follows:
(Step 1), declare a member variable in its own frame window to operate on the division window.
Class CMYFRAME: PUBLIC CMDICHILDWND
{. . . . . .
CsplitterWnd M_Splitter;
CsplitterWnd M_Splitter2;
}
(Step 2), overload the cmdichildwnd :: OnCreateClient function, create a split window.
Bool CMYFRAME :: OnCreateClient (lpcreateStruct LPCS, CCReateContext * PContext)
{
Bool btn = m_splitter.createstatic (this, 1, 2);
BTN | = m_splitter.createView (0,0, runtime_class (cavidispView), CSIZE (100, 100), PCONText);
m_splitter2.createstatic (& M_Splitter,
twenty one,
WS_CHILD | WS_VISIBLE | WS_BORDER, m_Splitter.IdFromRowCol (0, 1)); btn | = m_Splitter2.CreateView (0, 0, RUNTIME_CLASS (CBMPView), CSize (100,100), pContext); btn | = m_Splitter2.CreateView (1, 0 , Runtime_Class (CaviView), CSIZE (100, 100), PCONText); Return BTN; // Return CmdichildWnd :: OnCreateClient (LPCS, PCONTEXT);
The CFRAMEWND :: OnCreateClient function is:
Virtual Bool OncreateClient (LpCreateStruct LPCS, CCReateContext * PCONTEXT); The default cmdichildwnd :: oncreateclient function Calls the cframewnd :: createView function to create a view based on the information provided by the PCONText parameter. This function can be overloaded, load the value passed in the CCReateContext object, or change the creation of the control over the frame window. In the above program, the author created three cutting windows. For example, open a document called "a.avi", this document will have three views, a frame window. If a Window / New action is executed, there is a document, 6 views and 2 frames window. If the document calls the cDocument :: updateAllViews function, the 6 view of the cView :: onupdate function is excited.
(3) About CCREATECONTEXT discussions.
CCREATECONTEXT is a structure used by the MFC framework that connects components that make up document / view. This structure includes pointers, frame windows, view, and document templates to documents, which also contain pointers to CRUNTIMECLASS to indicate the type of view created. Its data is as follows:
M_PNewViewClass: Points to create a CRUNTIMECLASS that creates the context.
m_pcurrentdoc: Points to the pointer to the document object to connect with the new view.
M_PNewDOCTemplate: Points to the Create Document Template with the Frame Window.
m_plastview: Points to existing trends, which is a new model.
m_pcurrentframe: Points the existing frame window, which is a model of the newly generated frame window.
Programmers can create more flexible views by changing the value of the CCReateContext object. Since the process is more complicated, the author is no longer a narrative, readers can refer to the related Visual C Help documentation.
(5), conclude
The document / view structure of Visual C 5.0 represents a new programming method, and its core is the separation of documentation and viewing, that is, data storage and display (operation). In the MFC class library, the relationship between the individual objects is complicated, but as long as it is in-depth understanding, it will find that they are interconnected and can be accessed. If you want to design a flexible and robust app, you must know in-depth understanding of the MFC. Tracking the original code is a better way. The relationship between documents / depending on the document is indeed, if you can know where each function is tuned, what kind of operation has been performed, you can visit a beautiful application, write a beautiful application.