5

これは、XE3 までのすべての Delphi で発生します。

  1. フォームを作成し、その上にパネルを置きます。パネルを[akLeft, akTop, akRight, akBottom]に固定しますが、境界線との間にスペースを残します。
  2. 呼び出すボタンを追加するRecreateWnd()
  3. アプリを実行します。アンカーによりサイズが 0 ピクセル未満になるため、パネルが非表示になるようにフォームのサイズを変更します。RecreateWnd ボタンを押します。
  4. フォームのサイズを元に戻すと、パネルの固定が壊れていることに注意してください。

Delphi を使用していたことを覚えている限り、このためアンカーは常に使用できませんでした。フォームのサイズを変更してからドッキングします。ウィンドウが再作成され、レイアウトが壊れます。

なんらかの回避策があるのだろうか?

アップデート

コメントには 2 つの回避策があります。1 つは実証済みで安定していますが、フォームの点滅があります。もう 1 つは実験的ですが、より完全でクリーンな可能性があります。

そのうちの 1 つは私のものであり、それが安定しているかどうかさえわからないため、しばらくはどちらにも投票するつもりはありません。代わりに、一般の意見をお待ちしています。

4

2 に答える 2

4

私が使用した2つのオプションのうち、どちらも下と右のアンカーの問題には本当に理想的ではありません:

  1. を呼び出す前、または呼び出されるようにする前に、ウィンドウを再度大きくしてから RecreateWnd();、再度小さくします。ただし、再度小さくする前に表示する必要があります。
  2. フォームの制約を設定して、サイズ変更が小さすぎて物が隠れてしまうことがないようにします。

より大きなフォームをフラッシュする例では、高さと幅に十分大きな値を使用して、パネルが非表示にならないようにします。

procedure TForm1.Button1Click(Sender: TObject);
Var
  OldWidth, OldHeight : integer;
begin
  OldWidth := Form1.Width;
  OldHeight := Form1.Height;
  Form1.Visible := false;
  Form1.Width := 1000;
  Form1.Height := 800;
  RecreateWnd();
  Form1.Visible := true;
  Form1.Width := OldWidth;
  Form1.Height := OldHeight;
end;
于 2013-02-25T09:36:06.017 に答える
0

すべてを壊す関数はUpdateAnchorRules. に独自の元のサイズをTControl格納し、それを使用して、親のサイズ変更に合わせて自動サイズ変更します。は、現在の親のサイズと現在のコントロールを取得し、それらをおよびに保存します。FOriginalParentSizeFAnchorRulesUpdateAnchorRules()WidthHeightFOriginalParentSizeFAnchorRules

コントロールとその親が一致してサイズを変更するため、すべてが正常に機能した場合、通常のサイズ変更中に影響はありません。

しかし、Widthアンカリングのためにコントロールが 0 未満の場合、Windows、したがって Delphi は引き続きそれを と見なします0。そのUpdateAnchorRules時点で が呼び出されると、0元の幅に対して間違った不一致の値が保存されます。この後、レイアウトは修復不可能です。

(呼び出されない場合は、元のサイズが保持されるためWidth、親との適切な関係で引き続き更新されます)Width

ウィンドウ ハンドルの呼び出しをUpdateAnchorRules2 回作成する必要があることがわかります。最初は WinAPIで返される前 (およびハンドラー呼び出し)CreateWindowでディスパッチされ、次にハンドル作成後に明示的に呼び出されます。WM_SIZEWM_SIZEUpdateAnchorRulesCreateHandle

UpdateAnchorRulesの期間無効にできる限り、CreateHandle成功するようです。UpdateAnchorRulesしかし、 inへの明示的な呼び出しがあります。これは、ハンドルの作成後にアンカー ルールを調整する必要CreateHandleがあると誰かが考えたことを意味します。

おそらく私は何かが欠けているので、それを無効にすることで何かが壊れますか?

いずれにせよ、無効にする方法は 2 つありますUpdateAnchorRules: 設定するFAnchorMoveか設定するかcsLoadingです。途中でクリアしてから再度RecreateWnd呼び出すコードがあるため、最初のものは良くありませんUpdateAnchorRules

2番目のものは機能し、ここに解決策があります:

type
  TComponentHack = class helper for TComponent
  public
    procedure SetCsLoading(Value: boolean);
  end;

procedure TComponentHack.SetCsLoading(Value: boolean);
var i: integer;
begin
  if Value then
    Self.FComponentState := Self.FComponentState + [csLoading]
  else
    Self.FComponentState := Self.FComponentState - [csLoading];
  for i := 0 to Self.ComponentCount-1 do
    if Self.Components[i] is TControl then
      TControl(Self.Components[i]).SetCsLoading(Value);
end;

procedure SafeRecreateWnd();
begin
  MyControl.SetCsLoading(true);
  try
    MyControl.RecreateWnd(); //or any operation which triggers it -- such as docking or making the window visible first time after RecreateWnd()
  finally
    MyControl.SetCsLoading(false);
  end;
end;

免責事項

TControlcsLoading を設定して操作を実行すると、他に何が壊れるかわかりません。

より良い代替手段は、UpdateAnchorRulesプロシージャをフックし、この目的のために別のフラグ チェックを追加することですが、それにはUpdateAnchorRules完全に再実装するか (Original が異なる Delphi の異なるバージョンで壊れる傾向があります)、originalをUpdateAnchorRules呼び出す何らかの方法を発明する必要があります。UpdateAnchorRulesフックで書き換えます。

于 2013-03-04T13:36:32.487 に答える