2

我正在开发一个 Delphi 组件,它由一个带有一些标签和按钮的面板组成。它看起来像这样:

在此处输入图像描述

或像这样:

在此处输入图像描述

取决于属性的设置。此外,标签的布局会根据第一个标签的长度而变化。

我一直在用 TFrame 制作原型,并在框架的 OnPaint 方法中进行布局计算。在基于 TPanel 的组件中执行此操作的正确位置是什么?或者,更准确地说,在 TCustomAdvPanel 中,这就是我的派生。它是否像这样在 Paint 方法的覆盖中起作用?

procedure TDateRangePicker.Paint;
const
  hSpacing = 5;
begin
  if FShowRefresh then
  begin
    btnRefresh.Visible := true;
    btnRefresh.Left := Width - hSpacing - btnRefresh.Width;
    btnClearDates.Left := btnRefresh.Left - hSpacing - btnClearDates.Width;
    btnChooseDates.Left := btnClearDates.Left - hSpacing - btnChooseDates.Width;
  end
  else begin
    btnRefresh.Visible := false;
    btnClearDates.Left := Width - hSpacing - btnClearDates.Width;
    btnChooseDates.Left := btnClearDates.Left - hSpacing - btnChooseDates.Width;
  end;
  lblRangeCaption.Left := hSpacing;
  lblDateRange.Left := lblRangeCaption.Left + lblRangeCaption.Width + hSpacing;
  inherited Paint;
end;
4

3 回答 3

4

绝对不要使用该Paint方法重新定位控件。在最坏的情况下,这会再次触发该Paint方法,一次又一次......因为,好吧:由于更换控件,面板需要重新绘制。Paint,以及所有等价物,仅用于绘制自己。

关于何时实现您的代码:这应该在ShowRefresh属性的设置器中完成。

关于如何实现您的ShowRefresh属性:当然,您可以像现在一样移动控件。您还可以考虑使用Margins(Delphi XE) 并对齐按钮和标签。然后属性设置器将变得相当简单:

type
  TDateRangePicker = class(TCustomPanel)
  private
    FChooseButton: TButton;
    FClearButton: TButton;
    FRefreshButton: TButton;
    FLabel1: TLabel;
    FLabel2: TLabel;
    function GetLabel1Caption: String;
    function GetRefreshButtonVisible: Boolean;
    procedure SetLabel1Caption(const Value: String);
    procedure SetRefreshButtonVisible(Value: Boolean);
  public
    constructor Create(AOwner: TComponent); override;
  published
    property RefreshButtonVisible: Boolean read GetRefreshButtonVisible
      write SetRefreshButtonVisible default True;
    property Label1Caption: String read GetLabel1Caption
      write SetLabel1Caption;
  end;

...

constructor TDateRangePicker.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FChooseButton := TButton.Create(Self);
  FChooseButton.Caption := 'Choose';
  FChooseButton.Align := alRight;
  FChooseButton.AlignWithMargins := True;
  FChooseButton.Margins.Left := 10;
  FChooseButton.Parent := Self;
  FClearButton := TButton.Create(Self);
  FClearButton.Caption := 'Clear';
  FClearButton.Align := alRight;
  FClearButton.AlignWithMargins := True;
  FClearButton.Margins.Left := 10;
  FClearButton.Parent := Self;
  FRefreshButton := TButton.Create(Self);
  FRefreshButton.Caption := 'Refresh';
  FRefreshButton.Align := alRight;
  FRefreshButton.AlignWithMargins := True;
  FRefreshButton.Margins.Left := 10;
  FRefreshButton.Parent := Self;
  FLabel1 := TLabel.Create(Self);
  FLabel1.Caption := 'Foo caption: ';
  FLabel1.Align := alLeft;
  FLabel1.Layout := tlCenter;
  FLabel1.Parent := Self;
  FLabel2 := TLabel.Create(Self);
  FLabel2.Caption := 'From 03/08/2012 to 06/06/2012';
  FLabel2.Align := alLeft;
  FLabel2.Layout := tlCenter;
  FLabel2.Parent := Self;
end;

function TDateRangePicker.GetLabel1Caption: String;
begin
  Result := FLabel1.Caption;
end;

function TDateRangePicker.GetRefreshButtonVisible: Boolean;
begin
  Result := FRefreshButton.Visible;
end;

procedure TDateRangePicker.SetLabel1Caption(const Value: String);
begin
  FLabel1.Caption := Value;
end;

procedure TDateRangePicker.SetRefreshButtonVisible(Value: Boolean);
begin
  FRefreshButton.Visible := Value;
  FRefreshButton.Left := Width;
end;

和测试程序:

procedure TMainForm.TestButtonClick(Sender: TObject);
begin
  DateRangePicker1.Label1Caption := 'Test: ';
  DateRangePicker1.RefreshButtonVisible := not DateRangePicker1.RefreshButtonVisible;
end;
于 2012-06-06T23:02:51.927 回答
2

您可以为 TDateRangePicker 创建一个属性,例如:

property ShowRefresh:boolean read GetShowRefresh write SetShowRefresh

procedure TDateRangePicker.SetShowRefresh( Value : boolean);
begin
  btnRefresh.Visible := Value;
  // Force autosize after hidding Refresh button
  Autosize := True;
end;

因此,您在绘图期间无事可做。

于 2012-06-06T18:41:25.873 回答
2

您在创建子控件时设置初始位置,然后在需要更新它们时更新位置(更改属性时,调整父组件大小时等)。您不得更改Paint()方法或OnPaint事件中的位置。

如果您使用的是现代版本的 Delphi,则应该使用子控件的AlignMarginsAlignWithMargins属性。这样,您只需在创建控件时定位一次,并让 VCL 完成所有艰苦的工作,在需要时自动重新定位它们。

于 2012-06-06T23:24:54.843 回答