2

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

有谁知道如何解决它?

4

4 回答 4

6

我不确定我是否正确理解了您的问题。听起来您有一个带有按钮的框架(以及按钮上的 TAction 或单击事件处理程序),并且该框架位于表单上。现在您想以编程方式模拟对该按钮的单击。

显然,您需要将框架单元添加到表单的 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;

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

于 2009-01-27T23:32:32.343 回答
1
procedure TDiferentForm.DoSomething();
begin
  Form1.YourFrame.ButtonClick(nil);
end;
于 2009-01-28T11:01:41.250 回答
0

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

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

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

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

干杯

于 2009-01-29T01:30:54.117 回答
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 类中,并包含接口。不要忘记在你的接口使用子句中使用 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 单元并使用以下代码片段:

var
  FooIntf : IFoo;
begin
  if Not Supports(Application.MainForm, IFoo, FooIntf) then
    Raise Exception.create('Application.mainform does not implement IFoo');   
  FooIntf.Foo;
end;
于 2009-01-29T17:01:57.460 回答