【问题标题】:Chromium Embedded: TCefDomVisitorOwn.visit() method never is executedChromium Embedded:TCefDomVisitorOwn.visit() 方法永远不会被执行
【发布时间】:2018-09-09 18:52:21
【问题描述】:

我正在使用 CEF4Delphi 并尝试获取页面的确定 html input 元素,然后使用下面的代码将值设置为相同,但碰巧方法 TElementNameVisitor.visit(const document: ICefDomDocument); 从未被执行。

我该如何解决这个问题?

uses
uCEFChromium, uCEFWindowParent,
  uCEFChromiumWindow, uCEFInterfaces, uCEFDomVisitor;

type
  TElementNameVisitor = class(TCefDomVisitorOwn)
  private
    FName: string;
  protected
    procedure visit(const document: ICefDomDocument); override;
  public
    constructor Create(const AName: string); reintroduce;
  end;

  type
  TForm2 = class(TForm)
    Chromium1: TChromium;
    CEFWindowParent1: TCEFWindowParent;
    procedure FormShow(Sender: TObject);
    procedure Chromium1LoadEnd(Sender: TObject; const browser: ICefBrowser;
      const frame: ICefFrame; httpStatusCode: Integer);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form2: TForm2;

implementation

{$R *.dfm}

constructor TElementNameVisitor.Create(const AName: string);
begin
  inherited Create;
  FName := AName;
end;

procedure ProcessElementsByName(const AFrame: ICefFrame; const AName: string);
var
  Visitor: TElementNameVisitor;
begin
  if Assigned(AFrame) then
  begin
    Visitor := TElementNameVisitor.Create(AName);
    AFrame.VisitDom(Visitor);
  end;
end;

procedure TElementNameVisitor.visit(const document: ICefDomDocument);

  procedure ProcessNode(ANode: ICefDomNode);
  var
    Node: ICefDomNode;
  begin
    if Assigned(ANode) then
    begin
      Node := ANode.FirstChild;
      while Assigned(Node) do
      begin
        if Node.GetElementAttribute('name') = FName then
        begin
          Node.SetElementAttribute('value', '-15.792253570362445');
          ShowMessage(Node.GetElementAttribute('value'));
        end;
        ProcessNode(Node);
        Node := Node.NextSibling;
      end;
    end;
  end;

begin
  ProcessNode(document.Body);
end;

procedure TForm2.Chromium1LoadEnd(Sender: TObject; const browser: ICefBrowser;
  const frame: ICefFrame; httpStatusCode: Integer);
var
  CefStringVisitor: ICefStringVisitor;
begin
  ProcessElementsByName(Chromium1.browser.MainFrame, 'latitude'); // "latitude" = name of field that i want set a value
end;

procedure TForm2.FormShow(Sender: TObject);
begin
  while not(Chromium1.CreateBrowser(CEFWindowParent1, '')) and
    (Chromium1.Initialized) do
  begin
    Sleep(100);
    Application.ProcessMessages;
  end;
  Application.MessageBox('CEFWindowParent1 created!', 'Success', MB_OK + MB_ICONINFORMATION);
  Chromium1.LoadURL('file:///' + ReplaceStr(ExtractFilePath(Application.ExeName) + 'gmaps.html', '\', '/'));
end;

【问题讨论】:

    标签: delphi chromium-embedded delphi-10-seattle cef4delphi


    【解决方案1】:

    此代码在浏览器进程中创建 DOM 访问者,但在渲染进程中调用了 DOM 访问者函数,如您在 CEF3 code comments 中看到的那样

    如果您使用“单进程”模式,这将有效,但 CEF3 不支持该模式,它会导致错误,您应该将该模式仅用于调试目的。

    您需要使用多个进程。使用 DOMVisitor demo 作为您的应用程序的模板,并阅读该演示中的所有代码 cmets。

    DOM 访问者必须在渲染过程中创建。为此,您需要从浏览器进程向渲染进程发送一个进程消息,然后在接收进程消息的事件中创建 TCefDomVisitorOwn 子类。

    DOMVisitor 演示使用 GlobalCEFApp.OnProcessMessageReceived 事件在渲染过程中接收消息,并在该事件中创建一个 TCefFastDomVisitor2。

    TCefFastDomVisitor2 构造函数有一个称为“proc”的过程参数,该参数在触发 TCefDomVisitorOwn.visit 事件时执行。

    在这些过程中,您可以搜索 DOM 中的节点,然后将结果发送回调用 browser.SendProcessMessage(PID_BROWSER, msg) 的浏览器进程

    浏览器将在 TChromium.OnProcessMessageReceived 事件中接收这些消息。

    如您所知,Delphi 只能调试一个进程。如果您需要调试在渲染过程中执行的代码,您需要:

    • 使用“单进程”模式,但请记住,您不应在最终版本中使用此模式。
    • 在 Delphi 中使用“Run without Debugging...”选项并选择渲染进程。

    【讨论】:

      猜你喜欢
      • 2019-12-07
      • 2021-08-19
      • 2016-06-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多