发现2个很奇怪的问题。procedure TForm1.FormCreate(Sender: TObject);
var
Icon: TIcon;
begin
Icon:= TIcon.Create;
Icon.LoadFromFile('D:\1.ico'); // 1.ico 尺寸为16x16
Memo1.Lines.Add( IntToStr( Icon.Width ) ); // 获取的Width为32 Self.Canvas.Draw(0,0,Icon); // 但如果执行过一次Canvas.Draw绘制,就可以正确获取到尺寸。
Memo1.Lines.Add( IntToStr( Icon.Width ) ); // 正确获取到Width=16
Icon.Free;
end;但在实际应有中,不可能去执行一次Draw,请问这个Bug有方法解决吗?---------------------------------
第2个问题
我在窗口上有一个弹出菜单,PopupMenu1,我想让它弹出时,向上弹出(类似Windows的开始菜单)。
我现在用的方法是获取菜单中每个Item的高度,然后计算坐标后,再Popup(X,Y);
获取弹出菜单的高度的函数如下,是我在网上找到的。
function GetPopMenuHeight(hWnd: THandle; PopupMenu: TPopupMenu): Integer;
var
I: Integer;
lprcRect: TRect;
begin
Result:= 0;
for I:= 0 to PopupMenu.Items.Count - 1 do begin
GetMenuItemRect(hWnd, PopupMenu.Handle, I, lprcRect);
Inc(Result, lprcRect.Bottom - lprcRect.Top);
end;
end;但这函数在菜单第一次弹出是,获取到的高度都是0,第二次弹出菜单时,获取到的高度才正确。
调试后,发现菜单第一次弹出是GetMenuItemRect函数获取到的结果是错误的。
能不能向大家请教下,用什么方法才能正确的获取到菜单的高度,或者说,有什么方法能实现向上弹出菜单。
var
Icon: TIcon;
begin
Icon:= TIcon.Create;
Icon.LoadFromFile('D:\1.ico'); // 1.ico 尺寸为16x16
Memo1.Lines.Add( IntToStr( Icon.Width ) ); // 获取的Width为32 Self.Canvas.Draw(0,0,Icon); // 但如果执行过一次Canvas.Draw绘制,就可以正确获取到尺寸。
Memo1.Lines.Add( IntToStr( Icon.Width ) ); // 正确获取到Width=16
Icon.Free;
end;但在实际应有中,不可能去执行一次Draw,请问这个Bug有方法解决吗?---------------------------------
第2个问题
我在窗口上有一个弹出菜单,PopupMenu1,我想让它弹出时,向上弹出(类似Windows的开始菜单)。
我现在用的方法是获取菜单中每个Item的高度,然后计算坐标后,再Popup(X,Y);
获取弹出菜单的高度的函数如下,是我在网上找到的。
function GetPopMenuHeight(hWnd: THandle; PopupMenu: TPopupMenu): Integer;
var
I: Integer;
lprcRect: TRect;
begin
Result:= 0;
for I:= 0 to PopupMenu.Items.Count - 1 do begin
GetMenuItemRect(hWnd, PopupMenu.Handle, I, lprcRect);
Inc(Result, lprcRect.Bottom - lprcRect.Top);
end;
end;但这函数在菜单第一次弹出是,获取到的高度都是0,第二次弹出菜单时,获取到的高度才正确。
调试后,发现菜单第一次弹出是GetMenuItemRect函数获取到的结果是错误的。
能不能向大家请教下,用什么方法才能正确的获取到菜单的高度,或者说,有什么方法能实现向上弹出菜单。
难道只有在绘制前,将Icon的Width和Height作为参数传入的方法吗?第二个问题的代码是这样的procedure TForm1.Button1MouseDown(Sender: TObject;
Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
lpPoint: TPoint;
MenuHeight: Integer;
begin
if Button = mbLeft then begin
lpPoint.X:= Button1.Left;
lpPoint.Y:= Button1.Top;
windows.ClientToScreen(Button1.Handle, lpPoint); // 转Button1的坐标为屏幕坐标 MenuHeight:= GetPopMenuHeight(Self.Handle, PopupMenu1); // 获取弹出菜单的高度(函数在首帖里)
PopupMenu1.Popup(lpPoint.X, lpPoint.Y - MenuHeight); // 弹出菜单,第一次弹出时,MenuHeight为0,但第二次就正确了。
end;
end;
重写消息处理函数
procedure WMContextMenu(var Message: TWMContextMenu); message
下面是实现。
procedure TForm1.WMContextMenu(var Message: TWMContextMenu);
begin
Message.Pos.y := Message.Pos.y - GetSystemMetrics(SM_CYMENU) * PopupMenu1.Items.Count;
inherited;
end;
procedure WMContextMenu(var Message: TWMContextMenu); message WM_CONTEXTMENU;
你的方法也不行呢,GetSystemMetrics(SM_CYMENU)只是获取了系统中一个MenuItem所占像素的高度,是固定的。刚才测了下,如果PopupMenu中的Item有关联图标,或有作为分隔符的Item(就是Item.Caption:= '-'),那获取到的高度就不再正确了。在 WM_CONTEXTMENU 消息中执行GetMenuItemRect函数,第一次仍旧返回错误结果,哎
var
AFlags: Integer;
x, y: Integer;
begin
x := Message.Pos.x;
y := Message.Pos.y;
AFlags := TPM_LEFTALIGN or TPM_BOTTOMALIGN; // 这个值你自己可以调,参考MSDN。
TrackPopupMenu(PopupMenu1.Handle, AFlags, x, y, 0, PopupList.Window, nil);
end;
function TIcon.GetHeight: Integer;
begin
Result := FImage.FSize.y;//载入文件后第一次使用时,它会返回0,这样得到的结果就不正确了
if Result = 0 then
Result := GetSystemMetrics(SM_CYICON)
end;解决办法,还是用API来取:
procedure TForm1.Button1Click(Sender: TObject);
var
Icon: TIcon;
IconInf: TIconInfo;
begin
Icon := TIcon.Create;
Icon.LoadFromFile('c:\1.ico '); // 1.ico 尺寸为16x16
GetIconInfo(Icon.Handle, IconInf); //使用API获取真正的尺寸
Memo1.Lines.Add(IntToStr(IconInf.xHotspot * 2)); //获取的Width为16
Self.Canvas.Draw(0, 0, Icon); // 但如果执行过一次Canvas.Draw绘制,就可以正确获取到尺寸。
Memo1.Lines.Add(IntToStr(Icon.Width)); // 正确获取到Width=16
Icon.Free;end;
var
Icon: TIcon;
IconInf: TIconInfo;
begin
Icon := TIcon.Create;
Icon.LoadFromFile( 'c:\1.ico '); // 1.ico 尺寸为16x16
GetIconInfo(Icon.Handle, IconInf); //使用API获取真正的尺寸
Memo1.Lines.Add(IntToStr(IconInf.xHotspot * 2)); //获取的Width为16
Self.Canvas.Draw(0, 0, Icon); // 但如果执行过一次Canvas.Draw绘制,就可以正确获取到尺寸。
Memo1.Lines.Add(IntToStr(Icon.Width)); // 正确获取到Width=16
Icon.Free;
DeleteObject(IconInf.hbmColor);
DeleteObject(IconInf.hbmMask);end;