我正在使用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;
答案 0 :(得分:1)
此代码正在浏览器过程中创建DOM访问者,但是DOM访问者函数在呈现过程中被调用,如您在CEF3 code comments
中所见如果您使用“ 单进程”模式,但CEF3不支持该模式,则该方法将起作用,并且会导致错误,您应仅将该模式用于调试目的。
您需要使用多个过程。将DOMVisitor demo用作应用程序的模板,并阅读该演示中的所有代码注释。
必须在渲染过程中创建DOM访问者。为此,您需要从浏览器过程向渲染过程发送过程消息,然后在接收过程消息的事件内创建TCefDomVisitorOwn子类。
DOMVisitor演示使用GlobalCEFApp.OnProcessMessageReceived事件接收渲染过程中的消息,并在该事件内部创建TCefFastDomVisitor2。
TCefFastDomVisitor2构造函数具有一个称为“ proc”的过程参数,该参数在触发TCefDomVisitorOwn.visit事件时执行。
在这些过程中,您可以搜索DOM中的节点,然后将结果发送回调用浏览器的浏览器进程。SendProcessMessage(PID_BROWSER,msg)
浏览器将在TChromium.OnProcessMessageReceived事件中接收这些消息。
您知道,Delphi只能调试一个进程。如果您需要调试在渲染过程中执行的代码,则需要: