为应用程序添加悬停热工具栏。





5.00/5 (1投票)
2002年2月3日

67075
在没有工具栏源代码的情况下,向应用程序添加可交互的Hot工具栏。
引言
当前悬停工具栏实现的问题在于,它们假定你负责源代码,而这并非总是正确的。
例如,如果你正在设计一个容器,该容器旨在托管一些控件,那么该容器无法访问这些控件的工具栏实现源代码。 另一种情况也包括通过从外部源读取图像动态创建工具栏的情况,而这些外部源通常不提供所有 3 种可能的图标状态(正常、悬停和禁用)。
这里介绍的方法不演示如何实现挂钩或子类化以在加载到应用程序中的第三方工具栏上实现悬停效果,但通过一点努力,你可以修改和重用以下方法。
我使用 VC5 语法来演示此示例,因为并非所有读者都已切换到 VC6 或 VS .NET 和/或拥有最新的通用控件库。
让我们开始吧
好的,思路很简单:在标准创建工具栏之后,以下代码将查询当前的工具栏图像列表,创建“悬停”和“禁用”列表,并将它们设置为该工具栏。
在你的 CMainFrame::OnCreate 实现中添加以下内容
... if (!m_wndToolBar.Create(this) || !m_wndToolBar.LoadToolBar(IDR_MAINFRAME)) { TRACE0("Failed to create toolbar\n"); return -1; // fail to create } CHotToolbar(m_wndToolBar.GetToolBarCtrl()); ...
现在,这是 CHotToolbar 类:
class CHotToolbar { public: CHotToolbar(CToolBarCtrl& Bar, // see comments about crHighlightColor below COLORREF crHighlightNormal = RGB(0,0,0) , // see comments about crHighlightColor below COLORREF crHighlightDisabled = RGB(160,160,160), DWORD dwStyle = TBSTYLE_FLAT ) // CreateGrayScaleIcon -- will mix original Icon with "every-other-pixel" // pattern brush // crHighlightColor could be set to any color to give "special" effect // BLACK(RGB(0,0,0)) will correcspond to extremely contrast, // while WHITE(RGB(255,255,255)) will be less visible => default // RGB(160,160,160) is good for Disabled Buttons static HICON CreateGrayScaleIcon(HICON hIcon, COLORREF crHighlightColor = RGB(160,160,160)); }; ///////////////////////////////////////////////////////////////////////////// // CHotToolbar CHotToolbar::CHotToolbar(CToolBarCtrl& Bar, COLORREF crHighlightNormal /* = RGB(0,0,0) */, COLORREF crHighlightDisabled /* = RGB(160,160,160)*/, DWORD dwStyle /* = TBSTYLE_FLAT */) { CImageList* pImageList = CImageList::FromHandle( (HIMAGELIST)::SendMessage(Bar.m_hWnd, TB_GETIMAGELIST, 0, 0L)); if(pImageList) { int numButtons = pImageList->GetImageCount( ); if(numButtons > 0) { IMAGEINFO ImageInfo; if(pImageList->GetImageInfo(0, &ImageInfo )) { // OK, let's create copy of Original ImageList CImageList img, imgHot, imgDisabled; CSize size(CRect(ImageInfo.rcImage).Width(), CRect(ImageInfo.rcImage).Height()); if( img.Create(size.cx, size.cy, TRUE, 0, 1)&& imgHot.Create(size.cx, size.cy, TRUE, 0, 1)&& imgDisabled.Create(size.cx, size.cy, TRUE, 0, 1)) { for(int i=0; i<numButtons; i++) { HICON hIcon = pImageList->ExtractIcon(i); HICON hIconNormal = CreateGrayScaleIcon(hIcon, crHighlightNormal); img.Add( hIconNormal ); DeleteObject( hIconNormal ); HICON hIconDisabled = CreateGrayScaleIcon(hIcon, crHighlightDisabled); imgDisabled.Add( hIconDisabled ); DeleteObject( hIconDisabled ); imgHot.Add(hIcon); DeleteObject( hIcon ); } // Now Standard Images Grabed => Now we can SetImageList // ATTN: after that operation pImageList will not be valid anymore ::SendMessage(Bar.m_hWnd, TB_SETHOTIMAGELIST, 0, (LPARAM)imgHot.GetSafeHandle()); imgHot.Detach(); ::SendMessage(Bar.m_hWnd, TB_SETIMAGELIST, 0, (LPARAM)img.GetSafeHandle()); img.Detach(); ::SendMessage(Bar.m_hWnd, TB_SETDISABLEDIMAGELIST, 0, (LPARAM)imgDisabled.GetSafeHandle()); imgDisabled.Detach(); if(dwStyle) Bar.ModifyStyle(0, TBSTYLE_FLAT); } } } } } // // CreateGrayScaleIcon -- will mix original Icon with "every-other-pixel" // pattern brush // crHighlightColor could be set to any color to give "special" effect // BLACK(RGB(0,0,0)) will correcspond to extremely contrast, while WHITE(RGB(255,255,255)) // will be less visible => default RGB(160,160,160) is good for Disabled Buttons // /* static */ HICON CHotToolbar::CreateGrayScaleIcon(HICON hIcon, COLORREF crHighlightColor /*=RGB(160,160,160)*/) { // The bitmap bits are for a monochrome "every-other-pixel" // bitmap (for a pattern brush) static const WORD Bits[8] = { 0x0055, 0x00aa, 0x0055, 0x00aa, 0x0055, 0x00aa, 0x0055, 0x00aa }; ICONINFO iconinfo; GetIconInfo(hIcon, &iconinfo); BITMAP bm; GetObject(iconinfo.hbmColor, sizeof(bm), &bm); HDC hScreenDC = ::GetDC(NULL); HDC hDC = ::CreateCompatibleDC(hScreenDC); HBITMAP hOldColor = (HBITMAP)::SelectObject(hDC, iconinfo.hbmColor); // The Width and Height of the Icon Image int nWidth = bm.bmWidth + 1; int nHeight = bm.bmHeight + 1; // Create pattern bitmap HBITMAP hBrushBitmap = CreateBitmap( 8, 8, 1, 1, &Bits ); // Original bitmap HBITMAP hBitmap = CreateCompatibleBitmap( hScreenDC, nWidth, nHeight ); // Create memory DC to work on HDC hMemDC = CreateCompatibleDC( hScreenDC ); // Create pattern brush HBRUSH hBrush = CreatePatternBrush( hBrushBitmap ); // If somewthing is wrong => return with NULL if( ( !hBrushBitmap ) || ( !hBitmap ) || ( !hMemDC ) || ( !hBrush ) ) { if( hBrushBitmap ) DeleteObject(hBrushBitmap); if( hBitmap ) DeleteObject( hBitmap ); if( hMemDC ) DeleteDC( hMemDC ); if( hBrush ) DeleteObject( hBrush ); return NULL; } // Select bitmap into the memory DC HBITMAP hOldMemBitmap = (HBITMAP)SelectObject( hMemDC, hBitmap ); // Original Rectangle: RECT rcRect = { 0, 0, nWidth, nHeight}; // Lay down the pattern in the memory DC FillRect( hMemDC, &rcRect, hBrush ); // Fill in the non-color pixels with the original image BitBlt( hMemDC, 0, 0, nWidth, nHeight, hDC, 0, 0, SRCAND); // Set the color scheme COLORREF crOldTextColor = SetTextColor( hDC, crHighlightColor ); COLORREF crOldBkColor = SetBkColor( hDC, RGB(0,0,0) ); int OldBkMode = SetBkMode( hDC, OPAQUE ); // Select the pattern brush HBRUSH hOldBrush = (HBRUSH)SelectObject( hDC, hBrush ); // Fill in the color pixels, and set the others to black FillRect( hDC, &rcRect, hBrush ); // Fill in the black ones with the original image BitBlt( hDC, 0, 0, nWidth, nHeight, hMemDC, 0, 0, SRCPAINT ); // Restore target DC settings SetBkMode( hDC, OldBkMode ); SetBkColor( hDC, crOldBkColor ); SetTextColor( hDC, crOldTextColor ); // Clean up SelectObject( hMemDC, hOldMemBitmap ); DeleteObject( hBitmap ); DeleteDC( hMemDC ); DeleteObject( hBrushBitmap ); SelectObject( hDC, hOldBrush ); DeleteObject( hBrush ); SelectObject( hDC, hOldColor ); ReleaseDC( NULL, hScreenDC ); return CreateIconIndirect(&iconinfo); }