首页 > MFC > MFC单文档添加CTabCtrl(二)

MFC单文档添加CTabCtrl(二)

2013年4月12日 发表评论 阅读评论

之前说了在单文档中建立一个Tab标签控件的方法,但是我一直觉得那个方法比较绕,没那么直接,最直接的方法是什么?那就是直接在C***View中Create一个CTabCtrl控件变量,然后给他添加一些对话框和消息响应什么的,这样就可以少用一个CFormView类,改来改去什么的最烦了~ 下面就是这个方法: 首先第一步还是建立你想要的几个最后作为标签页的对话框,我们这里还是用两个标签页来做例子,假设新建了两个对话框,生成相应的类,最重要的是,要将他们的Style设置成Child。假设ID为IDD_DIALLOG_TAB1,IDD_DIALLOG_TAB2。而且将它们的Boarder设置成None,以免影响美观效果。 然后回到我们的C***View类,假设建立的是CTabCtrlTestView,我们在里面添加两个变量:

CTabCtrl*    m_TabCtrl;
CTypedPtrArray<CObArray, CDialog*> m_DlgArray;

一个就是Tab控件,另一个是存储对话框的数组。 接下来写好View类的构造函数的析构函数:

CTabCtrlTestView::CTabCtrlTestView()
{
    m_TabCtrl = NULL;
}

CTabCtrlTestView::~CTabCtrlTestView()
{
    if (m_TabCtrl)
        delete m_TabCtrl;

    int num = m_DlgArray.GetSize();
    for (int i = 0; i < num; i++)
    {
        if (m_DlgArray[i])
            delete m_DlgArray[i];
    }
}

然后给View类添加OnCreate,OnSize和OnSetFocus三个消息函数:(这里我们要自己定义ID_TABCTRL这个宏这不用我说了吧。。)

int CTabCtrlTestView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    if (CView::OnCreate(lpCreateStruct) == -1)
        return -1;

    m_TabCtrl = new CTabCtrl;

    if (m_TabCtrl->Create(WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS,
        CRect(0, 0, 0, 0), this, ID_TABCTRL) == FALSE)
        return -1;

    CreatePages();
    return 0;
}

void CTabCtrlTestView::OnSize(UINT nType, int cx, int cy)
{
    CView::OnSize(nType, cx, cy);
    m_TabCtrl->MoveWindow(0, 0, cx, cy);
}

void CTabCtrlTestView::OnSetFocus(CWnd* pOldWnd)
{
    CView::OnSetFocus(pOldWnd);
    OnTabSelChange(NULL, NULL);
}

这里遇到的还没定义的函数自然先别急,下文都会提到的。 接下来就是给TabCtrl添加两个消息响应函数OnTabSelChange和OnTabSelChanging,方法我也再说一下吧,在View类的DECLARE_MESSAGE_MAP()下面添加:

afx_msg void OnTabSelChanging(NMHDR* pnmhdr, LRESULT* pResult);
afx_msg void OnTabSelChange(NMHDR* pnmhdr, LRESULT* pResult);

然后在View的CPP源文件中BEGIN_MESSAGE_MAP(CTabCtrlTestView, CView)和END_MESSAGE_MAP()之间消息映射,如下面所示:

BEGIN_MESSAGE_MAP(CTabCtrlTestView, CView)
    // 标准打印命令
    ON_COMMAND(ID_FILE_PRINT, &CView::OnFilePrint)
    ON_COMMAND(ID_FILE_PRINT_DIRECT, &CView::OnFilePrint)
    ON_COMMAND(ID_FILE_PRINT_PREVIEW, &CView::OnFilePrintPreview)
    ON_WM_CREATE()
    ON_WM_SIZE()
    ON_WM_SETFOCUS()

    ON_NOTIFY(TCN_SELCHANGE, ID_TABCTRL, OnTabSelChange)
    ON_NOTIFY(TCN_SELCHANGING, ID_TABCTRL, OnTabSelChanging)
    ON_COMMAND(ID_TEST, &CTabCtrlTestView::OnTest)
    ON_WM_KEYDOWN()
END_MESSAGE_MAP()

下面是这两个函数的本体:

void CTabCtrlTestView::OnTabSelChanging(NMHDR* pnmhdr, LRESULT* pResult)
{
    int sel_index = m_TabCtrl->GetCurSel();
    m_DlgArray[sel_index]->ShowWindow(SW_HIDE);
    *pResult = FALSE;
}

void CTabCtrlTestView::OnTabSelChange(NMHDR* pnmhdr, LRESULT* pResult)
{
    RECT rc;
    m_TabCtrl->GetItemRect (0, &rc);

    int sel_index = m_TabCtrl->GetCurSel();
    m_DlgArray[sel_index]->SetWindowPos (
        NULL,
        rc.left + 5, rc.bottom + 5, 0, 0,
        SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW);
    m_DlgArray[sel_index]->SetFocus();
}

最后就是OnCreate里面用到的CreatePage这个函数了:

void CTabCtrlTestView::CreatePages()
{
    CDialog*    dlg;

    dlg = new CTab1;
    m_DlgArray.Add(dlg);
    dlg->Create(IDD_DIALOG_TAB1, m_TabCtrl);

    dlg = new CTab2;
    m_DlgArray.Add(dlg);
    dlg->Create(IDD_DIALOG_TAB2, m_TabCtrl);

    CString str;
    for (int i = 0; i < NUM_PAGES; i++)
    {    
        dlg = m_DlgArray[i];
        str.Format("Tab%d",i);
        m_TabCtrl->InsertItem(i, str);
    }
}

如果要在View类中访问对话框的内容,自然就是:

((CStatic*)m_DlgArray[1]->GetDlgItem(IDC_STATIC))->SetWindowText("aaaa");

最后假设要添加一个Ctrl+Tab的快捷键切换页面,那就在View类中添加一个BOOL HandleKeyDownMsg(MSG* pMsg)函数,如下:

BOOL CTabCtrlTestView::HandleKeyDownMsg( MSG* pMsg )
{
    if (pMsg->wParam == VK_TAB && GetKeyState(VK_CONTROL) < 0)
    {
        BOOL    shift_down    = GetKeyState(VK_SHIFT) < 0;
        int        old_sel        = m_TabCtrl->GetCurSel();
        int        num            = m_TabCtrl->GetItemCount() ;
        int        new_sel        =
            shift_down ? (old_sel + (num -1)) % num
            : (old_sel + 1) % num;

        RECT    r;
        m_TabCtrl->GetItemRect(new_sel, &r);
        m_TabCtrl->SendMessage(WM_LBUTTONDOWN, MK_LBUTTON, MAKELONG(r.left, r.top));
        return TRUE;
    }

    if (pMsg->wParam == VK_RETURN || pMsg->wParam == VK_ESCAPE)
        return TRUE;
}

但是这显然没完,还要在APP类中重写PreTranslateMessage函数,本体如下:

BOOL CTabCtrlTestApp::PreTranslateMessage(MSG* pMsg)
{
    // TODO: 在此添加专用代码和/或调用基类
    if (pMsg->message == WM_KEYDOWN)
    {
        CView* view = ((CFrameWnd *) AfxGetMainWnd())->GetActiveView();
        if (((CTabCtrlTestView *) view)->HandleKeyDownMsg(pMsg))
            return TRUE;            
    }
    return CWinApp::PreTranslateMessage(pMsg);
}

【完】

本文内容遵从CC版权协议,转载请注明出自http://www.kylen314.com

分类: MFC 标签: ,