如何排列 TPopupMenu 以使其准确地将自己定位在按钮上方?

2023-11-24

我想要一个按钮上方的弹出菜单:

enter image description here

Delphi 包装 Win32 菜单系统的方式似乎排除了底层 Win32 API 提供的每种模式或标志,而这些模式或标志当时并没有出现在 VCL 作者的脑海中。一个这样的例子似乎是TPM_BOTTOMALIGN可以传递到TrackPopupMenu但是,Delphi 包装器似乎不仅在库存 VCL 中不可能做到这一点,而且通过不明智地使用私有和受保护的方法,不可能(至少在我看来不可能)在运行时或通过覆盖准确地做到这一点。 VCL 组件 TPopupMenu 的设计也不是很好,因为它应该有一个名为PrepareForTrackPopupMenu除了调用之外,它还做了所有事情TrackPopupMenu or TrackPopupMenuEx,然后允许某人重写实际调用该 Win32 方法的方法。但现在已经太晚了。也许 Delphi XE5 将正确完成 Win32 API 的基本覆盖。

我尝试过的方法:

方法 A:使用指标或字体:

准确确定弹出菜单的高度,以便我可以在调用 popupmenu.Popup(x,y) 之前减去 Y 值。结果:必须处理 Windows 主题的所有变体,并做出我似乎无法确定的假设。在现实世界中似乎不太可能产生好的结果。以下是基本字体度量方法的示例:

   height := aPopupMenu.items.count * (abs(font.height) + 6) + 34;

您可以考虑隐藏项目,并且对于具有有效的单一主题模式设置的单一版本的窗口,您可能会像这样接近,但并不完全正确。

方法 B:让 Windows 来做:

尝试传入TPM_BOTTOMALIGN最终达到Win32 API调用TrackPopupMenu.

到目前为止,我想我可以做到,如果我修改VCL menus.pas..我在这个项目中使用Delphi 2007。不过我对这个想法不太高兴。

这是我正在尝试的代码:

procedure TMyForm.ButtonClick(Sender: TObject);
var
  pt:TPoint;
  popupMenuHeightEstimate:Integer;
begin
   // alas, how to do this accurately, what with themes, and the OnMeasureItem event
   // changing things at runtime.
      popupMenuHeightEstimate := PopupMenuHeight(BookingsPopupMenu); 

      pt.X := 0;
      pt.Y := -1*popupMenuHeightEstimate;
      pt := aButton.ClientToScreen(pt);  // do the math for me.
      aPopupMenu.popup( pt.X, pt.Y );

end;

或者我想这样做:

  pt.X := 0;
  pt.Y := 0;
  pt := aButton.ClientToScreen(pt);  // do the math for me.
  aPopupMenu.popupEx( pt.X, pt.Y, TPM_BOTTOMALIGN);

当然,VCL中没有popupEx。也没有办法传递更多 标记为TrackPopupMenu比那些 VCL 人员可能在 1995 年添加的那些, 在1.0版本中。

注意:我相信在显示菜单之前估计高度的问题是不可能的,因此我们实际上应该通过以下方式解决问题TrackPopupMenu不是通过估计高度。

更新:打电话TrackPopupMenu直接不行,因为VCL方法中的其余步骤TPopupMenu.Popup(x,y)有必要调用我的应用程序来绘制其菜单并使其看起来正确,但是如果没有邪恶的欺骗手段就不可能调用它们,因为它们是私有方法。修改 VCL 是一个可怕的提议,我也不想接受。


有点hacky,但它可能会解决它。

为 TPopupMenu 重写 Popup 声明一个拦截器类:

type
  TPopupMenu = class(Vcl.Menus.TPopupMenu)
  public
    procedure Popup(X, Y: Integer); override;
  end;

procedure TPopupMenu.Popup(X, Y: Integer);
const
  Flags: array[Boolean, TPopupAlignment] of Word =
    ((TPM_LEFTALIGN, TPM_RIGHTALIGN, TPM_CENTERALIGN),
     (TPM_RIGHTALIGN, TPM_LEFTALIGN, TPM_CENTERALIGN));
  Buttons: array[TTrackButton] of Word = (TPM_RIGHTBUTTON, TPM_LEFTBUTTON);
var
  AFlags: Integer;
begin
  PostMessage(PopupList.Window, WM_CANCELMODE, 0, 0);
  inherited;
  AFlags := Flags[UseRightToLeftAlignment, Alignment] or
    Buttons[TrackButton] or
    TPM_BOTTOMALIGN or
    (Byte(MenuAnimation) shl 10);
  TrackPopupMenu(Items.Handle, AFlags, X, Y, 0 { reserved }, PopupList.Window, nil);
end;

诀窍是向菜单窗口发布一条取消消息,以取消继承的 TrackPopupMenu 调用。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何排列 TPopupMenu 以使其准确地将自己定位在按钮上方? 的相关文章

