我有一个很大的应用程序,目前正在设计。 为了节省我更改IDE / Object Inspector中的所有按钮,我计划为主要对象执行一些功能,例如
procedure StyleButton(AButton : TButton)
begin
AButton.Color := clGreen;
AButton.Font.Style = [fsBold];
end;
等等,然后根据需要将其添加到表单onCreates
StyleButton(Button1); whatever etc
在这样的参数中传递对象没有问题。它只引用第一个对象吗?
它工作正常,我想不出任何问题,但因为这是一个大型应用程序,我只想确保没有问题/内存泄漏/资源消耗问题的数千名用户。
也将使用TAdvStringGrid和TEdit / TMemo组件做类似的事情。
然后只允许1个地方更改这些设置。
或者有人有更好的主意?
答案 0 :(得分:6)
这是一个很好的主意。该函数将修改传递给它的任何对象。
您没有通过引用传递。你正在经历价值。您传递的值是引用。 “通过引用传递”表示您使用var
或out
个关键字,在这种情况下,不是适当的。
答案 1 :(得分:4)
你的想法很好,正如其他回答者已经说过的那样。只是想提出一个比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处查找类将在另一个列表中的相同索引处找到样式器。这当然可以在很大程度上得到改善,但这足以说明这个概念。
答案 2 :(得分:2)
不,没有问题(在您的特定情况下)将对象作为参数传递
procedure StyleButton(AButton : TButton)
当你这样做时,你传递一个地址存储器(引用)并设置引用对象的一些属性,所以没有问题。
答案 3 :(得分:2)
要添加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);
请注意,我将open数组作为const参数传递,因为在处理数组时更有效。因为数组的每个元素本身都是对按钮的引用,所以您可以修改实际按钮。 const只表示您无法更改引用。