Delphi 将引用中的对象/一个位置传递给样式对象
我得到了一个相当大的应用程序,目前正在设计中。 为了节省我更改IDE/对象检查器中的所有按钮的时间,我计划只为主要对象执行一些功能,如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
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)。当一个循环足够时,为什么要写两个循环?移动到单独的问题->