TWebBrowser Ajax Yanıtı Beklemek

Delphi'de kod yazma ile ilgili sorularınızı bu foruma yazabilirsiniz.
Cevapla
Kullanıcı avatarı
vkamadan
Kıdemli Üye
Mesajlar: 1935
Kayıt: 17 Mar 2004 03:52
Konum: Adapazarı
İletişim:

TWebBrowser Ajax Yanıtı Beklemek

Mesaj gönderen vkamadan »

Merhaba ,

peş peşe sayfaları gezmenin gerektiği bazı durumlarda sayfanın yüklenmesini bekleyip kod akışına devam etmek için kullanılan

Kod: Tümünü seç

  while (webBrowser1.ReadyState <>  READYSTATE_COMPLETE) do    Application.ProcessMessages;
ya da

Kod: Tümünü seç

  while webBrowser1.Busy do    Application.ProcessMessages;
yapıları ,örneğin ilgili sayfada tıklanan bir buton Ajax yanıtı bekliyorsa yani sayfa komple yeniden sunucuya gidip gelen bir sayfa değilse işe yaramıyor ,ajax yanıtını bekleyip yola devam etmem gerekiyor bu konuda tecrübesi olan arkadaşlardan yardım rica ederim.

İyi çalışmalar.
Volkan KAMADAN
www.polisoft.com.tr
Kullanıcı avatarı
mrmarman
Üye
Mesajlar: 4740
Kayıt: 09 Ara 2003 08:13
Konum: İstanbul
İletişim:

Re: TWebBrowser Ajax Yanıtı Beklemek

Mesaj gönderen mrmarman »

Merhaba.

TWebBrowser STATE özelliği READYSTATE_COMPLETE yani integer 4 değeri aldığında sayfa tamamlanmış olduğu konusu NAVIGATE komutuyla halen geçerli. Ancak sayfa içeriğindeki bir procedure işlerse bu STATE özelliği tetiklenmiyor. Bu doğru. Ancak DocumentComplete eventi tetikleniyor. Bunu kullanıyoruz.

Projelerde uyguladığım iki farklı yöntem var. ( bugüne kadar hiç sekmedi )

Yöntem 1.

GLOBAL iki değişken tanımlıyoruz. Örnekte

Kod: Tümünü seç

Var
  xTamam : Boolean = False;
  xBeklenenURL : String = '';
GLOBAL derken en tepedeki bu değişkenlere her procedure'den erişmek hedeflenmektedir. Çünkü biz OnDocumentComplete eventinde tetikleyeceğimiz bu değişkenlerin durumunu READYSTATE gibi takip edicez...

Kod: Tümünü seç

procedure TForm1.WebBrowser1DocumentComplete(ASender: TObject;
  const pDisp: IDispatch; var URL: OleVariant);
begin
  if  ( ( xBeklenenURL <> '') AND (URL = xBeklenenURL) )
    then xTamam := True;
end;
şimdi sitemizi etüd ederek tüm içerik geldiğinde URL değişimini takip ederek sayfanın tamamlandığı an hangi URL varsa onu not ediyoruz.
Yapılması gereken işlem şu kalıyor.

SanalPazar.COM'dan takip ettiğim son dakika otomatik arttırma işlemi için hazırladığım içeriği örnek vereyim.. Örnekte xBeklenenURL ile verdiğim linkleri arşiv olsun diye direkt DocumtentComplete içinde vermiştim. Siz bunu navigasyon öncesi xBeklenenURL değişkenine de atayabilir, DocumentComplete eventini sadece yukarıdaki gibi sadeleştirebilirsiniz..

Kod: Tümünü seç

procedure TForm1.WebBrowser1DocumentComplete(ASender: TObject;
  const pDisp: IDispatch; var URL: OleVariant);
