首页 新闻 论坛 群组 Blog 文档 下载 读书 Tag 网摘 搜索 .NET Java 游戏 视频 人才 外包 培训 数据库 书店 程序员
中国软件网
欢迎您:游客 | 登录 注册 帮助
  • [提问]Icon.LoadFromFile()后,Icon.width不正确;PopupMenu第一次弹出时,用GetMenuItemRect函数获取高度不正确。 [已结贴,结贴人:slxx0712]
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2007-11-01 15:50:46 楼主
    发现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函数获取到的结果是错误的。
    能不能向大家请教下,用什么方法才能正确的获取到菜单的高度,或者说,有什么方法能实现向上弹出菜单。


    100  修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2007-11-01 16:10:321楼 得分:0
    第一个问题可能是你已经把1.ico读进去了,但是并没有画出来,所以取出来的还是刚创建时的尺寸(默认32)

    第二个没看出什么问题
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2007-11-01 16:43:182楼 得分:0
    因为我需要将Icon绘制在另一张Bitmap上,而绘制的坐标X,Y是需要根据Icon的Width,Height来定的,所以需要在绘制前读取Icon的Width,Height.
    难道只有在绘制前,将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;
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2007-11-01 17:04:343楼 得分:0
    第二个问题:
    重写消息处理函数
      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;
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2007-11-01 17:05:394楼 得分:0
    丢了点东西,补上 
    procedure WMContextMenu(var Message: TWMContextMenu); message  WM_CONTEXTMENU;
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2007-11-01 18:09:215楼 得分:0
    to: jwpl190
    你的方法也不行呢,GetSystemMetrics(SM_CYMENU)只是获取了系统中一个MenuItem所占像素的高度,是固定的。

    刚才测了下,如果PopupMenu中的Item有关联图标,或有作为分隔符的Item(就是Item.Caption:= '-'),那获取到的高度就不再正确了。

    在 WM_CONTEXTMENU 消息中执行GetMenuItemRect函数,第一次仍旧返回错误结果,哎。。。
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2007-11-01 21:10:556楼 得分:50
    我再改! 看来关键时刻还是WIN32 SDK 基础啊。

    procedure TFMenu.WMContextMenu(var Message: TWMContextMenu);
    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;
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2007-11-02 11:23:577楼 得分:0
    一会再弄,呵呵,中午吃饭先~~~
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2007-11-02 12:44:068楼 得分:0
    还好了,呵呵,终于搞定了,谢谢jwpl190,我之前也试过用 TrackPopupMenu但没试成功,^_^,万分感谢。

    关于Icon.loadfromfile后,在没被绘制前,获取width和height是错误的问题有人能帮忙下吗?
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • xzhifei
    • 等级:
    发表于:2007-11-02 16:31:379楼 得分:50
    看了一下TIcon的源码,发现果然有问题:
    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;
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    发表于:2007-11-02 16:41:3710楼 得分:0
    谢谢 xzhifei, 呵呵,终于都解决了~~

    给分,结贴~~
    修改 删除 举报 引用 回复
    进入用户个人空间
    加为好友
    发送私信
    在线聊天
    • xzhifei
    • 等级:
    发表于:2007-11-02 16:46:1911楼 得分:0
    刚才忘记释放了,加了两行

    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;
        DeleteObject(IconInf.hbmColor);
        DeleteObject(IconInf.hbmMask);

    end;
    修改 删除 举报 引用 回复

    网站简介广告服务网站地图帮助联系方式诚聘英才English 问题报告
    北京创新乐知广告有限公司 版权所有 京 ICP 证 070598 号
    世纪乐知(北京)网络技术有限公司 提供技术支持
    Copyright © 2000-2008, CSDN.NET, All Rights Reserved