我正在尝试从如下定义的过程中调用Timer的Enabled属性:procedure Slide(Form: TForm; Show: Boolean);
而不是使用固定的表单名称(例如:Form2.Timer...
)
将表单的单位放入使用列表后,这可以正常工作:Form2.Timer1.Enabled := True;
但是以下内容不起作用:Form.Timer1.Enabled := True;
(其中Form是作为参数传递给过程的表单。
如何访问表单上的Timer组件?
提前致谢。
答案 0 :(得分:6)
如果您要传递给函数的每个表单都有一个名为“Timer1”的已发布字段,那么您可以使用FindComponent
方法获取对它的引用:
procedure Slide(Form: TForm; Show: Boolean);
var
TimerObj: TComponent;
Timer: TTimer;
begin
TimerObj := Form.FindComponent('Timer1');
Assert(Assigned(TimerObj), 'Form has no Timer1');
Assert(TimerObj is TTimer, 'Form.Timer1 is not a TTimer');
Timer := TTimer(TimerObj);
// Continue using Form and Timer
end;
但是,这是一个相当弱的编程接口。如果你不小心忽略了在你的表单上放置一个计时器,或者你给它一个错误的名字,或者你给它一个不同的可见性,你就不会发现你的错误直到运行时(断言时)失败)。即使表单 符合所需的界面,也无法保证它是有意的。可能有许多表单已发布名为TTimer
的{{1}}字段,但它们并非全部用于此Timer1
函数。他们可能已经将他们的计时器用于其他目的,因此调用它们上的Slide
将破坏程序的其他部分,可能是难以调试的方式。
如果您为计时器提供了更具描述性的名称,例如Slide
,那么这将是一个稍强的界面。 SlideTimer
仅表示它是您在该表单上创建的第一个Timer1
,一旦您离开表单设计器,它就不再是一个有意义的名称。您不需要使用IDE的命名选项。
另一个更好的选择是让所有可滑动的表单都有一个公共基类,并将计时器放在该基类中。然后,更改TTimer
中的参数类型以获取该表单类,而不仅仅是Slide
。
TForm
您似乎担心自己必须在type
TSlidableForm = class(TForm)
Timer1: TTimer;
end;
procedure Slide(Form: TSlidableForm; Show: Boolean);
单元中包含对Form2单元的引用,这通常是一个很好的问题。您不希望代码过于紧密耦合,因为此Slide
函数应该能够在一个项目中使用多个表单。但如果它太松散,那么你会遇到我上面描述的问题。这个Slide
课程是妥协;您的TSlidableForm
函数不直接绑定到Slide
或其单位。将TForm2
更改为TForm2
。
The_Fox's second suggestion是我的第一个版本,但还有另一种变体。您可以传递对组件本身的引用,而不是传递计时器组件的名称:
TSlidableForm
现在您不需要使用procedure Slide(Form: TForm; Timer: TTimer; Show: Boolean);
来搜索要使用的计时器;你已经提供了它的直接参考。组件的名称甚至不重要,因此不同的表单可以使用不同的名称。你可以这样称呼它:
FindComponent
一旦你走到这一步,你可能会超越原来的问题,并意识到计时器甚至不再需要属于表格了。您可以专门为Slide(Form2, Form2.Timer1, True);
Slide(AnotherForm, AnotherForm.SlideTimer, False);
调用创建它,或者计时器可以完全属于其他东西(如数据模块)。但是,如果您要为Slide
调用创建计时器,那么您可以使用David建议在例程本身内创建计时器,而不是让调用者或表单处理它:
Slide
答案 1 :(得分:4)
将单位添加到使用列表中。
...
implementation
uses Unit2;
{$R *.dfm}
...
答案 2 :(得分:4)
您无法从您的过程访问Timer,因为您的参数是TForm,而TForm没有Timer1成员。你必须像这样调整你的程序:
uses
Unit2; //unit with your form
procedure Slide(Form: TForm2; Show: Boolean); //change TForm2 to the classname you use
begin
Form.Timer1.Enabled := True;
end;
修改强>
如果您想传递任何表格,可以试试这个:
procedure Slide(Form: TForm; const aTimerName: string; Show: Boolean);
var
lComponent: TComponent;
begin
lComponent := Form.FindComponent(aTimerName);
if Assigned(lComponent) and (lComponent is TTimer) then
TTimer(lComponent).Enabled := True;
end;
通过表单上的按钮进行如下调用:
procedure TForm2.Button1Click(Sender: TObject);
begin
Slide(Self, 'Timer1', False);
end;
或者你让你的Form继承一个接口,打开定时器的方法。但它有点复杂。
答案 3 :(得分:2)
在当前单位的使用列表中使用Form2的单位名称。
编辑:
使用TForm
您无法访问TTimer
因为TForm
有no fields or properties as TTimer.
所以你需要使用TForm1 as the parameter
。
如果您有一个表单Form1,您要为其创建多个实例并向用户显示,请将您的过程语法更改为procedure Slide(Form: TForm1; Show: Boolean);
但是如果您有多个具有不同组件的表单,则会变得困难。您需要使用不同的参数重载过程。下面的代码显示了方法。
Form1单元
var
Form1: TForm1;
implementation
{$R *.dfm}
uses Unit3;
procedure TForm1.Button1Click(Sender: TObject);
begin
Slide(Form1, True)
end;
Form2单元
var
Form2: TForm2;
implementation
{$R *.dfm}
uses Unit3;
procedure TForm2.Button1Click(Sender: TObject);
begin
Slide(Form2, True)
end;
您的程序所在的单位
unit Unit3;
interface
uses Forms, ExtCtrls, Unit1, Unit2;
procedure Slide(Form: TForm1; Show: Boolean) overload;
procedure Slide(Form: TForm2; Show: Boolean) overload;
implementation
procedure Slide(Form: TForm2; Show: Boolean);
begin
Form.Timer1.Enabled := True;
end;
procedure Slide(Form: TForm1; Show: Boolean);
begin
Form.Timer1.Enabled := True;
end;
end.
答案 4 :(得分:2)
只是添加更多信息。
在Delphi项目中,代码被组织成单元。每个单元都是一个名称和.pas扩展名的文件。
该单位具有以下形式:
unit Name;
interface
uses
// The definition of these units can be used both in the
// interface as in the implementation section.
unit1, unit2;
// Public interface, visible to other units that use this unit.
implementation
uses
// The definition of these units can be used only in the
// implementation section.
unit3, unit4;
// Private implementation, not visible outside.
initialization
// code to initialize the unit, run only once
finalization
// code to cleanup the unit, run only once
end.
一个单位可以使用单位中定义的任何东西,只要它在被使用之前被定义。
如果名称相同,有时这会导致令人困惑的情况:
unit1;
interface
type
TTest = Integer;
// ...
unit2;
interface
type
TTest = Boolean;
// ...
unit3;
interface
uses
unit1, unit2;
var
a: TTest; // Which TTest?
// ...
您可以通过了解评估顺序或使用单位前缀来解决此问题:
unit3;
interface
uses
unit1, unit2;
var
a: unit1.TTest; // TTest from unit1
b: unit2.TTest; // TTest from unit2
// ...
在您的情况下,您需要使用定义Form2的单位。
如果两个表单都需要计时器,您也可以使用数据模块(就像表单一样,您可以将不可见的组件拖到它上面,但它们将不可见)。这两种形式都可以使用数据模块。
修改强>
您尝试使用:
procedure Slide(Form: TForm; Show: Boolean);
而且TForm没有Timer1。
您可以执行以下操作:
procedure Slide(Form: TForm2; Show: Boolean);
如果TForm2是包含Timer的表单。
答案 5 :(得分:1)
最简单的方法是在表单上找到它:
procedure Slide(Form: TForm; Show: Boolean);
var
Timer: TTimer;
begin
Timer := Form.FindComponent('Timer1');
if Assigned(Timer) then
Timer.Enabled := True;
end;
安抚大卫;-),这是一个更“类型安全”的选择:
procedure Slide(Form: TForm; Show: Boolean);
var
i: Integer;
begin
// Could use a TComponent and for..in instead. This works in
// all Delphi versions, though.
for i := 0 to Form.ComponentCount - 1 do
if Form.Components[i] is TTimer then
TTimer(Form.Components[i]).Enabled := True;
end;♦♠
答案 6 :(得分:0)
实现此目的的一种简单(和OOP)方法是使用接口。
声明一个接口ISlideable,它定义一个SlideTimer属性(使用getter和setter方法)然后编写Slide方法,如
Slide(const Target: ISlideable; Show: Boolean);
每个应该传递的表格都说它是可滑动的
MyFormN = class(TForm, ISlideable)
...