2017-04-13 2 views
1

J'ai une application Windows MFC C++ (non gérée) qui utilise une icône "standard" dans la barre d'état système. Cette icône a été créée & modifiée à l'aide de Visual Studio et est de 32 x 32 pixels avec seulement 4 bits de couleur (en fonction de l'éditeur de ressources de VS).Comment maintenir la transparence lors de l'écriture de texte sur une icône de barre d'état système Windows à partir d'un programme C non géré

Avec Visual Studio, je définis également un arrière-plan transparent (affiché en blanc dans l'image «avant»).

Je souhaite changer dynamiquement l'icône en écrivant 2 chiffres (1-99) au-dessus. En utilisant le code ci-dessous (basé sur celui de cette question: How to draw text with transparency using GDI?) pour superposer "55" en jaune sur l'icône, cela fonctionne sauf que la transparence disparaît (elle apparaît en noir dans l'image "après" et sur la Plateau du système). Mon code diffère vraiment très légèrement en ce que la taille de police (20), le nom de police (Courier New), la couleur du texte (jaune - RVB (255, 255, 0)) et la valeur numérique (55) sont des variables d'exécution que les valeurs fixes.

Toutes les suggestions sur la façon de rendre l'arrière-plan restent transparentes dans la mesure où la zone de notification est reçue avec reconnaissance.

Ces images ont été capturées à l'aide de l'outil Coupure de MS avec l'image ouverte dans MS Paint, car une icône 32x32 ne serait pas très visible telle quelle.

Avant Image:

Before Image

Après l'image:

After image

code:

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); 
} 

Répondre

0

Il y a plusieurs problèmes avec notre code:

  • Vous tentez de dessiner du texte de qualité cleartype sur une partie d'icône transparente. Mais le rendu des polices cleartype doit être effectué sur un fond opaque car il doit inspecter la couleur de fond. Vous devez donc passer à la qualité Anitialiased (ou à la qualité anti-alias) ou fournir un arrière-plan opaque pour votre texte.
  • Lorsque vous créez hBmpMskyou skip it's content initialization by supplying NULL for bits pointer, l'icône résultant aura réellement une transparence complètement aléatoire. Vous devez remplir ce masque bitmat de manière appropriée.

De même, vous devez probablement passer à une profondeur de bits supérieure car le masque bitmap monochrome ne peut pas gérer les parties semi-transparentes du texte anti-aliasé.

mise à jour

Je pense que vous devez dessiner le texte ClearType mais avec un fond opaque, puis obtenir un rectangle de texte en utilisant quelque chose comme GetTextExtentPoint32, puis copiez les données du masque bitmap d'origine dans hBmpMsk puis enfin remplir blanc (texte) Rectangle sur elle donc la nouvelle icône préservera la transparence de l'original et aura un bloc de texte opaque.

+0

Avec une icône ce petit qualité (32x32), je ne ont pas besoin police de caractères claire et j'ai donc maintenant commentted à la fois « lf.lfOutPrecision » et « lf.lfQuality ». Mais comment puis-je "remplir correctement ce bitmap de masque"? – DDK

+0

En fait, la taille de l'icône de la barre d'état dépend des paramètres du système et peut varier. Vous devez donc récupérer les dimensions requises à l'aide de [GetSystemMetrics avec SM_CXSMICON et SM_CYSMICON] (https://msdn.microsoft.com/fr-fr/library/windows/desktop/ms724385 (v = vs.85) .aspx). Commenter 'lf.lfQuality' le fait contenir DEFAULT_QUALITY (0) ce qui ne signifie pas nécessairement cleartype. De toute façon, j'ai édité ma réponse originale parce que je manque d'espace de commentaire. – VTT

+0

Y a-t-il des chances pour que je modifie un code de modèle, car je ne suis pas sûr de ce que vous suggérez? En ce qui concerne la taille de l'icône, cette application a fonctionné pendant des années de XP à W10 avec l'icône actuelle de la barre d'état système et je la modifie juste au moment de l'exécution et je pense que je resterai avec sa taille actuelle. Je peux aussi chercher à changer cela une fois que cela fonctionne pour 32x32. Juste testé: SM_CXICON = 32 et SM_CXSMICON = 16. – DDK

0

Merci pour toute l'aide de VTT sans laquelle je n'aurais pas pu aller aussi loin. Cela semble fonctionner pour moi.

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); 
}