6

次の方法で TFlowPanel コンポーネントを使用しようとしています。

  1. メイン フォームForm1コンポーネントに配置しますFlowPanel1: TFlowPanel
  2. Form1.Width = 400FlowPanel1.Align = alTopFlowPanel1.AutoSize = True、 を設定しFlowPanel1.AutoWrap = Trueます。
  3. FlowPanel15 つの SpeedButtonsに配置し、それらWidthを 64 に設定します。
  4. コンパイルして実行します。
  5. フォームの幅を減らします (約Form1.Width = 200)。

何らかの理由で、ユーザーがフォームのサイズを変更したときに、スピード ボタンが自動的に 2 行に整列しません。ただし、 の場合は 2 列に並んAutoSize = FalseでいAutoWrap = Trueます。
この動作の理由と解決方法は何ですか?

編集:「すばやく汚い」解決策を見つけました。次のコードは、イベントのイベント ハンドラーTFlowPanel.OnResizeです。

procedure TForm1.FlowPanel1Resize(Sender: TObject);
begin
  with FlowPanel1 do
  begin
    AutoSize := False;
    Realign;            // line up controls
    AutoSize := True;   // adjust TFlowPanel.Height
  end;
end;

ただし、問題を解決する標準的な方法があるかどうかはまだ疑問です。

4

2 に答える 2

6

コードでこのような動作の正確な理由を見つけることはできませんでしたが、基本的には、AutoSizeAlign. 問題は、フォームのサイズを変更すると、AutoSizeTrue にAlign設定され、設定されalTopたコントロールが最初にコントロールの自動サイズ変更を試み、次にその親の上部に配置されることです。確かに言えることは、これら 2 つのプロパティは、少なくとも論理的な意味からは組み合わせてはならないということです。

私があなたの回避策として提案するのは、デフォルトでオートサイズをオフにし、OnResizeイベントで一時的にオンにしてからオフに戻し、高さを自動的に調整することです。したがって、コードでは次のように単純に変更されます。

procedure TForm1.FlowPanel1Resize(Sender: TObject);
begin
  // there's no Realign here, since the AlignControls request is called
  // at control resize, so here you have children already aligned, what
  // you then need is to request the control to autosize the height and
  // turn off the autosizing to the default, disabled state
  FlowPanel1.AutoSize := True;
  FlowPanel1.AutoSize := False;
end;
于 2012-09-13T07:26:11.030 に答える
3

tl,dr:のバグですTFlowPanel

通常、これはレベルですでに処理されているため、プロパティAutoSizeAlignプロパティはデフォルトで非常にうまく連携しますTControl。なぜこれが起こったのか疑問に思いました。AlignControlsオーバーライドされたメソッドに気づき、TFlowPanelテスト目的でそれをバイパスすることを考えました:

type
  TWinControlAccess = class(TWinControl);
  TAlignControls = procedure(Instance: TObject; AControl: TControl;
    var Rect: TRect);

  TFlowPanel = class(Vcl.ExtCtrls.TFlowPanel)
  protected
    procedure AlignControls(AControl: TControl; var Rect: TRect); override;
  end;

  TForm1 = class(TForm)
    ...

procedure TFlowPanel.AlignControls(AControl: TControl; var Rect: TRect);
begin
  // Skip TCustomFlowPanel.AlignControls
  TAlignControls(@TWinControlAccess.AlignControls)(Self, AControl, Rect);
end;

procedure TForm1.FlowPanel1Resize(Sender: TObject);
begin
  // Do my own aligning of the last button
  if FlowPanel1.ClientWidth < Button5.BoundsRect.Right then
  begin
    Button5.Left := 1;
    Button5.Top := Button1.Height + 1;
  end
  else if FlowPanel1.ClientWidth > Button4.BoundsRect.Right + Button5.Width then
  begin
    Button5.Left := Button4.BoundsRect.Right;
    Button5.Top := 1;
  end;
end;

これで、期待どおりに動作します。TFlowPanelでは、の の実装の何が問題なのAlignControlsですか? 次のスニペットが理由のようです。

if AutoSize then
  Rect := TRect.Create(
    Rect.Left,
    Rect.Top,
    Rect.Left + (ExplicitWidth - (Width - (Rect.Right - Rect.Left))),
    Rect.Top + (ExplicitHeight - (Height - (Rect.Bottom - Rect.Top))));

この部分をコメントアウトするとAlignsetでもなくても期待通りの動作になります。さて、これを QC に提出したいと思いますが、見落としている部分があるかもしれません。このコードが実際に必要な場合 (およびその理由) を編集またはコメントしてください。

于 2012-09-13T18:08:30.550 に答える