首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> 關於VC++

在 MDI 程式中實現類似 WPS 2000 的文件切換標籤

     編輯:關於VC++

使用過 WPS 2000 的開發者一定對其文件切換功能印象深刻。當同時開啟多個文件時,該功能能讓使用者快速切換到指定文件。本文將詳細說明如何在自己的 MDI 程式中加入這樣的標籤功能。下圖是本文範例程式的執行畫面。

圖一 範例程式執行畫面

WPS 2000 文件切換標籤功能分析

這是一個 Tab 標籤控制項,具備以下核心功能:

  1. 滑鼠移至 Tab 標籤上時,對應文字會變為藍色
  2. 新建或開啟文件時,Tab 標籤會以文件標題為文字自動新增項目
  3. 切換 Tab 標籤時,對應的文件視窗會跟著切換
  4. 激活不同文件視窗時,Tab 標籤會自動切換
  5. 關閉文件視窗時,Tab 標籤中對應項目會自動消失

本文範例在實現上述功能外,還做了以下改進:

  1. 增加雙擊 Tab 標籤時最大化、還原子視窗功能
  2. 將 Tab 標籤修改為按鈕風格

具體實作思路

在 MDI 程式中加入一個包含 Tab 標籤的對話方塊列,並建立 CViewManager 類別。該類別使用指標陣列儲存所有開啟子視窗的視圖指標,使用字串陣列儲存文件標題。在視圖類別的 OnInitialUpdate() 中取得視圖指標與文件標題,存入 CViewManager 陣列並在 Tab 標籤中新增項目。在視圖類別的解構函式中從 Tab 標籤和 CViewManager 陣列中刪除對應項目。切換 Tab 標籤時,取得對應子視窗指標,並以該指標為參數呼叫 CMDIFrameWnd::MDIActivate() 激活該子視窗。

詳細實作步驟

一、建立 MDI 專案

在 VC6.0 中使用精靈建立名為 TabMDIDemo 的 MDI 專案,各步驟均採用預設選項。

二、加入 Tab 標籤對話方塊列

  1. 在 ResourceView 中加入對話方塊模板 IDD_TAB_DLG_BAR,設定如下:
    Style: Child
    Border: Thin
    移除標題列與系統選單
    字型:新細明體,大小:10
    在模板中加入 Tab 控制項 IDC_TAB,設定如下:
    勾選 Buttons 選項 // 使 Tab 標籤呈現按鈕風格
    勾選 Hot Track 選項 // 使滑鼠移上時文字變藍
    仔細調整對話方塊列與 Tab 控制項的位置、尺寸。建立主框架時,將以該模板建立 Tab 標籤對話方塊列。
  2. 使用類別精靈加入 CMyTab 類別,繼承自 CTabCtrl。
  3. 為 CMyTab 加入 TCN_SELCHANGE 通知訊息對應函式,實現文件切換:
    void CMyTab::OnSelchange(NMHDR* pNMHDR, LRESULT* pResult)
    {
        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;
    }
  4. 為 CMyTab 加入 WM_LBUTTONDBLCLK 訊息對應函式,實現雙擊最大化或還原子視窗:
    void CMyTab::OnLButtonDblClk(UINT nFlags, CPoint point)
    {
        int idx = GetCurSel();
        TC_ITEM ti;
        ti.mask = TCIF_PARAM;
        GetItem(idx, &ti);
        CView * pView = (CView *) ti.lParam;
        ((CMDIFrameWnd *)AfxGetMainWnd())->MDIActivate((pView->GetParent())->GetParent());
        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() 中加入建立 Tab 列的程式碼:
    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))
        {
            TRACE0("Failed to create dialog bar m_wndDialogbar\n");
            return -1;
        }
        // 將 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);
        CRect rcClient;
        GetClientRect(&rcClient);
        m_wndTabBar.MoveWindow(rcClient.left, rcClient.top + 24, rcClient.Width(), 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():建構/解構函式
  • 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();
        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)
    {
        ((CMainFrame*)AfxGetMainWnd())->m_ViewManager.OnActivateView(bActivate, this);
        CView::OnActivateView(bActivate, pActivateView, pDeactiveView);
    }

五、編譯執行

本文附帶完整原始碼,編譯執行即可看到效果。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved