1. 程式人生 > >MFC視窗的拆分

MFC視窗的拆分

靜態拆分視窗的行列數在拆分視窗被建立時就設定好了,使用者不能更改。但是使用者可以縮放各行各列。一個靜態拆分視窗最多可以包含16行16列。

要找一個使用了靜態拆分視窗的應用程式,只要看一下windows管理器即可。

動態拆分視窗最多可以有兩行兩列,但它們可以相互拆分和合並。Vc就使用了動態拆分視窗使得可以同時編輯源程式檔案的兩個以上不同的部分。

選擇靜態或動態拆分的一個準則是是否希望使用者能夠互動地修改拆分視窗的行列配置。另一個決定因素是計劃在拆分視窗中使用的檢視種類。

在靜態拆分視窗中很容易使用兩個以上不同種類的檢視,因為您可以在每個窗格中指定所用的檢視型別。但是在動態拆分視窗中,MFC管理著檢視,

除非從 CsplitterWnd派生一個新類並修改拆分視窗的預設操作效能,否則拆分視窗中的所有檢視使用的都是相同的檢視類。

靜態拆分視窗是用CsplitterWnd::CreateStatic而不是CsplitterWnd::Create建立,並且由於MFC不會自動建立靜態拆分視窗中顯示的檢視,

所以您要親自在CreateStatic返回之後建立檢視。CsplitterWnd為此提供了名為 CreateView的函式。

你應按如下步驟建立一個CSplitterWnd物件:

       1. 在父框架中嵌入一個CSplitterWnd成員變數。

  2. 過載父框架的CFrameWnd::OnCreateClient成員函式。

  3. 從過載的OnCreateClient函式中呼叫類CSplitterWnd的Create或CreateStatic成員函式,並呼叫CreateView來建立檢視。

使用靜態拆分視窗的一個優點是由於您自己給窗格新增檢視,所以可以控制放入檢視的種類。

關鍵函式

BOOL CreateStatic( CWnd* pParentWnd, int nRows,int nCols, DWORD dwStyle = WS_CHILD | WS_VISIBLE, UINT nID = AFX_IDW_PANE_FIRST );

 函式有5個引數,意義如下:

  ● pParentWnd:切分視窗的父視窗指標

  ● nRows:水平方向分隔視窗的數目

  ● nCols:垂直方向分隔視窗的數目

  ● dwStyle:切分視窗的風格

  ● nID:子視窗的ID值,預設為系統定義的AFX_IDW_PANE_FIRST

  返回值:如果建立成功,返回非零值(TRUE),否則返回0(FALSE)。

     m_wndSplitter.CreateStatic(this, 2,1);// 切分為2行1列

  virtual BOOL CreateView( int row, int col, CRuntimeClass* pViewClass, SIZE sizeInit, CCreateContext* pContext );

  函式有5個引數,意義如下:

  ● row:窗格的行標,從0開始

  ● col:窗格的列標,從0開始

     ● pViewClass:檢視的執行期類CRuntimeClass指標,可以用巨集RUNTIME_CLASS獲得

  ● sizeInit:一個SIZE(或者CSize)型別的資料,指定窗格的初始大小

  ● pContext:一般是由父視窗傳遞過來,包含視窗的建立資訊

  返回值:如果建立成功,返回非零值(TRUE),否則返回0(FALSE)。

      m_wndSplitter.CreateView(0,0,RUNTIME_CLASS(CTest),CSize(190,100),pContext)

      

實現的關鍵程式碼

BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext) 
{
	// TODO: Add your specialized code here and/or call the base class
	if(!m_wndSplitter.CreateStatic(this,1,2))
	{
		return FALSE;
	}

	CRect rect;
	GetClientRect(&rect);
	if(!m_wndSplitter.CreateView(0,0,RUNTIME_CLASS(CTest),CSize(rect.Width()/4,rect.Height()),pContext)||
		!m_wndSplitter.CreateView(0,1,RUNTIME_CLASS(CSplitterSDIView), CSize(rect.Width()/4*3,rect.Height()),pContext))
	{
		return FALSE;
	}
	return TRUE;
}
過載該函式之前需要做的步驟:
1. 在CMainFrame類中新增protected成員CSplitterWnd m_wndSplitter;
2. 建立對話方塊資源(IDD_FORMVIEW),並以CFormView類為基類建立相應的視類;
3. 過載OnCreateClient函式(如上述程式碼)。
4. 如果需要更多的劃分,則再新增其他的CSplitterWnd成員變數,但在m_wndSplitter2.CreateStatic()
   函式裡的第一個引數則採用需要劃分的那個子檢視,如m_wndSplitter2.CreateStatic(&m_wndSplitter1,
   1, 2, WS_CHILD|WS_VISIBLE, m_wndSplitter1.IdFromRowCol(0,0)) ),當然也需要自己建立需要的所
   有檢視。

