【问题标题】:Delphi: frozen form德尔福:冷冻形式
【发布时间】:2011-08-11 05:37:55
【问题描述】:

有两种形式。

Form2 不是自动创建的。

 Form2:=TForm2.Create(Application);
 Form2.Show;

如果在任何表格中执行Sleep(10000);,那么另一个表格将被冻结。如何防止这种行为?

我的问题:一个大文本文件 (3 Mb) 被连续分配 (Lines.Assign) 到文本编辑器中,因此表单被冻结。

我可以使用另一个未冻结的表单(不是模态)来显示进度条(样式是 pbstMarquee)吗?

【问题讨论】:

  • Sleep() 函数的定义是“冻结此线程”,如果您冻结主线程,则冻结所有表单,因为它们都只能在主线程中工作。听起来您需要了解消息泵在 win32 应用程序设计中的重要性。 en.wikipedia.org/wiki/Event_loop
  • 曾经真正的理由调用睡眠吗?
  • 在前台线程中?不,即使在后台线程中,WaitForSingleObject 也会更好。我认为 OP 正在使用 Sleep() 来模拟他的 3mb 文本文件的加载时间。
  • 最大传真;如果您要加载 3mb 的文件,请尝试使用 SynEdit 而不是 TMemo。
  • @Nick Hodges - 当然。例如,许多协议需要延迟。 WFSO 需要创建一个同步对象来等待,而这种复杂性的唯一理由是 Delphi 中近乎绝望的线程支持,(是的,我知道,其他语言同样糟糕或好不了多少),这迫使开发人员努力终止在应用程序上释放表单之前的后台线程。关闭。

标签: multithreading forms delphi


【解决方案1】:

所有的 GUI 代码都应该从主线程运行,看起来你正在遵循这条规则。

如果你调用Sleep,那么调用线程在超时之前不会执行代码。如果你从主线程调用Sleep,那么在超时时间过去之前,消息队列不会被抽取。因此,整个应用程序似乎被冻结了。

为什么从一个表单调用Sleep 会影响另一个表单?因为所有 GUI 组件都由主线程的单个消息队列提供服务。一旦您停止发送该队列,所有 GUI 组件都会停止接收排队的消息,例如 WM_PAINTWM_KEYDOWN 等。

据我了解,您的问题是当您将 3MB 文本文件加载到编辑控件时,您的应用程序似乎挂起。这个文件大小对我来说听起来不是很大,一个明显的解决方案是找到一个可以更好地执行加载的编辑控件。例如,我很确定 Notepad、Notepad++ 等在加载此类文件时不会采取显示进度等步骤。我宁愿怀疑这些应用程序在加载文件时不会抽出队列,但由于花费的时间很短,您只是没有注意到。

您不希望发生的事情是让您抽出队列以保持 GUI 响应,进而允许用户在第一个文件仍在加载时开始加载另一个文件。您需要在处理加载操作时禁用 UI。模态进度对话框是一种方法。

如果您无法切换到性能更好的控件,您可以显示一个模态进度对话框并使用这样的后台线程。后台线程会以小块的形式加载文件,比如放入字符串列表中。在文件的每个块准备好之后,它会调用 Synchronize 并让主线程将字符串列表的内容添加到编辑控件,然后清除字符串列表。然后线程将继续并加载下一个块。以小块的形式添加到编辑控件将允许您保持消息队列的服务。

您可以在状态栏而不是模式对话框中显示进度,这样会减少干扰。但请记住禁用任何会导致重入执行的 UI。

【讨论】:

  • 记事本在加载大文件时非常慢。它不处理消息并在加载完成之前显示为挂起。
  • 阿列克谢是对的。尝试用记事本打开 3 Mb。我想,Notepad++ 不会加载整个文件,它会向用户显示文件的一部分,并在滚动时加载其他文件。我使用 SynEdit。如何加载块?如果逐个字符串添加它会很慢。我需要按字节加载字节:)
  • 因此可以加载 100 Mb,但 100 Mb 并没有真正加载。我认为如果连续加载 5 Mb,任何程序都会卡住。
  • @Alexey 我必须承认我从不使用记事本,我只接触过 Notepad++。
【解决方案2】:

最好在单独的线程中加载您的文件。或者你将不得不在一个普通的 WinAPI 中创建你的第二个表单,因为 VCL 不支持多线程。

【讨论】:

    猜你喜欢
    • 2014-07-08
    • 1970-01-01
    • 2017-07-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-02
    • 2011-10-04
    相关资源
    最近更新 更多