我想让一个按钮上方弹出一个弹出菜单:
Delphi 将 Win32 菜单系统包装起来,以一种方式似乎排除了每种模式或标志,这些模式或标志在底层 Win32 API 中提供,但不在 VCL 作者的大脑中。其中一个例子似乎是 TPM_BOTTOMALIGN,它可以传递到 TrackPopupMenu,但 Delphi 包装器似乎不仅在股票 VCL 中无法实现这一点,而且通过不慎使用私有和受保护的方法,在运行时或重写方面都是不可能的(至少对我来说似乎是不可能的)。VCL 组件 TPopupMenu 的设计也不太好,因为它应该有一个名为 PrepareForTrackPopupMenu 的虚拟方法,该方法除了调用 TrackPopupMenu 或 TrackPopupMenuEx 外其他都做了,然后允许某人覆盖实际调用该 Win32 方法的方法。但现在为时已晚。也许 Delphi XE5 会正确地完成 Win32 API 的基本覆盖率。
我尝试过的方法:
方法 A:使用 METRICS 或字体:
精确确定弹出菜单的高度,以便在调用 popupmenu.Popup(x,y) 之前减去 Y 值。结果:必须处理所有变量的 Windows 主题,并做出我似乎无法确定的假设。在现实世界中似乎不太可能产生良好的结果。这是一个基本字体度量方法的示例:
您可以考虑隐藏的项目,对于一个单一版本的Windows,并且只有一个主题模式设置生效,您可能会接近这样的效果,但不是完全正确的。
方法B:让Windows来完成:
尝试传递`TPM_BOTTOMALIGN`以最终到达Win32 API调用`TrackPopupMenu`。
到目前为止,我认为如果修改VCL menus.pas,我就可以做到。在这个项目中,我使用的是Delphi 2007。但我对这个想法并不是很满意。
这是我正在尝试的代码类型:
当然,在VCL中没有popupEx。也没有任何方法可以传递比那些VCL人员在1995年版本1.0中添加的更多标志到TrackPopupMenu中。注意:我认为在显示菜单之前估算高度的问题是不可能的,因此我们实际上应该通过TrackPopupMenu解决问题,而不是估算高度。更新:直接调用TrackPopupMenu无法正常工作,因为需要调用VCL方法TPopupMenu.Popup(x,y)中的其他步骤,以便我的应用程序可以绘制其菜单并使其看起来正确,但是不可能在没有恶意策略的情况下调用它们,因为它们是私有方法。修改VCL是一个非常困难的任务,我也不希望考虑这个方案。
Delphi 将 Win32 菜单系统包装起来,以一种方式似乎排除了每种模式或标志,这些模式或标志在底层 Win32 API 中提供,但不在 VCL 作者的大脑中。其中一个例子似乎是 TPM_BOTTOMALIGN,它可以传递到 TrackPopupMenu,但 Delphi 包装器似乎不仅在股票 VCL 中无法实现这一点,而且通过不慎使用私有和受保护的方法,在运行时或重写方面都是不可能的(至少对我来说似乎是不可能的)。VCL 组件 TPopupMenu 的设计也不太好,因为它应该有一个名为 PrepareForTrackPopupMenu 的虚拟方法,该方法除了调用 TrackPopupMenu 或 TrackPopupMenuEx 外其他都做了,然后允许某人覆盖实际调用该 Win32 方法的方法。但现在为时已晚。也许 Delphi XE5 会正确地完成 Win32 API 的基本覆盖率。
我尝试过的方法:
方法 A:使用 METRICS 或字体:
精确确定弹出菜单的高度,以便在调用 popupmenu.Popup(x,y) 之前减去 Y 值。结果:必须处理所有变量的 Windows 主题,并做出我似乎无法确定的假设。在现实世界中似乎不太可能产生良好的结果。这是一个基本字体度量方法的示例:
height := aPopupMenu.items.count * (abs(font.height) + 6) + 34;
您可以考虑隐藏的项目,对于一个单一版本的Windows,并且只有一个主题模式设置生效,您可能会接近这样的效果,但不是完全正确的。
方法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。也没有任何方法可以传递比那些VCL人员在1995年版本1.0中添加的更多标志到TrackPopupMenu中。注意:我认为在显示菜单之前估算高度的问题是不可能的,因此我们实际上应该通过TrackPopupMenu解决问题,而不是估算高度。更新:直接调用TrackPopupMenu无法正常工作,因为需要调用VCL方法TPopupMenu.Popup(x,y)中的其他步骤,以便我的应用程序可以绘制其菜单并使其看起来正确,但是不可能在没有恶意策略的情况下调用它们,因为它们是私有方法。修改VCL是一个非常困难的任务,我也不希望考虑这个方案。
TPopupMenu
定位在按钮上方,并使用x
和y
坐标以及适当的标志和菜单句柄来跟踪弹出菜单,这正是TrackPopupMenu
为您提供的功能。您的要求缺少哪些功能? - Ken WhiteSelf
。这使得绕过VCL设计决策变得更加容易。 - Marjan Venema