すべてを壊す関数はUpdateAnchorRules
. に独自の元のサイズをTControl
格納し、それを使用して、親のサイズ変更に合わせて自動サイズ変更します。は、現在の親のサイズと現在のコントロールを取得し、それらをおよびに保存します。FOriginalParentSize
FAnchorRules
UpdateAnchorRules()
Width
Height
FOriginalParentSize
FAnchorRules
コントロールとその親が一致してサイズを変更するため、すべてが正常に機能した場合、通常のサイズ変更中に影響はありません。
しかし、Width
アンカリングのためにコントロールが 0 未満の場合、Windows、したがって Delphi は引き続きそれを と見なします0
。そのUpdateAnchorRules
時点で が呼び出されると、0
元の幅に対して間違った不一致の値が保存されます。この後、レイアウトは修復不可能です。
(呼び出されない場合は、元のサイズが保持されるためWidth
、親との適切な関係で引き続き更新されます)Width
ウィンドウ ハンドルの呼び出しをUpdateAnchorRules
2 回作成する必要があることがわかります。最初は WinAPIで返される前 (およびハンドラー呼び出し)CreateWindow
でディスパッチされ、次にハンドル作成後に明示的に呼び出されます。WM_SIZE
WM_SIZE
UpdateAnchorRules
CreateHandle
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;
免責事項:
TControl
csLoading を設定して操作を実行すると、他に何が壊れるかわかりません。
より良い代替手段は、UpdateAnchorRules
プロシージャをフックし、この目的のために別のフラグ チェックを追加することですが、それにはUpdateAnchorRules
完全に再実装するか (Original が異なる Delphi の異なるバージョンで壊れる傾向があります)、originalをUpdateAnchorRules
呼び出す何らかの方法を発明する必要があります。UpdateAnchorRules
フックで書き換えます。