Forms 在同一应用程序中更改另一个独立窗体上控件的状态

Forms 在同一应用程序中更改另一个独立窗体上控件的状态,forms,delphi,Forms,Delphi,情况: 具有2个表单和1个数据模块单元的应用程序 两个包含表单的单元都使用DataModule。包含Form1的单元使用包含Form2的单元 Form1上有两个按钮 两个表单同时显示,Form1不是Form2的父级,反之亦然 我需要的是: 我需要能够通过Form2上的操作来控制Form1上两个按钮的状态 我所做的: 我在Form1上使用了一个计时器,它连续250ms检查DataModule中的一个变量,并根据它的值更改Form1上按钮的状态。然后,我从Form2修改DataModule中的变量

情况:

具有2个表单和1个数据模块单元的应用程序 两个包含表单的单元都使用DataModule。包含Form1的单元使用包含Form2的单元 Form1上有两个按钮 两个表单同时显示,Form1不是Form2的父级,反之亦然 我需要的是:

我需要能够通过Form2上的操作来控制Form1上两个按钮的状态

我所做的:

我在Form1上使用了一个计时器,它连续250ms检查DataModule中的一个变量,并根据它的值更改Form1上按钮的状态。然后,我从Form2修改DataModule中的变量

DataModule中的变量:

public
  BtnToDisable: string;
Form1上的计时器:

procedure TForm1.Timer1Timer(Sender: TObject);
var
  i: integer;
begin
  if Datamodule4.BtnToDisable = 'All' then
    for i := 0 to Form1.ControlCount - 1 do
    begin
      if Form1.Controls[i].ClassType = TButton then
        Form1.Controls[i].Enabled := False;
    end
  else if Datamodule4.BtnToDisable = 'None' then
    for i := 0 to Form1.ControlCount - 1 do
    begin
      if Form1.Controls[i].ClassType = TButton then
        Form1.Controls[i].Enabled := True;
    end
  else if Datamodule4.BtnToDisable = 'Button1' then
    for i := 0 to Form1.ControlCount - 1 do
    begin
      if Form1.Controls[i].Name = 'Button1' then
        Form1.Controls[i].Enabled := False;
    end
  else if Datamodule4.BtnToDisable = 'Button2' then
    for i := 0 to Form1.ControlCount - 1 do
    begin
      if Form1.Controls[i].Name = 'Button2' then
        Form1.Controls[i].Enabled := False;
    end;
end;
关于表格2的行动:

DataModule4.BtnToDisable := 'All'     // All, None, "name"
DataModule4.BtnToDisable := 'Button1' // All, None, "name"
...
问题是:


好吧,它可以工作,但在更复杂的场景中,有很多按钮需要启用/禁用,更多的表单和更多可能的组合启用三个特定的按钮,禁用所有其他按钮,等等,它变得复杂,并且很难维护。考虑到我没有可以从Form2访问的Form1对象,有没有办法直接访问Form1上的按钮?

您始终可以访问每个Form对象,即使您不直接使用它们的单位。所有创建的TForm对象都存储在Forms单元中全局对象的属性中

也就是说,我建议使用TActionList.OnUpdate或TApplicationEvents.OnIdle事件处理程序来执行按钮更新,而不是使用TTimer。每当主UI消息循环完成处理来自主消息队列的消息并空闲等待新消息到达时,就会触发这些事件。当您开始处理需要更新的多个表单时,您可以为每个表单提供自己的TActionList或TApplicationEvents

我还建议定义一个枚举来表示每个按钮,然后将BTNTODABLE变量更改为这些枚举值的集合。这样,您可以禁用所需的任何按钮组合。将这些枚举值指定给每个按钮的标记属性,或使用字典、类帮助器或任何其他方法将枚举值与按钮对象关联。然后,当需要更新时,您可以简单地在按钮之间循环,如果给定按钮的关联枚举值在集合中,则禁用该按钮,否则启用它。根本不需要检查名称属性


最后,我建议让表单将其按钮存储在数组或TObjectList中,您可以循环使用,而不是每次都循环使用表单的Controls[]属性。

您始终可以访问每个表单对象,即使您不直接使用它们的单位。所有创建的TForm对象都存储在Forms单元中全局对象的属性中

也就是说,我建议使用TActionList.OnUpdate或TApplicationEvents.OnIdle事件处理程序来执行按钮更新,而不是使用TTimer。每当主UI消息循环完成处理来自主消息队列的消息并空闲等待新消息到达时,就会触发这些事件。当您开始处理需要更新的多个表单时,您可以为每个表单提供自己的TActionList或TApplicationEvents

我还建议定义一个枚举来表示每个按钮,然后将BTNTODABLE变量更改为这些枚举值的集合。这样,您可以禁用所需的任何按钮组合。将这些枚举值指定给每个按钮的标记属性,或使用字典、类帮助器或任何其他方法将枚举值与按钮对象关联。然后,当需要更新时,您可以简单地在按钮之间循环,如果给定按钮的关联枚举值在集合中,则禁用该按钮,否则启用它。根本不需要检查名称属性


最后,我建议让表单将其按钮存储在可以循环的数组或TObjectList中,而不是每次都循环表单的Controls[]属性。

您不需要仲裁器,比如数据模块。因为form1知道form2,所以可以从form1填充的form2中公开一个结构,比如按钮数组。为什么这么复杂?定义表单的两个单元可以访问另一个单元。因此,在form1代码中,您可以直接访问form2,反之亦然。这不一定是一个好主意,但它将大大提高您当前的代码。换句话说,您说有没有办法直接访问Form1上的按钮,考虑到我没有Form1对象,可以从Form2访问?但是你可以很容易地从Form2访问Form1。更重要的是,如果你根本不想使用计时器的话。您希望使用操作或操作列表。结合这两种观察,你的代码将变得干净。你不需要仲裁
例如数据模块。因为form1知道form2,所以可以从form1填充的form2中公开一个结构,比如按钮数组。为什么这么复杂?定义表单的两个单元可以访问另一个单元。因此,在form1代码中,您可以直接访问form2,反之亦然。这不一定是一个好主意,但它将大大提高您当前的代码。换句话说,您说有没有办法直接访问Form1上的按钮,考虑到我没有Form1对象,可以从Form2访问?但是你可以很容易地从Form2访问Form1。更重要的是,如果你根本不想使用计时器的话。您希望使用操作或操作列表。结合这两种观察,您的代码将变得干净。更容易将Unit1添加到Unit2的实现部分使用。@DavidHeffernan将Unit1添加到Unit2的实现部分使用-这是原始问题的答案。我很惊讶这是多么简单。我将把它与雷米的建议结合起来。感谢您帮助我们将Unit1添加到Unit2的“使用”实现部分。@DavidHeffernan将Unit1添加到Unit2的“使用”实现部分-这是原始问题的答案。我很惊讶这是多么简单。我将把它与雷米的建议结合起来。谢谢大家