2017-04-13 44 views
1

我有一个使用系统托盘中“标准”图标的MFC C++(非托管)Windows应用程序。这个图标是使用Visual Studio编辑的&创建的,只有4位颜色的32x32像素(根据VS的资源编辑器)。如何在从非托管C程序在Windows系统托盘图标上书写文本时保持透明

使用Visual Studio,我还设置了透明背景(在“之前”图像中显示为白色)。

我希望通过在上面写入2位数字(1-99)来动态更改图标。

使用下面的代码(系基于这样一个问题:How to draw text with transparency using GDI?)叠加“55”,在黄色的图标,它的工作原理不同之处在于透明度消失(出现黑色图像“之后”,并在系统托盘)。我的实际代码与字体大小(20),字体名称(Courier New),文本颜色(黄色--RGB(255,255,0))和数字值(55)之间的差异非常小,而非运行时变量比固定值。

有关如何使背景保持透明的任何建议,只要感谢系统托盘的关注。

这些图像已使用MS的剪切工具捕获,并且在MS Paint中打开该图像,因为32x32图标不会非常明显。

图像之前:

Before Image

图像后:

After image

代码:

void CreateNewIcon(HICON &hNewIcon, HICON hBackgroundIcon) 
{ 
    ::DestroyIcon(hNewIcon); 

    // First create font 
    LOGFONT lf = { 0 }; 
    lf.lfHeight = -20; 
    lf.lfWeight = FW_BOLD; 
    lf.lfOutPrecision = OUT_TT_PRECIS; 
    lf.lfQuality = CLEARTYPE_QUALITY; 
    wmemset(lf.lfFaceName, 0, LF_FACESIZE); 
    lstrcpy(lf.lfFaceName, L"Courier New"); 

    HFONT hFont = ::CreateFontIndirect(&lf); 

    ICONINFO ii = { 0 }; 
    ::GetIconInfo(hBackgroundIcon, &ii); 

    BITMAP bm = { 0 }; 
    ::GetObject(ii.hbmColor, sizeof(bm), &bm); 
    SIZE szBmp = { bm.bmWidth, bm.bmHeight }; 

    HDC hDc = ::GetDC(NULL); 
    HDC hMemDC = ::CreateCompatibleDC(hDc); 

    HGDIOBJ hOldBmp = ::SelectObject(hMemDC, ii.hbmColor); 
    HGDIOBJ hOldFont = ::SelectObject(hMemDC, hFont); 

    ::SetBkMode(hMemDC, TRANSPARENT); 
    ::SetTextColor(hMemDC, RGB(255, 255, 0)); 
    ::TextOut(hMemDC, 0, 8, L"55", 2); 

    ::SelectObject(hMemDC, hOldFont); 
    ::SelectObject(hMemDC, hOldBmp); 

    // We need a simple mask bitmap for the icon 
    HBITMAP hBmpMsk = ::CreateBitmap(szBmp.cx, szBmp.cy, 1, 1, NULL); 

    ICONINFO ii2 = { 0 }; 
    ii2.fIcon = TRUE; 
    ii2.hbmColor = ii.hbmColor; 
    ii2.hbmMask = hBmpMsk; 

    // Create updated icon 
    hNewIcon = ::CreateIconIndirect(&ii2); 

    // Cleanup 
    ::DeleteObject(hBmpMsk); 
    ::DeleteDC(hMemDC); 
    ::ReleaseDC(NULL, hDc); 
    ::DeleteObject(ii.hbmColor); 
    ::DeleteObject(ii.hbmMask); 
    ::DeleteObject(hFont); 
} 

回答

0

有我们的代码中的多个问题:

  • 您试图通过透明图标部件绘制纯文本类型的文本。但是cleartype字体渲染必须在不透明的背景上执行,因为它需要检查背景颜色。所以你应该改用Anitialiased质量(或者不要抗锯齿质量)或为你的文字提供不透明的背景。
  • 当您创建hBmpMskyou skip it's content initialization by supplying NULL for bits pointer时,所生成的图标实际上会具有完全随机的透明度。您需要适当填充此掩码bitmat。

此外,您可能需要切换到更高的位深度,因为单色位图遮罩无法处理反锯齿文本的半透明部分。

更新

我想你应该吸取的ClearType文本,但与不透明的背景,然后使用类似GetTextExtentPoint32得到文本矩形,然后从原始图蒙版将数据复制到hBmpMsk,最后补白(文本)矩形,因此新图标将保留来自原始的透明度并具有不透明文本块。

