Как достоверно (программно) узнать, когда страница загружена в 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 вещей,
Данные вашей формы испорчены, и каким-то образом событие больше не присоединяется, перепроверьте свойства события в вашем компоненте.
Что-то не так с вашей сборкой, попробуйте запустить GUIClient в каталоге примеров, у него такое же событие, и он должен сработать, если он не попытается найти другую сборку (предпочтительно версию DCEF3, с которой я связывался ранее)
Удачи