在引用/一个位置传递对象以设置对象样式

发布于 2024-10-26 07:36:50 字数 523 浏览 1 评论 0原文

我有一个相当大的应用程序,目前正在设计中。 为了节省我更改 IDE/对象检查器中的所有按钮,我计划只为主要对象(例如

procedure StyleButton(AButton : TButton)
begin
    AButton.Color := clGreen;
    AButton.Font.Style = [fsBold];
end;

等)执行一些功能,然后根据需要将其添加到 onCreates 表单中

StyleButton(Button1); whatever etc

。像这样在参数中传递对象没有问题。它确实只引用第一个对象,对吗?

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

还将使用 TAdvStringGrid 和 TEdit/TMemo 组件做类似的事情。

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

或者有人有更好的主意?

I got quite a large application which is currently being styled up.
To save me changing all the buttons in the IDE/Object Inspector I am planning on just doing a few functions for the main objects like

procedure StyleButton(AButton : TButton)
begin
    AButton.Color := clGreen;
    AButton.Font.Style = [fsBold];
end;

etc etc and then add that to the forms onCreates as needed

StyleButton(Button1); whatever etc

There is no issue passing objects in params like this. It does just reference the first object right?

It works fine and I can't think of any issues, but because this is a large application which thousands of users I just want to be sure there will be no issues/memory leaks/resource consumpution issues.

Will also be doing similar things with TAdvStringGrid and TEdit/TMemo components.

Then allows just 1 place to change these settings.

Or someone have a better idea?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

煞人兵器 2024-11-02 07:36:50

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

您不是通过引用传递的。你正在按价值传递。您传递的值是一个引用。 “通过引用传递”意味着您将使用 varout 关键字,这些关键字适合这种情况。

This is an excellent idea. The function will modify whichever object you pass to it.

You are not passing by reference. You are passing by value. The value you are passing is a reference. "Passing by reference" means you'd use the var or out keywords, which are not appropriate in this situation.

—━☆沉默づ 2024-11-02 07:36:50

你的想法很好,正如其他回答者已经说过的。只是想提出一个比 David 的解决方案更进一步的解决方案,以及您可能需要考虑的解决方案,以避免必须添加许多语句,例如:

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 处查找类将在另一个列表中的相同索引处找到样式器。这当然可以进行很大的改进,但这里足以展示这个概念。

Your idea is just fine, as the other answerers have already said. Just want to propose a solution that goes even further than David's and something you may want to consider in order to avoid having to add many statements like:

StyleButton(Button1);
StyleButton(Button2);

to each and every form for each and every control you would like to style;

What I would propose is to add a single method call to for example each form's OnShow event:

procedure TForm1.FormShow(Sender: TObject);
begin
  TStyler.StyleForm(Self);
end;

The TStyler could be implemented in a separate unit that looks like this:

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.

This solution basically employs polymorphism and a registry that links control classes to styler classes. It also uses class procedures and functions to avoid having to instantiate anything.

Please note that the registry is implemented in this example as two lists that need to be kept in sync manually as the code assumes that finding a class at index X will find the styler at the same index in the other list. This can of course be improved upon very much, but is sufficient here to show the concept.

笑梦风尘 2024-11-02 07:36:50

不,在您的具体情况下,将对象作为参数传递是没有问题的,

procedure StyleButton(AButton : TButton)

当您这样做时,您正在传递地址内存(引用)并设置引用对象的一些属性,因此没有问题。

No, There is no issue (in your specific case) passing a object as parameter

procedure StyleButton(AButton : TButton)

when you do this you are passing a address memory (reference) and setting some properties of the referenced object, so there is not problem.

时光是把杀猪刀 2024-11-02 07:36:50

要补充 Rob 和 RRUZ 已经说过的内容,您可以考虑使用开放数组参数的额外帮助程序:

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);

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

To add to what Rob and RRUZ have already said, you could consider an extra helper using open array parameters:

procedure StyleButtons(const Buttons: array of TButton);
var
  i: Integer;
begin
  for i := low(Buttons) to high(Buttons) do
    StyleButton(Buttons[i]);
end;

You can then call this as:

StyleButtons([btnOK, btnCancel, btnRelease64bitDelphi]);

which is, in my view, more readable at the call-site than:

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

Note that I passed the open array as a const parameter because that is more efficient when dealing with arrays. Because each element of the array is itself a reference to the button, you are able to modify the actual button. The const just means that you cannot change the reference.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文