Delphi - 从表单访问Frame对象

时间:2009-01-27 23:10:02

标签: delphi frames

我需要运行一个附加到按钮(例如SQLBtn)的动作,该动作放在我的应用程序中的Frame1上,来自Form1。
我已经在Form1中使用了框架,但似乎无法以任何方式解决 我已经尝试过Frame1.SQLbtn TFrame1.SQLbtn TFrameSQLBtn等,但无法达到它。
我想得到类似于'SQLbtn.click'的东西来运行它背后的事件。

有没有人有任何想法如何解决?

4 个答案:

答案 0 :(得分:5)

我不确定我是否理解你的问题。听起来你有一个带按钮的框架(按钮上有一个TAction或click事件处理程序),这个框架就坐在一个表格上。现在,您希望以编程方式模拟该按钮上的单击。

显然,您需要将帧单位添加到表单的uses子句中。您还需要表单上的框架实例,该实例应该导致框架类型的表单字段,例如

TForm1...
  ...
  Frame1: TFrame1;
end;

然后,您可以从任何表单的方法中通过Frame1.SQLbtn.Click执行该代码。更好的方法可能是在框架上提供可以从表单中使用的公共方法。然后你不需要直接访问该按钮(该按钮是框架的实现细节,框架私有可以这么说)。

澄清后编辑

我知道您有以下情况:

TFrameForm1...
  ...
  Frame1: TFrame1;
end;

TForm1...
  ...
  procedure something;
end;

procedure TForm1.something;
begin
  // how to call a method on Frame1 which is on FrameForm1
end;

您最好的选择是将代码从框架按钮OnClick事件处理程序移动到一个单独的单元中。这可以是数据模块,也可以是具有独立过程的另一个单元。然后,您可以从Form1和Frame1按钮事件处理程序中调用该代码。这就是Vegar评论的内容。

如果不可能,例如因为处理需要访问Frame1上的其他控件,将代码移动到Frame1上的新程序(我的原始建议):

TFrame1...
  ...
public
  procedure framestuff;
end;

procedure TFrame1.framestuff;
begin
  ...
end;

procedure TFrame1.SQLbtnClick(Sender...);
begin
  framestuff;
end;

现在需要从Form1调用该方法。你需要一个对FrameForm1的引用。在创建TFrameForm1时需要手动初始化(!)。在此示例中,引用是字段FFrameForm:

TForm1...
  ...
  FFrameForm: TFrameForm1;
  procedure something;      
end;

procedure TForm1.something;
begin
  FrameForm.framestuff;
end;

或者,默认情况下,Delphi将所有表单的全局变量添加到表单单元(自动表单创建,检查项目选项/表单)。然后你这样做:

procedure TForm1.something;
begin
  FrameForm1.framestuff; // if FrameForm1 is the name Delphi used for the global variable
end;

当然还有很多其他的变化......

答案 1 :(得分:1)

procedure TDiferentForm.DoSomething();
begin
  Form1.YourFrame.ButtonClick(nil);
end;

答案 2 :(得分:0)

有一件事可能有助于您理解:当您创建表单(或框架)的实例时,delphi会遍历DFM并创建其中描述的所有对象的实例。

IF 您在表单的定义中有一个与DFM中对象名称匹配的变量,加载器将使变量指向该对象;如果您没有变量,则会创建该对象,但您必须遍历.Components或.Controls才能访问它。

如果表单有一个框架的实例变量(并且该变量是公共的),那么任何其他表单的代码都可以访问它(例如MainForm.Frame1 ...)并按照自己的意愿行事。

要封装框架,表单(毕竟只是一个类)可以具有公共属性,它们具有访问器和更改器,用于代理嵌入式帧的信息。封装是好的(恕我直言是OOP最重要的方面),因为它使调用者和框架之间的链接松散:你可以在不破坏任何东西的情况下改变任何一方。

干杯

答案 3 :(得分:0)

另一种解决方案是使用接口来避免循环引用问题并稍微简化代码。假设您要从系统中的任何位置调用名为 foo 的过程。此过程的实现在 tFooForm 中,它不是主要表单,而是主表单知道的表单。

首先创建一个新单位并将其命名为 Foo_Intf.pas

其内容如下:

unit Foo_Intf;

interface

type
  IFoo = interface
    ['{4AC12AB9-557B-4E61-AB2D-8B10E591E33A}'] 
    // CTRL-SHIFT-G to create a new guid
    procedure Foo;
  end;

implementation

end.

然后将方法添加到tFooForm类,并且还包括接口。不要忘记在interface uses子句中使用foo_intf.pas单元。实现foo类以执行您希望该过程执行的操作。

tFooForm = class(tForm,IFoo)
  :
  procedure Foo;
  :
end;

还要将IFoo接口添加到主窗体,与上一步完全相同,但将实现更改为以下内容:

procedure tMainForm.Foo;
begin
  if not Assigned(FooForm) then
    FooForm := tFooForm.Create(Application);  // for simplicity sake
  FooForm.Foo;
end;

现在,您想要调用foo函数的任何地方,只需在uses子句中包含Foo_Intf单元并使用以下snippit:

var
  FooIntf : IFoo;
begin
  if Not Supports(Application.MainForm, IFoo, FooIntf) then
    Raise Exception.create('Application.mainform does not implement IFoo');   
  FooIntf.Foo;
end;