Как достоверно (программно) узнать, когда страница загружена в Chromium

У меня проблема с использованием события OnLoadEnd TChromium (DCEF1).

У меня есть форма с 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;

Любая идея? заранее спасибо

3 ответа

Ну, я знаю, что этот вопрос задавался много лет назад, но я довольно новичок в 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, это кажется ненужным. Как вы думаете, ребята?

У меня была та же проблема, и я заметил, что страница полностью загружена, когда 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;

Я использовал 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 вещей,

  1. Данные вашей формы испорчены, и каким-то образом событие больше не присоединяется, перепроверьте свойства события в вашем компоненте.

  2. Что-то не так с вашей сборкой, попробуйте запустить GUIClient в каталоге примеров, у него такое же событие, и он должен сработать, если он не попытается найти другую сборку (предпочтительно версию DCEF3, с которой я связывался ранее)

Удачи

Другие вопросы по тегам