多視類之間的互動

在MFC程式中,各個視類之間進行資料互動是通過Doc類來完成的,由CDocument類來處理文件,

而由CView類來顯示。即將資料儲存到CDocument類中,而用到資料的時候再從該類中讀取。

處理按鈕事件:
void CTest::OnShowInt() 
{
	// TODO: Add your control notification handler code here
	CSplitterSDIDoc* pDoc =(CSplitterSDIDoc*) GetDocument();
	UpdateData(TRUE);
	pDoc->x=m_int;
	pDoc->UpdateAllViews(NULL);
}
在CSplitterSDIView中顯示:
void CSplitterSDIView::OnDraw(CDC* pDC)
{
	CSplitterSDIDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	// TODO: add draw code for native data here
	CString str;
	str.Format("%d", pDoc->x);
	pDC->TextOut(0,0,str);
}

CSplitterWnd類的其他成員資訊

有關該類的其他成員函式,可以參考MSDN。

其他資訊

鎖定切分條
當用戶建立好分割視窗後,有時並不希望通過拖動切分條來調節視窗的大小。這時就必須鎖定切分條。鎖定切分條的最簡單的 方法莫過於不讓CSplitterWnd來處理WM_LBUTTONDOWN,WM_MOUSEMOVE,WM_SETCURSOR訊息,而是將這些消 息交給CWnd視窗進行處理,從而遮蔽掉這些訊息。拿WM_LBUTTONDOWN處理過程來說。修改為如下: 
void CXXSplitterWnd::OnLButtonDown(UINT nFlags,CPoint point) 
{         CWnd::OnLButtonDown(nFlags,point);} 
其餘的處理方法類似。 
切分條的定製 
由Window自己生成的切分條總是固定的,沒有任何的變化,我們在使用一些軟體比如ACDSee的時候卻能發現它們的切分條 卻是和自動生成的切分條不一樣的。那麼如何定製自己的切分條呢?通過過載CSplitterWnd的虛方法OnDrawSplitter和 OnInvertTracker可以達到這樣的目的。下面的程式碼生成的效果是分割視窗的邊界顏色為紅色,分割條的顏色為綠色.程式碼如下:
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: 
                 //重畫分割視窗邊界,使之為紅色 
                          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:  
                 //重畫分割條,使之為綠色  
                         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中的其餘的一些虛擬方法就可以生成具有自己個性的分割視窗了。

另外參考:

用MFC將SDI視窗三叉拆分並初始化各個View

最近做MFC介面,發現《深入淺出MFC》等很多資料裡只是教我們如何將視窗三叉拆分,但是拆分後每個View類的初始化和設定很少有資料設計,讓我這種初學者鬱悶樂半天。這裡是我自己的總結,十分簡陋……

      我需要三個試圖,一個ListView,一個TreeView和一個EditView。類似於vc6的介面最下方為list,上部分左邊為tree,右邊為edit。首先,建立一個工程PaperInfoCrawler,選擇SDI視窗,並將CPaperInfoCrawer繼承CListview

      在MainFram中加入變數 CSplitterWnd m_wndSplitter和CSplitterWnd m_wndTopSplitter並重載函式virtual BOOL OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext),下面為函式內容{ m_wndSplitter.CreateStatic(this,2,1);
m_wndSplitter.SetRowInfo(0,450,450);
m_wndTopSplitter.CreateStatic(&m_wndSplitter,1,2,WS_CHILD|WS_VISIBLE,m_wndSplitter.IdFromRowCol(0,0));
m_wndTopSplitter.CreateView(0,0,RUNTIME_CLASS(CMyTreeView),CSize(300,0),pContext);
m_wndTopSplitter.CreateView(0,1,RUNTIME_CLASS(CMyEditView),CSize(0,0),pContext);
m_wndSplitter.CreateView(1,0,RUNTIME_CLASS(CPaperInfoCrawerView),CSize(0,0),pContext);
return TRUE;}

      這其中CMyTreeView和CMyEditView是自己繼承的View類,CPaperInfoCrawerView為自動生成的類,此時需要在MainFram.cpp中include相應的標頭檔案。這時候編譯通過應該視窗已經被劃分為三部分了,下面開始對各個View進行初始化。

      MyTreeView.cpp中增加變數 CTreeCtrl* ptheTree過載virtual void OnInitialUpdate()函式內容為{
CTreeView::OnInitialUpdate();
ptheTree=&GetTreeCtrl();
ptheTree->ModifyStyle(0,TVS_HASLINES|TVS_LINESATROOT|TVS_HASBUTTONS|TVS_EDITLABELS);
TVINSERTSTRUCT tvInsert;
HTREEITEM hTreeItem;
tvInsert.hInsertAfter = NULL;//TVI_LAST;
tvInsert.hParent = TVI_ROOT;
tvInsert.item.mask = TVIF_TEXT;
tvInsert.item.pszText = "搜尋引擎";
hTreeItem = ptheTree->InsertItem(&tvInsert);
tvInsert.hParent = hTreeItem;
tvInsert.item.pszText = "Google";
ptheTree->InsertItem(&tvInsert);
tvInsert.item.pszText = "Baidu";
ptheTree->InsertItem(&tvInsert);
ptheTree->Expand(hTreeItem,TVE_EXPAND); //預設為合上的TVE_COLLAPSE,開啟的TVE_EXPAND
}

      PaperInfoCrawler.cpp中增加變數 CListCtrl* ptheList過載virtual void OnInitialUpdate()函式內容為{
CListView::OnInitialUpdate();

ptheList=&GetListCtrl();
ptheList->ModifyStyle(0,LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SORTASCENDING);
ptheList->SendMessage(LVM_SETEXTENDEDLISTVIEWSTYLE,0,LVS_EX_GRIDLINES | LVS_EX_FULLROWSELECT);
ptheList->InsertColumn(0,"標題",LVCFMT_LEFT,200,0);
ptheList->InsertColumn(1,"URL",LVCFMT_LEFT,200,0);
ptheList->InsertColumn(2,"引擎",LVCFMT_LEFT,200,0);
int pos;
pos = ptheList->InsertItem(0,"123");
ptheList->SetItemText(pos,1,"http:\\\\");
ptheList->SetItemText(pos,2,"Google");
}

    編譯通過就可以發現每個視窗都按我們的要求進行了劃分和初始化

