2017-04-13 40 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); 
} 
相關問題