Chromium Embedded:永远不会执行 TCefDomVisitorOwn.visit() 方法
Chromium Embedded: TCefDomVisitorOwn.visit() method never is executed
我正在使用 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;
此代码在浏览器进程中创建 DOM 访问者,但 DOM 访问者函数在渲染过程中被调用,正如您在 CEF3 code comments
如果您使用“单进程”模式,这会起作用,但 CEF3 不支持该模式,它会导致错误,您应该仅出于调试目的使用该模式。
您需要使用多个进程。使用 DOMVisitor demo 作为您应用的模板,并阅读该演示中的所有代码注释。
必须在呈现过程中创建 DOM 访问者。为此,您从浏览器进程向渲染进程发送进程消息,然后在接收进程消息的事件中创建 TCefDomVisitorOwn 子类。
DOMVisitor 演示使用 GlobalCEFApp.OnProcessMessageReceived 事件接收渲染过程中的消息,并在该事件中创建一个 TCefFastDomVisitor2。
TCefFastDomVisitor2 构造函数有一个名为 "proc" 的过程参数,它在触发 TCefDomVisitorOwn.visit 事件时执行。
在这些过程中,您可以在 DOM 中搜索节点,然后将结果发送回调用 browser.SendProcessMessage(PID_BROWSER, msg)
的浏览器进程
浏览器将在 TChromium.OnProcessMessageReceived 事件中接收这些消息。
如您所知,Delphi只能调试一个进程。如果您需要调试在渲染过程中执行的代码,您需要:
- 使用 "single process" 模式,但请记住,您不应在最终版本中使用此模式。
- 在 Delphi 和 select 渲染过程中使用 "Run Without Debugging..." 选项。
我正在使用 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;
此代码在浏览器进程中创建 DOM 访问者,但 DOM 访问者函数在渲染过程中被调用,正如您在 CEF3 code comments
如果您使用“单进程”模式,这会起作用,但 CEF3 不支持该模式,它会导致错误,您应该仅出于调试目的使用该模式。
您需要使用多个进程。使用 DOMVisitor demo 作为您应用的模板,并阅读该演示中的所有代码注释。
必须在呈现过程中创建 DOM 访问者。为此,您从浏览器进程向渲染进程发送进程消息,然后在接收进程消息的事件中创建 TCefDomVisitorOwn 子类。
DOMVisitor 演示使用 GlobalCEFApp.OnProcessMessageReceived 事件接收渲染过程中的消息,并在该事件中创建一个 TCefFastDomVisitor2。
TCefFastDomVisitor2 构造函数有一个名为 "proc" 的过程参数,它在触发 TCefDomVisitorOwn.visit 事件时执行。
在这些过程中,您可以在 DOM 中搜索节点,然后将结果发送回调用 browser.SendProcessMessage(PID_BROWSER, msg)
的浏览器进程浏览器将在 TChromium.OnProcessMessageReceived 事件中接收这些消息。
如您所知,Delphi只能调试一个进程。如果您需要调试在渲染过程中执行的代码,您需要:
- 使用 "single process" 模式,但请记住,您不应在最终版本中使用此模式。
- 在 Delphi 和 select 渲染过程中使用 "Run Without Debugging..." 选项。