1. Relationship between templates, documents, views, and frameworks
Serialization 1 ~ 5. We have explained documents, document templates, views, and framework categories individually. serialization 1 has emphasized that these classes have close internal relationships. Conclusion 1 ~ 5. We can summarize the contact information as follows:
(1) The document retains the View list of the document and the pointer to the document template that created the document. The document has at least one associated view, and the view can only be associated with one document.
(2) The view retains the pointer to its document and is contained in its parent frame window;
(3) The document Framework Window (I .e. the MDI child window containing the view) retains the pointer pointing to its current active view;
(4) The document template retains the list of open documents and maintains the ing of framework windows, documents, and views;
(5) The application retains the list of its document templates.
We can use a group of functions to make these classes accessible to each other. Table 6-1 lists these functions.
Table 6-1 mutual access between documents, document templates, views, and framework classes
From this object |
How to access other objects |
Global Functions |
Call the global function afxgetapp to obtain the cwinapp application class pointer. |
Application |
Afxgetapp ()-> m_pmainwnd is the frame window pointer; Use cwinapp: getfirstdoctemplatepostion, cwinapp: getnextdoctemplate to traverse all document templates |
Document |
Call cdocument: getfirstviewposition, cdocument: getnextview to traverse all views associated with the document. Call cdocument: getdoctemplate to obtain the document template pointer. |
Document Template |
Call cdoctemplate: getfirstdocposition, cdoctemplate: getnextdoc to traverse all corresponding documents |
View |
Call cview: getdocument to obtain the corresponding document pointer. Call cview: getparentframe to obtain the Framework Window. |
Document Framework Window |
Call cframewnd: getactiveview to obtain the pointer to the current active view. Call cframewnd: getactivedocument to obtain the document pointer appended to the current view. |
MDI frame window |
Call cmdiframewnd: mdigetactive to obtain the MDI subwindow (cmdichildwnd) of the current activity) |
Let's take an example to describe how to use the functions in the above table and write a piece of code to traverse the document templates, documents, and views:
Cmyapp * pmyapp = (cmyapp *) afxgetapp (); // get the application pointer Position P = pmyapp-> getfirstdoctemplateposition (); // get 1st document templates While (P! = NULL) // traverse the Document Template { Cdoctemplate * pdoctemplate = pmyapp-> getnextdoctemplate (P ); Position p1 = pdoctemplate-> getfirstdocposition (); // obtain the 1st documents corresponding to the document template. While (P1! = NULL) // traverse the document corresponding to the Document Template { Cdocument * pdocument = pdoctemplate-> getnextdoc (P1 ); Position P2 = pdocument-> getfirstviewposition (); // obtain the 1st views corresponding to the document. While (P2! = NULL) // traverse the view corresponding to the document { Cview * pview = pdocument-> getnextview (P2 ); } } } |
It can be seen that the following management relationships and implementation approaches are completely similar:
(1) apply to document templates;
(2) The document template is for the document;
(3) view the document.
Figure 6.1 and 6.2 respectively show the composition of a Multi-document/view framework MFC program and the hierarchy of the classes contained in the program.
Figure 6.1 composition of the Multi-document/view framework MFC Program |
Figure 6.2 hierarchical relationship between document/view Framework Program classes |
The relationship between documents and views can be further divided into three types:
(1) Documents correspond to multiple identical view objects, each of which is in a separate MDI document Framework Window;
(2) The document corresponds to multiple view objects of the same class, however, these view objects are in the same document Framework Window (through the "Split Window", the view space of a single document window is split into multiple separate document views );
(3) Documents correspond to multiple view objects of different classes. These view objects are only in a single MDI document Framework Window. In this model, multiple views constructed by different classes share a single frame window. Each view provides different ways to view the same document. For example, one view displays documents in word processing mode, and the other view displays documents in "document structure" mode.
Figure 6.3 shows the interface features of the corresponding three document and view relationship applications.
Figure 6.3 relationship between documents and views |
2. Message Flow Mechanism
In the MFC program based on the "document/View" architecture, user messages (mouse, keyboard input, etc.) are first sent to the view. If the view is not processed, the message is sent to the Framework Window. Therefore, message ing should be defined in the view. In addition, if an application has multiple views at the same time and the current active view does not process messages, the messages will be sent to the Framework Window.
Next let's take a look at the example. We use the Visual C ++ Wizard to create a single-document/View-based MFC program and add a menu item "Custom" (ID: idm_self, 6.4 ).
Figure 6.4 single document/view architecture MFC program with "Custom" menu |
We add message ing for the "Custom" menu in the View class and framework window class respectively. The Code is as follows:
// Message ing and processing functions in the view Begin_message_map (cexampleview, cview) // {Afx_msg_map (cexampleview) On_command (idm_self, onself) //} Afx_msg_map End_message_map () Void cexampleview: onself () { // Todo: add your command handler code here Afxmessagebox ("Message Processing in view "); }// Message ing and processing functions in the Framework Window Begin_message_map (cmainframe, cframewnd) // {Afx_msg_map (cmainframe) On_command (idm_self, onself) //} Afx_msg_map End_message_map () Void cmainframe: onself () { // Todo: add your command handler code here Afxmessagebox ("Message Processing in Framework Window "); } |
In this case, click the "Custom" menu. the dialog box that appears displays "Message Processing in view". If we delete the message ing in the framework window, click the "Custom" menu, the displayed dialog box also displays "Message Processing in view". However, if we delete the message ing in the view, "Message Processing in Framework Window" is displayed "! This verifies the correctness of our discussion on the message processing sequence.
To thoroughly understand the message flow process, you also need to carefully analyze the source code of the cframewnd: onjavasmsg, cview: onjavasmsg function:
Bool cframewnd: on1_msg (uint NID, int ncode, void * pextra, Afx_cmdhandlerinfo * phandlerinfo) { // Pump through current view first Cview * pview = getactiveview (); If (pview! = NULL & pview-> on1_msg (NID, ncode, pextra, phandlerinfo )) Return true;// Then pump through frame If (cwnd: on1_msg (NID, ncode, pextra, phandlerinfo )) Return true; // Last but not least, pump through app Cwinapp * PAPP = afxgetapp (); If (PAPP! = NULL & PAPP-> on1_msg (NID, ncode, pextra, phandlerinfo )) Return true; Return false; } Bool cview: on1_msg (uint NID, int ncode, void * pextra, afx_cmdhandlerinfo * phandlerinfo) { // First pump through pane If (cwnd: on1_msg (NID, ncode, pextra, phandlerinfo )) Return true; // Then pump through document Bool bhandled = false; If (m_pdocument! = NULL) { // Special State for saving view before routing to document _ Afx_thread_state * pthreadstate = afxgetthreadstate (); Cview * poldroutingview = pthreadstate-> m_proutingview; Pthreadstate-> m_proutingview = this; Bhandled = m_pdocument-> on1_msg (NID, ncode, pextra, phandlerinfo ); Pthreadstate-> m_proutingview = poldroutingview; } Return bhandled; } |
By analyzing the source code, we can see that the actual flow sequence of the wm_command message is much more complex than the "first view, then Framework Window" described above. Both the document and application are involved in the message processing process. If we add message ing and processing functions for documents and applications:
// Message ing and processing functions of the document Begin_message_map (cexampledoc, cdocument) // {Afx_msg_map (cexampledoc) On_command (idm_self, onself) //} Afx_msg_map End_message_map ()Void cexampledoc: onself () { // Todo: add your command handler code here Afxmessagebox ("Message Processing in document "); } // Message ing and processing functions of the application Begin_message_map (cexampleapp, cwinapp) // {Afx_msg_map (cexampleapp) On_command (idm_self, onself) //} Afx_msg_map End_message_map () Void cexampleapp: onself () { // Todo: add your command handler code here Afxmessagebox ("Message Processing in application "); } |
Unmask the message ing between the view and framework window, click the "Custom" menu, and a dialog box is displayed, showing "Message Processing in the document". Then, the message ing in the document is blocked, the displayed dialog box shows "Message Processing in application "! It can be seen that the complete processing order of wm_command messages is "View-document-Framework Window-application "!
In fact, message flow of MFC is a complicated issue. We cannot give a more detailed introduction to it due to space limitations. Readers can find relevant information on their own.