Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Delphi 将引用中的对象/一个位置传递给样式对象_Delphi_Object_Pass By Reference - Fatal编程技术网

Delphi 将引用中的对象/一个位置传递给样式对象

Delphi 将引用中的对象/一个位置传递给样式对象,delphi,object,pass-by-reference,Delphi,Object,Pass By Reference,我得到了一个相当大的应用程序,目前正在设计中。 为了节省我更改IDE/对象检查器中的所有按钮的时间,我计划只为主要对象执行一些功能,如 procedure StyleButton(AButton : TButton) begin AButton.Color := clGreen; AButton.Font.Style = [fsBold]; end; etc等,然后根据需要将其添加到表单onCreate中 StyleButton(Button1); whatever etc

我得到了一个相当大的应用程序,目前正在设计中。 为了节省我更改IDE/对象检查器中的所有按钮的时间,我计划只为主要对象执行一些功能,如

procedure StyleButton(AButton : TButton)
begin
    AButton.Color := clGreen;
    AButton.Font.Style = [fsBold];
end;
etc等,然后根据需要将其添加到表单onCreate中

StyleButton(Button1); whatever etc
在这样的参数中传递对象是没有问题的。它只引用第一个对象,对吗

它工作得很好,我想不出任何问题,但因为这是一个有数千用户的大型应用程序,我只想确保不会出现问题/内存泄漏/资源消耗问题

也将对TadvString和TEdit/TMemo组件进行类似的操作

然后只允许1个位置更改这些设置

或者有人有更好的主意?

不,将对象作为参数传递(在您的特定情况下)没有问题

procedure StyleButton(AButton : TButton)

执行此操作时,您正在传递地址内存(引用)并设置引用对象的某些属性,因此没有问题。

这是一个很好的主意。该函数将修改传递给它的任何对象


您不是通过引用传递。您正在传递值。您传递的值是一个引用。“通过引用”意味着您将使用<代码> var >代码>或>代码> OUT/<代码>关键字,这在这种情况下是不合适的。

< P> > Rob和Ruz已经说过的,可以使用开放数组参数考虑额外的帮助:

procedure StyleButtons(const Buttons: array of TButton);
var
  i: Integer;
begin
  for i := low(Buttons) to high(Buttons) do
    StyleButton(Buttons[i]);
end;
然后,您可以将其称为:

StyleButtons([btnOK, btnCancel, btnRelease64bitDelphi]);
在我看来,这在呼叫站点上比:

StyleButton(btnOK);
StyleButton(btnCancel);
StyleButton(btnRelease64bitDelphi);

请注意,我将open数组作为const参数传递,因为这样在处理数组时效率更高。因为数组的每个元素本身就是按钮的引用,所以可以修改实际的按钮。常量只是意味着你不能更改引用。

正如其他回答者所说,你的想法很好。只想提出一个比戴维更进一步的解决方案,还有一些你可能需要考虑的问题,以便避免添加很多语句,比如:

StyleButton(Button1);
StyleButton(Button2);
为您想要的每个控件的每个窗体设置样式

我建议为每个表单的OnShow事件添加一个方法调用:

procedure TForm1.FormShow(Sender: TObject);
begin
  TStyler.StyleForm(Self);
end;
TStyler可以在一个单独的单元中实现,如下所示:

interface

type
  TStyler = class;
  TStylerClass = class of TStyler;

  TStyler = class(TObject)
  public
    class procedure StyleForm(const aForm: TCustomForm);
    class procedure StyleControl(const aControl: TControl); virtual;
    class function GetStyler(const aControl: TControl): TStylerClass;
  end;

implementation

uses
  Contnrs;

type
  TButtonStyler = class(TStyler)
  public
    class procedure StyleControl(const aControl: TControl); override;
  end;

  TEditStyler = class(TStyler)
  public
    class procedure StyleControl(const aControl: TControl); override;
  end;

  TLabelStyler = class(TStyler)
  public
    class procedure StyleControl(const aControl: TControl); override;
  end;