//獲取主視窗

CMainFrame* pFrame=static_cast<CMainFrame*>(AfxGetMainWnd());


//獲取某個view

CMyTreeView* pView=static_cast<CMyTreeView*>(pFrame->m_wndTopSplitter.GetPane(0,0));


//啟用View                                                                                                                                                     

pFrame->SetActiveView(pView);                                                                                                                  

pFrame->m_wndTopSplitter.RecalcLayout();


//想幹什麼就幹什麼                                                                                                                                                                 

pView->XXXXXX();
pView->SendMessage(WM_PAINT);

通過以上程式碼我們就可以在各個view間互相通訊了

相關推薦

MFC視窗拆分

靜態拆分視窗的行列數在拆分視窗被建立時就設定好了,使用者不能更改。但是使用者可以縮放各行各列。一個靜態拆分視窗最多可以包含16行16列。 要找一個使用了靜態拆分視窗的應用程式,只要看一下windows管理器即可。 動態拆分視窗最多可以有兩行兩列,但它們可以相互拆分和合

MFC單文件視窗拆分,生成多個窗格

1.生成單文件應用程式,執行結果如下: 2.專案-新增類-MFC(MFC類)新增 注:選擇CFormView基類,類名自定義同理新增CDownView類 3.在框架類(CMainFrame)中新增OnCreateClient訊息,

vs2010、MFC視窗中繪製點、線、面

詳細地記錄了一下在VS2010中建立MFC工程的過程,以及繪製點、線、面功能的實現。因為是教學所用,所以過程記錄的比較繁瑣。主要包含了如何建立在MFC中建立MFC工程、繪製固定座標的圖形、通過滑鼠繪製線段。 一、建立MFC工程  

單文件mfc視窗分割

說明:第一次發表部落格,全當為自己學習做個記錄,將自己的學習新東西和bug整理記錄,方便自己日後的學習。內容有借鑑別人的地方,結尾均附上別人的連結。 1、新建單文件專案,生成如下幾個類 2、在mainFrm。h檔案中新增如下程式碼 CSplitterWnd m_spl

MFC視窗風格 WS_style/WS_EX_style

視窗風格(Window style) WS_BORDER   有邊框視窗 WS_CAPTION   必須和WS_BORDER風格配合,但不能與WS_DLGFRAME風格一起使用。指示視窗包含標題要部分。 WS_CHILD  

MFC視窗位置和大小的獲取

最近在做一個專案,需要控制元件隨對話方塊大小的變化而變化,因此需要準確獲取對話方塊視窗、控制元件的大小和位置。 經過好一番查尋、測試,終於看到了希望。下面是一些獲取視窗位置和大小的函式,示例如下: 1、獲取螢幕解析度 //下邊兩個函式獲取的是顯示螢幕的大小,但不包括工作列等區域 in

VS2010 MFC視窗程式 pugixml讀寫XML

       為了用VC++讀寫XML檔案前後弄了差不多5天了,試過微軟自家的MSXML和libxml2庫,介紹MSXML的相關書籍和CSDN部落格裡的文章基本全是XP時代的MSXML4.dll,WINDOWS 7 system32目錄只有MSXML3.d

MFC視窗之間傳遞資料(結構體)

