Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Forms Delphi-表单创建和新创建表单上的对象_Forms_Delphi - Fatal编程技术网

Forms Delphi-表单创建和新创建表单上的对象

Forms Delphi-表单创建和新创建表单上的对象,forms,delphi,Forms,Delphi,动态表单创建主题已经被涵盖了很多次,但我找不到解决我的问题的方法,所以我在这里。。。再次…:-) 我之前的问题让我认为,如果不是所有表单都是在启动时创建的,而是在需要时动态创建的,那么我的应用程序将启动得更快。 这基本上是正确的,当我只创建了主窗体和数据模块时,启动速度要快得多 点击按钮,下面是我用来创建和按需释放表单的代码(主要受Jerry Dodge和Craig Young的答案启发,感谢他们的帮助): 同样,这很好,但是在创建frmKeywords时,一个主表格网格应该由一个FDQuery

动态表单创建主题已经被涵盖了很多次,但我找不到解决我的问题的方法,所以我在这里。。。再次…:-)

我之前的问题让我认为,如果不是所有表单都是在启动时创建的,而是在需要时动态创建的,那么我的应用程序将启动得更快。 这基本上是正确的,当我只创建了主窗体和数据模块时,启动速度要快得多

点击按钮,下面是我用来创建和按需释放表单的代码(主要受Jerry Dodge和Craig Young的答案启发,感谢他们的帮助):

同样,这很好,但是在创建frmKeywords时,一个主表格网格应该由一个FDQuery填充,该FDQuery在显示表单时触发。 当然(或者我不会在这里),他补充道

在FormShow或FormCreate中,事件以“访问冲突错误”结束

所以我修改了我的创建代码,现在看起来像:

procedure TfrmWelcome.BtKeywordsClick(Sender: TObject);
  var
    F_Keywords : TfrmKeywords;
  begin
    F_Keywords := Tfrmkeywords.Create(nil);
      try
        F_Keywords.FDQuery1.Open;
        F_Keywords.ShowModal;
      finally
        F_Keywords.FDQuery1.Close;
        F_Keywords.Free;
      end;
end;
(我甚至不确定
FDQUery1.Close
在finally块中是否有用)

太好了,现在我的表单出现了,主数据网格中充满了数据

问题是,当用户在DBGrid1中单击时,所选记录的数据库id作为参数传递给辅助FDQuery,后者反过来用数据填充辅助DBGrid(DBGrid1中的主数据,DBGrid2中的子数据)

这是这样做的:

procedure TfrmKeywords.DBGridEh1CellClick(Column: TColumnEh);
var
  kwid : Integer;
begin
  frmKeywords.FDQuery2.Close; //Closing secondary query
  kwid := FDQuery1.FieldByName('id').AsInteger; //Assigning kw_id according to selected row
  frmKeywords.FDQuery2.ParamByName('kw_id').AsInteger := kwid; //Linking query2 parameter to kwid
  frmKeywords.FDQuery2.Open; //Reopening query2 to display assets
end;
和之前一样,这里也有“访问冲突错误”。像FDQuery不存在可能吗

所以我的问题是:当动态创建表单时,该表单的所有可视和非可视组件是否都会自动创建?Dbgrids出现在我的表单上,似乎可以工作,因为数据已经显示(至少在其中一个中),但第二个FDQuery不想工作。 很明显,我遗漏了一些东西。我排除了数据模块上的FDConnection,因为FDQuery1可以工作,所以我没有想法

提前谢谢


数学

问题在于,您正在访问预先声明的全局变量frmKeywords,该变量在您尝试访问它时为nil。相反,您正在实例化表单并将引用存储在局部变量中,这本身就很好,但不需要访问未分配的变量。因此,只需修改代码,如下所示:

procedure TfrmKeywords.DBGridEh1CellClick(Column: TColumnEh);
var
  kwid: Integer;
begin
  { do not access the frmKeywords variable here; if you want to explicitly
    hint yourself about accessing the current form instance, you can write
    Self.FDQuery2.Close; but that Self is not necessary, e.g. the following
    lines refer to the current form instance as well }
  FDQuery2.Close;
  kwid := FDQuery1.FieldByName('id').AsInteger;
  FDQuery2.ParamByName('kw_id').AsInteger := kwid;
  FDQuery2.Open;
end;
关于在数据集发布之前显式关闭数据集,您不需要在数据集发布之前显式关闭数据集。这在内部发生

