Use the VC6.0 to implement the window of the window of Nanjing Post Office, Zhang Zhongqing
1. About the CSPLitterWnd class We generally be attracted by their complex interface when using Cuteftp or Netant, in which the window is split into several regions, and any segmentation of the window is truly segmented. So how do we create a similar interface, and also implement any segmentation of the window? This is required to use the CSPLitterWnd class in VC6.0. CSplitterWnd looks like a special frame window, each window being filled with the same or different views. When the window is split, the user can use the mouse to move the cutlet to adjust the relative dimensions of the window. Although VC6.0 supports the creation of splitting windows from AppWizard, the auto-added split bar can not satisfy us, so we are also familiar with this class by manual increases code. The constructor of CSPLitterWnd mainly includes three below.
Bool Create (CWND * PParentWnd, Int NmaxRows, int Nmaxcols, size sizemin, ccreatecontext * pContext, DWORD DWSTYLE, UINT NID); Function Description: This function is used to create a dynamic split window. Parameter Meaning: Parent Framework Window of PParentWnd Split Window. NmaxRows, NmaxCols is the maximum number of columns and rows of created. SIZEMIN is the real size of the pane. Most of PCONText is passed to the parent window. NID is the ID number of the word window. Bool createStatic (CWND * PParentWnd, int NROWS, INT NCOLS, DWORD DWSTYLE, UINT NID) Function Description: Used to create a split window. Parameter meaning is the same. Bool CreateView (int Row, int COL, CRUNTIMECLASS * PVIEWCLASS, SIZE SIZEINIT, CCREATECONTEXT * PCONTEXT); Function Description: Fill view of the grid for static cutting windows. You must first create a split window when you link the view to the division window. Parameter meanings: From the CSPLitterWnd source program, you can use dynamically created CREATE or use Static CreateStatic, which calls a protective function CreateCommon in the function, which can see the essence of CSPLitterWnd from the critical code from the following CreateCommon function. A series of MDI sub-windows. DWORD dwCreateStyle = dwStyle & ~ (WS_HSCROLL | WS_VSCROLL); if (afxData.bWin4) dwCreateStyle & = ~ WS_BORDER; // create with the same wnd-class as MDI-Frame (no erase bkgnd) if (CreateEx (0, _afxWndMDIFrame! NULL, DWCREATESTYLE, 0, 0, 0, 0, PPARENTWND-> M_HWND, (HMENU) NID, NULL) RETURN FALSE; // Create Invisible
Second, create a nested split window 2.1 Creating a dynamic split window Dynamic split window Using the CREATE method. The following code will create a 2x2 pane. M_Wndsplitter.create (this, 2, 2, csize (100, 100), pcontext);
However, the number of panes that dynamically created will not exceed 2x2, and for all panes, the same view must be shared, and the restrictions are more restrictions, so we do not use dynamic creation as a focus. Our main energy is placed on a static segmentation window. 2.2 Creating a Static Split window Compared to dynamic creation, the code for static creation is simple, and you can create up to the 16x16 pane. Different panes We can use createView to fill different views. Here we will create a window split of Cuteftp. The segmentation of CUTEFTP is as follows: ----------------------- | CcuteftPview | ------------------------------------------------------------------------------------------------------------------ ----- | CView2 | CView3 | ----------------------- | CVIEW4 | -------------------------------------------------------------------------- --------- Creation steps: ▲ We must first generate single document cuteftp with AppWizard before creating, and generate the view class as ccuteftPView. At the same time, add three view classes or derived classes that inherited from view classes CView2, CView3 CView4. ▲ Add member: In CMAINFRM.H we will increase the following code:
CsplitterWnd Wndsplitter1; csplitterwnd Wndsplitter2;
▲ Overload cmainframe :: oncreateclient () function: BOOL CMAINFRAME :: OnCreateClient (lpcreateStruct / * lpcs * /, ccreatecontext * pContext) {
// Create a static column window, divided into three rows of a column IF (M_WndSplitter1.createstatic (this, 3, 1) == null) Return False; // Connect CCUTEFTPVIEW to 0 row 0 column pane on M_Wndsplitter1.createView ( 0,0, Runtime_Class (ccuteftpView), CSIZE (100, 100), PCONText);
// The line 2 is connected to CView4 0 m_wndSplitter1.CreateView (2,0, RUNTIME_CLASS (CView4), CSize (100,100), pContext); if (m_wndSplitter2.CreateStatic (& m_wndSplitter, 1,2, WS_CHILD | WS_VISIBLE, m_wndSplitter.IdFromRowCol (1, 0)) == NULL) Return False; // Reconnect 1 row of 2 lines
// Connect the CView2 class to 0 rows of the second column object M_Wndsplitter2.createView (0, 0, Runtime_Class (CView2), CSIZE (400, 300), PCONText);
// Connect the CView3 class to the 0 row of the second column object, 1 column M_WndSplitter2.createView (0, 1, Runtime_Class (CView3), CSIZE (400, 300), PCONText);
Return True;}
2.3 Communication to implement individual segmentation ■ Communication between the views connected to the document is connected by appwizard, which is connected to the document, and we also let CView2 are connected to the document, so we need to modify the ccuteftpapp's initInstance () function, we will Add the following part. AddDDOCTemplate (iDR_View2Type, Runtime_class (cmaindoc), runtime_class (cmdichildwnd), runtime_class (cView2)); we now implement communication between CcuteFTPVIEW and CVIEW2. Since the view class connected to the document class is unacceptable to communicate with the remaining view class outside the document class. So we can only let them communicate with document class. In the document we set the corresponding pointer to be used by each view. We overloaded CCuteFTPView :: OnOpenDocument () function; CCuteFTPView * pCuteFTPView; CView2 * pView2; POSITION pos; CView * pView; while (! Pos = NULL) {pView = GetNextView (pos); if (pView-> IsKindOf (RUNTIME_CLASS ( CCuteFTPView)) == NULL) pCuteFTPView = (CCuteFTPView *) pView; else (pView-> IsKindOf (RUNTIME_CLASS (CCuteFTPView)) == NULL) pView2 = (CView2 *) pView;} we won it in the document class of the The pointer to all views connected to it. If you need to call a method in CView2 in CCUTEftPVIEW, you are as follows: ccuteftpdoc * pdoc = getDocument (); cView2 * pView2 = pdoc-> pView3; pView3.doot (); ■ No document view and document association view Communication CView3 and CView4 are not associated with documents. We now realize communication with CView3 and CView2. As mentioned earlier, CView2 can only communicate with Ccutefpdoc, so CVIEW3 must also be communicated with CVIEW2, and must also be used by the document class. Therefore, the key to the program is how to obtain a pointer to the document in CVIEW3. There is no such a member in the view class to access the document class directly. But we know that we can get the pointer of any window class of the program in the main window MAINFRAME. Therefore, we can solve the problem as long as we get the pointer of the program main window. The code implements the DOIT () method in CVIEW2 in CView3.
The code in CView3 is as follows: cmainframe * mainframe = (cmainframe *) this-> getParent () -> getParent (); ccuteftpdoc * DOC = (ccuteftpdoc *) mainframe-> getActiveDocument (); if (doc! = Null) DOC- > DOIT (); CCUTEFTPDOC's corresponding processing function DOIT () code is as follows: cView2 * pView2; position pos; cView * pView; while (pOS! = Null) {pView = getNextView (POS); if (pView-> iskindof (Runtime_Class (CView2)) == NULL) PView2 = (cView2 *) PView;} PView2-> DOIT (); ■ Communication CView3 and CView4 between non-document association views are not connected to documents, how to implement them Communication between. As we mentioned above, because we can access any view in the main frame, our main task is still a pointer to the main frame in the program. Access the method DOIT () in CView4 in CVIEW3. CMAINFRAME * mainframe = (cmainframe *) this-> getParent () -> getParent (); cView4 * view4 = (cView4 *) mainframe-> m_wndsplitter1.getpane (2, 0); view4-> doit (); to now we The framework of the main window of CUTEFTP has been implemented and the framework that communicates between them can be implemented. Similarly we can implement other popular interfaces such as Netants, Foxmail split.
Third, the segmentation of the dialog to now, only document / view-based programs can use CSPLitterWnd, while dialog-based applications do not support CSPLitterWnd, but if we overload some virtual methods in inherited classes, CsplitterWnd is used in the dialog box. As can be seen from the MFC source program Winsplit.cpp, the virtual method getParentFrame () is called to get the parent window, so if we use it in the dialog, we must change it to getParent (); therefore we will The following methods of CSplitterWnd are overloaded. virtual void StartTracking (int ht); virtual CWnd * GetActivePane (int * pRow = NULL, int * pCol = NULL); virtual void SetActivePane (int row, int col, CWnd * pWnd = NULL); virtual BOOL OnCommand (WPARAM wParam, LPARAM lParam); virtual BOOL OnNotify (WPARAM wParam, LPARAM lParam, LRESULT * pResult); virtual BOOL OnWndMsg (UINT message, WPARAM wParam, LPARAM lParam, LRESULT * pResult); following specific implementation, implementation will be given of the existing code I The main part and the modified code for comparison. Add the following enumeration type in the CPP file. Enum hittestValue {nohit = 0, // Indicates no object vsplitterbox = 1, hsplitterbox = 2, BothSplitterbox = 3, vsplitterbar1 = 101, // represents horizontal segmentation strips in each direction vsplitterbar15 = 115, hsplitterbar1 = 201, // representative each divided vertical direction hSplitterBar15 = 215, splitterIntersection1 = 301, // Representative respective intersections splitterIntersection225 = 525}; CWnd * CxSplitterWnd :: GetActivePane (int * pRow, int * pCol) {ASSERT_VALID (this); // get the current The window // of the focus is noted below the main part of the original code.
// CWnd * pView = NULL; // CFrameWnd * pFrameWnd = GetParentFrame (); // ASSERT_VALID (pFrameWnd); // pView = pFrameWnd-> GetActiveView (); // if (pView == NULL) // pView = GetFocus (); CWnd * pView = getfocus (); if (pView! = Null&&! Ischildpane (pView, prow, pcol)) PView = null; return pView;} void cxsplitterWnd :: SetActivePane (int Row, Int col, cwnd * PWND) {CWND * PPANE = PWND == NULL? GetPane (Row, Col): PWND; // The following is the main part of the original code.
// FrameWnd * pFrameWnd = GetParentFrame (); // ASSERT_VALID (pFrameWnd); // pFrameWnd-> SetActiveView ((CView *) pPane); pPane-> SetFocus (); // the modified statement} void CxSplitterWnd :: StartTracking (int ht) {ASSERT_VALID (this); if (ht == noHit) return; // GetHitRect will restrict '' '' m_rectLimit '' '' as appropriate GetInsideRect (m_rectLimit); if (ht> splitterIntersection1 && ht = <= splitterIntersection225) {// split two directions (two tracking rectangles) int row = (ht - splitterIntersection1) / 15; int col = (ht - splitterIntersection1)% 15; GetHitRect (row vSplitterBar1, m_rectTracker); int yTrackOffset = m_ptTrack Offset.y; m_bTracking2 = TRUE; GetHitRect (col hSplitterBar1, m_rectTracker2); m_ptTrackOffset.y = yTrackOffset;} else if (ht == bothSplitterBox) {// hit on splitter boxes (for keyboard) GetHitRect (vSplitterBox, m_rectTracker); INT YTRACKOFFSET = m_PTTRACKOFFSET.Y; M_BTRACKING2 = true; gethitRect (hsplitterbox, m_recttracker2); m_pttrackoffset.y = ytrackoffset;
// center it m_recttracker.offsetRect (0, m_rectlimit.height () / 2); m_rectracker2.offsetRect (m_rectlimit.width () / 2, 0);} else {// only Hit One bar gethitRect (ht, m_rectracker); } // The following is deleted from the program.
// CView * pView = (cView *) getActivePane (); // if (pView! = Null && pView-> iskindof (runtime_class (cView))) // {// assert_valid (pView); // cframewnd * pframeWnd = GetParentFrame (); // ASSERT_VALID (pFrameWnd); // pView-> OnActivateFrame (WA_INACTIVE, pFrameWnd); //} // steal focus and capture SetCapture (); SetFocus (); // make sure no updates are pending RedrawWindow ( NULL, NULL, RDW_ALLCHILDREN | RDW_UPDATENOW); // set tracking state and appropriate cursor m_bTracking = TRUE; OnInvertTracker (m_rectTracker); if (m_bTracking2) OnInvertTracker (m_rectTracker2); m_htTrack = ht; SetSplitCursor (ht);} BOOL CxSplitterWnd :: OnCommand (WPARAM WPARAM, LPARAM LPARAM) {IF (CWnd :: OnCommand WPARAM, LPARAM) RETURN TRUE; // The bold below is the original program // return getParentFrame () -> sendM_command, wparam, lparam); return getParent () -> sendMessage (WM_Command, WParam, lparam) } BOOL CXSPLITTERWND:: ONNOTIFY (WPARAM WPARAM, LPARAM LPARAM, LRESULT * PRESULT) {IF (CWnd :: Onnotify (WPARAM, LPARAM, PRESULT)) Return true; // The following bold is the statement of the source program // * PRESULT = getParentFrame () -> SendMessage (wm_notify, wparam, lparam); * PRESULT = getParent () -> SendMessage (wm_notify, wparam, lparam);
return TRUE;} BOOL CxSplitterWnd :: OnWndMsg (UINT message, WPARAM wParam, LPARAM lParam, LRESULT * pResult) {// The code line below is necessary if using CxSplitterWnd in a regular dll // AFX_MANAGE_STATE (AfxGetStaticModuleState ()); return CWnd :: OnWndmsg (Message, WParam, Lparam, PRESULT);} This can use the cxsplitterwnd class in the dialog box. Fourth, CSPLitterWnd's extended CSPLitterWnd extension topic is much, we can extend CSPLitterWnd by overwriting the original method or adding new methods. We only have two examples here. 4.1 Lock Slicicle When the user creates a split window, sometimes it does not want to adjust the size of the window by dragging the cut strip. At this time, you must lock the cutting. The easiest way to lock the cutlets is not too much not to processes WM_LBUTTONDOWN, WM_MOUSEMOVE, WM_SETCURSOR messages, but give these messages to the CWND window to process these messages. Take the WM_LBUTTONDOWN process process. Modifications are as follows: void cxxsplitterWnd :: ONLBUTTONDOWN (UINT NFLAGS, CPOINT POINT) {CWND: ONLBUTTONDOWN (NFLAGS, POINT);} The rest of the processing method is similar. 4.2 Customization of Slices is always fixed by Window's own split, without any changes, we can find their splitters when using some software, such as ACDSEE, but it can discover their splitters but automatically generated splice strips. Different. So how do you customize your own cutings? This is the purpose of this purpose by overloading CSPLitterWnd's imaginary method overdrawsplitter and onNinVertTracker.
The following code generation is the result of the boundary color of the split window is red, the color of the split strip is green. The code is as follows: void csplitterWndex :: OndrawSplitter (CDC * PDC, ESPLITTYPE NTYPE, Const CRect "{ix (pdc == null) {RedrawWindow (rectArg, NULL, RDW_INVALIDATE | RDW_NOCHILDREN); return;} ASSERT_VALID (pDC); CRect rc = rectArg; switch (nType) {case splitBorder: // redraw split window border, so that red pDC-> draw3dRect ( RC, RGB (255, 0), RGB (255, 0)); rc.inflatecture (-cx_border, -cy_border); PDC-> Draw3DRECT (RC, RGB (255, 0, 0), RGB ( 255, 0, 0)); RETURN; Case Splitbox: PDC-> Draw3DRECT (RC, RGB (0, 0), RGB (0, 0, 0)); rc.inflaterect (-cx_border, -cy_border); PDC-> Draw3DRECT (RC, RGB (0, 0), RGB (0, 0, 0)); Rc.inflatecture (-cx_border, -cy_border); PDC-> FillSolidRect (RC, RGB (0, 0)); PDC-> Draw3DRECT (RC, RGB (0, 0), RGB (0, 0, 0)); RETURN; Case Splitbar: // Heavy painting split bars make it green PDC-> FillSolidRect (RC, RGB (255, 255, 255)); rc.inflatecture (-5, -5); PDC-> Draw3DRect (RC RGB (255, 0), RGB (255, 0)); return; default: assert (false);} PDC-> FillsolidRect (RC, RGB (0, 0, 255));
} Void CSplitterWndEx :: OnInvertTracker (CRect & rect) {ASSERT_VALID (this); ASSERT (rect.IsRectEmpty ()!); ASSERT ((GetStyle () & WS_CLIPCHILDREN) == 0); CRect rc = rect; rc.InflateRect (2, 2); CDC * pDC = GetDC (); CBrush * pBrush = CDC :: GetHalftoneBrush (); HBRUSH hOldBrush = NULL;! if hOldBrush (pBrush = NULL) = (HBRUSH) SelectObject (pDC-> m_hDC, pBrush-> m_hObject ); PDC-> PATBLT (rc.wid, rc.top, rc.width (), rc.Height (), blackness; if (Holdbrush! = Null) SelectObject (PDC-> M_HDC, HOLDBRUSH); ReleaseDC (PDC Also, as well as some of the remaining virtual methods in CSPLitterWnd can generate a split window with its own personality.