MFC視窗之間的通訊一般會利用傳送訊息的方式傳遞,那麼具體如何實現呢,程式碼如下: 下面實現的是一個子視窗把訊息傳送到主視窗的示例: 1.訊息傳送視窗部分程式碼: 首先新增自定義訊息; #defi

MFC視窗程式退出訊息的響應

1.MFC三個結束訊息的區別 WM_CLOSE: 在系統選單裡選擇了“關閉”或者點選了視窗右上角的“X”按鈕,你的視窗過程就會收到WM_CLOSE。DefWindowProc對 WM_CLOSE的處理是呼叫DestroyWindow。當然,你可以不讓DefWin

MFC視窗風格 WS_style/WS_EX_style(超詳細)

視窗風格(Window style) WS_BORDER 有邊框視窗 WS_CAPTION 必須和WS_BORDER風格配合,但不能與WS_DLGFRAME風格一起使用。指示視窗包含標題要部分。 WS_CHILD 說明視窗為子視窗,不能應用於彈出式視窗風格(WS_POPUP)。

MFC視窗動態改變其child模態或popup模態

在dialog的虛擬函式 PreSubclassWindow中設定視窗模式 void CMyDlg::PreSubclassWindow() { long lStyle=GetWindowLong(m_hWnd,GWL_STYLE); //獲取風格 if (m_bCh

MFC(2):底層實現視窗MFC視窗建立與訊息對映、windows字符集和嚮導的使用

=====================從底層去實現一個視窗=============== 程式入口是WinMain函式 視窗的建立步驟: -->  設計(WNDCLASS)  -->  註冊(RegisterClass)  -->

MFC視窗的清除過程[轉]

對於vc++初學者來說,總覺得視窗物件的清除過程有些莫名其妙.在程式中看不到對delete的顯式呼叫,這似乎違反了c++中有關初始化和清除的規則.那麼,程式是怎樣取消一個視窗物件? 要消除視窗物件,必須清楚視窗物件的構成.在一個通常的程式中,先建立c++視窗物件,然後由Windows建立實際

如何去除MFC視窗的自動記憶功能 (如去除工具欄,選單欄上次執行程式自動儲存的內容)

BCG登錄檔清除: 第一次在CXXXApp::ExitInstance() 加入CleanState(), 執行一次 接著註釋掉,再在OnInitInstance加入m_bSaveState=FALSE 估計在BCG控制元件要寫登錄檔的時候,它自己的寫入登錄檔函式會判斷m

基於對話方塊的MFC視窗之間值的傳遞

編碼時碰到一個MFC多個對話方塊視窗之間值的傳遞的問題,花了些時間總結一下。問題具體是這樣的: 單擊CWorkerBorrow對話方塊類中的“新增借調“功能按鈕,彈出CMBorrow對話方塊來編輯資訊,然後滑鼠點選CEdit型別的編輯框區域,在CMBorrow對話方塊上彈出

MFC視窗銷燬過程

考慮單視窗情況: 假設自己通過new建立了一個視窗物件pWnd,然後pWnd->Create。則銷燬視窗的呼叫次序: 1.手工呼叫pWnd->DestroyWindow(); 2.DestroyWindow會發送WM_DESTROY; 3.WM_DESTROY對

WPF嵌入MFC視窗

1.新建MFC DLL (1)追加Dialog資源,新增類 (2)新增匯出函式,在匯出函式中啟用顯示Dialog 2.新建WPF程式 (1)新增WindowsFormsHost控制元件 (2)新增Panel控制元件為WindowsFormsHost控制元件的子控制元件 (3

MFC----視窗的縮放及控制元件隨拖動改變大小

當我們想得到一個視窗物件(CWnd的派生物件)指標的控制代碼(HWND)時,最安全的方法是使用GetSafeHwnd()函式,通過下面的例子來看其理由:   CWnd *pwnd = FindWindow(“ExploreWClass”,NULL); //希望找到資源管理器   HWND hwnd = pwn

MFC視窗中畫圖,如何使視窗最小化後圖形不消失

我遇到的問題:在MFC的視窗中畫圖,如何使最小化後圖形不消失?在mfc的視窗中畫圖形,但當這個視窗被遮蔽覆蓋或最小化後,圖就消失了,如何能使視窗還原後圖形依然顯示。解決辦法:新增對WM_PAINT訊息的處理,也就是加上OnPaint函式,把畫圖的程式碼放到這個函式中,這樣就可

MFC 視窗重繪

      系統為什麼不在呼叫Invalidate時傳送WM_PAINT訊息呢?又為什麼非要等應用訊息佇列為空時才傳送WM_PAINT訊息呢?這是因為系統把在視窗中的繪製操作當作一種低優先順序的操作,於是儘可能地推後做。不過這樣也有利於提高繪製的效率:兩個WM_PAINT訊息之間通過InvalidateRec