ボタンの上にポップアップメニューが欲しい:
Delphi は、その時点では VCL 作成者の頭になかった、基礎となる Win32 API が提供するすべてのモードまたはフラグを排除するように見える方法で、Win32 メニュー システムをラップします。そのような例の 1 つは、TPM_BOTTOMALIGN
which を渡すことができるよう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 call に到達するために渡してみてください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);
もちろん、popupEx は VCL にはありません。TrackPopupMenu
おそらく 1995 年にバージョン 1.0 で VCL 関係者が追加したものよりも多くのフラグを渡す方法はありません。
注: メニューを表示する前に高さを見積もるという問題は不可能だと思います。したがって、実際にはTrackPopupMenu
、高さを見積もらないことで問題を解決する必要があります。
更新: TrackPopupMenu
VCL メソッドの残りのステップは、アプリケーションがメニューをペイントして正しく表示されるようにするために呼び出す必要があるため、直接呼び出すことはできませんTPopupMenu.Popup(x,y)
が、プライベート メソッドであるため、邪悪な策略なしでそれらを呼び出すことは不可能です。 . VCL を変更することは地獄のような命題であり、私もそれを楽しませたくありません。