VaVel
VaVel

Reputation: 89

WebBrowser component navigation through multiple pages does not work

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

Answers (1)

MartynA
MartynA

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

Related Questions