我想要一个按钮上方的弹出菜单:
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 是一个可怕的提议,我也不想接受。