6

我在使用 TChromium (DCEF1) 的 OnLoadEnd 事件时遇到问题。

我有一个带有 TButton 和 TChromium 的表单。

按钮的 OnClick 事件调用一个函数,该函数列出了已加载页面的表单。如果我等待页面加载完成然后单击按钮,此功能可以正常工作;但是如果我从 TChromium OnLoadEnd 事件处理程序调用此函数,则永远不会调用回调函数,因此,我得到一个空列表。

按钮代码(将注释读入代码):

procedure TForm2.Button3Click(Sender: TObject);
var
  Q: TWebChromium;
begin
  Q := TWebChromium.Create(Chromium1); // <- class to access DOM
  Q.WebFormNames; // <- method to get forms name
  ShowMessage(Q.Forms.Text); // <- show forms
end;

OnLoadEnd 代码:

procedure TForm2.Chromium1LoadEnd(Sender: TObject; const browser: ICefBrowser;
  const frame: ICefFrame; httpStatusCode: Integer; out Result: Boolean);
begin
  if (browser <> nil) and (browser.GetWindowHandle = TChromium(Sender).BrowserHandle) and ((frame = nil) or (frame.IsMain)) then
  begin
    Button3Click(nil);
  end;
end;

获取表单名称的方法代码(将注释读入代码):

procedure TWebChromium.WebFormNames;
var
  Finish: Boolean;
  EndTime: TTime;
begin
  FForms.Clear; // <- property (TStringList)
  if not Assigned(FWebBrowser) then // <- FWebBrowser: property that contain the TChromium
    raise Exception.Create('WebBrowser not assigned');
  if not (FWebBrowser is TChromium) then 
    raise Exception.Create('The WebBrowser property is not a TChromium.');

  Finish := False;
  TChromium(FWebBrowser).Browser.MainFrame.VisitDomProc(
        procedure (const doc: ICefDomDocument) // <- this procedure is not called if this method is called from OnLoadEnd event
        begin
          FForms.CommaText := GetFormsName(doc.Body); 
          Finish := True;
        end
  );
  EndTime := IncSecond(Time, 4);

  repeat Application.ProcessMessages until Finish or (Time > EndTime);
  if Time > EndTime then
    raise Exception.Create('Time out');
end;
4

3 回答 3

1

好吧,我知道这个问题是几年前提出的,但我对 TChromium 还是很陌生。这是我从以前的提案中提出的解决方案。一般情况下,TChromium 会发送 Event OnLoadEnd,但会在加载之前发送,例如 JS。所以我解决了这个问题,以便我在 OnLoadEnd 过程中等待一段时间,以防仍然加载任何脚本,然后发送通知,像这样

procedure TForm1.OnLoadEndCust(Sender: TObject; const browser: ICefBrowser;
  const frame: ICefFrame; httpStatusCode: Integer);
var EndTime: TTime;
begin
  EndTime := IncSecond(Now, 2);

  repeat Application.ProcessMessages until (Now > EndTime);

end;

到目前为止 - 这已经足够了,但还有其他更好或更优雅的解决方案吗?

为什么我们应该在上面的代码中使用 VisitDomProc?当我们从 OnLoadEnd 调用它时,它似乎是不必要的。小伙伴们怎么看?

于 2017-04-11T11:35:51.870 回答
0

我已经使用了 DCEF 1 和 DCEF 3,如果你可以切换到 3,你应该有很多改进。

这是 DCEF 3 的链接: https ://code.google.com/p/dcef3/

您拥有的方法绝对应该有效:

procedure TMainForm.Chromium1LoadEnd(Sender: TObject; const browser: ICefBrowser;
  const frame: ICefFrame; httpStatusCode: Integer);
begin
  if IsMain(browser, frame) then begin
    // main window done from here on in
  end;
end;

如果不是,它可能是两件事中的一件,

  1. 您的表单数据搞砸了,不知何故不再附加事件,请仔细检查组件中的事件属性。

  2. 您的构建有问题,尝试在示例目录中运行 GUIClient,它具有相同的事件并且应该被触发,如果它没有尝试找到另一个构建(最好是我之前链接到的 DCEF3 版本)

祝你好运

于 2014-05-06T09:37:27.323 回答
0

我遇到了同样的问题,我注意到当 httpStatusCode 为 200 时页面已完全加载。为了方便起见,我实现了一个布尔变量。

  TForm2 = class(TForm)
    procedure Chromium1LoadEnd(Sender: TObject; const browser: ICefBrowser;
      const frame: ICefFrame; httpStatusCode: Integer);
    procedure Chromium1LoadStart(Sender: TObject; const browser: ICefBrowser;
  private
    { Private declarations }
    IsFullyDisplayed : Boolean;
  end;

procedure TForm2.Chromium1LoadEnd(Sender: TObject; const browser: ICefBrowser;
  const frame: ICefFrame; httpStatusCode: Integer);
begin
  if frame = nil then
    exit;

  if httpStatusCode=200 then
  begin
    IsFullyDisplayed:=True;
  end;
end;

procedure TForm2.Chromium1LoadStart(Sender: TObject; const browser: ICefBrowser;
  const frame: ICefFrame);
begin
  IsFullyDisplayed := False;
end;
于 2017-10-22T10:32:43.383 回答