• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            鐵觀音

            C++編程寶典

               ::  ::  ::  ::  :: 管理 ::
              1 隨筆 :: 19 文章 :: 0 評(píng)論 :: 0 Trackbacks
            [ 原創(chuàng)文檔 本文適合中級(jí)讀者 已閱讀n次 ]

            使用VC6.0實(shí)現(xiàn)窗口的任意分割
            南京郵政局計(jì)算機(jī)中心 張中慶

            一、關(guān)于CSplitterWnd類
            我們?cè)谑褂肅uteFtp或者NetAnt等工具的時(shí)候,一般都會(huì)被其復(fù)雜的界面所吸引,在這些界面中窗口被分割為若干的區(qū)域,真正做到了窗口的任意分割。 那么我們自己如何創(chuàng)建類似的界面,也實(shí)現(xiàn)窗口的任意的分割呢 ?在VC6.0中這就需要使用到CSplitterWnd類。CSplitterWnd看上去像是一種特殊的框架窗口,每個(gè)窗口都被相同的或者不同的視圖所填充。當(dāng)窗口被切分后用戶可以使用鼠標(biāo)移動(dòng)切分條來(lái)調(diào)整窗口的相對(duì)尺寸。雖然VC6.0支持從AppWizard中創(chuàng)建分割窗口,但是自動(dòng)加入的分割條總是不能讓我們滿意,因此我們還是通過(guò)手工增加代碼來(lái)熟悉這個(gè)類。
            CSplitterWnd的構(gòu)造函數(shù)主要包括下面三個(gè)。

            BOOL Create(CWnd* pParentWnd,int nMaxRows,int nMaxCols,SIZE sizeMin,CCreateContext* pContext,DWORD dwStyle,UINT nID);
            功能描述:該函數(shù)用來(lái)創(chuàng)建動(dòng)態(tài)切分窗口。 參數(shù)含義:pParentWnd 切分窗口的父框架窗口。 nMaxRows,nMaxCols是創(chuàng)建的最大的列數(shù)和行數(shù)。 sizeMin是窗格的現(xiàn)實(shí)大小。 pContext 大多數(shù)情況下傳給父窗口。 nID是字窗口的ID號(hào).
            BOOL CreateStatic(CWnd* pParentWnd,int nRows,int nCols,DWORD dwStyle,UINT nID) 
            功能描述:用來(lái)創(chuàng)建切分窗口。 參數(shù)含義同上。
            BOOL CreateView (int row,int col,CruntimeClass* pViewClass,SIZE sizeinit,CcreateContext* pContext);
            功能描述:為靜態(tài)切分的窗口的網(wǎng)格填充視圖。在將視圖于切分窗口聯(lián)系在一起的時(shí)候必 須先將切分窗口創(chuàng)建好。
            參數(shù)含義:同上。
            從CSplitterWnd源程序可以看出不管是使用動(dòng)態(tài)創(chuàng)建Create還是使用靜態(tài)創(chuàng)建CreateStatic,在函數(shù)中都調(diào)用了一個(gè)保護(hù)函數(shù)CreateCommon,從下面的CreateCommon函數(shù)中的關(guān)鍵代碼可以看出創(chuàng)建CSplitterWnd的實(shí)質(zhì)是創(chuàng)建了一系列的MDI子窗口。
            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 
                      

            二、創(chuàng)建嵌套分割窗口
            2.1創(chuàng)建動(dòng)態(tài)分割窗口
            動(dòng)態(tài)分割窗口使用Create方法。下面的代碼將創(chuàng)建2x2的窗格。
            m_wndSplitter.Create(this,2,2,CSize(100,100),pContext);

            但是動(dòng)態(tài)創(chuàng)建的分割窗口的窗格數(shù)目不能超過(guò)2x2,而且對(duì)于所有的窗格,都必須共享同一個(gè)視圖,所受的限制也比較多,因此我們不將動(dòng)態(tài)創(chuàng)建作為重點(diǎn)。我們的主要精力放在靜態(tài)分割窗口的創(chuàng)建上。
            2.2創(chuàng)建靜態(tài)分割窗口
            與動(dòng)態(tài)創(chuàng)建相比,靜態(tài)創(chuàng)建的代碼要簡(jiǎn)單許多,而且可以最多創(chuàng)建16x16的窗格。不同的窗格我們可以使用CreateView填充不同的視圖。
            在這里我們將創(chuàng)建CuteFtp的窗口分割。CuteFtp的分割情況如下:
            CCuteFTPView
            CView2
            CView3
            CView4

            創(chuàng)建步驟:
            ▲ 在創(chuàng)建之前我們必須先用AppWizard生成單文檔CuteFTP,生成的視類為 CCuteFTPView.同時(shí)在增加三個(gè)視類或者從視類繼承而來(lái)的派生類CView2,CView3 CView4.
            增加成員:
            在Cmainfrm.h中我們將增加下面的代碼:

            CSplitterWnd wndSplitter1;
                              CSplitterWnd wndSplitter2;
            重載CMainFrame::OnCreateClient()函數(shù):
            BOOL CMainFrame::OnCreateClient( LPCREATESTRUCT  /*lpcs*/, CCreateContext* pContext) 
            { //創(chuàng)建一個(gè)靜態(tài)分欄窗口,分為三行一列 
                 if(m_wndSplitter1.CreateStatic(this,3,1)==NULL) 
                          return FALSE;
              //將CCuteFTPView連接到0行0列窗格上
                 m_wndSplitter1.CreateView(0,0,RUNTIME_CLASS(CCuteFTPView),CSize(100,100), pContext); 
                 m_wndSplitter1.CreateView(2,0,RUNTIME_CLASS(CView4),CSize(100,100),pContext); 
              //將CView4連接到0行2列
                 if(m_wndSplitter2.CreateStatic(&m_wndSplitter,1,2,WS_CHILD|WS_VISIBLE, 
                      m_wndSplitter.IdFromRowCol(1, 0))==NULL) 
                           return FALSE; //將第1行0列再分開(kāi)1行2列 
              //將CView2類連接到第二個(gè)分欄對(duì)象的0行0列
                      m_wndSplitter2.CreateView(0,0,RUNTIME_CLASS(CView2),CSize(400,300),pContext); 
              //將CView3類連接到第二個(gè)分欄對(duì)象的0行1列
                      m_wndSplitter2.CreateView(0,1,RUNTIME_CLASS(CView3),CSize(400,300),pContext); 
                           return TRUE; 
            } 
            2.3實(shí)現(xiàn)各個(gè)分割區(qū)域的通信
            有文檔相連的視圖之間的通信
            由AppWizard生成的CCuteFTPView是與文檔相連的,同時(shí)我們也讓CView2與文檔相連,因此我們需要修改CCuteFTPApp的InitInstance()函數(shù),我們將增加下面的部分。
            AddDocTemplate (new CMultiDocTemplate(IDR_VIEW2TYPE, 
                      
                      RUNTIME_CLASS(CMainDoc), 
                      RUNTIME_CLASS(CMDIChildWnd), 
                      RUNTIME_CLASS(CView2))); 
            我們現(xiàn)在來(lái)實(shí)現(xiàn)CCuteFTPView與CView2之間的通信。由于跟文檔類相連的視圖類 是不能安全的與除文檔類之外的其余的視圖類通信的。因此我們只能讓他們都與文檔 類通信。在文檔中我們?cè)O(shè)置相應(yīng)的指針以用來(lái)獲的各個(gè)視圖。我們重載 CCuteFTPView::OnOpenDocument()函數(shù);
            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; }
            這樣我們?cè)谖臋n類中就獲的了跟它相連的所有的視圖的指針。
            如果需要在 CCuteFTPView中調(diào)用CView2中的一個(gè)方法DoIt()則代碼如下:
            CCuteFTPDoc* pDoc=GetDocument();
            CView2* pView2=pDoc->pView3;
            pView3.DoIt();

            無(wú)文檔視圖與文檔關(guān)聯(lián)視圖之間的通信
            CView3和CView4都是不與文檔相關(guān)聯(lián)的。我們現(xiàn)在實(shí)現(xiàn)CView3與CView2的通信.正如前面所說(shuō),CView2只能安全的與CCuteFTPDoc通信,因此,CView3如果需要跟CView2通信,也必須借助于文檔類。因此程序的關(guān)鍵是如何在CView3中獲得文檔的指針。視圖類中沒(méi)有這樣的類成員可以用來(lái)直接訪問(wèn)文檔類。但是我們知道在主窗口類MainFrame中我們可以獲得程序的任意窗口類的指針。因此我們只要獲得程序主窗口了的指針,就可以解決問(wèn)題了。代碼實(shí)現(xiàn)在CView3中訪問(wèn)CView2中的DoIt()方法。

            CView3中的代碼如下:
            CMainFrame* MainFrame=(CMainFrame*)this->GetParent()->GetParent(); 
                      
                      CCuteFTPDoc* Doc=(CCuteFTPDoc*)MainFrame->GetActiveDocument();
                      if(Doc!=NULL) Doc->DoIt(); 
                      
                      CCuteFTPDoc中的相應(yīng)的處理函數(shù)DoIt()代碼如下: 
                      
                      CView2* pView2; 
                      POSITION pos; 
                      CView* pView; 
                      while(pos!=NULL) 
                      { 
                              pView=GetNextView(pos);
                              if(pView->IsKindOf(RUNTIME_CLASS(CView2))==NULL) 
                              pView2=(CView2*)pView; 
                      } 
                      pView2->DoIt(); 
            無(wú)文檔關(guān)聯(lián)視圖之間的通信
            CView3和CView4都是不跟文檔相連的,如何實(shí)現(xiàn)他們之間的通信呢。 正如我們?cè)谏厦嫠f(shuō)的那樣,由于在主框架中我們可以訪問(wèn)任意的視圖,因此我們的主要任 務(wù)還是在程序中獲得主框架的指針。在CView3中訪問(wèn)CView4中的方法DoIt()。
            CMainFrame* MainFrame=(CMainFrame*)this->GetParent()->GetParent(); 
                      
                      CView4* View4=(CView4*)MainFrame->m_wndSplitter1.GetPane(2,0); 
                      View4->DoIt(); 

            到現(xiàn)在我們已經(jīng)實(shí)現(xiàn)了CuteFTP的主窗口的框架并且能夠?qū)崿F(xiàn)他們之間相互通信的框架。 同樣的我們可以實(shí)現(xiàn)其他的一些流行界面例如NetAnts,F(xiàn)oxmail的分割。

            三、關(guān)于對(duì)話框的分割
            到目前為止,只有基于文檔/視圖的程序才能使用CSplitterWnd,而基于對(duì)話框的應(yīng)用程序卻不支持CSplitterWnd,但是如果我們?cè)诶^承類中重載一些虛擬方法,也能使CSplitterWnd 在對(duì)話框程序中使用。從MFC的源程序WinSplit.cpp中可以看出,為了獲得父窗口的地方程序都調(diào)用了虛擬方法GetParentFrame(),因此如果在對(duì)話框中使用,我們必須將它改為GetParent();因此我們將CSplitterWnd的下面幾個(gè)方法重載。
            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 ); 
            具體實(shí)現(xiàn)如下,實(shí)現(xiàn)中我將給出原有代碼的主要部分以及修改后的代碼以作對(duì)比。
            在cpp文件中加入下面的枚舉類型。
            enum HitTestValue 
            { 
                              noHit = 0,//表示沒(méi)有選中任何對(duì)象
                              vSplitterBox = 1,
                              hSplitterBox = 2,
                              bothSplitterBox = 3,
                              vSplitterBar1 = 101,//代表各個(gè)方向的水平分割條
                              vSplitterBar15 = 115,
                              hSplitterBar1 = 201,//代表垂直方向的各個(gè)分割條
                              hSplitterBar15 = 215,
                              splitterIntersection1 = 301,//代表各個(gè)交叉點(diǎn)
                              splitterIntersection225 = 525
            };
                      
            CWnd* CxSplitterWnd::GetActivePane(int* pRow, int* pCol) { ASSERT_VALID(this); //獲得當(dāng)前的獲得焦點(diǎn)的窗口 //下面注釋粗體的是原有的代碼的主要部分。 // 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; //下面加注釋粗體的是原有代碼的主要部分。 //FrameWnd* pFrameWnd = GetParentFrame(); //ASSERT_VALID(pFrameWnd); //pFrameWnd->SetActiveView((CView*)pPane); pPane->SetFocus();//修改后的語(yǔ)句 } 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_ptTrackOffset.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_rectTracker2.OffsetRect(m_rectLimit.Width()/2, 0); } else { // only hit one bar GetHitRect(ht, m_rectTracker); } //下面加注釋的將從程序中刪去。 //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; //下面粗體的是原程序的語(yǔ)句 //return GetParentFrame()->SendMessage(WM_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; //下面粗體的是源程序的語(yǔ)句 //*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); }
            這樣我們就可以在對(duì)話框中使用CxSplitterWnd類了。

            四、CSplitterWnd的擴(kuò)展
            CSplitterWnd擴(kuò)展話題是很多的,我們可以通過(guò)對(duì)原有方法的覆蓋或者增加新的方法來(lái)擴(kuò)展CSplitterWnd。我們?cè)诖藘H舉兩個(gè)方面的例子。
            4.1鎖定切分條
            當(dāng)用戶創(chuàng)建好分割窗口后,有時(shí)并不希望通過(guò)拖動(dòng)切分條來(lái)調(diào)節(jié)窗口的大小。這時(shí)就必須鎖定切分條。鎖定切分條的最簡(jiǎn)單的方法莫過(guò)于不讓CSplitterWnd來(lái)處理WM_LBUTTONDOWN,WM_MOUSEMOVE,WM_SETCURSOR消息,而是將這些消息交給CWnd窗口進(jìn)行處理,從而屏蔽掉這些消息。拿WM_LBUTTONDOWN處理過(guò)程來(lái)說(shuō)。修改為如下:
            void CXXSplitterWnd::OnLButtonDown(UINT nFlags,CPoint point) 
            { CWnd::OnLButtonDown(nFlags,point); }
            其余的處理方法類似。
            4.2切分條的定制
            由Window自己生成的切分條總是固定的,沒(méi)有任何的變化,我們?cè)谑褂靡恍┸浖热鏏CDSee的時(shí)候卻能發(fā)現(xiàn)它們的切分條卻是和自動(dòng)生成的切分條不一樣的。那么如何定制自己的切分條呢?通過(guò)重載CSplitterWnd的虛方法OnDrawSplitter和OnInvertTracker可以達(dá)到這樣的目的。下面的代碼生成的效果是分割窗口的邊界顏色為紅色,分割條的顏色為綠色.代碼如下:
            void CSplitterWndEx::OnDrawSplitter(CDC *pDC, ESplitType nType, const CRect &rectArg)
            {
                              if(pDC==NULL) 
                              { 
                              RedrawWindow(rectArg,NULL,RDW_INVALIDATE|RDW_NOCHILDREN);
                              return;
                              } 
                              ASSERT_VALID(pDC);
                              CRect rc=rectArg;
                              switch(nType) 
                              { 
                              case splitBorder:
                              //重畫(huà)分割窗口邊界,使之為紅色 
                                      pDC->Draw3dRect(rc,RGB(255,0,0),RGB(255,0,0));
                                      rc.InflateRect(-CX_BORDER,-CY_BORDER); 
                                      pDC->Draw3dRect(rc,RGB(255,0,0),RGB(255,0,0)); 
                      
                                      return; 
                              case splitBox:
                                      pDC->Draw3dRect(rc,RGB(0,0,0),RGB(0,0,0));
                                      rc.InflateRect(-CX_BORDER,-CY_BORDER); 
                                      pDC->Draw3dRect(rc,RGB(0,0,0),RGB(0,0,0));
                                      rc.InflateRect(-CX_BORDER,-CY_BORDER);
                                      pDC->FillSolidRect(rc,RGB(0,0,0)); 
                                      pDC->Draw3dRect(rc,RGB(0,0,0),RGB(0,0,0));
                                      return; 
                              case splitBar: 
                              //重畫(huà)分割條,使之為綠色 
                                      pDC->FillSolidRect(rc,RGB(255,255,255));
                                      rc.InflateRect(-5,-5); 
                                      pDC->Draw3dRect(rc,RGB(255,0,0),RGB(255,0,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(pBrush!=NULL) hOldBrush=(HBRUSH)SelectObject(pDC->m_hDC,pBrush->m_hObject);
                              pDC->PatBlt(rc.left,rc.top,rc.Width(),rc.Height(),BLACKNESS); 
                      
                              if(hOldBrush!=NULL) 
                              SelectObject(pDC->m_hDC,hOldBrush);
                              ReleaseDC(pDC); 
            } 
            同樣我們只要繼承CSplitterWnd中的其余的一些虛擬方法就可以生成具有自己個(gè)性的分割窗口了。

            我的電子信箱:tingya@njpost.com.cn 和tingya@263.net
            地址:南京郵政局計(jì)算機(jī)中心 張中慶
            郵政編碼:210008
            posted on 2006-09-01 09:56 鐵觀音 閱讀(262) 評(píng)論(0)  編輯 收藏 引用 所屬分類: VC界面控件類
            av无码久久久久久不卡网站| 久久久久国产一区二区三区| 一个色综合久久| 亚洲国产成人久久一区WWW| 思思久久99热免费精品6| 久久久午夜精品| 99久久人妻无码精品系列| 2021国产成人精品久久| 久久综合一区二区无码| 久久综合精品国产二区无码| 国产精品美女久久久网AV| 色综合久久夜色精品国产| 97r久久精品国产99国产精| 久久国产成人午夜aⅴ影院 | 久久亚洲欧美国产精品| 成人亚洲欧美久久久久 | 久久精品中文字幕无码绿巨人| 日本福利片国产午夜久久| 国产精品久久久久蜜芽| 99久久国产综合精品网成人影院| 99久久国产精品免费一区二区| 国产精品内射久久久久欢欢| 亚洲香蕉网久久综合影视| 久久影视国产亚洲| 91久久精品视频| 九九久久自然熟的香蕉图片| 国产香蕉久久精品综合网| 91精品国产高清久久久久久国产嫩草 | 国产成人精品久久| 欧美日韩精品久久久久 | 国内精品伊人久久久久av一坑| 久久一区二区三区免费| 99久久精品免费看国产| 精品久久久久久亚洲| 久久婷婷五月综合国产尤物app| 2021国产精品午夜久久| 免费精品国产日韩热久久| 久久亚洲电影| 伊人久久大香线蕉精品不卡| 青春久久| 亚洲精品无码久久千人斩|