2

TDBChartTFlowPanel. 当用户点击其中一个时,我希望它填满整个flow panel客户区。但是,在运行时更改子控件的visibleand属性似乎没有任何效果。这有什么特别的技巧吗?我找到了方法,但它似乎对控件的布局没有任何影响。这是我的活动的代码:alignflow panelRealign()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客户区。

4

2 回答 2

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;
于 2012-09-19T15:51:22.343 回答
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;

我应该注意,这仅适用于固定大小的流程面板。

于 2012-09-19T15:07:25.140 回答