begin
  if ( URL = 'http://www.sanalpazar.com/users_area.php' )
     or
     ( URL = 'http://www.sanalpazar.com/users_area.php?page=bidding&section=current_bids' )
     or
     ( ( xBeklenenURL <> '') AND (URL = xBeklenenURL) )
    then xTamam := True;
end;

Kod: Tümünü seç

  WebBrowser1.Navigate( 'https://www.sanalpazar.com/login.php' );
  while WebBrowser1.ReadyState <> READYSTATE_Complete
    do Application.ProcessMessages;

  WebBrowser1.OleObject.Document.GetElementByID('username').Value := Edit2.Text;
  WebBrowser1.OleObject.Document.GetElementByID('password').Value := Edit3.Text;
  WebFormSubmit( WebBrowser1.Document as IHTMLDocument2, 1 );
  xTamam := False;
  while NOT xTamam do Application.ProcessMessages;
Yöntem 2.
Her JAVA içerik döngüsü sonunda INNERHTML içeriğindeki değişikliği takibe alırsınız. Nasıl mı ? Formunuza bir button koyun, bu buton HTML içeriğini program dizininde bir TEXT dosyaya yazsın. Yazarken de her butona basışta yeni bir dosya ismi kullansın ki önceki yazılana zarar vermesin.

Bu işlem için hazırladığım Fonksiyon şöyle.

Kod: Tümünü seç

procedure TextKaydet( Icerik : String; Dosya : TFileName; DosyaVarsaUzerineYaz:Boolean );
Var
  i : Integer;
  HedefDosya : String;
begin
  i := 0;
  HedefDosya := Dosya;
  if NOT DirectoryExists(ExtractFilePath(HedefDosya))
    then ForceDirectories(ExtractFilePath(HedefDosya));

  if NOT DosyaVarsaUzerineYaz
  then while FileExists(HedefDosya) do
       begin
         Inc(i);
         HedefDosya := ChangeFileExt(Dosya, Format('_%.2d%s', [i, ExtractFileExt(Dosya)]));
       end;

  With TStringList.Create do begin
    Text := Icerik;
    SaveToFile(HedefDosya);
    Free;
  end;
end;
Her butona basışınızda şunu yapsın.

Kod: Tümünü seç

