如何从位图创建带透明(Alpha通道)的系统托盘数字图标?
修复系统托盘图标透明显示问题
你当前的代码存在两个核心问题导致透明失效:
- 32位DIB section的Alpha通道未初始化,默认像素Alpha值为255(完全不透明),导致文字外的区域显示为黑色背景
- 手动创建了单色掩码位图
hMaskBmp,系统会优先使用掩码而非Alpha通道处理透明,覆盖了Alpha效果
以下是修正后的代码:
function CreateHiColorIcon(DC: HDC; nWidth, nHeight: Integer; Status: Byte; Color: COLORREF): HICON; var lpbi: PBITMAPINFO; lpBits: Pointer; hBmp, hOldBitmap: HBITMAP; hMemDC: HDC; OldFnt, Fnt: HFONT; Sts: string; R: TRect; IconInfo: TIconInfo; Icon: HICON; PixelData: PRGBQuad; I: Integer; PixelCount: Integer; begin Result := 0; // 分配BITMAPINFO结构,32位无需调色板,仅需BITMAPINFOHEADER GetMem(lpbi, SizeOf(TBITMAPINFOHEADER)); try with lpbi^.bmiHeader do begin biSize := SizeOf(TBITMAPINFOHEADER); biWidth := nWidth; biHeight := nHeight; biPlanes := 1; biBitCount := 32; // 带Alpha通道的32位DIB biCompression := BI_RGB; biSizeImage := 0; biXPelsPerMeter := 0; biYPelsPerMeter := 0; biClrUsed := 0; biClrImportant := 0; end; hBmp := CreateDIBSection(DC, lpbi^, DIB_RGB_COLORS, lpBits, 0, 0); if hBmp = 0 then RaiseLastOSError; try // 初始化所有像素的Alpha通道为0(全透明) PixelCount := nWidth * nHeight; PixelData := lpBits; for I := 0 to PixelCount - 1 do begin PixelData^.rgbReserved := 0; // Alpha分量设为0 Inc(PixelData); end; hMemDC := CreateCompatibleDC(DC); if hMemDC = 0 then RaiseLastOSError; try hOldBitmap := SelectObject(hMemDC, hBmp); if hOldBitmap = 0 then RaiseLastOSError; try Sts := IntToStr(Status); Fnt := GetNCMFont; // 获取窗口标题字体 OldFnt := SelectObject(hMemDC, Fnt); R := TRect.Create(0, 0, nWidth, nHeight); SetBkMode(hMemDC, TRANSPARENT); SetTextColor(hMemDC, Color); // 绘制文字,文字区域的Alpha会被自动设为255(不透明) DrawTextEx(hMemDC, PWideChar(Sts), -1, R, DT_CENTER or DT_VCENTER or DT_SINGLELINE or DT_NOCLIP, nil); // 配置图标信息:依赖32位位图的Alpha通道实现透明 ZeroMemory(@IconInfo, SizeOf(TIconInfo)); IconInfo.fIcon := TRUE; IconInfo.hbmColor := hBmp; IconInfo.hbmMask := 0; // 无需手动设置掩码,系统自动从Alpha通道生成 Icon := CreateIconIndirect(IconInfo); if Icon = 0 then RaiseLastOSError; Result := Icon; finally SelectObject(hMemDC, hOldBitmap); SelectObject(hMemDC, OldFnt); DeleteObject(Fnt); end; finally DeleteDC(hMemDC); end; finally DeleteObject(hBmp); end; finally FreeMem(lpbi); end; end;
关键修改说明
- 初始化Alpha通道:创建DIB后遍历所有像素,将Alpha分量(
rgbReserved)设为0,确保文字以外的区域完全透明 - 移除手动掩码:不再创建单色掩码位图,将
IconInfo.hbmMask设为0,让系统优先使用32位位图的Alpha通道处理透明逻辑 - 简化内存分配:32位DIB不需要调色板,仅分配
BITMAPINFOHEADER的内存即可,减少不必要的内存开销
内容的提问来源于stack exchange,提问作者yonni
相关产品推荐
相关产品推荐

