在单独的线程中更新TWebBrowser?

21

我使用TWebBrowser来显示Google地图。问题是它在加载地图时会阻塞主UI线程。是否可能在单独的线程中更新地图?

编辑: RRUZ,你是对的,TWebBrowser有用于URL的异步加载。 但是我找到了它阻塞的原因:

if WaitWhileProcessing and (MapQueryResult.Count > 0) then 
  Result := MapQueryResult[0] as TMapQuery;

以及这个方法:

function TMapItemCollection.WaitWhileProcessing: Boolean;
var
  vMaxSleepCnt: Integer;
begin
  Result := True;
  vMaxSleepCnt := 0;
  while Processing or Loading do
  begin
    inc(vMaxSleepCnt);
    Application.ProcessMessages;
    Sleep(100);
    if vMaxSleepCnt = 100 then
    begin
      Result := False;
      Break;
    end;
  end;
end;

看起来要解决这个问题需要重构代码,但这不是这个问题的范围。


3
你确定是地图加载时 GUI 卡住了吗?因为 TWebBrowser 是异步的。你能否展示一下你用来加载地图的代码? - RRUZ
感谢RRUZ和WarrenP的建议。RRUZ是正确的,TWebBrowser已经实现了异步加载。所以在我的情况下,原因是其他的。我必须进行调查,因为代码相当复杂... - Roland Bengtsson
1个回答

3

当if语句被执行并调用WaitWhileProcessing来评估条件时,它会循环100次,每次暂停10分之一秒。但是在调用ProcessMessages时等待哪些消息呢?这个方法能够递归地再次调用吗?它将永远不会进入睡眠状态,而是一直调用此方法。顺便提一下,要注意ProcessMessages确实是一个很糟糕的做法,但现在...请尝试以下操作:

var
  isWaitWhileProcessingBusy :boolean = false;

function TMapItemCollection.WaitWhileProcessing: Boolean;
var
 vSleepCnt: Integer;
begin      
  if not isWaitWhileProcessingBusy then
  begin
    isWaitWhileProcessingBusy = true;
    vSleepCnt := 0;
    while Processing or Loading or vSleepCnt < 100 do
    begin
      inc(vSleepCnt);
      Application.ProcessMessages;
      Sleep(100);
    end;
    isWaitWhileProcessingBusy := false;
  end;
  Result = Processing or Loading;
end;

正如你所看到的,我还进行了其他一些小修改。break语句不在while条件中,结果只是Processing或Loading的结果(因为该表达式给出了实际结果)。函数外的额外isWaitWhileProcessingBusy可防止消息循环重新进入。希望这能够避免锁定用户界面。虽然这并不是最好的做法,但现在它可能有助于解决问题并找出问题所在。
你轮询Loading/Processing有什么原因吗?使用TWebBrowser的OnDocumentComplete事件会不会更容易些?
……我又想到了另一个问题……你有检查过任务管理器吗?谷歌地图使用flash,也使用主UI线程的activex组件。这也可能是导致资源饥饿的元凶。
祝你好运!

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