+0

带图标这个小的质量(32×32),我并不需要明确的字体类型,所以我现在已经commentted了两个“lf.lfOutPrecision”和“lf.lfQuality”。但我该如何“适当地填充此掩码位图”? – DDK

+0

实际上,托盘图标大小取决于系统设置,可能会有所不同,因此您应该使用[GetSystemMetrics with SM_CXSMICON and SM_CYSMICON](https://msdn.microsoft.com/en-us/library/windows/desktop/ms724385(v = vs.85)的.aspx)。注释掉'lf.lfQuality'使其包含DEFAULT_QUALITY(0),这不一定意味着没有明文类型。无论如何,我已经编辑了我的原始答案,因为我的评论空间不足了。 – VTT

+0

任何机会的一些模板代码我修改,因为我不知道你的建议是什么?至于图标大小,这个应用程序已经运行了多年,从XP到W10使用当前的System Tray图标,我只是在运行时修改它,所以我认为我会保持它的当前大小。我也可以改变这一点,一旦这是32x32的工作。刚刚测试过:SM_CXICON = 32和SM_CXSMICON = 16。 – DDK

0

感谢所有来自VTT的帮助,否则我将无法获得这么多。这似乎对我有用。

void CreateNewIcon(HICON &hNewIcon, HICON hBackgroundIcon) 
{ 
    ::DestroyIcon(hNewIcon); 

    HDC hDc = ::GetDC(NULL); 
    HDC hMemDC = ::CreateCompatibleDC(hDc); 

    // Load up background icon 
    ICONINFO ii = { 0 }; 
    ::GetIconInfo(hBackgroundIcon, &ii); 

    HGDIOBJ hOldBmp = ::SelectObject(hMemDC, ii.hbmColor); 

    // Create font 
    LOGFONT lf = { 0 }; 
    lf.lfHeight = -20; 
    lf.lfWeight = FW_BOLD; 
    lf.lfOutPrecision = OUT_TT_PRECIS; 
    lf.lfQuality = ANTIALIASED_QUALITY; 
    wmemset(lf.lfFaceName, 0, LF_FACESIZE); 
    lstrcpy(lf.lfFaceName, L"Courier New"); 

    HFONT hFont = ::CreateFontIndirect(&lf); 
    HGDIOBJ hOldFont = ::SelectObject(hMemDC, hFont); 

    // Write text 
    ::SetBkMode(hMemDC, TRANSPARENT); 
    ::SetTextColor(hMemDC, RGB(255, 255, 0)); 
    ::TextOut(hMemDC, 0, 8, L"55", 2); 

    // Set up mask 
    HDC hMaskDC = ::CreateCompatibleDC(hDc); 
    HGDIOBJ hOldMaskBmp = ::SelectObject(hMaskDC, ii.hbmMask); 

    // Also write text on here 
    HGDIOBJ hOldMaskFont = ::SelectObject(hMaskDC, hFont); 
    ::SetBkMode(hMaskDC, TRANSPARENT); 
    ::SetTextColor(hMaskDC, RGB(255, 255, 0)); 
    ::TextOut(hMaskDC, 0, 8, L"55", 2); 

    // Get handle to create mask bitmap 
    HBITMAP hMaskBmp = (HBITMAP)::SelectObject(hMaskDC, hOldMaskBmp); 

    // Use new icon bitmap with text and new mask bitmap with text 
    ICONINFO ii2 = { 0 }; 
    ii2.fIcon = TRUE; 
    ii2.hbmMask = hMaskBmp; 
    ii2.hbmColor = ii.hbmColor; 

    // Create updated icon 
    hNewIcon = ::CreateIconIndirect(&ii2); 

    // Cleanup bitmap mask 
    ::DeleteObject(hMaskBmp); 
    ::DeleteDC(hMaskDC); 

    // Cleanup font 
    ::SelectObject(hMaskDC, hOldMaskFont); 
    ::SelectObject(hMemDC, hOldFont); 
    ::DeleteObject(hFont); 

    // Release background bitmap 
    ::SelectObject(hMemDC, hOldBmp); 

    // Delete background icon bitmap info 
    ::DeleteObject(ii.hbmColor); 
    ::DeleteObject(ii.hbmMask); 

    ::DeleteDC(hMemDC); 
    ::ReleaseDC(NULL, hDc); 
} 
相关问题