【问题标题】:List Index Out of Bounds on screen.forms在 screen.forms 上列出索引超出范围
【发布时间】:2023-04-10 04:21:01
【问题描述】:

我使用reportbuilder 对表单进行一些报告。 在主窗体上,我在网格上选择了一些项目,然后生成项目的报告。 我想在 Tthread 中执行此操作,但出现错误“列表索引超出范围”。

这里是调用栈:

Classes.TList.Get(1244868)
Classes.TList.Get(???)
Forms.TScreen.GetCustomForms(???)
Forms.TApplication.DoActionIdle
Forms.TApplication.Idle(???)
Forms.TApplication.HandleMessage
Forms.TApplication.Run

似乎某些表单没有被添加到 Screen.Forms 及时收集或在收集期间被释放 在 DoActionIdle 中循环。

关于如何规避这个问题的任何想法? 我在 windows XP 和 delphi 2010 上工作。

我的应用程序的测试程序也有问题 TForm3 只是一个没有代码的表单。

TDebugThread = class(TThread)
protected
  procedure Execute; override;
public
  constructor Create();
end;

constructor TDebugThread.Create;
begin
   FreeOnTerminate := True;
   inherited Create(False);
end;

procedure TDebugThread.Execute;
var
  oReport:  DeBugReport.TForm3;
begin
  inherited;
  oReport:=  DeBugReport.TForm3.Create(Nil);
  try
    sleep(1000);
  finally
    oReport.Free;
  end;
end;

....
procedure RunThread();
begin
  TDebugThread.Create();
end;

回顾:

我在表格上有一份干预清单。我可以在 2/5 报告上打印干预的每个细节和恢复。因此,我在另一个表单(不可见)上使用报告组件(reportbuilder)。新功能是多选列表中的一些干预措施,并将报告设置为 pdf 格式的文件夹。这很简单,只需在每次干预时调用报告表和一些要更改并保存为 pdf 的参数。 但这需要很长时间。用户必须等到程序结束。没问题我在一个线程中设置程序。但是我收到错误“列表索引超出范围”。 ArgggArggg,我怀疑报告表(创建,他的工作,然后销毁)的问题,但希望有另一种解决方案。我正在考虑将 TForm 更改为 TDataModule。我可以将表单的所有组件设置到数据模块中吗?我使用 TDbGrid 来查看设计中的一些值。但是在 Tdatamodule 中我无法设置 TDBGrid。好的,我可以没有 TDbGrid。所以我将 TForm 转换为 TDataModule。 但 TDataModule 不是答案。在那里,我从 TBitmap 收到错误“Graphics.OutOfResource”。我认为 TBitmap 是从 TppReport 调用的。现在我完成了。我更改代码超过 2 天都没有结果。我暂时离开 TThread。

【问题讨论】:

  • 几个cmets。你在这里问了两个完全不同的不相关的问题。你应该一次问一个问题。其次,您实际上并没有说出问题的第二部分的问题所在。你刚才说“我有问题”这真的太含糊了。你需要解释问题是什么。
  • @DavidHeffernan:同样的错误。我消除了一些代码来捕获过程 DoActionIdle 中的错误。我得到的错误是“项目越界”。 screen.customformcount 正在循环中改变
  • 好吧,我没能推断出来。无论如何,我认为我在答案中所说的一切都站得住脚。

标签: multithreading delphi delphi-2010


【解决方案1】:

我们来看看TApplication.DoActionIdle

procedure TApplication.DoActionIdle;
var
  I: Integer;
begin
  for I := 0 to Screen.CustomFormCount - 1 do
    with Screen.CustomForms[I] do
      if HandleAllocated and IsWindowVisible(Handle) and
        IsWindowEnabled(Handle) then
        UpdateActions;
end;

假设Screen.CustomFormCount 和被正确实现并且总是返回由Screen.CustomForms 索引的项目数。在这种情况下,结论是循环体正在删除一个表单。即Screen.CustomFormCount在循环执行过程中发生变化。

可能发生的唯一方法是表单的操作更新处理程序之一导致表单被删除。所以,我不能告诉你更多,但这个分析应该会引导你找到问题的根本原因。


您问题的第二部分非常简单。您不能在主 GUI 线程之外使用 VCL 组件。

事实上,在你的线程中销毁 VCL 表单是导致Screen.CustomFormCountTApplication.DoActionIdle 的 GUI 线程中执行期间发生变化的原因,这似乎是合理的。

【讨论】:

  • 我不明白关于主 GUI 线程之外的 VCL 的最后评论
  • 没什么好说的了。您只能在 GUI 线程上与 VCL 对象交互。你违反了这条规则。
  • 很抱歉,我看不到错误。你是说我不能像我在线程中创建的表单那样使用 VCL 对象创建 TThread。
  • 这正是我要说的。
  • 好的,如果我将 Tform 更改为 TDataModule,那么我的 TDataModule 不是表单。所以 custmformcount 不会改变。
猜你喜欢
  • 2021-05-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-17
  • 2018-12-16
  • 2014-08-25
相关资源
最近更新 更多