(3) Contact between documents and views
In the view class, there is a protective data member: cdocument * m_pdocument; It saves all pointers that are displaying the views of the document, and access to these views can be implemented by cdocument's member function GetFirstViewPosition and GetNextView functions.
When the view is created, the view and documentation in the oncreate function have been associated:
INT CView :: OnCreate (LPCReatestruct LPCS)
{
IF (CWnd :: OnCreate (LPCS) == -1)
Return -1;
CcreateContext * pContext = (ccreatecontext *) lpcs-> lpcreateparams;
IF (PContext! = null &&pontext-> m_pcurrentdoc! = null)
{
PCONTEXT-> M_PCurrentDoc-> AddView (this);
Assert (m_pdocument! = Null);
}
Else
{
Trace0 ("Warning: Creating a Pane with no cdocument./n");
}
Return 0;
}
This association is implemented by the AddView function of the document class:
Void CDocument :: AddView (CView * PView)
{
......
m_viewlist.addtail (pVIEW);
PVIEW-> m_pdocument = tris;
OnchangeDViewList ();
}
In this function, first, the document object first adds the added view pointer to its own view chain table, then pointing to the M_PDocument member of the added view.
It is well known that the way documents communicate with the view first calls the UpdateAllViews function of the document, thus calling the view's onupdate function:
Void CDocument :: UpdateAllViews (CView * psenter, lparam lhint, cobject * phint)
// Walk THROUGH ALL VIEWS
{
/ / The view is not empty and the sender cannot be empty.
AskERT (psenter == null ||! M_viewlist.isempty ());
Position POS = getFirstViewPosition ();
While (POS! = null)
{
CView * pView = getNextView (POS);
Ask_VALID (PVIEW);
/ / Do not invoke the sender's onupdate function
IF (PView! = psenter)
PView-> onupdate (psenter, lhint, phint);
}
}
The default implementation in the ONUPDATE function of the view is only the notification view for redrawing:
INVALIDATE (TRUE);
We generally overload some of this update view or other operations, such as updating the scroll range of the view scroll bar.
(4) Connection between frame windows and documents
When the frame window is created, the view is created, the relevant functions are as follows:
INT CFrameWnd :: OnCreate (lpcreateStruct LPCS)
{
CcreateContext * pContext = (ccreatecontext *) lpcs-> lpcreateparams;
Return OncreateHelper (LPCS, PCONTEXT);
}
Int cframeWnd :: OnCreateHelper (lpcreateStruct LPCS, CCReateContext * PContext)
{
IF (CWnd :: OnCreate (LPCS) == -1)
Return -1;
// Create Special Children Firstren First
IF (! OncreateClient (LPCS, PCONTEXT))
{
Trace0 ("Failed to Create Client Pane / View for Frame./N");
Return -1;
}
// Post Message for Initial Message String
Postmessage (WM_SetMESSAGESTRING, AFX_IDS_IDLEMESSAGE);
// Make Sure The Child Windows Have Been Properly Sized
RECALCLAYOUT ();
Return 0; // Create OK
}
Bool cframewnd :: oncreateclient (lpcreatestruct, ccreatecontext * pcontext)
{
// Default Create Client Will Create a View if asked for IT
IF (PContext! = null &&pontext-> m_pnewview! = null)
{
IF (CreateView (PCONTEXT, AFX_IDW_PANE_FIRST) == NULL)
Return False;
}
Return True;
}
CWnd * cframeWnd :: CreateView (ccreateContext * PContext, uint NID)
{
CWND * pView = (cwnd *) PContext-> m_pnewviewclass-> createObject ();
IF (pView == null)
{
Return NULL;
}
Ask_KINDOF (CWND, PVIEW);
IF (! pView-> Create (null, null, afx_ws_default_view,
CRECT (0, 0, 0, 0), THIS, NID, PCONTEXT))
{
Return null; // can't Continue without a view
}
IF (AfxData.bwin4 && (PView-> getExStyle () & ws_ex_cliented))
{
ModifyStyleex (WS_EX_CLIENTEDGE, 0, SWP_FRAMECHANGED);
}
Return PVIEW;
}
The OpenDocumentFile function in the document template has occurred as follows:
InitialUpdateFrame (pframe, pdocument, bmakevisible);
The implementation of this function of the document template is:
Pframe-> InitialUpdateFrame (PDOC, Bmakevisible);
It is actually called the same name function for the frame window:
Void CFrameWnd :: InitialUpdateFrame (cdocument * pdoc, bool bmakevisible)
{
CView * pView = null; if (getActiveView () == NULL)
{
// Take the main view
CWND * PWND = getDescendantWindow (AFX_IDW_PANE_FIRST, TRUE);
IF (PWND! = null && pwnd-> iskindof (runtime_class (cView))))
{
/ / The main view exists and legal, set the current main view as an active view
PVIEW = (CView *) PWND;
SetActiveView (PVIEW, FALSE);
}
}
IF (BMakevisible)
{
SendMessageTodescendants (WM_Initialupdate, 0, 0, True, True);
IF (PView! = NULL)
PView-> OnactivateFrame (Wa_INACTIVE, THIS);
......
ActivateFrame (ncmdshow);
IF (PView! = NULL)
PView-> OnactivateView (True, PView, PView);
}
// Update Frame Counts and Frame Title (May Already Have Been Visible)
IF (PDOC! = NULL)
PDOC-> UPDATEFRAMECUNTS ();
OnUpdateFrameTitle (TRUE);
}
The operation in the above function is mainly used to set the active view with SetActiveView and call the onactivateFrame function of the view. Maintain a protective member in the CFrameWnd class: cView * m_pviewactive;, the setacitveView function is mainly to do it:
Void CFrameWnd :: SetActiveView (CView * PViewNew, Bool Bnotify)
{
CView * pViewold = m_pviewactive;
IF (PVIEWNEW == PVIEWOLD)
Return; // do not re-activate if setActiveView Called More Than ONCE
m_pviewactive = null; // no active for the folloading processing
// deactivate the old one
IF (PViewOLD! = NULL)
PViewold-> OnactivateView (False, PViewNew, PViewOLD);
IF (M_PViewActive! = NULL)
Return; // already set
m_pviewactive = pViewnew;
// Activate
IF (PVIEWNEW! = null && bnotify)
PVIEWNEW-> OnactivateView (True, PViewNew, PViewOLD);
}
CframeWnd has another function returns to this member:
CView * cframeWnd :: getActiveView () const
{
Assert (m_pviewactive == null ||
m_pviewactive-> iskindof (runtime_class (cView)));
Return M_PViewActive;
}
CFrameWnd has a function that can get the current active document, which is indirect through the active view:
CDocument * cframeWnd :: getActiveDocument () {
Assert_Valid (this);
CView * pView = getActiveView ();
IF (PView! = NULL)
Return pView-> getDocument ();
Return NULL;
}
(5) The association between the MDI main window and the sub-window:
When you created in the MDI sub-window, specify the relationship between it and the MDI:
Bool cmdichildwnd :: Create (LPCTSTR LPSZCLASSNAME,
LPCTSTSTSZZWINDOWNAME, DWORD DWSTYLE,
Const Rect & Re, cmdiframeWnd * PParentWnd,
CCReateContext * PCONText)
{
IF (pParentWnd == null)
{
CWND * PMainWnd = AFXGETTHREAD () -> m_pmainwnd;
Assert (PMainWnd! = NULL);
Assert_kindof (cmdiframewnd, pmainwnd);
PParentWnd = (cmdiframewnd *) PMainWnd;
}
......
PparentWnd-> RecalcLayout ();
Createstruct CS;
......
/ / Specify the MDI sub-window to which you belong
cs.hwndparent = pparentWnd-> m_hwnd;
......
cs.lpcreateparams = (lpvoid) PCONText;
IF (! PrecreateWindow (CS))
{
Postncdestroy ();
Return False;
}
MDICREATESTRUCT MCS;
......
MCS.Style = cs.style & ~ (ws_maximize | ws_visible);
MCS.LPARAM = (long) cs.lpcreateparams;
AfxhookWindowCreate (this);
// Send a WM_MDICREATE message, create a MDI sub-window
HWnd hwnd = (hwnd) :: SendMessage (pparentWnd-> m_hwndmdiclient,
WM_MDicReate, 0, (LPARAM) & MCS);
IF (! AFXUNHOOKWINDOWCREATE ())
Postncdestroy (); // Cleanup if Mdicreate Fails Too Soon
......
Return True;
}
When the MDI sub-window is created, the MDI main window can implement the management of sub-windings with its own function, for example, get the current active sub-window is achieved by sending a WM_MDiGetActive message.