65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIconstarIcon

5.00/5 (1投票)

2002年2月3日

viewsIcon

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);
}
© . All rights reserved.