Reputation: 89
Trying to navigate using WebBrowser component automatically through code it doesn't work. The navigation includes the login page and after that some other pages. The first page button login works fine. On second page the next button needed an application.processmessages before executing to make it work. On the next/third page I cannot make automatically the next button to work.
CODE:
//CLICK BUTTON
function clickForm1(WebBrowser: TWebBrowser; FieldName: string): Boolean;
var
i, j: Integer;
FormItem: Variant;
begin
Result := False;
//no form on document
if WebBrowser.OleObject.Document.all.tags('FORM').Length = 0 then
begin
Exit;
end;
//count forms on document
for I := 0 to WebBrowser.OleObject.Document.forms.Length - 1 do
begin
FormItem := WebBrowser.OleObject.Document.forms.Item(I);
for j := 0 to FormItem.Length - 1 do
begin
try
//when the fieldname is found, try to fill out
if FormItem.Item(j).Name = FieldName then
begin
FormItem.Item(j).click;
Result := True;
end;
except
Exit;
end;
end;
end;
end;
//SEARCH INSIDE THE MEMO
procedure TForm2.Button7Click(Sender: TObject);
var
i: Integer;
a: string;
begin
Memo1.Lines.Add('');
Memo1.Lines.Text := ' ' + Memo1.Lines.Text;
for i := 0 to Length(Memo1.Lines.Text) - Length(edit7.Text) do
begin
a := Copy(Memo1.Lines.Text, i, Length(edit7.Text));
if CheckBox1.Checked = True then //FIND CASE Sensitive
begin
if a = edit7.Text then
begin
find := True;
x := 2;
Memo1.Lines.Text := Copy(Memo1.Lines.Text, 2, Length(Memo1.Lines.Text) - 1);
Memo1.SetFocus;
Memo1.SelStart := i - 2;
Memo1.SelLength := Length(edit7.Text);
break;
end;
end
else
begin
if lowercase(a) = lowercase(edit7.Text) then
begin
Memo1.Lines.Text := Copy(Memo1.Lines.Text, 2, Length(Memo1.Lines.Text) - 1);
find := True;
x := 2;
Memo1.SetFocus;
Memo1.SelStart := i - 2;
Memo1.SelLength := Length(edit7.Text);
break;
end;
end;
end;
end;
//HTML TO MEMO
procedure TForm2.Button6Click(Sender: TObject);
var
iall : IHTMLElement;
begin
if Assigned(WebBrowser1.Document) then
begin
iall := (WebBrowser1.Document AS IHTMLDocument2).body;
while iall.parentElement <> nil do
begin
iall := iall.parentElement;
end;
memo1.Text := iall.outerHTML;
end;
end;
procedure TForm2.WebBrowser1DocumentComplete(ASender: TObject;
const pDisp: IDispatch; var URL: OleVariant);
var
Document: IHtmlDocument2;
CurWebrowser : IWebBrowser;
TopWebBrowser: IWebBrowser;
WindowName : string;
ovElements: OleVariant;
i: Integer;
begin
CurWebrowser := pDisp as IWebBrowser;
TopWebBrowser := (ASender as TWebBrowser).DefaultInterface;
if CurWebrowser=TopWebBrowser then
begin
button6.Click; // HTML TO MEMO
TRY
button7.Click; //SEARCH LOGIN FORM
if find=true then Begin
clickForm1(WebBrowser1, 'move'); //CLICK LOGIN BUTTON
End Else begin Null; End;
FINALLY find:=false; END;
TRY
button8.Click; //SEARCH HOME (AFTER LOGIN) FORM
if find1=true then Begin
Application.ProcessMessages;//NEEDED IN ORDER THE BUTTON TO BE PRESSED.
clickForm1(WebBrowser1, 'refresh'); //CLICK NEXT PAGE BUTTON
End;
FINALLY find1:=false;END;
TRY
button9.Click; //SEARCH WORKLIST FORM
if find2=true then Begin
clickForm1(WebBrowser1, 'next'); //CLICK NEW FORM BUTTON
End;
FINALLY find2:=false;END;
end;
end;
Upvotes: 0
Views: 1696
Reputation: 30715
I'm not sure how much you know about working with Event Handlers in code.
Objects like Forms and WebBrowsers typically have one or more event properties that are used to define what happens when the event occurs. So, an event property is a property of an object that can hold the information necessary to invoke (call) a procedure (or function, but not usually) of the same object or another one. The procedure to call has to have the right "signature" for the type definition of the event. If it does then an "event handler" can be assigned to the event property in code, as I'll show below.
One can use event properties and event-handling code in Delphi in a simple way, without knowing any of this, just by going to the Events tab of the Object Inspector and double-clicking next to one of the event names. What that actually does is to create a new handler procedure and to assign it to the corresponding event property of the object (well, not quite, actually that assignment is done at run-time when the host form is loaded).
What I mean by "signature" is the routine type (procedure or function) and its list of parameters, and their types, in its definition.
So, for a WebBrowser, the signature of the OnDocumentComplete event is
procedure (Sender: TObject; const pDisp: IDispatch; var URL: OLEVariant);
The clever thing is that you can assign the OnDocumentComplete property to any procedure of an object that has the exact same signature. The event type for the WB's OnDocumentComplete is defined in the import unit ShDocVw, btw
So, let's suppose you write three methods that contain the code you want to run when the WB completes loading URLs A, B and C, respectively:
procedure TForm1.DocCompleteA(Sender: TObject; const
pDisp: IDispatch; var URL: OLEVariant);
begin
// Do your stuff for arrival at site/page A here
// Then update NavigationOK flag to reflect if you succeeded or failed
if NavigationOK then begin
WebBrowser1.OnDocumentComplete := DocCompleteB;
// Now navigate to site/page B
end
else
WebBrowser1.OnDocumentComplete := Nil;
end;
procedure TForm1.DocCompleteB(Sender: TObject; const
pDisp: IDispatch; var URL: OLEVariant);
begin
end;
procedure TForm1.DocCompleteC(Sender: TObject; const
pDisp: IDispatch; var URL: OLEVariant);
begin
end;
Then, you can assign the WB's OnDocumentComplete property to each of them in turn, with something like the code at the end of DocCompleteA which updates the WB's OnDocumentComplete to the code needed for B, and so on, in turn. The NavigationOK variable is just a flag to indicate that our navigation stays "on course" as it progresses. If it gets set to false because something went wrong, we set the WB's OnDocumentComplete to Nil, so that it does nothing next time the event occurs.
Then, you can kick off the whole "tour" of sites with something like this:
procedure TForm1.NavigateSites;
begin
NavigationOK := True;
WebBrowser1.OnDocumentComplete := DocCompleteA;
WebBrowser1.Navigate(...); // Navigate to site A
end;
Of course, you don't have to do the updating of the WB's OnDocumentComplete property and navigation to the next URL in the current DocCompleteX. In fact, it's probably clearer if you do those if a higher level procedure like the NavigateSites one, and more easily maintainable, which can be important if you're navigating others' sites, which are apt to be changed without any prior warning.
Upvotes: 1