2.13 标签控件典型实例
标签控件(Tab Control)提供了一组水平标签,可以单击不同的标签进入相应的页面。但标签控件不能直接在各个标签页上插入控件,只能在选中不同标签页时显示不同的对话框或控件。
实例084 应用标签控件
这是一个可以提高基础技能的实例
实例位置:光盘\mingrisoft\02\084
实例说明
在程序中经常会使用标签控件来切换界面。本实例实现了使用标签控件进行切换的功能,运行结果如图2.51所示。
图2.51 应用标签控件
技术要点
在使用标签控件时,最主要的功能就是,选择不同的标签时有不同的显示信息,要实现这一功能,需要使用标签控件的TCN_SELCHANGE事件,该事件当选中标签改变后触发。可以在该事件的处理函数中使用GetCurSel方法和SetCurSel方法获得或设置当前被选中的标签索引。
(1)GetCurSel方法。GetCurSel方法用于获得当前被选中的标签索引,语法如下:
int GetCurSel( ) const;
返回值:返回当前被选中的标签项索引。
(2)SetCurSel方法。SetCurSel方法用于将某个标签设置为当前选中的标签。语法如下:
int SetCurSel( int nItem );
参数说明:
● nItem:标识标签索引。
返回值:之前选中的标签索引。
实现过程
(1)新建一个基于对话框的应用程序。
(2)添加3个对话框资源,资源ID分别为IDD_DIALOG_EMP、IDD_DIALOG_CLI和IDD_DIALOG_PRO,并设置对话框资源的Style属性为Child,Border属性为None,为3个对话框资源关联类,分别为CEmployee 、CClient和Cprovidedlg,并分别向对话框资源中添加控件。
(3)向主对话框中添加一个标签控件,并为标签控件关联变量m_Tab。
(4)在主对话框头文件中声明1个图像列表对象和3个对话框类对象,代码如下:
CImageList m_ImageList; //图像列表对象 CEmployee* m_eDlg; //员工对话框对象 CClient* m_cDlg; //客户对话框对象 CProvidedlg* m_pDlg; //供应商对话框对象
(5)在主对话框的OnInitDialog函数中创建图像列表,向图像列表中添加图标,关联标签控件和图像列表控件,并创建对话框,代码如下:
m_ImageList.Create(24,24,ILC_COLOR24|ILC_MASK,1,0); //创建图像列表 m_ImageList.Add(AfxGetApp()->LoadIcon(IDI_ICON1)); //向图像列表中添加图标 m_ImageList.Add(AfxGetApp()->LoadIcon(IDI_ICON2)); //向图像列表中添加图标 m_ImageList.Add(AfxGetApp()->LoadIcon(IDI_ICON3)); //向图像列表中添加图标 m_Tab.SetImageList(&m_ImageList); //将图像列表关联到标签控件中 m_Tab.InsertItem(0,"员工信息",0); //插入标签项 m_Tab.InsertItem(1,"客户信息",1); //插入标签项 m_Tab.InsertItem(2,"供应商信息",2); //插入标签项 m_eDlg=new CEmployee; //为指针分配内存空间 m_cDlg=new CClient; //为指针分配内存空间 m_pDlg=new CProvidedlg; //为指针分配内存空间 m_eDlg->Create(IDD_DIALOG_CLI,&m_Tab); //创建员工对话框 m_cDlg->Create(IDD_DIALOG_EMP,&m_Tab); //创建客户对话框 m_pDlg->Create(IDD_DIALOG_PRO,&m_Tab); //创建供应商对话框 m_eDlg->CenterWindow(); //设置员工窗口在中心位置 m_eDlg->ShowWindow(SW_SHOW); //显示客户窗口
(6)处理对话框的TCN_SELCHANGE事件,在该事件中获得当前选中标签项的索引,根据索引判断显示的对话框,代码如下:
void CUseTabDlg::OnSelchangeTab1(NMHDR*pNMHDR,LRESULT*pResult) //事件处理函数 { int index=m_Tab.GetCurSel(); //获得当前选中标签项索引 switch(index) //判断标签项索引值 { case 0: //值为0时 m_eDlg->CenterWindow(); //设置员工对话框在中心位置 m_eDlg->ShowWindow(SW_SHOW); //显示员工对话框 m_cDlg->ShowWindow(SW_HIDE); //隐藏客户对话框 m_pDlg->ShowWindow(SW_HIDE); //隐藏供应商对话框 break; case 1: //值为1时 m_cDlg->CenterWindow(); //设置客户对话框在中心位置 m_eDlg->ShowWindow(SW_HIDE); //隐藏员工对话框 m_cDlg->ShowWindow(SW_SHOW); //显示客户对话框 m_pDlg->ShowWindow(SW_HIDE); //隐藏供应商对话框 break; case 2: //值为2时 m_pDlg->CenterWindow(); //设置供应商对话框在中心位置 m_eDlg->ShowWindow(SW_HIDE); //隐藏员工对话框 m_cDlg->ShowWindow(SW_HIDE); //隐藏客户对话框 m_pDlg->ShowWindow(SW_SHOW); //显示供应商对话框 break; } *pResult = 0; }
(7)处理对话框的WM_CLOSE事件,在主对话框关闭时销毁3个非模态对话框,并释放指针,代码如下:
void CUseTabDlg::OnClose() { m_eDlg->DestroyWindow(); //销毁员工对话框 delete m_eDlg; //释放员工对话框指针 m_cDlg->DestroyWindow(); //销毁客户对话框 delete m_cDlg; //释放客户对话框指针 m_pDlg->DestroyWindow(); //销毁供应商对话框 delete m_pDlg; //释放供应商对话框指针 CDialog::OnClose(); //关闭对话框 }
举一反三
根据本实例,读者可以:
使用标签控件控制显示的控件。
实例085 自定义标签控件
这是一个可以提高基础技能的实例
实例位置:光盘\mingrisoft\02\085
实例说明
图2.52 自定义标签控件
许多应用软件都具有漂亮的标签控件,本实例通过自绘标签控件实现了一个类似.NET环境下的标签控件,实例运行结果如图2.52所示。
技术要点
在设计自定义选项卡时,主要应用了设备上下文CDC类的几个方法实现区域的填充、文本绘制等功能。下面逐一介绍。
(1)FillSolidRect方法。设备上下文的FillSolidRect方法用于使用指定的颜色来填充矩形区域。语法如下:
void FillSolidRect(LPCRECT lpRect, COLORREF clr);
参数说明:
● lpRect:表示填充的矩形区域。
● clr:表示使用的RGB颜色值。
(2)SetTextColor方法。设备上下文的SetTextColor方法用于设置输出的文本颜色。语法如下:
virtual COLORREF SetTextColor(COLORREF crColor);
参数说明:
● crColor:表示设置的文本颜色。
返回值:表示之前设备上下文的文本颜色。
(3)SetBkMode方法。设备上下文的SetBkMode方法用于设置背景模式。语法如下:
int SetBkMode(int nBkMode);
● nBkMode:表示设置的背景模式,为OPAQUE,表示使用当前的背景颜色填充背景。为TRANSPARENT,表示使用透明的背景模式。
返回值:表示之前设备上下文的背景模式。
(4)SelectObject方法。设备上下文的SelectObject方法用于选中一个GDI对象。例如,当用户需要输出文本时,可以定义一个字体对象,然后利用该方法载入字体,之后输出的文本将以载入的字体输出。语法如下:
CGdiObject* SelectObject(CGdiObject* pObject);
● pObject:表示一个GDI对象,可以是画刷、画笔、字体、位图等对象。
返回值:表示设备上下文之前选中的GDI对象。
(5)DrawText方法。设备上下文的DrawText方法用于按指定的格式输入文本。语法如下:
int DrawText(const CString& str, LPRECT lpRect, UINT nFormat);
● str:表示输出的字符串。
● lpRect:表示输出字符串所在的矩形区域。
● nFormat:表示文本输出格式,是一组标记的集合。为DT_LEFT,表示水平居左对齐,为DT_VCENTER,表示垂直居中,为DT_SINGLELINE,表示单行输出,不回行。
实现过程
(1)新建一个基于对话框的应用程序。
(2)以CTabCtrl类为基类派生一个子类CNetTabCtrl。
(3)向对话框中添加一个标签控件,设置标签控件的Bottom属性,添加一个CNetTabCtrl类的成员变量m_Tab。
(4)向CNetTabCtrl中添加DrawTabBorder方法,绘制标签页的边框。代码如下:
void CNetTabCtrl::DrawTabBorder(CDC *pDC, CRect &TabRC) { pDC->Draw3dRect(&TabRC, RGB(255, 255, 255), RGB(177, 174, 162));//绘制标签控件的矩形边框 }
(5)向CNetTabCtrl中添加DrawItemFrame方法,绘制标签控件中各个选项卡的边框。代码如下:
void CNetTabCtrl::DrawItemFrame(DRAWITEMSTRUCT *lpDrawItem) { int nCurSel=GetCurSel(); //获取选中的选项卡索引 int nIndex=lpDrawItem->itemID; //获取当前的选项卡索引 BOOL bSelected=(nCurSel==nIndex); //判断选中的选项卡与当前的选项卡是否相同 CDC dc; CRect itemRC=lpDrawItem->rcItem; //获取选项卡的矩形区域 dc.Attach(lpDrawItem->hDC); if(bSelected) //项目处于选中状态 { itemRC.OffsetRect(-1, 0); dc.FrameRect(&itemRC,&CBrush(RGB(172,168,153))); //绘制选项卡边框 } else //项目处于非选中状态 { //绘制左右两端的分隔线 if (nIndex == 0) dc.FillSolidRect(itemRC.left, itemRC.top + 2, 1, itemRC.Height() -4, RGB(172, 168, 153)); dc.FillSolidRect(itemRC.right -1, itemRC.top + 2, 1, itemRC.Height() -4, RGB(172, 168, 153)); } dc.Detach(); //分离设备上下文句柄 }
(6)改写标签控件的DrawItem虚方法,根据当前选项卡的不同状态,绘制不同效果的选项卡。代码如下:
void CNetTabCtrl::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) { ASSERT(lpDrawItemStruct->CtlType == ODT_TAB); CDC dc; dc.Attach(lpDrawItemStruct->hDC); CRect itemRC(lpDrawItemStruct->rcItem); //获取项目区域 int nIndex=lpDrawItemStruct->itemID; //获取项目索引 int nState=lpDrawItemStruct->itemState; //获取项目状态 static COLORREF clrBK=RGB(229,229,215); //定义默认背景颜色 static COLORREF clrSelBK=RGB(252,252,254); //定义选中的背景颜色 COLORREF clrText = RGB(113, 111, 100); if(nState&ODS_SELECTED) //处于选中状态 { dc.FillSolidRect((CRect)lpDrawItemStruct->rcItem,clrSelBK); clrText=RGB(0,0,0); } else //非选中状态 { if(nIndex==0) //第一个选项卡 { CRect itemRC = lpDrawItemStruct->rcItem; itemRC.OffsetRect(-1, 0); dc.FillSolidRect(itemRC,clrBK); //填充选项卡区域 } else { dc.FillSolidRect((CRect)lpDrawItemStruct->rcItem,clrBK); //填充选项卡区域 } } //绘制项目文本和图像 char szText[MAX_PATH]={0}; //定义字符数组 TC_ITEM tcItem; //定义选项卡对象 tcItem.mask =TCIF_TEXT|TCIF_IMAGE; //设置掩码 tcItem.pszText =szText; tcItem.cchTextMax =MAX_PATH; GetItem(nIndex,&tcItem); //获取选项卡信息 CImageList*pImages=GetImageList(); //获取控件关联的图像列表 if (pImages != NULL) { CPoint iconPT; iconPT.x = itemRC.left; iconPT.y = itemRC.top; pImages->Draw(&dc,tcItem.iImage,iconPT,ILD_NORMAL); //绘制选项卡显示的位图 } itemRC.left+=40; //设置位图与文本的间距 dc.SetTextColor(clrText); //设置文本颜色 dc.SetBkMode(TRANSPARENT); //设置透明的背景模式 CFont*pFont=GetFont(); //获取字体对象 dc.SelectObject(pFont); //选中字体对象 //输出文本 dc.DrawText(szText, strlen(szText), itemRC, DT_LEFT|DT_VCENTER|DT_SINGLELINE); dc.Detach(); //分离设备上下文句柄 }
(7)处理标签控件的WM_PAINT消息,在其消息处理函数中绘制每个选项卡。代码如下:
void CNetTabCtrl::OnPaint() { CPaintDC dc(this); DRAWITEMSTRUCT drawItem; //定义一个选项结构 drawItem.CtlType=ODT_TAB; //设置选项类型为选项卡 drawItem.CtlID=GetDlgCtrlID(); //获取标签控件的ID drawItem.hwndItem=GetSafeHwnd(); //获取标签控件句柄 drawItem.hDC=dc.GetSafeHdc(); //获取设备上下文 drawItem.itemAction=ODA_DRAWENTIRE; //设置自绘风格 GetClientRect(&drawItem.rcItem); //获取客户区域 CRect clientRC; CRect pageRC; pageRC = drawItem.rcItem; AdjustRect(FALSE,pageRC); //调整区域 drawItem.rcItem.top = pageRC.top -2; DrawTabBorder(&dc,(CRect)drawItem.rcItem); //绘制标签页的边框 int nItemCount=GetItemCount(); //获取选项卡数量 int nCurSel=GetCurSel(); //获取选中的选项卡索引 if (nItemCount < 1) return; for(int i=0;i<nItemCount;i++) //遍历选项卡 { drawItem.itemID = i; if(i==nCurSel) //当前选项卡处于选中状态 drawItem.itemState=ODS_SELECTED; //设置选中标记 else drawItem.itemState = 0; GetItemRect(i,&drawItem.rcItem); //获取选项卡的区域 DrawItem(&drawItem); //调用DrawItem方法绘制选项卡 DrawItemFrame(&drawItem); //绘制项目边框 } }
(8)改写标签控件的PreSubclassWindow方法,设置标签控件选项卡最小宽度和默认的宽度和高度。代码如下:
void CNetTabCtrl::PreSubclassWindow() { SetMinTabWidth(100); //设置最小选项卡的宽度 SetItemSize(CSize(120,32)); //设置选项卡的宽度和高度 CTabCtrl::PreSubclassWindow(); }
(9)创建一个对话框类—CIndexDlg,向对话框中添加编辑框和图片控件。设置对话框Style属性为Child,设置Border属性为None。
(10)在主对话框中利用类向导为标签控件命名为“m_Tab”,其类型为CNetTabCtrl。向主对话框类中添加成员变量。代码如下:
CImageList m_ImageList; //定义图像列表 CIndexDlg m_IndexDlg; //定义子对话框
(11)在主对话框初始化时创建子对话框,创建图像列表,向图像列表中添加位图,向标签控件中添加选项卡。代码如下:
m_IndexDlg.Create(IDD_INDEXDLG_DIALOG,&m_Tab); //在标签控件上创建子窗口 m_ImageList.Create(32,32,ILC_COLOR16|ILC_MASK,1,1); //创建图像列表控件 CBitmap bmp; //定义位图对象 bmp.LoadBitmap(IDB_BITMAP1); //载入位图 m_ImageList.Add(&bmp,RGB(255,255,255)); //向图像列表中添加位图 bmp.Detach(); //分离位图句柄 bmp.LoadBitmap(IDB_BITMAP2); //载入位图 m_ImageList.Add(&bmp,RGB(255,255,255)); //向图像列表中添加位图 bmp.Detach(); //分离位图句柄 bmp.LoadBitmap(IDB_BITMAP3); //载入位图 m_ImageList.Add(&bmp,RGB(255,255,255)); //向图像列表中添加位图 bmp.Detach(); //分离位图句柄 m_Tab.SetImageList(&m_ImageList); //为标签控件设置选项卡 m_Tab.InsertItem(0,"索引",0); //向标签控件中插入选项卡 m_Tab.InsertItem(1, "查找", 1); m_Tab.InsertItem(2, "目录", 2); m_Tab.SetCurSel(0); //将第一个选项卡选中 LRESULT result; OnSelchangeTab1(NULL,&result); //当前选项卡发生了改变
举一反三
根据本实例,读者可以:
设计具有热点效果的标签控件。