用過WPS2000的朋友,肯定對其文件切換功能有很深的印象。當打開多個文件時,他可以使我們快速的切換到指定的文件。本文將詳細地說明如何在自己的MDI程序中加入這樣一個標簽。 圖一是本文例子程序運行畫面。
圖一 例子程序運行畫面
開始之前,我們先對WPS2000中的文件切換標簽做簡單分析,這是一個Tab標簽,該標簽具有以下功能:
1、當鼠標移到Tab標簽上時,對應的文字將變為藍色;
2、新建或打開一個文件時,Tab標簽會以文件標題為標簽文本自動加入一項;
3、切換Tab標簽時,對應的文件窗口會跟著切換;
4、當我們激活不同的文件窗口時,Tab標簽會自動切換;
5、關閉一個文件窗口時,Tab標簽中對應的項會自動消失。
在本文的例子中,除實現上述功能外,還作如下修改:
1、增加雙擊Tab標簽時最大化、恢復子窗口功能;
2、修改Tab標簽為按鈕風格。
具體思路:
在MDI程序中加入一個包含Tab標簽的對話框條,並加入類CViewManager,該類用一個指針數組存放所有打開子窗口的視指針,用一個字符串數組存放文檔標題。在視類的初始化函數OnInitUpdate() 裡取得視指針及文檔標題,存放到CViewManager的數組中,並在Tab標簽中加入一項。在視類的析構函數裡從Tab標簽和CViewManager的數組中刪除對應的項。切換Tab標簽時,取得對應子窗口的指針,並以該指針為參數調用CMDIFrameWnd::MDIActivate()激活這個子窗口。下面請看具體的實現步驟:
一、在VC6.0中,用向導創建一個MDI工程TabMDIDemo。在向導各步中均采用默認項
二、為工程加入Tab標簽對話框條
1、在工作區的ResourceView中加入一個對話框模板IDD_TAB_DLG_BAR,按如下設置:
Style: Child
Border: Thin
去掉標題條和系統菜單選項;
字體:宋體,字號:10
在模板中加入一個Tab標簽控件IDC_TAB,按如下設置:
選中按鈕選項。//這使的Tab標簽呈現按鈕風格
選中Hot Track選項。//這使得鼠標移上時文字變藍
仔細調整對話框條及Tab控件的位置、尺寸。創建主框架時,將以該模板創建出Tab標簽對話框條。
2、利用類向導加入類CMyTab,派生於CTabCtrl。
3、利用類向導為類CMyTab添加TCN_SELCHANGE通知消息映射函數,實現文件切換,編輯如下:
void CMyTab::OnSelchange(NMHDR* pNMHDR, LRESULT* pResult)
{
// TODO: Add your control notification handler code here
int idx = GetCurSel();
TC_ITEM ti;
ti.mask = TCIF_PARAM;
GetItem(idx, &ti);
CView * pView = (CView *) ti.lParam;
((CMDIFrameWnd *)AfxGetMainWnd())->MDIActivate((pView->GetParent())->GetParent());
*pResult = 0;
*pResult = 0;
}
4、利用類向導為類CMyTab添加WM_LBUTTONDBLCLK消息映射函數,實現雙擊時最大化或恢復子窗口,編輯如下:
void CMyTab::OnLButtonDblClk(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
int idx = GetCurSel();
TC_ITEM ti;
ti.mask = TCIF_PARAM;
GetItem(idx, &ti);
CView * pView = (CView *) ti.lParam;
((CMDIFrameWnd *)AfxGetMainWnd())->MDIActivate((pView->GetParent())->GetParent());
// maximize or restore MDIChild window based on its current state
BOOL bMaximize=FALSE;
CWnd* pActiveWnd=((CMDIFrameWnd *)AfxGetMainWnd())->MDIGetActive(&bMaximize);
if(bMaximize)
((CMDIFrameWnd *)AfxGetMainWnd())->MDIRestore(pActiveWnd);
else
((CMDIFrameWnd *)AfxGetMainWnd())->MDIMaximize(pActiveWnd);
}
5、在MainFrm.h中加入:#include "MyTab.h"
6、為主框架類CMainFrame加入如下成員變量:
protected:
CDialogBar m_wndTabBar;
public:
CMyTab m_MyTab;
7、在菜單資源"查看"中加入菜單項"文件切換",ID值為ID_VIEW_TAB_BAR。在MainFrm.cpp中消息映射部分加入以下兩行:
ON_COMMAND_EX(ID_VIEW_TAB_BAR, OnBarCheck)
ON_UPDATE_COMMAND_UI(ID_VIEW_TAB_BAR, OnUpdateControlBarMenu)
8、在CMainFrame::OnCreate()加入以下代碼:
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
//向導生成代碼略去
//創建TAB條
if (!m_wndTabBar.Create(this, IDD_TAB_DLG_BAR,
CBRS_TOP | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_HIDE_INPLACE,
ID_VIEW_TAB_BAR)) //ID_VIEW_TAB_BAR是菜單命令ID,用於顯示或隱藏對話框條
{
TRACE0("Failed to create dialog bar m_wndDialogbar\n");
return -1; // fail to create
}
//m_wndTabBar.EnableDocking(CBRS_ALIGN_LEFT | CBRS_ALIGN_RIGHT);
//EnableDocking(CBRS_ALIGN_ANY);
//DockControlBar(&m_wndTabBar);
//將m_MyTab與控件IDC_TAB綁定
m_MyTab.SubclassDlgItem(IDC_TAB, &m_wndTabBar);
return 0;
}
9、為類CMainFrame添加WM_SIZE消息映射函數,如下:
void CMainFrame::OnSize(UINT nType, int cx, int cy)
{
CMDIFrameWnd::OnSize(nType, cx, cy);
// TODO: Add your message handler code here
CRect rcClient;
GetClientRect(&rcClient);
int left,top,right,bottom;
left=rcClient.left;
top=rcClient.top;
right=rcClient.right;
bottom=rcClient.bottom;
m_wndTabBar.MoveWindow(left,top+24,right-left,24,TRUE);
CRect rcTab;
m_wndTabBar.GetClientRect(&rcTab);
CTabCtrl *pMyTab=(CTabCtrl *)(m_wndTabBar.GetDlgItem(IDC_TAB));
pMyTab->MoveWindow(rcTab,TRUE);
}
三、手工創建類CViewManager
新建兩個文件ViewManager.h、ViewManager.cpp ,並添加到當前工程。類的源碼參見本文所附例子。下面對其成員作簡單說明:
OnActivateView(); //當一個視被激活時,該函數被調用,刷新Tab控件
GetWindowNum(); //返回打開的子窗口數
RemoveAll(); //清空數組arViews、arViewTitles
RemoveView(); //用於在數組及Tab控件中刪除一項
AddView(); //用於在數組及Tab控件中加入一項
CViewManager(); //構造函數
~CViewManager(); //析構函數,清空數組arViews、arViewTitles
CPtrArray arViews; //用來存放子窗口的視指針
CstringArray arViewTitles; //用來存放文檔標題
bool bClosing; //用於表示程序是否正在關閉
四、實現文件切換。
1、在MainFrm.h文件加入:#include "ViewManager.h"
2、為類CMainFrame加入公有成員變量: public:
CViewManager m_ViewManager;
3、在視類TabMDIDemoView.cpp文件中加入:#include "MainFrm.h"
4、重載視類的OnInitialUpdate()函數,編輯如下:
void CTabMDIDemoView::OnInitialUpdate()
{
CView::OnInitialUpdate();
//取得文檔標題及視指針並加入到視管理器數組及tab控件中
CMDIDialogbarDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
CString cs=pDoc->GetTitle();
((CMainFrame*)AfxGetMainWnd())->m_ViewManager.AddView(cs,this);
}
5、在視類的析構函數中加入以下代碼:
CTabMDIDemoView::~CTabMDIDemoView()
{
((CMainFrame*)AfxGetMainWnd())->m_ViewManager.RemoveView(this);
}
6、重載視類的OnActivateView()函數,編輯如下:
void CTabMDIDemoView::OnActivateView(BOOL bActivate,
CView* pActivateView,
CView* pDeactiveView)
{
// TODO: Add your specialized code here and/or call the base class
((CMainFrame*)AfxGetMainWnd())->m_ViewManager.OnActivateView(bActivate, this);
CView::OnActivateView(bActivate, pActivateView, pDeactiveView);
}
五、編譯
本文配套源碼