如何使用 Windows API 将菜单背景渐变复制或复制到位图上?
How to copy or reproduce the menu background gradient onto a bitmap using the Windows API?
我正在尝试(未成功)copy/reproduce Windows 菜单栏的背景渐变到位图上。
在下面的 IconToBitmap 函数中,FillRect(一厢情愿)使用 GetSysColorBrush(COLOR_MENU) 试图让它按照 Windows 中的方式绘制菜单背景(不出所料,画笔不是渐变,但值得一试。)
下面的 BitBlt 是 "cheat" 的尝试。抓住一部分已经绘制的菜单栏并使用它。这也不起作用,我怀疑原因可能是因为在主 window 的 WM_CREATE 期间调用了函数 IconToBitmap (我不确定菜单栏是否存在于 window 创建。)在 window 首次可见之前我确实需要背景,这就是在处理 WM_CREATE 时调用该函数的原因(但在 [=36= 之前工作的任何其他方式) ]可见即完美。)
在这一点上,我没主意了。
如果有人知道如何抓取该菜单背景或在位图上复制它,那就太好了。
谢谢。
PS:函数中的硬编码值将在最终工作版本中删除(希望会有一个。)此外,对于 Delphi,数据类型 ptrint 必须更改为NativeInt.
function IconToBitmap(Wnd : HWND; Icon : HICON) : HBITMAP;
var
Bitmap : HBITMAP;
BitmapDc : HDC;
BitmapRect : TRECT;
OldBitmap : HBITMAP;
dc : HDC;
MenuHeight : ptrint;
MenuY : ptrint;
WindowDc : HDC;
begin
Bitmap := 0;
BitmapDc := 0;
OldBitmap := 0;
dc := 0;
MenuY := 0;
MenuHeight := 0;
WindowDc := 0;
MenuY := GetSystemMetrics(SM_CYSIZEFRAME) +
GetSystemMetrics(SM_CYCAPTION);
MenuHeight := GetSystemMetrics(SM_CYMENUSIZE);
WindowDc := GetWindowDC(Wnd);
dc := GetDC(0);
BitmapDc := CreateCompatibleDC(dc);
Bitmap := CreateCompatibleBitmap(dc, 16, 16);
OldBitmap := SelectObject(BitmapDc, Bitmap);
with BitmapRect do
begin
Left := 0;
Top := 0;
Right := 16;
Bottom := 16;
end;
FillRect(BitmapDc, BitmapRect, GetSysColorBrush(COLOR_MENU));
BitBlt(BitmapDc, 0, 0, 16, 16, WindowDc, 20, MenuY, SRCCOPY);
DrawIconEx(BitmapDc,
0,
0,
Icon,
16,
16,
0,
0,
DI_NORMAL);
SelectObject(BitmapDc, OldBitmap);
DeleteDC(BitmapDc);
ReleaseDC(0, dc);
IconToBitmap := Bitmap;
end;
使用visual styles API绘制主题部分。下面的示例在窗体的客户区顶部绘制了一个菜单栏背景。您可以调整它以绘制到位图 canvas.
uses
uxtheme, types;
procedure TForm1.FormPaint(Sender: TObject);
var
Theme: HTHEME;
Size: TSize;
Rect: TRect;
begin
Theme := OpenThemeData(Handle, VSCLASS_MENU);
GetThemePartSize(Theme, Canvas.Handle, MENU_BARBACKGROUND, MB_ACTIVE, nil,
TS_TRUE, Size);
Rect.Create(0, 0, ClientWidth, Size.cy);
DrawThemeBackground(Theme, Canvas.Handle, MENU_BARBACKGROUND, MB_ACTIVE,
Rect, nil);
CloseThemeData(Theme);
end;
在 WM_PAINT
处理程序中,这可能如下所示。
procedure TForm1.WMPaint(var Message: TWMPaint);
var
DC: HDC;
PS: TPaintStruct;
Theme: HTHEME;
Size: TSize;
Rect: TRect;
begin
if Message.DC = 0 then
DC := BeginPaint(Handle, PS)
else
DC := Message.DC;
Theme := OpenThemeData(Handle, VSCLASS_MENU);
GetThemePartSize(Theme, DC, MENU_BARBACKGROUND, MB_ACTIVE, nil,
TS_TRUE, Size);
Rect.Create(0, 0, ClientWidth, Size.cy);
DrawThemeBackground(Theme, DC, MENU_BARBACKGROUND, MB_ACTIVE,
Rect, nil);
CloseThemeData(Theme);
if Message.DC = 0 then begin
Message.DC := DC;
inherited;
EndPaint(Handle, PS);
end else
inherited;
end;
我正在尝试(未成功)copy/reproduce Windows 菜单栏的背景渐变到位图上。
在下面的 IconToBitmap 函数中,FillRect(一厢情愿)使用 GetSysColorBrush(COLOR_MENU) 试图让它按照 Windows 中的方式绘制菜单背景(不出所料,画笔不是渐变,但值得一试。)
下面的 BitBlt 是 "cheat" 的尝试。抓住一部分已经绘制的菜单栏并使用它。这也不起作用,我怀疑原因可能是因为在主 window 的 WM_CREATE 期间调用了函数 IconToBitmap (我不确定菜单栏是否存在于 window 创建。)在 window 首次可见之前我确实需要背景,这就是在处理 WM_CREATE 时调用该函数的原因(但在 [=36= 之前工作的任何其他方式) ]可见即完美。)
在这一点上,我没主意了。
如果有人知道如何抓取该菜单背景或在位图上复制它,那就太好了。
谢谢。
PS:函数中的硬编码值将在最终工作版本中删除(希望会有一个。)此外,对于 Delphi,数据类型 ptrint 必须更改为NativeInt.
function IconToBitmap(Wnd : HWND; Icon : HICON) : HBITMAP;
var
Bitmap : HBITMAP;
BitmapDc : HDC;
BitmapRect : TRECT;
OldBitmap : HBITMAP;
dc : HDC;
MenuHeight : ptrint;
MenuY : ptrint;
WindowDc : HDC;
begin
Bitmap := 0;
BitmapDc := 0;
OldBitmap := 0;
dc := 0;
MenuY := 0;
MenuHeight := 0;
WindowDc := 0;
MenuY := GetSystemMetrics(SM_CYSIZEFRAME) +
GetSystemMetrics(SM_CYCAPTION);
MenuHeight := GetSystemMetrics(SM_CYMENUSIZE);
WindowDc := GetWindowDC(Wnd);
dc := GetDC(0);
BitmapDc := CreateCompatibleDC(dc);
Bitmap := CreateCompatibleBitmap(dc, 16, 16);
OldBitmap := SelectObject(BitmapDc, Bitmap);
with BitmapRect do
begin
Left := 0;
Top := 0;
Right := 16;
Bottom := 16;
end;
FillRect(BitmapDc, BitmapRect, GetSysColorBrush(COLOR_MENU));
BitBlt(BitmapDc, 0, 0, 16, 16, WindowDc, 20, MenuY, SRCCOPY);
DrawIconEx(BitmapDc,
0,
0,
Icon,
16,
16,
0,
0,
DI_NORMAL);
SelectObject(BitmapDc, OldBitmap);
DeleteDC(BitmapDc);
ReleaseDC(0, dc);
IconToBitmap := Bitmap;
end;
使用visual styles API绘制主题部分。下面的示例在窗体的客户区顶部绘制了一个菜单栏背景。您可以调整它以绘制到位图 canvas.
uses
uxtheme, types;
procedure TForm1.FormPaint(Sender: TObject);
var
Theme: HTHEME;
Size: TSize;
Rect: TRect;
begin
Theme := OpenThemeData(Handle, VSCLASS_MENU);
GetThemePartSize(Theme, Canvas.Handle, MENU_BARBACKGROUND, MB_ACTIVE, nil,
TS_TRUE, Size);
Rect.Create(0, 0, ClientWidth, Size.cy);
DrawThemeBackground(Theme, Canvas.Handle, MENU_BARBACKGROUND, MB_ACTIVE,
Rect, nil);
CloseThemeData(Theme);
end;
在 WM_PAINT
处理程序中,这可能如下所示。
procedure TForm1.WMPaint(var Message: TWMPaint);
var
DC: HDC;
PS: TPaintStruct;
Theme: HTHEME;
Size: TSize;
Rect: TRect;
begin
if Message.DC = 0 then
DC := BeginPaint(Handle, PS)
else
DC := Message.DC;
Theme := OpenThemeData(Handle, VSCLASS_MENU);
GetThemePartSize(Theme, DC, MENU_BARBACKGROUND, MB_ACTIVE, nil,
TS_TRUE, Size);
Rect.Create(0, 0, ClientWidth, Size.cy);
DrawThemeBackground(Theme, DC, MENU_BARBACKGROUND, MB_ACTIVE,
Rect, nil);
CloseThemeData(Theme);
if Message.DC = 0 then begin
Message.DC := DC;
inherited;
EndPaint(Handle, PS);
end else
inherited;
end;