随机推荐

  • 在 Dask 中排序

    我想找到替代方案pandas dataframe sort value在 dask 中运行 我走过来了设置索引 但它会按单个列排序 如何对 Dask 数据框的多列进行排序 目前为止Dask似乎还不支持多列排序 但是 创建一个新列来连接已排序
  • 找不到文件:mainwindow.obj

    我创建了一个 GUI 应用程序 gt QMainWindow 我在菜单 插槽中添加了 1 项 我创建了一个新项目 gt QDialog 我使用插槽方法尝试显示创建的对话框 但出现以下错误 mainwindow obj 1 错误 LNK201
  • 有没有办法了解“平台”访问网页的硬件资源?

    我希望能够从网页中了解浏览器的硬件资源 或者至少是一个粗略的估计 即使您检测到现代技术的存在 例如csstransforms3d csstransitions requestAnimationFrame 在浏览器中通过类似的工具Modern
  • Python,多线程太慢,多进程

    我是多处理新手 我了解一些有关线程的知识 但我需要提高计算速度 希望通过多重处理 示例说明 将字符串发送到线程 更改字符串 基准测试 将结果发回打印 from threading import Thread class Alter Thre
  • 将多维Json数组解析为Python

    我第一次尝试解析 JSON 并处理多维数组 这让我不知所措 secret Hidden minutes 20 link http www 1 com bookmark collection free link name free link
  • 在 Guice 中绑定,无需

    我有个问题 通常在Guice中我使用bind class to 另一个类实现 但是我在代码源中发现他们仅使用了bind class 没有 to another class Implementation 部分 这是什么意思 bind clas
  • 如何用关系代数求 MAX?

    使用数据库时 如何使用关系代数求 MAX 假设您有一个关系 A 具有单个属性 a 减少一个更复杂的关系是关系代数中的一个简单任务 我确信您已经做到了这一点 所以现在您想要找到最大值A 中的值 一种方法是找到 A 与其自身的叉积 请务必重命名
  • 从定期异步请求创建 observable

    我想要一种将异步方法转换为可观察方法的通用方法 就我而言 我正在处理使用的方法HttpClient从 API 获取数据 假设我们有方法Task
  • 为什么在 Ruby 中应该避免使用 then 关键字?

    一些 Ruby 风格指南中提到 您应该 永远不要使用 就我个人而言 我认为 then 关键字可以使代码更密集 这往往更难阅读 这个建议还有其他理由吗 我几乎从不使用then关键词 然而 有一种情况我认为它极大地提高了可读性 考虑以下多条件
  • 除了 new object() 之外,还有什么理由要锁定其他东西吗?

    object theLock new object lock theLock 我总是用一个new object 为此 但我想知道 是否有任何情况下您会锁定更具体的类型 在我看来 任何引用类型都可以被锁定 使用虚拟对象的原因是为了避免常见的锁
  • Angular2 - 如何使用具有动态 url 的路由器

    假设我有一个嵌套的 itemListComponent 它是 rootComponent 的子组件 使用以下模板 span a item title a span 由 Json 服务提供的路径 item url 可能具有以下路径结构之一 c
  • 将解决方案应用于实际数据时结果不正确

    我尝试将此问题中提供的解决方案应用于我的真实数据 选择多索引数据框中的行 不知怎的 我无法得到它应该给出的结果 我已附上可供选择的数据框以及结果 我需要的 应返回第 3 11 和 12 行 当您连续添加 4 列时 也应选择 12 现在不是
  • Heroku 可以使用哪些级别的日志记录?

    我有一个在 Heroku 上运行的 Rails 应用程序 它运行良好 我让它以调试级别日志记录运行 但现在我切换回 INFO 还有哪些其他级别的调试可用 当运行生产时 我应该使用什么级别的日志记录 在 Heroku 上 您可以使用 LOG
  • 为什么我无法运行我的 Node.js Express Web 应用程序

    Node js 和 Express 生成器确实非常方便且易于理解 但是 我无法通过运行 c my application root gt DEBUG my application bin www 来启动我的服务器 Windows 似乎不理解
  • 找不到 matplotlib 数据文件

    我是 python 新手 我正在尝试使用 pyinstaller 从 py 脚本创建 exe 但在尝试运行 exe 时出现此错误 无法找到 matplotlib 数据文件 当我在 python 空闲中运行脚本时 我没有收到此错误 我试过了
  • Eclipse CDT Indexer 不能完全识别 c++11

    首先 我了解用于启用 c 11 支持的 std c 11 标志及其放置位置 我已附加 std c 11 to Project gt Properties gt C C Build gt Settings gt Tool Settings g
  • Internet Explorer-10 websocket 中的 IPv6 地址给出语法错误

    我从服务器获取 ipv6 地址 然后我为 websocket 创建 url 我的网址看起来 喜欢 ws xxxx xxxx xxxx xxxx xxxx xxxx 十进制端口 其中 x 十六进制的 0 f 这个网址在 chrome 和 fi
  • $_SERVER["REMOTE_ADDR"] 提供服务器 IP 而不是访问者 IP

    我正在尝试跟踪访问者的 IP 地址 使用时 SERVER REMOTE ADDR 我得到的是服务器的IP地址而不是访问者的IP地址 我在多个位置的多台机器上进行了尝试 它们都产生了完全相同的 IP 是否有一些 PHP 服务器设置可能会影响这
  • Ruby 中的有符号和无符号整数

    像 C 一样 Ruby 是否有有符号和无符号整数 如果有的话 是否意味着 String 类的 length 方法返回有符号整数 因为在 C 整数中 如果未指定则意味着有符号 Ruby 实现整数的方式使得有符号 无符号的区别无关紧要 因为 R
  • 如何排列 TPopupMenu 以使其准确地将自己定位在按钮上方?

    我想要一个按钮上方的弹出菜单 Delphi 包装 Win32 菜单系统的方式似乎排除了底层 Win32 API 提供的每种模式或标志 而这些模式或标志当时并没有出现在 VCL 作者的脑海中 一个这样的例子似乎是TPM BOTTOMALIGN