procedure TForm1.BitBtn1Click(Sender: TObject);
begin
  TextKaydet( WebBrowser1.OleObject.Document.body.InnerHtml, ExtractFilePath(Application.Exename) + 'GELEN\'+'HTML_Icerik', False );
end;
Böylece program dizininde GELEN isminde bir klasör açılacak ve önceki içerik zarar görmeden daima yeni bir dosya ismiyle yeni içerik kayıt altına alınacak.

Bu neden önemli ?!

AJAX içeren sayfayı çalıştırdığınızda veya işlettiğinizde bir kere butona basın. Sonra işlem bitince yine butona basın. İşlem sonunda ile işlem sırasında INNERHTML değişimini kontrol ederek içerikte tekil ve benzersiz bir son nokta arayın. Mesela ekranda bekleyiniz diye bir panel çıkıyorsa bu sizin için biçilmiş kaftandır. Bu ifadenin INNERHTML'de olduğu sürece siz de bekleyin. bu ifade INNERHTML'den kaybolduğunda JAVA AJAX işlemi tamamlanmış olduğu kanaatine varmış olun.

Örneklemek gerekirse. Çalıştığım kurumda Gusto BPM kullanılıyor. Buradan veri kontrolü için kullandığım bir script paylaşayım..

Kod: Tümünü seç

  xYukleniyor1 = '<TD style="PADDING-RIGHT: 8px" class=dx><IMG alt="" align=middle src="/DXR.axd?r=1_13-Oj0x3"></TD>'
         +#13#10+'<TD style="PADDING-LEFT: 0px" id=callbackPanel_genel_callbackPanel_hizmet_T class=dx>Yükleniyor…</TD></TR></TBODY></TABLE></DIV>'
         ;

  xYukleniyor2 = '<TD style="PADDING-RIGHT: 5px" class=dx><IMG alt="" align=middle src="/DXR.axd?r=0_1791-Pj0x3"></TD>'
         +#13#10+'<TD style="PADDING-LEFT: 0px" id=callbackPanel_T class=dx>Yükleniyor…</TD></TR></TBODY></TABLE></DIV>'
         ;

  xYukleniyor3 = '<TD style="PADDING-RIGHT: 5px" class=dx><IMG alt="" align=middle src="/DXR.axd?r=0_1791-Pj0x3"></TD>'
         +#13#10+'<TD style="PADDING-LEFT: 0px" class=dx>Yükleniyor…</TD></TR></TBODY></TABLE>'
         ;
  xYukleniyor4 = '<TD style="PADDING-RIGHT: 8px" class=dx><IMG alt="" align=middle src="/DXR.axd?r=1_13-Oj0x3"></TD>'
         +#13#10+'<TD style="TEXT-ALIGN: center; PADDING-LEFT: 0px; VERTICAL-ALIGN: middle" id=callbackPanel_genel_T class=dx>Yükleniyor…</TD></TR></TBODY></TABLE></DIV>'
         ;

Kod: Tümünü seç

procedure TForm1.YukleniyorBekle( WebBrowser:TWebBrowser );
begin
  while
  ( Pos( xYukleniyor1, WebBrowser.OleObject.Document.body.InnerHtml ) > 0 )
  or
  ( Pos( xYukleniyor2, WebBrowser.OleObject.Document.body.InnerHtml ) > 0 )
  or
  ( Pos( xYukleniyor3, WebBrowser.OleObject.Document.body.InnerHtml ) > 0 )
  or
  ( Pos( xYukleniyor4, WebBrowser.OleObject.Document.body.InnerHtml ) > 0 )
   do begin
    StatusBar1.Panels[0].Text := 'Yükleniyor...';
    Application.ProcessMessages;
    Sleep(1);
  end;
  StatusBar1.Panels[0].Text := '';
end;
Örnek yeterince açık sanırım. AJAX çalışınca YukleniyorBekle(); diyorum. Sistem duraklıyor. Ta ki AJAX bitene kadar.

Uzun oldu ama hem forumdan işlerim gereği biraz uzak kaldım, hem de özellikle bu konuda delphi forumlarında ve/veya özelden çok soru geldiğinden detaylı açıklama gereği duydum.

Başarılar.
Resim
Resim ....Resim
Kullanıcı avatarı
vkamadan
Kıdemli Üye
Mesajlar: 1935
Kayıt: 17 Mar 2004 03:52
Konum: Adapazarı
İletişim:

Re: TWebBrowser Ajax Yanıtı Beklemek

Mesaj gönderen vkamadan »

Merhaba sayın @mrmarman ,

Öncelikle değerli vaktinizi ayırıp gayet açıklayıcı ve yararlı bilgiler paylaştığınız için teşekkür ederim.

Üzerinde çalıştığım sayfada bazı aşamalarda "DocumentComplate" kesinlikle tetiklenmiyor, sistem IceFaces ve JQuery kütüpaneleriyle inşaa edilmiş , örneğin sayfada bazen bir butona tıkladığınızda kaynakta hiç olmayan yeni form elemanları yaratılıyor, hiç olmayan Div ler beliriyor, hal böyle olunca bende şöyle bir yol izledim ,

1. Nesnenin olup olmadığını sürekli kontrol ettim ,
2. Mevcut bir nesnedeki değişimi sizin de örneklediğiniz gibi InnerHTML indeki değişiklikleri takip ederek algıladım sonuç olarak çözüme ulşatım ,

Nesnenin gelip gelmediğini ,

Kod: Tümünü seç

function GetElementById(const Doc: IDispatch;
  const Id: string): IDispatch;
var
  Document: IHTMLDocument2;
  Body: IHTMLElement2;
  Tags: IHTMLElementCollection;
  Tag: IHTMLElement;
  I: Integer;
begin
  Result := nil;

  if not Supports(Doc, IHTMLDocument2, Document) then
    begin
    Result := nil;
    Exit;
    end;

  if not Supports(Document.body, IHTMLElement2, Body) then
    begin
      Result := nil;
      Exit;
    end;
  Tags := Body.getElementsByTagName('*');
  for I := 0 to Pred(Tags.length) do
  begin
    Tag := Tags.item(I, EmptyParam) as IHTMLElement;
    if AnsiSameText(Tag.id, Id) then
    begin
      Result := Tag;
      Break;
    end;
  end;
end;

Kod: Tümünü seç

 while not Assigned( GetElementById( WebBrowser1.Document, 'IstatistikForm:j_id588:0:j_id522' ) as IHTMLElement ) do
     begin
        Application.ProcessMessages ;
     end;
Burada doğrudan WebBrowser.OleObject.Document.GetElementById() kullanarak çözüme gidemeyip IHTMLDocument2 dan yardım almamın nedeni doğrudan kullanımda "WebBrowser.OleObject.Document" sayfa geçişlerinde bir anlıkta olsa NULL olabiliyor sürekli WHILE ile kontrol aşamasında kırılma meydana geliyor.

mevcut nesne InnerHTML indeki değişikliği de ,

Kod: Tümünü seç

while Pos('OPTION value=' , WebBrowser1.OleObject.Document.GetElementByID('dtIstatistik:5:newselectOneIstatistik').InnerHTML)=0  do Application.ProcessMessages;
gibi bir yapıyla kontrol altına aldım.

Herşey güzel hoş fakat hiç hesapta olmayan bir durumla karşılaştım , TWebBrowser ve parentControl ün mutlaka görünür olması gerekiyor, yani bir windows hizmet uygulamasında ya da ekranda görünmeden arka planda çalıştıramıyorum. bu konuda bir çözüm öneriniz var mı?
Volkan KAMADAN
www.polisoft.com.tr
Kullanıcı avatarı
mrmarman
Üye
Mesajlar: 4740
Kayıt: 09 Ara 2003 08:13
Konum: İstanbul
İletişim:

Re: TWebBrowser Ajax Yanıtı Beklemek

Mesaj gönderen mrmarman »

Durumu yanlış anlamadıysam ben de benzer durumlarla sık olmasa da karşılaşıyorum.

Sorunu doğru algılamışsam, bunun için forma bir adet panel bu panel içine de yedek bir TWebBrowser yerleştirip işlemleri göstermemek için üzerine bir panel daha açıp arkada saklanmasını sağlıyorum. Böylece Browserın açık ve görünür olma şartını hem sağlamış hem de gizlenmiş halde yerine getirmiş oluyorum.
Resim
Resim ....Resim
Kullanıcı avatarı
vkamadan
Kıdemli Üye
Mesajlar: 1935
Kayıt: 17 Mar 2004 03:52
Konum: Adapazarı
İletişim:

Re: TWebBrowser Ajax Yanıtı Beklemek

Mesaj gönderen vkamadan »

Aslında ben bu işleri tamamen arka planda yaptıran bir hizmet uygulaması yapmak istiyordum fakat windows hizmet uygulamalarında ekrana form gösteremeyeceğim bilgisine ulaştım (form ları ayrı birer DLL içinde tasarlayıp bu DLL i hizmetten çağırmak dışında) bunun yerine system tray uygulamasına döndüm, TWebBrowser ın bulunduğu formuda mutlak suretle Show etmem gerektiği için ilgili formu ekran sınırları dışında bir koordinatta görünmesini sağladım (L: -500 , T: -500) gibi. iptidai bir yöntem oldu fakat şimdilik istediğim gibi davranıyor.
Volkan KAMADAN
www.polisoft.com.tr
Cevapla