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;

そうでない場合は、2 つのうちの 1 つである可能性があります。

  1. フォーム データが台無しになり、どういうわけかイベントが添付されなくなりました。コンポーネントのイベント プロパティを再確認してください。

  2. ビルドに何か問題があります。samples ディレクトリで GUIClient を実行してみてください。同じイベントが発生し、別のビルド (できれば以前にリンクした DCEF3 バージョン) を見つけようとしない場合は、トリガーされるはずです。

幸運を

于 2014-05-06T09:37:27.323 に答える