7

私は非常に奇妙なことに気づきました。フォームを閉じるときに上、左、幅、高さのプロパティを保持し、この情報を使用して、以前に保存された情報を使用して SetBounds を呼び出すことにより、フォームが再び開かれたときにフォームの最後の位置を復元します。これはうまく機能しますが、フォームの Position プロパティが設計時に poDefault に設定されている場合に限られます。poDesigned、poScreenCenter、poMainFormCenter などの別の値に設定した場合、SetBounds はフォームの以前の位置とサイズを復元しません。

ここが奇妙な部分です。問題のように見えるのは、設計時に Position プロパティが何に設定されているかです。実行時にこのプロパティの値を poDefault に変更できますが、SetBounds の呼び出しはまだ正しく機能しません。私は次のようなものを試しました

if Self.Position <> poDefault then
  Self.Position := poDefault;

フォームの OnCreate イベント ハンドラーとオーバーライドされたコンストラクターの両方で (コンストラクターで Position を poDefault に設定し、OnCreate イベント ハンドラーで SetBounds を呼び出しました)。いずれの場合も、実行時にフォームの Position プロパティを poDefault に変更しても、SetBounds で確認した問題は修正されません。私が見つけた唯一の一貫したパターンは、フォームの Position プロパティが設計時に poDefault であった場合にのみ SetBounds が機能することです。

設計時にフォームの Position プロパティが poDefault に設定されていない場合に SetBounds がどのように機能するかに関して、私が気付いたことが他にもあります。たとえば、設計時に Position プロパティが poScreenCenter に設定されているフォームは、SetBounds を呼び出した場合、画面の中央に表示されるとは限りません。ただし、SetBounds で定義された左上の位置には表示されず、SetBounds の呼び出しで指定された幅と高さも考慮されません。ただし、SetBounds を呼び出す前に、フォームの Position プロパティを poDefault に設定していることを繰り返しましょう。2 つの操作の間に Application.ProcessMessages への呼び出しをスタックしましたが、それでも問題は解決しません。

Windows 10 で実行されている Delphi 10.1 Berlin でこれを広範囲にテストしました。また、Windows 7 で Delphi XE6 を使用してテストしました。同じ結果です。

疑問がある場合は、4 つのフォームを含む VCL アプリケーションを作成してください。最初のフォームに 3 つのボタンを配置し、各ボタンに次の OnClick のようなものを追加します。

 with TForm2.Create(nil) do
 try
   ShowModal;
 finally
   Release;
 end;

ここで、コンストラクターは TForm2 を作成し、次に TForm3 と TForm4 を作成します。

フォーム 2 ~ 4 の OnCreate で、次のコードを追加します。

if Self.Position <> poDefault then
  Self.Position := poDefault;
Self.SetBounds(500,500,500,500);

form2 では Position を poDefault に設定し、form3 では Position を poScreenCenter に設定し、form4 では Position をデフォルトの poDefaultPosOnly に設定したままにします。form2 のみが 500, 500 に表示され、幅は 500、高さは 500 です。

誰かがこの結果の論理的な説明を持っていますか?

4

1 に答える 1

4

poDefaultそして友人は、「フォームが作成して表示するときに、 Microsoft Windows がこのフォームのウィンドウを配置できるようにする」ことを意味します。

HWNDDelphi オブジェクトを作成したばかりですが、Windows オブジェクト (ハンドルおよび対応するすべての Windows 内部構造)も作成/表示されているのではないかと思います。特に、XP より前の標準的なルック アンド フィールを使用するアプリケーションではなく、テーマ付きアプリケーションの場合は、ReCreateHWND表示するときにそうなる傾向があります。これらの凝った Windows テーマのプリロードは比較的コストのかかる操作であり、必要な場合にのみ実行する必要があるためです。

あなたのデフォルトの境界(コンストラクターで設定されたすべてのプロパティ値は、デフォルトの調整されていない値と見なされる可能性があり、オブジェクトが構築された後に後で調整される可能性があります)はTApplication、最終的に(またはトピックにほとんど違いをもたらさない)ときに正しく無視されると思いますFormXXX.Show.

フォームがそのプロパティを見て、MS Windowsに「内部HWNDオブジェクトを作成し、それをデフォルトの座標/サイズで自由に配置したい」のようなことを伝えるのは、「ウィンドウを作成して表示する」シーケンス中です。 .

そして、それは絶対に正しい動作です-そうでなければ、いつ、どのTFormようにプロパティを適用できますPositionか??? 画面上にまだ存在しないウィンドウの座標を Windows に要求しても意味がありません。Windows は、尋ねられたまさにその秒のデフォルトの座標/サイズを提供し、他にいくつのウィンドウがあり、それらがどこに配置されているかを調べます (AMD/NVidia ビデオ ドライバーもそれに修正を適用する場合があります)。

今すぐデフォルトを取得し、2 時間後にすべてが異なる場合に適用するのはほとんど意味がありません。たとえば、他のウィンドウの数と位置が異なり、接続されているモニターのセットが異なり、解像度が異なるなどです。

「デスクトップの置き換え」タイプのノートブックを検討してください。固定式の大型外部モニターに接続されたテーブルに設置されました。それから - 想像してみましょう - 私はあなたのアプリケーションを実行し、tform Delphi オブジェクトを作成し、コンストラクターで MS Windows に位置を要求しました。しかし、それから 1 時間後、私はノートブックのプラグを抜き、それを持って立ち去りました。1 時間後、フォームを表示するようにアプリケーションに指示すると、アプリケーションは何をするのでしょうか? 取り外された外部ディスプレイに属する座標で表示しますか? 現時点でしか持っていないノートブックの内部ディスプレイのビューポートの外ですか? このフォームを「非表示」に表示する必要があります 私がアプリケーションを起動したとき、そのスポットがまだそこにまだ見えていたという理由だけで位置を変えましたか??? 無駄にユーザーを混乱させる方法だと思います。

したがって、唯一の正しい動作は、フォームが非表示から表示に切り替わるときに、1 秒前ではなく、この 1 秒前に Windows にデフォルトの座標を要求することです。

つまり、フォームを移動したい場合は、フォームが表示された後に移動する必要があります。イベント ハンドラに配置Self.SetBounds(500,500,500,500);します。そのため、MS Windowsに inプロパティでOnShow必要なようにフォームをデフォルトの位置に具体化させ、その後ウィンドウを移動させます。まだ存在していないウィンドウを移動しようとすると、無駄に見えます。poDefaultPosition

MS Windowsのデフォルトを明示的に無視して事前に設定されたコードを使用するために(シーケンスの構築中に)フォームをPRESETするかpoDesigned、フォームにWindows座標を要求させますが、ハンドラーを介して表示されSetBounds た後にフォームを移動します。OnShow

于 2016-08-19T09:36:06.903 に答える