如何从窗体单元外部访问 Delphi 控件?
我试图从如下定义的过程中调用计时器的 Enabled 属性: procedure Slide(Form: TForm; Show: Boolean);
并且不使用固定的表单名称(例如: Form2.Timer...
)
将表单的单位放入使用列表中后,此方法有效:Form2.Timer1.Enabled := True;
但以下内容不起作用: Form.Timer1.Enabled := True;
(其中 Form 是作为参数传递给过程的表单。
如何访问我的表单上的计时器组件?
谢谢进步。
I'm trying to call the Enabled property of a Timer from a procedure defined like this: procedure Slide(Form: TForm; Show: Boolean);
and not with a fixed form name (like: Form2.Timer...
)
After putting the form's unit in the uses list, this works: Form2.Timer1.Enabled := True;
but the following is not working: Form.Timer1.Enabled := True;
(where Form is the form passed as parameter to the procedure.
How to get access to the Timer component on my form?
Thanks in advance.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
如果您要传递到函数中的每个表单都有一个名为“Timer1”的已发布字段,那么您可以使用
FindComponent
方法来获取对其的引用:不过,这是一个相当弱的编程接口。如果您不小心忽略了在表单上放置计时器,或者您给了它错误的名称,或者您给了它不同的可见性,那么直到运行时(当断言失败)。即使表单确实满足所需的接口,也不能保证它是故意的。可能有很多表单发布了名为
Timer1
的TTimer
字段,但它们并不都适合与此Slide
函数一起使用。它们可能已经将计时器用于其他目的,因此对它们调用Slide
会破坏程序的其他部分,而且可能会以难以调试的方式破坏。如果您为计时器指定一个更具描述性的名称(例如
SlideTimer
),那么界面会稍微强大一些。Timer1
只是表示它是您在该表单上创建的第一个TTimer
,一旦您离开表单设计器,它就不再是一个有意义的名称。您不需要使用 IDE 的命名选择。另一个更好的选择是让所有可滑动表单都有一个公共基类,并将计时器放入该基类中。然后,更改
Slide
中的参数类型以采用该表单类,而不仅仅是TForm
。您似乎担心必须在
Slide
单元中包含对 Form2 单元的引用,这通常是一个值得关注的问题。您不希望代码耦合得太紧密,因为此Slide
函数应该能够在一个项目中使用不止一种表单。但如果太松,就会遇到我上面描述的问题。这个TSlidableForm
类是一个折衷方案;您的Slide
函数未直接绑定到TForm2
或其单元。将TForm2
更改为TSlidableForm
的下降形式。The_Fox 的第二个建议< /a> 是我第一个的变体,但还有另一个变体。您可以传递对组件本身的引用,而不是传递计时器组件的名称:
现在您不需要使用
FindComponent
来搜索要使用的计时器;您已经提供了对其的直接引用。组件的名称并不重要,因此不同的形式可以使用不同的名称。您可以这样称呼它:一旦您走到这一步,您可能会超越原来的问题,并意识到计时器甚至不再需要属于表单。您可以专门为调用
Slide
创建它,或者计时器可以完全属于其他东西(例如数据模块)。但是,如果您打算仅为Slide
调用创建计时器,那么您可以使用 David 的建议,在例程本身内创建计时器,而根本不需要调用者或表单处理它:If every form you're going to pass into your function will have a published field named "Timer1," then you can use the
FindComponent
method to get a reference to it:That's a rather weak interface to program against, though. If you've accidentally neglected to place a timer on your form, or if you've given it the wrong name, or if you've given it a different visibility, you won't discover your mistake until run time (when the assertions fail). And even if the form does meet the required interface, there's no guarantee that it was intentional. There may be lots of forms that have published
TTimer
fields namedTimer1
, but they're not all meant to be used with thisSlide
function. They might already be using their timers for other purposes, so callingSlide
on them will break other parts of your program, possibly in difficult-to-debug ways.It would be a slightly stronger interface if you gave the timer a more descriptive name, such as
SlideTimer
.Timer1
merely says it was the firstTTimer
you created on that form, and once you leave the Form Designer, that ceases to be a meaningful designation. You are not required to use the IDE's naming choices.Another, better, option is to make all your slidable forms have a common base class, and put the timer in that base class. Then, change the parameter type in
Slide
to take that form class instead of justTForm
.You seemed concerned that you would have to include a reference to Form2's unit in your
Slide
unit, and that's generally a good concern to have. You don't want your code to be too tightly coupled since thisSlide
function should be able to work with more than just one form in one project. But if it's too loose, then you run into the problems I described above. ThisTSlidableForm
class is a compromise; yourSlide
function isn't bound directly toTForm2
or its unit. ChangeTForm2
to descend fromTSlidableForm
.The_Fox's second suggestion is a variation on my first, but there's still another variation. Instead of passing the name of the timer component, you can pass a reference to the component itself:
Now you don't need to use
FindComponent
to search for the timer to use; you've provided a direct reference to it. The component's name doesn't even matter, so different forms can use different names. You can call it like this:Once you've come this far, you may go beyond your original question and realize that the timer doesn't even need to belong to the form anymore. You could create it specially for the call to
Slide
, or the timer could belong to something else entirely (like a data module). But if you're going to create the timer just for theSlide
call, then you could use David's suggestion of creating the timer within the routine itself and not have the caller or the form deal with it at all:您无法从过程中访问 Timer,因为您的参数是 TForm,而 TForm 没有 Timer1 成员。您必须像这样调整您的程序:
编辑:
如果您想传递任何表单,您可以尝试以下操作:
从表单上的按钮像这样调用:
或者让您的表单继承一个接口方法来打开定时器。但它有点复杂。
You cannot access the Timer from your procedure because your parameter is a TForm, and TForm does not have a Timer1 member. You have to adjust your procedure like this:
Edit:
If you want to pass any form, you can try this:
Call like this from a button on your form:
Or you let your Form inherit an interface with methods to turn on the timer. It's a little bit more complicated though.
将单位添加到使用列表中。
Add the unit to the uses list.
使用当前单位使用列表中Form2的单位名称。
对于您的编辑:
通过使用
TForm
您无法访问TTimer
,因为TForm
没有没有 TTimer 那样的字段或属性。
因此您需要使用
TForm1作为参数
。如果您有一个表单(例如 Form1),您要为其创建多个实例并向用户显示,则将过程语法更改为
procedure Slide(Form: TForm1; Show: Boolean);
但如果您如果有多种形式和不同的组成部分,就会变得很困难。您需要使用不同的参数重载过程。下面的代码显示了该方法。
Form1 单位
Form2 单位
您的程序所在的单位
Use Form2's unit name in uses list of current unit.
For your Edit:
By using
TForm
you cant accessTTimer
becauseTForm
hasno fields or properties as TTimer.
So you need to use
TForm1 as the parameter
.If you are having a form say Form1, for which you are creating multiple instances and showing to the user, then change your procedure syntax to
procedure Slide(Form: TForm1; Show: Boolean);
But if you are having multiple forms with different components, it will become difficult. You need to overload procedures with different parameters. Below code shows the approach.
Form1 Unit
Form2 Unit
Unit in which your procedures lies
只是添加一些更多信息。
在 Delphi 项目中,代码被组织成单元。每个单元都是一个具有名称和 .pas 扩展名的文件。
单元具有以下形式:
单元可以使用单元中定义的任何内容,只要在使用之前定义它即可。
有时,如果名称相同,这会导致混乱的情况:
您可以通过了解计算顺序或使用单位前缀来解决此问题:
在您的情况下,您需要使用定义 Form2 的单位。
如果两种表单都需要计时器,您还可以使用数据模块(就像表单一样,您可以将不可见的组件拖到其中,但它们将不可见)。两种形式都可以使用数据模块。
编辑
您尝试使用:
并且TForm没有Timer1。
您可以执行以下操作:
如果 TForm2 是包含计时器的表单。
Just to add some more information.
In a Delphi project, code is organised into units. Each unit is a file with a name and a .pas extention.
The unit has the following form:
A unit can use anything defined in the unit as long as it is defined before it is beïng used.
Sometimes this leads to confusing situations if names are identical:
You can solve this by either knowing the evaluation order, or use a unit prefix:
In your case, you need to use the unit in which Form2 is defined.
If the timer is needed by both forms, you can also use a datamodule (just like a form, you can drag nonvisible components to it but they won't be visible). Both forms then can use the datamodule.
Edit
You try to use:
And TForm has no Timer1.
You can do the following:
If TForm2 is the form containing the Timer.
最简单的方法是在表单上找到它:
为了安抚大卫;-),这里有一个更“类型安全”的替代方案:
The easiest way is to find it on the form:
To appease David ;-), here's a more "type-safe" alternative:
实现此目的的一种简单(和 OOP)方法是使用接口。
声明一个 ISlideable 接口,它定义一个 SlideTimer 属性(带有 getter 和 setter 方法),然后编写 Slide 方法,如下所示
并且应该传递的每个表单都表示它是 Slideable
A simple (and OOP) way to implement this is to use interfaces.
Declare an interface ISlideable which defines a SlideTimer property (with getter and setter methods) and then write the Slide method like
And every form which should be passed says that it is Slideable