gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-03 14:43:57 25 4
gpt4 key购买 nike

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

enter image description here

Delphi 包装 Win32 菜单系统的方式似乎排除了底层 Win32 API 提供的每种模式或标志,而这些模式或标志当时不在 VCL 作者的脑海中。一个这样的例子似乎是 TPM_BOTTOMALIGN ,它可以传递到 TrackPopupMenu 中,但是,Delphi 包装器似乎不仅在库存 VCL 中不可能实现这一点,而且由于不明智地使用私有(private)和 protected 方法,不可能(至少在我看来是不可能)在运行时准确地执行或通过覆盖执行。 VCL 组件 TPopupMenu 的设计也不是很好,因为它应该有一个名为 PrepareForTrackPopupMenu 的虚拟方法,该方法除了调用 TrackPopupMenuTrackPopupMenuEx,然后允许某人重写实际调用该 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) 中的其余步骤是我的调用所必需的应用程序绘制其菜单并使其看起来正确,但是如果没有邪恶的欺骗手段就不可能调用它们,因为它们是私有(private)方法。修改 VCL 是一个 hell 般的提议,我也不想接受它。

最佳答案

有点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 调用。

关于delphi - 如何排列 TPopupMenu 以使其准确地将自己定位在按钮上方?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16860642/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com