var
  _Controls: TClassList;
  _Stylers: TClassList;

{ TStyler }

class function TStyler.GetStyler(const aControl: TControl): TStylerClass;
var
  idx: Integer;
begin
  Result := TStyler;
  idx := _Controls.IndexOf(aControl.ClassType);
  if idx > -1 then
    Result := TStylerClass(_Stylers[idx]);
end;

class procedure TStyler.StyleForm(const aForm: TCustomForm);

  procedure _StyleControl(const aControl: TControl);
  var
    i: Integer;
    StylerClass: TStylerClass;
  begin
    StylerClass := TStyler.GetStyler(aControl);
    StylerClass.StyleControl(aControl);
    if (aControl is TWinControl) then
      for i := 0 to TWinControl(aControl).ControlCount - 1 do
        _StyleControl(TWinControl(aControl).Controls[i]);
  end;

var
  i: Integer;
begin
  _StyleControl(aForm);
end;

class procedure TStyler.StyleControl(const aControl: TControl);
begin
// Do nothing. This is a catch all for all controls that do not need specific styling.
end;

{ TButtonStyler }

class procedure TButtonStyler.StyleControl(const aControl: TControl);
begin
  inherited;
  if aControl is TButton then
  begin
    TButton(aControl).Font.Color := clRed;
    TButton(aControl).Font.Style := [fsBold];
  end;
end;

{ TEditStyler }

class procedure TEditStyler.StyleControl(const aControl: TControl);
begin
  inherited;
  if aControl is TEdit then
  begin
    TEdit(aControl).Color := clGreen;
  end;
end;

{ TLabelStyler }

class procedure TLabelStyler.StyleControl(const aControl: TControl);
begin
  inherited;
  if aControl is TLabel then
  begin
    TLabel(aControl).Font.Color := clPurple;
    TLabel(aControl).Font.Style := [fsItalic];
  end;
end;

initialization
  _Controls := TClassList.Create;
  _Stylers := TClassList.Create;

  _Controls.Add(TButton);
  _Stylers.Add(TButtonStyler);

  _Controls.Add(TEdit);
  _Stylers.Add(TEditStyler);

  _Controls.Add(TLabel);
  _Stylers.Add(TLabelStyler);

finalization
  FreeAndNiL(_Controls);
  FreeAndNiL(_Stylers);
end.
此解决方案基本上采用多态性和将控制类链接到样式器类的注册表。它还使用类过程和函数来避免实例化任何东西


请注意,在本例中,注册表是作为两个列表实现的,需要手动保持同步,因为代码假定在索引X处查找类将在另一个列表中的相同索引处找到样式器。这当然可以得到很大的改进,但在这里就足以说明这一概念。

感谢您提供的关于在数组中使用常量的提示,我正在考虑使用类似这样的方法来帮助您,正如您所展示的那样,它非常有帮助。再次感谢。@David:是的,如果我有一个多小时的时间来准备这个,我可能还会添加递归…;)应该很容易添加,只有一种方法可以更改,我相信OP可以做到,但如果你再给我半个小时,我也会。。。虽然没有时髦的统计员,但我将把它作为练习留给读者。:-)非常好。我去散步,正在考虑一些事情,我会在这里添加它作为一个答案,但有一个想法可能是一个问题,如果你想某些按钮的样式是单向的。“OK”按钮您可能想要绿色,但“cancel”按钮您可能想要灰色。@David:反正我也想自己做,但一个小问题是您需要一个TWinControl而不是TControl来控制孩子和孙子。(尽管我不想要任何!)顺便说一句,谢谢你的编辑,这是我的荷兰式风格闪耀着…@Wizzard:谢谢。使用按钮的“取消”属性可以解决按钮问题。当然,始终存在标记属性来区分同一类的控件(如果您还没有将其用于其他用途)。@Marjan是的,TWinControl/TControl,您必须处理该属性。最好不要在TStyler.StyleForm中使用循环并调用_StyleControl(aForm)。当一个循环足够时,为什么要写两个循环?移动到单独的问题->