TabCtrl控件的使用一则——程序架构

传统地,Tab控件在切换Tab页时,需要切换页相对应的子窗体的隐藏与显示。单独对子窗体控制,略显繁杂。

本文采取如下思路: 将诸子窗体放到某个承载窗体(比如CWnd类型或者CDialog类型对象)上,在Tab切换时,操控承载窗体的显隐即可达到目的。

又传统地,程序需要维护一个对象数组,每个对象用于维护Tab和承载窗体或子窗体之间的关系;而本文采取如下方法:利用TCITEM结构体的lParam字段存储对应承载窗体的句柄。这样即可构建对应关系。

         本例所需类:

         1CMainFrame

         2CChildView : public CWnd

         3CTabCtrl,此处亦作TabCtrl,因大部分属性对于Win32对象亦适用。

         4CDialog 作为承载窗体若干,用CDialog的好处在于,可以直接利用resource template,便于在工程rc中设计控件位置等。

        

         步骤:

         一、以VCApplication Wizard创建一个MFC exe-SDI-no Document/View,那么即具备以上12两对象,、

二、在2中定义一成员变量,类型为3

三、在资源rc中画好对话框,并制定相应resource ID

四、重载2 (CChildView)LRESULT CChildView::WindowProc(UINT message, WPARAM wParam, LPARAM lParam),处理消息

WM_CREATE,创建TabCtrl、承载窗体,后者在此挂上资源;

WM_NOTIFY,遍历所有与TabCtrl相关的承载窗体,显示当前选中Tab对应的个体,其他个体隐藏;

WM_SIZE,调整TabCtrl的大小以适应CChildView,调整承载窗体的大小适应TabCtrlDisplay Area

 
LRESULT CChildView::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) 
{
    CRect rt;
    TCITEM item;
    
int j,i;
    TCITEM ItemTemp;
    
// TODO: Add your specialized code here and/or call the base class
    switch(message)
    
{
    
case WM_CREATE:
        
if(!m_Tab.Create (/*TCS_OWNERDRAWFIXED|*/TCS_TABS|WS_CHILD|WS_VISIBLE, CRect(0,0,0,0),this,IDC_TABCTRL))
        
{
            MessageBox(_T(
"Tab creation failed!"),_T("Error"));
        }


        //FormView1.Create (IDD_FORMVIEW1,
this);
        //FormView0.Create (IDD_FORMVIEW,
this);

            FormView1.Create (IDD_FORMVIEW1,&m_Tab);//MUST like this, if do like above, will occur some problem described in comment1
        FormView0.Create (IDD_FORMVIEW,
&m_Tab);//一定要这么做,若如上面代码,则会引发评论一所述及的问题


    
        item.mask 
= TCIF_TEXT|TCIF_PARAM ;

        item.pszText
=_T("第一个");
        item.lParam 
=(LPARAM)FormView0.m_hWnd ;
        m_Tab.InsertItem (
0,&item);
        
        item.pszText
=_T("第二个");
        item.lParam 
=(LPARAM)FormView1.m_hWnd ;
        m_Tab.InsertItem (
1,&item);

        
break;
        
    
case WM_NOTIFY:
        
if(IDC_TABCTRL == (int) wParam)
        
{
            LPNMHDR pnmh
=(LPNMHDR) lParam;
            
if (pnmh->code ==TCN_SELCHANGE )
            
{
                j
=m_Tab.GetCurSel ();
                
//if(ItemTemp.lParam!=NULL)
PointA:    if(m_Tab.GetItem(j,&ItemTemp))
                
if(IsWindow((HWND)ItemTemp.lParam))
                
{
                    ::ShowWindow((HWND)ItemTemp.lParam,SW_SHOW);
                    Invalidate();
//important!! Avoid some dialog unshowed!
PointB:
    }

                
for(i=0;i<m_Tab.GetItemCount ();i++)
                
{
                    
if(m_Tab.GetCurSel ()==i)
                        
continue;

                    
if(m_Tab.GetItem (i,&ItemTemp))
                        
if(IsWindow((HWND)ItemTemp.lParam))
                            ::ShowWindow((HWND)ItemTemp.lParam,SW_HIDE);
                }
    PointC:
            }

        }

        
        
break;    
        
    
case WM_SIZE:
        GetClientRect(rt);
        rt.DeflateRect (
100,100,100,100);
        m_Tab.MoveWindow (rt);

        m_Tab.GetWindowRect (rt);
        ScreenToClient(rt);
        m_Tab.AdjustRect (FALSE,rt);

        
for(i=0;i<m_Tab.GetItemCount ();i++)
        
{
            m_Tab.GetItem (
/*m_Tab.GetCurSel ()*/i,&ItemTemp);
            
if(ItemTemp.lParam!=NULL && ::IsWindow ((HWND)ItemTemp.lParam))
            ::MoveWindow(((HWND)(ItemTemp.lParam)),rt.left ,rt.top ,rt.Width (),rt.Height(),FALSE);
        }

        
break;

    
case WM_LBUTTONDBLCLK:
        
            item.mask 
= TCIF_TEXT;
            item.pszText
=_T("第三个");
            
//item.lParam =;
            m_Tab.InsertItem (m_Tab.GetItemCount (),&item);
        
break;

    
case WM_RBUTTONDBLCLK:
        m_Tab.DeleteItem (m_Tab.GetItemCount ()
-1);
        
break;
    }

    
return CWnd ::WindowProc(message, wParam, lParam);
}

那么在模拟单击某个Tab页的动作,代码为:

m_wndView.m_Tab.SetCurSel(1);

         NMHDR nh;

         nh.hwndFrom=m_wndView.m_Tab.m_hWnd;

         nh.idFrom=IDC_TABCTRL;

         nh.code=TCN_SELCHANGE;

         m_wndView.SendMessage(WM_NOTIFY,IDC_TABCTRL,(LPARAM)&nh);

 

假设动态地创建了多个Tab,其中一些可能对应某个Dialog派生类,那么如果需要查找某个特定的Dialog就必须仰赖MFCRTTIDialog某甄别字段。如下例展示查找一个Dialog并将其杀掉,将界面切换至第1个(zero based indexTab

void CMainFrame::KillDialingPad(CString StrContactName)

{

         CWnd* pWnd;

         HWND hWnd;

         TCITEM ItemTemp;

         int i=0;

         for (i=1;i<m_wndView.m_Tab.GetItemCount();i++)//start from 1, avoid searching from the CONTACT LIST

         {

                   m_wndView.m_Tab.GetItem(i,&ItemTemp);

                   hWnd=(HWND)ItemTemp.lParam;

                   pWnd=CWnd::FromHandle(hWnd);//avoid to bring a new CWnd object;

                   if (pWnd->IsKindOf(RUNTIME_CLASS(CDialingBoxDlg)))

                   {

                            if(((CDialingBoxDlg *)pWnd)->m_StrContactName==StrContactName)

                                     break;

                   }

         }

 

         if(i<m_wndView.m_Tab.GetItemCount())//found

         {

                   pWnd->DestroyWindow();

                   delete pWnd;

                   pWnd=NULL;

                   m_wndView.m_Tab.DeleteItem(i);

         }

 

         m_wndView.m_Tab.SetCurSel(1);

         NMHDR nh;

         nh.hwndFrom=m_wndView.m_Tab.m_hWnd;

         nh.idFrom=IDC_TABCTRL;

         nh.code=TCN_SELCHANGE;

         m_wndView.SendMessage(WM_NOTIFY,IDC_TABCTRL,(LPARAM)&nh);

}

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值