分类: C/C++
2008-08-07 17:36:18
图一 例子程序运行画面
CToolBar不支持多行文字,本文将通过一个定制的MFC/C 类 CMTToolBar 实现在工具条中显示多行文字。其思路是先把文字变成位图,再替换原来的工具条位图,达到显示多行文字的效果。这个类中最主要的一个成员函数是ShowText(UINT nIDResource),其定义如下:
// 显示工具条文字 BOOL CMTToolBar::ShowText(UINT nIDResource) { // determine location of the bitmap in resource fork HINSTANCE hInst = AfxFindResourceHandle(MAKEINTRESOURCE(nIDResource), RT_TOOLBAR); HRSRC hRsrc = ::FindResource(hInst, MAKEINTRESOURCE(nIDResource), RT_TOOLBAR); if (hRsrc == NULL) return FALSE; HGLOBAL hGlobal = LoadResource(hInst, hRsrc); if (hGlobal == NULL) return FALSE; CToolBarData* pData = (CToolBarData*)LockResource(hGlobal); if (pData == NULL) return FALSE; ASSERT(pData->wVersion == 1); // 得到单个按钮的图像大小 CSize sizeImage(pData->wWidth, pData->wHeight); // release the resource UnlockResource(hGlobal); FreeResource(hGlobal); // 得到 CToolBarCtrl CToolBarCtrl& bar = GetToolBarCtrl(); // 得到 ToolBarCtrl的DC CDC *pdcCtrl = bar.GetDC(); CDC dcDst; // 目标DC , 用于生成新位图 dcDst.CreateCompatibleDC(pdcCtrl); // 新建字体 LOGFONT logFont; ZeroMemory(&logFont,sizeof(logFont)); logFont.lfWidth = 6; logFont.lfHeight = 12; logFont.lfCharSet = GB2312_CHARSET; strcpy(logFont.lfFaceName, "宋体" ); CFont fntNew; fntNew.CreateFontIndirect(&logFont); CFont *pfntOld = dcDst.SelectObject(&fntNew); // 新单个按钮的图片大小 CSize sizeNewImage(sizeImage.cx, 0); // 创建字符串数组 const int nCount = bar.GetButtonCount(); CStringArray *pstrArray = new CStringArray[nCount]; int nLines = 0; // 文字行数 int nIndex = 0; int nCharHeight = 0; // 单个字符高度 TBBUTTON tb; int nBtnCount = 0; // 按钮个数(除去分隔条) for (int i = 0; i < nCount; i) { ZeroMemory(&tb, sizeof(TBBUTTON)); bar.GetButton(i, &tb); // 如果是分隔条 if ((tb.fsStyle & TBSTYLE_SEP) == TBSTYLE_SEP) { continue; } CString strT; strT.LoadString(tb.idCommand); int nPos = strT.Find(_T(''\n'')) 1; while(nPos > 0) { int nPos2 = strT.Find(_T(''\n''), nPos); int nIndex; if(nPos2>nPos) { nIndex = pstrArray[nBtnCount].Add( strT.Mid(nPos, nPos2-nPos) ); nPos = nPos2 1; } else if(strT.GetLength() > nPos) { nIndex = pstrArray[nBtnCount].Add( strT.Mid(nPos) ); nPos = -1; } nLines = max(nLines, nIndex 1); CSize size = dcDst.GetTextExtent(pstrArray[nBtnCount][nIndex]); nCharHeight = max(size.cy, nCharHeight); sizeNewImage.cx = max(size.cx, sizeNewImage.cx); } nBtnCount ; } // 换算成实际像素 sizeNewImage.cy = nLines*nCharHeight; // 读取工具条位图资源 CBitmap bmpToolBar; BITMAP bmBitmap; if (!bmpToolBar.Attach(LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(nIDResource), IMAGE_BITMAP, 0, 0, LR_DEFAULTSIZE|LR_CREATEDIBSECTION |LR_LOADMAP3DCOLORS )) || !bmpToolBar.GetBitmap(&bmBitmap)) return FALSE; // 取得位图总宽高 int nWidth = bmBitmap.bmWidth; int nHeight = bmBitmap.bmHeight; // 新位图的总宽高 int nWidthNew = sizeNewImage.cx * nBtnCount; sizeNewImage.cy = nHeight; int nHeightNew = sizeNewImage.cy; CDC dcSrc; // 源DC dcSrc.CreateCompatibleDC(pdcCtrl); CBitmap *pbmpOldSrc = dcSrc.SelectObject(&bmpToolBar); CBitmap bmpDst; // 新位图 bmpDst.CreateCompatibleBitmap(&dcSrc, nWidthNew, nHeightNew); CBitmap *pbmpOldDst = dcDst.SelectObject(&bmpDst); // 先填充背景色 dcDst.FillSolidRect(CRect(0, 0, nWidthNew, nHeightNew), ::GetSysColor(COLOR_BTNFACE)); dcDst.SetBkMode(TRANSPARENT); // 设置透明背景方式 int nStartX = (sizeNewImage.cx-sizeImage.cx)/2; // 计算开始横坐标,用于居中处理 // 开始制作工具条位图 for( i = 0; i < nBtnCount; i) { dcDst.BitBlt(i*sizeNewImage.cx nStartX, 0, sizeImage.cx, sizeImage.cy, &dcSrc, i*sizeImage.cx, 0, SRCCOPY); int j; for(j = 0; j < pstrArray[i].GetSize(); j ) { CSize size = dcDst.GetTextExtent(pstrArray[i][j]); int nStratX = (sizeNewImage.cx-size.cx)/2; dcDst.TextOut(i*sizeNewImage.cx nStratX, sizeImage.cy j*nCharHeight, pstrArray[i][j]); } } // 恢复DC并释放资源 dcSrc.SelectObject(pbmpOldSrc); dcDst.SelectObject(pbmpOldDst); dcDst.SelectObject(pfntOld); bar.ReleaseDC(pdcCtrl); delete [] pstrArray; // 重新设置大小 SetSizes(sizeNewImage CSize(7,7), sizeNewImage); // 替换工具条位图 //SetBitmap((HBITMAP)bmpDst.Detach()); AddReplaceBitmap((HBITMAP)bmpDst.Detach()); return TRUE; }
使用的时候只需要简单在工具条资源里添加文字,每行用\n分开,如图二所示:
图二 在工具条资源里添加文字
再用CMTToolBar替换原CToolBar类。调用一下BOOL CMTToolBar::ShowText(UINT nIDResource)
就成了。
nIDResource是工具条资源id。