Delphi: 在后台线程中使用TWebBrowser

3
在TWebBrowser中是否可能在后台线程中加载网页?
当应用程序加载时,我想从Web下载一个页面到TWebBrowser中,但我不想阻塞GUI线程。
有什么建议吗?
一些澄清:
WebBrowser组件存在于一个表单中,并且我想显示来自Web的页面。但我希望将所有下载该页面的工作都放在后台线程中,以便加载重型页面不会阻塞GUI线程。
我认为我能够编写一般的线程。
3个回答

9

TWebBrowser已经在一个单独的线程中下载内容。在下载期间,您的程序应该保持响应。您可以通过设置URL并等待下载完成来验证此操作:

WebBrowser1.Navigate(...);
while WebBrowser1.Busy do
  Application.ProcessMessages;

这段代码使用了ProcessMessages,因此我不能良心推荐它。如果您想在下载完成时收到通知,而不是像该代码一样轮询,请处理控件的OnNavigateComplete2事件。请注意,该事件可能会为框架以及主页面触发。

如果您要显示页面,那么您的TWebBrowser控件无论如何都不应该在单独的线程中,因为它遵循与VCL中使用的任何其他控件相同的规则。如果您只是使用该控件来下载页面,则TWebBrowser可能过于复杂。您可以使用Indy或操作系统内置的文件下载功能。这些功能可以轻松地在单独的线程中使用。


这很有道理。我的应用程序会停顿几秒钟,但我想我必须找到另一个原因。 - Vegar
1
整体想法不错。你只需要使用ReadyState而不是Busy。请查看我的评论以获取更多信息。 - Wouter van Nifterick

3

我需要相同的功能(自动截取页面屏幕截图),然后我开始使用Rob的代码。但是对于我正在加载的页面,它并没有起作用...有一半的时间繁忙标志没有被设置,而页面明显还没有完成。

经过一些研究,似乎这个方法可行:

while (webBrowser1.ReadyState <>  READYSTATE_COMPLETE) do
  Application.ProcessMessages;

其中readyState是以下状态之一:

const READYSTATE_UNINITIALIZED = 0; // Default initialisation state.
const READYSTATE_LOADING = 1; // Object is currently loading data.
const READYSTATE_LOADED = 2; // Object has been initialised.
const READYSTATE_INTERACTIVE = 3; // User can interact with the object but loading has not yet finished.
const READYSTATE_COMPLETE = 4; // All of the object's data has been loaded.

这个使用readystate的想法来自于这里: http://gaskell.org/making-the-webbrowser-control-synchronous/

readystate Delphi常量来自于这里: http://www.cryer.co.uk/brian/delphi/twebbrowser/twebbrowser_properties.htm


1

我必须说我从未尝试过类似的事情,但我认为你会遇到问题。

您可以在一个进程中拥有多个线程,所有线程都实现消息循环并处理该线程窗口的消息,但所有窗口都绑定到创建它们的线程。窗口消息将始终在创建窗口的线程中处理。因此,您可能能够从另一个线程调用嵌入式TWebBrowser控件的方法,但是由于这将涉及向Web浏览器窗口发送消息,因此仍将在GUI线程中处理。

有关更多信息,请查看维基百科关于COM中的线程和Raymond Chen关于STA的博客文章,例如这篇文章


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接