2013-02-25 2 views
5

これはXE3までのすべてのDelphiで起こりますウィンドウを再作成するときにアンカーが壊れてしまうのを回避するには?

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

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

回避策がありますか?

更新

2つの回避策は、コメントでご利用いただけます1実績のある安定したが、フォームで、実験が、潜在的に、より徹底したクリーンな別のものを点滅します。

私はしばらくの間投票するつもりはありません。そのうちの1つは私のものであり、安定しているかどうかもわかりません。代わりに、私はいくつかの公共の入力を待つでしょう。下で問題と右のアンカーのための本当に理想的ではありませんどちらもそのうち私が使用している

+0

"使えない"とは少し上にあると思います。フォームのハンドルが決して再作成されない多くのユースケース。 –

+0

私はそうは思わない。たとえあなたが一度もやっていないような気がしても、一ヶ月後にあなたが作り直すようなことをすると、知らないうちにバグが発生しました。アンカーは予測できません。 – himself

+0

ええええええええええええええ、確かに、彼らはあまりにも使用されている理由です...アンカーはかなり機能し、私と他の多くの年のためにそうしてきました。明らかにあなたの走行距離は異なりますが、それらを使用することができないことは、他の人のために使用することを不可能にしません。 –

答えて

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; 
+0

ありがとうございます。トリックが役立ちます。それでも、アンカーを扱うのはPITAです。 – himself

+0

「メイン」パネルを使用すると、点滅を回避するのに役立つのではないかと思います。私はパネルを 'alClient'に設定し、すべての内容を保持していることを意味します。レクリエーションの前に、フォームの代わりにパネルを拡大します。いくつかのちらつきがまだ目に見えているかもしれませんが、おそらくフォームを拡大するときよりも小さい程度です。 –

0

はすべてを壊す機能がUpdateAnchorRulesであることが判明しました。 TControlFOriginalParentSizeを格納しており、それ自体の元のサイズはFAnchorRulesで、それを使用して親サイズとして自動サイズ変更されます。 UpdateAnchorRules()は現在の親サイズと現在のコントロールWidthHeightをとり、それらをFOriginalParentSizeFAnchorRulesに保存します。

通常のサイズ変更時に効果がないすべてが正常に動作していれば、コントロールと親のサイズが一致します。

しかし、コントロールWidthが固定のためにゼロよりも小さい場合、Windowsは、したがって、Delphiはまだそれを0とみなします。その時点でUpdateAnchorRulesが呼び出された場合は、元の幅の値である0の間違った値を保存します。この後、レイアウトは修理の余地がありません。

(それが呼び出されていない場合は、Widthが原因保存元のサイズに親Widthへの適切な関係で更新され続けて)

は、ウィンドウハンドルを作成する必要が何かが二回UpdateAnchorRulesを呼び出し判明:それとしてWinAPIのCreateWindowの最初の返される前にWM_SIZEを送出します(ハンドラはハンドラが呼び出され、UpdateAnchorRulesが呼び出されます)。また、ハンドルの作成後にはCreateHandleに明示的に送出されます。

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

おそらく私は何かが不足しているため、無効にすると何かが壊れますか?

いずれにしても、UpdateAnchorRulesを無効にする2つの方法があります。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; 

免責事項

私はcsLoadingセットでTControl操作を実行することによって破壊される他に何見当がつかない。

より良い代替手段がUpdateAnchorRulesプロシージャをフックし、特にこの目的のために別のフラグチェックを追加することですが、それは(別の元UpdateAnchorRulesでのDelphiの異なるバージョンに破壊しやすい)完全UpdateAnchorRulesを再実装するかにいくつかの方法を発明のいずれかが必要ですと思います元のUpdateAnchorRulesを呼び出します。これは通常、フックで書き直すことで破壊されます。

関連する問題