如何使用Align属性调整TFlowPanel内的控件大小?

时间:2012-09-19 12:42:17

标签: delphi flowpanel

我在TDBChart中有一些控件(即TFlowPanel)。当用户点击其中一个时,我希望它填满整个flow panel的客户区。但是,似乎在运行时更改visible内的子控件的alignflow panel属性没有任何影响。这有什么特别的诀窍吗?我找到了Realign()方法,但它似乎对控件的布局没有任何影响。这是我的OnClick事件的代码:

var
  AChart: TDBChart;
  V: Boolean;
  i: Integer;
begin
  AChart := TDBChart(Sender);
  if AChart.Align = alNone then
  begin
    V := False;
    AChart.Align := alClient;
  end else begin
    V := True;
    AChart.Align := alNone;
  end;
  for i := 0 to FlowPanel1.ControlCount - 1 do
    if FlowPanel1.Controls[i] is TDBChart then
      if FlowPanel1.Controls[i] <> AChart then
        FlowPanel1.Controls[i].Visible := V;
end;

图表会按预期隐藏或显示,但ADBChart不会填满整个flow panel的客户区。

2 个答案:

答案 0 :(得分:3)

按照设计,T(Custom)FlowPanel使用自定义的子控件​​对齐方式,这是通过覆盖AlignControls方法实现的。

你可以通过跳过来阻止这种默认行为,从它的祖先那里回过头来。此外,不需要隐藏所有相邻的控件。将点击的图表放在前面就足够了。

type
  TFlowPanel = class(Vcl.ExtCtrls.TFlowPanel)
  private
    FFlowDisabled: Boolean;
    procedure SetFlowDisabled(Value: Boolean);
  protected
    procedure AlignControls(AControl: TControl; var Rect: TRect); override;
  public
    property FlowDisabled: Boolean read FFlowDisabled write SetFlowDisabled;
  end;

...

{ TFlowPanel }

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

procedure TFlowPanel.AlignControls(AControl: TControl; var Rect: TRect);
begin
  if FFlowDisabled then
    // Skip inherited in TCustomFlowPanel:
    TAlignControls(@TWinControlAccess.AlignControls)(Self, AControl, Rect)
  else
    inherited;
end;

procedure TFlowPanel.SetFlowDisabled(Value: Boolean);
begin
  if FFlowDisabled <> Value then
  begin
    FFlowDisabled := Value;
    Realign;
  end;
end;    

{ TForm1 }

procedure TForm1.DBChartClick(Sender: TObject);
const
  FlowAligns: array[Boolean] of TAlign = (alNone, alClient);
var
  Chart: TDBChart;
  Panel: TFlowPanel;
  DisableFlow: Boolean;
begin
  Chart := TDBChart(Sender);
  Panel := Chart.Parent as TFlowPanel;
  DisableFlow := not Panel.FlowDisabled;
  Chart.Align := FlowAligns[DisableFlow];
  Chart.BringToFront;
  Panel.FlowDisabled := DisableFlow;
end;

答案 1 :(得分:2)

FlowPanel不关心其控件的对齐设置,就像它不关心它们的位置一样 - 它只是为了让它们流动而设计。

一种解决方案可以是派生一个新类并覆盖AlignControls,并在其中调整相应填充表面的控件的大小。举个例子:

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

..

procedure TFlowPanel.AlignControls(AControl: TControl; var Rect: TRect);
var
  i, VisibleCount, VisibleControl: Integer;
begin
  VisibleCount := 0;
  VisibleControl := 0;
  for i := 0 to ControlCount - 1 do
    if Controls[i].Visible then begin
      Inc(VisibleCount);
      VisibleControl := i;
    end;

  if (VisibleCount = 1) and (Controls[VisibleControl] = AControl) and
      (AControl.Align = alClient) then begin
    // preserve 'Explicit..' settings
    AControl.ControlState := AControl.ControlState + [csAligning];
    AControl.SetBounds(1, 1, ClientWidth - 1, ClientHeight -1);
    AControl.ControlState := AControl.ControlState - [csAligning];
  end;

  inherited;
end;

然后,您可以将所有图表的点击事件设置为此处理程序:

var
  AChart: TTDBChart;

  procedure SetVisibility(Visible: Boolean);
  var
    i: Integer;
  begin
    for i := 0 to FlowPanel1.ControlCount - 1 do
      if FlowPanel1.Controls[i] is TDBChart then
        if FlowPanel1.Controls[i] <> AChart then
          FlowPanel1.Controls[i].Visible := Visible;
  end;

begin
  AChart := TDBChart(Sender);
  if AChart.Align = alNone then
  begin
    SetVisibility(False);
    AChart.Align := alClient;
  end else begin
    AChart.Align := alNone; // set before changing visible
    SetVisibility(True);
    AChart.SetBounds(0, 0, AChart.ExplicitWidth, AChart.ExplicitHeight);
  end;
end;

我应该注意,这只适用于固定尺寸的流动面板。