最后一点注意,在更改参数值时,不必重新打开数据集来刷新数据视图。事实上,这不是我们想要的。您可以设置一个SQL查询,打开在DBMS上准备查询的数据集,然后您只需修改参数并调用以刷新视图,因此在您的情况下,代码可以简化为(不要忘记在发生这种情况之前的某个地方,但只需一次)FDQuery2


或者查看主题,了解如何在不使用任何代码的情况下执行所需操作(它适用于您,因为您使用的是DB-aware控件)。

问题在于,您正在访问预先声明的全局变量frmKeywords,在尝试访问它时,该变量为nil。相反,您正在实例化表单并将引用存储在局部变量中,这本身就很好,但不需要访问未分配的变量。因此,只需修改代码,如下所示:

procedure TfrmKeywords.DBGridEh1CellClick(Column: TColumnEh);
var
  kwid: Integer;
begin
  { do not access the frmKeywords variable here; if you want to explicitly
    hint yourself about accessing the current form instance, you can write
    Self.FDQuery2.Close; but that Self is not necessary, e.g. the following
    lines refer to the current form instance as well }
  FDQuery2.Close;
  kwid := FDQuery1.FieldByName('id').AsInteger;
  FDQuery2.ParamByName('kw_id').AsInteger := kwid;
  FDQuery2.Open;
end;
关于在数据集发布之前显式关闭数据集,您不需要在数据集发布之前显式关闭数据集。这在内部发生

最后一点注意,在更改参数值时,不必重新打开数据集来刷新数据视图。事实上,这不是我们想要的。您可以设置一个SQL查询,打开在DBMS上准备查询的数据集,然后您只需修改参数并调用以刷新视图,因此在您的情况下,代码可以简化为(不要忘记在发生这种情况之前的某个地方,但只需一次)FDQuery2

或者看一下主题,看看如何在没有任何代码的情况下做你想做的事情(它适用于你,因为你使用的是DB-aware控件)。

如果你按住Ctrl键并点击
frmKeywords
,你将看到Delphi自动为你生成的标识符的默认全局定义(imho毫无帮助)

请注意,当您在运行时创建表单时,您正在将新创建的表单分配给一个完全不同的引用:
F_关键字:=Tfrmkeywords.create(nil)。请务必注意,这不会设置全局变量
frmKeywords
。如果您调试了以下任何访问冲突:

  • 在有问题的行上放置断点
  • 在调试模式下运行
  • 当你点击断点时,检查
    frmKeywords
    的值,你会发现它是
    nil
  • 这就是AV触发的原因:你试图访问“无”的成员
提示:尽管表单和数据模块有一些特殊功能,但它们仍然是“普通对象”。因此,它们的行为与其他对象完全相同:

  • 可以创建多个实例
  • 引用仍然必须显式分配才能使用
  • 对象方法可以很容易地引用它们自己的成员
(您可能知道上述内容,但正如您将看到的,有意识的提醒很重要。)


因此,您可能认为只需将运行时创建更改为
frmKeywords:=Tfrmkeywords.Create(nil)。是的,那会管用,但不是个好主意。不使用全局变量做得很好。因此,您应该删除Delphi创建的全局变量。此时,您将发现您的应用程序不再编译,因为您仍然有许多对全局变量的引用。例如

procedure TfrmKeywords.DBGridEh1CellClick(Column: TColumnEh);
var
  kwid : Integer;
begin
  frmKeywords.FDQuery2.Close;
  kwid := FDQuery1.FieldByName('id').AsInteger;
  frmKeywords.FDQuery2.ParamByName('kw_id').AsInteger := kwid;
  frmKeywords.FDQuery2.Open;
end;
上面的3行将产生
procedure TfrmKeywords.DBGridEh1CellClick(Column: TColumnEh);
begin
  { dataset must be opened here, which means that FDQuery2.Open method has
    been called before (but only once for the query) }
  FDQuery2.ParamByName('kw_id').AsInteger := FDQuery1.FieldByName('id').AsInteger;
  FDQuery2.Refresh;
end;
procedure TfrmKeywords.DBGridEh1CellClick(Column: TColumnEh);
var
  kwid : Integer;
begin
  frmKeywords.FDQuery2.Close;
  kwid := FDQuery1.FieldByName('id').AsInteger;
  frmKeywords.FDQuery2.ParamByName('kw_id').AsInteger := kwid;
  frmKeywords.FDQuery2.Open;
end;