English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Italiano
MetaTrader 5'te RSS Beslemelerini Görüntülemek için Etkileşimli Bir Uygulama Oluşturma

MetaTrader 5'te RSS Beslemelerini Görüntülemek için Etkileşimli Bir Uygulama Oluşturma

MetaTrader 5Uzman Danışmanlar | 14 Ocak 2022, 13:45
256 0
Francis Dube
Francis Dube

İçindekiler


Giriş

"MQL4 Aracılığıyla RSS Haber Beslemelerini Okuma" makalesi, aslen HTML belgelerini ayrıştırmak için oluşturulmuş basit bir kitaplık aracılığıyla RSS beslemelerini terminalin konsolunda görüntülemek için kullanılabilecek oldukça ilkel bir komut dosyasını tanımladı.

MetaTrader 5 ve MQL5 programlama dilinin ortaya çıkmasıyla, RSS içeriğini daha iyi görüntüleyebilecek etkileşimli bir uygulama oluşturmanın mümkün olduğunu düşündüm. Bu makale, kapsamlı MQL5 Standart kitaplığı ve MQL5 topluluğu katılımcıları tarafından geliştirilen diğer bazı araçları kullanarak bu uygulamanın nasıl üretileceğini açıklar.


1. Genel olarak RSS belgeleri

Uygulamanın özelliklerini kavramadan önce, bir RSS belgesinin genel yapısına genel bir bakış vermek gerektiğini düşünüyorum.

İzlenecek açıklamayı anlamak için genişletilebilir biçimlendirme diline ve ilgili kavramlara aşina olmanız gerekir. XML belgelerine aşina değilseniz, lütfen XML Eğitimi'ne bakın. Bu makalede, düğümün XML belgesindeki bir etiketi ifade ettiğini unutmayın. Yukarıda atıfta bulunulan MQL4 makalesinde bahsedildiği gibi, RSS dosyaları sadece belirli bir etiket yapısına sahip XML belgeleridir.

Her RSS belgesinin global bir kapsayıcı olan RSS etiketi vardır. Bu, tüm RSS belgeleri için aynıdır. Kanal etiketi her zaman RSS etiketinin doğrudan bir devamıdır. Bu, beslemenin açıkladığı web sitesi hakkında bilgi içerir. Buradan itibaren RSS belgeleri içerdikleri belirli etiketler açısından farklılık gösterebilir ancak RSS dosyalarının doğrulanması için tüm belgelerin içermesi gereken bazı etiketler vardır.

Gerekli etiketler şunlardır:

  • başlık - Kanalın başlığı. Web sitesinin adını içermelidir;
  • bağlantı - bu kanalı sağlayan web sitesinin URL'si;
  • açıklama - Web sitesinin ne hakkında olduğunun özeti;
  • öğe - içerik için en az bir öğe etiketi.

Yukarıda gösterilen etiketlerin tümü, kanal etiketinin alt düğümleri olmalıdır. Öğe düğümü, belirli içerikle ilgili verileri içeren düğümdür.

Her öğe düğümü sırayla aşağıdaki etiketleri de içermelidir:

  • başlık - İçeriğin başlığı;
  • bağlantı - İçeriğe giden URL bağlantısı;
  • açıklama - İçeriğin özeti;
  • tarih - İçeriğin web sitesinde yayınlandığı tarih.

Tüm RSS belgeleri açıklanan etiketler içerir ve aynı yapıyı takip eder.

Eksiksiz bir RSS belgesi örneği aşağıda verilmiştir.

<?xml version="1.0"?>
<rss version="2.0">
  <channel>
    <title>Xul.fr: Tutorials and Applications of the Web 2.0</title>
    <link>http://www.xul.fr/</link>
    <description>Ajax, JavaScript, XUL, RSS, PHP and all technologies of the Web 2.0. Building a CMS, tutorial and application.</description>
    <pubDate>Wed, 07 Feb 2007 14:20:24 GMT</pubDate>
    <item>
    <title>News on interfaces of the Web in 2010</title>
    <link>http://www.xul.fr/en/2010.php</link>
    <description>Steve Jobs explains why iPad does not support Adobe Flash:&lt;em&gt;At Adobe they are lazy. 
    They have the potential to make  interesting things, but they refuse to do so. 
    Apple does not support Flash because it is too buggy.
     Each time a Mac crashes, most often it is because of Flash. Nobody will use Flash. 
     The world is moving  to &lt;a href="http://www.xul.fr/en/html5/" target="_parent"&gt;HTML 5&lt;/a&gt;</description>
     <pubDate>Sat, 11 Dec 10 09:41:06 +0100</pubDate>
    </item>
    <item>
      <title>Textured Border in CSS</title>
      <link>http://www.xul.fr/en/css/textured-border.php</link>
      <description>   The border attribute of the style sheets can vary in color and width, but it was not expected to give it a texture. However, only a CSS rule is required to add this graphic effect...   The principle is to assign a texture to the whole &lt;em&gt;fieldset&lt;/em&gt; and insert into it another &lt;em&gt;fieldset&lt;/em&gt; (for rounded edges) or a &lt;em&gt;div&lt;/em&gt;, whose background is the same as that of the page</description>
      <pubDate>Wed, 29 Jul 09 15:56:54  0200</pubDate>
    </item>
    <item>
      <title>Create an RSS feed from SQL, example with Wordpress</title>
      <link>http://www.xul.fr/feed/rss-sql-wordpress.html</link>
      <description>Articles contain at least the following items: And possibly, author's name, or an image. This produces the following table: The returned value is true if the database is found, false otherwise. It remains to retrieve the data from the array</description>
      <pubDate>Wed, 29 Jul 09 15:56:50  0200</pubDate>
    </item>
    <item>
      <title>Firefox 3.5</title>
      <link>http://www.xul.fr/gecko/firefox35.php</link>
      <description>Les balises audio et vid&#xE9;o sont impl&#xE9;ment&#xE9;es. Le format de donn&#xE9;e JSON est reconnu nativement par Firefox. L'avantage est d'&#xE9;viter l'utilisation de la fonction eval() qui n'est pas s&#xFB;r, ou d'employer des librairies additionnelles, qui est nettement plus lent</description>
      <pubDate>Wed, 24 Jun 09 15:18:47  0200</pubDate>
    </item>
    <item>
      <title>Contestation about HTML 5</title>
      <link>http://www.xul.fr/en/html5/contestation.php</link>
      <description>  Nobody seemed to be worried so far, but the definition of HTML 5 that is intended to be the format of billions of Web pages in coming years, is conducted and decided by a single person! &lt;em&gt;Hey, wait! Pay no attention to the multi-billions dollar Internet corporation behind the curtain. It's me Ian Hickson! I am my own man</description>
      <pubDate>Wed, 24 Jun 09 15:18:29  0200</pubDate>
    </item>
    <item>
      <title>Form Objects in HTML 4</title>
      <link>http://www.xul.fr/javascript/form-objects.php</link>
      <description>   It is created by the HTML &lt;em&gt;form&lt;/em&gt; tag:   The name or id attribute can access by script to its content. It is best to use both attributes with the same identifier, for the sake of compatibility.   The &lt;em&gt;action&lt;/em&gt; attribute indicates the page to which send the form data. If this attribute is empty, the page that contains the form that will be charged the data as parameters</description>
      <pubDate>Wed, 24 Jun 09 15:17:49  0200</pubDate>
    </item>
    <item>
      <title>DOM Tutorial</title>
      <link>http://www.xul.fr/en/dom/</link>
      <description>  The Document Object Model describes the structure of an XML or HTML document, a web page and allows access to each individual element.</description>
      <pubDate>Wed, 06 May 2009 18:30:11 GMT</pubDate>
    </item>    
  </channel>
</rss>


2. Uygulamanın genel yapısı

Burada RSS Okuyucuda gösterilmesi gereken bilgilerin bir tanımını ve uygulamanın grafiksel kullanıcı arayüzünün genel görünümünü vereceğim.

Uygulamada gösterilmesi gereken ilk özellik, başlık etiketinde yer alan kanal başlığıdır. Bu bilgi, beslemenin referans gösterdiği web sitesinin bir göstergesi olarak hizmet edecektir.

Uygulama ayrıca, beslemenin açıkladığı tüm içeriğin bir anlık görüntüsünü göstermelidir, bu, belgedeki tüm öğe etiketleriyle ilgilidir. Her öğe etiketi için içeriğin başlığı görüntülenecektir. Son olarak, RSS Okuyucunun içeriğin açıklamasını gösterebilmesini istiyorum; bu, her öğe düğümünün açıklama etiketinde bulunan veriler olacaktır.


2.1. Kullanıcı arayüzü

Kullanıcı arayüzü uygulama tarafından gösterilcek bilgilerin bir işlevidir.

Kullanıcı arayüzü için sahip olduğum fikir en iyi aşağıdaki diyagramda tasvir edilmiştir.


Uygulama diyaloğunun taslağı

Şek. 1. Uygulama diyaloğunun taslağı


Diyagram kullanıcı arayüzünü oluşturan farklı bölümleri gösterir.

  • Birincisi başlık çubuğudur. Kanal başlığının gösterileceği yer burasıdır;
  • Giriş alanı. Kullanıcıların bir RSS beslemesinin web adresini gireceği yer burasıdır;
  • Başlık alanı. Belirli içeriğin başlığı burada görüntülenecektir;
  • Metin alanı. İçeriğin açıklaması burada gösterilir;
  • Liste görünüm alanı. Bu kaydırılabilir liste, yayının içerdiği tüm içerik başlıklarını görüntüler;
  • Soldaki düğme Başlık, metin ve liste görünümü alanlarında görüntülenen metni sıfırlar ve siler;
  • Geçerli beslemeyi güncelle düğmesi, o anda yüklü olan bir özet akışı için yeni güncellemeleri alır.

RSS Okuyucu aşağıdaki şekilde çalışacaktır; program grafiğe yüklendiğinde, boş uygulama diyaloğu görüntülenir, kullanıcının giriş alanına istenen RSS beslemesinin web adresini girmesi ve ardından enter tuşuna basması gerekir. Bu tüm içerik başlıklarını, yani her bir öğe etiketi için başlık etiketi değerlerini liste görünümü alanına yükleyecektir. Liste, en son yayınlanan içeriği temsil eden 1'den numaralandırılacaktır.

Her liste öğesi tıklanabilir olacak, bir liste öğesine tıklandığında vurgulanacak ve başlık içeriğinin ilgili açıklaması metin alanında görüntülenecektir. Aynı zamanda içerik başlığı başlık alanı bölümünde daha net gösterilecektir. Feed'in yüklenmesi sırasında herhangi bir nedenle bir hata oluşursa metin alanı bölümünde bir hata mesajı görüntülenir.

Sıfırlama düğmesi daha sonra metin alanı, liste görünümü alanı, başlık alanı alanı bölümlerindeki herhangi bir metni silmek için kullanılabilir.

Mevcut beslemeyi güncelle, mevcut özet akışı için herhangi bir güncelleme olup olmadığını kontrol eder.


2.2. Kod uygulaması

RSS Okuyucu, Expert Advisor olarak uygulanacak ve MQL5 Standart kitaplığı kullanılacaktır.

Kod, CAppDialog sınıfının soyundan gelen bir CRssReader sınıfında yer alacaktır. Dialog.mqh ekleme dosyasında verilen CAppDialog sınıfı, bir başlık çubuğu için işlevsellik ve simge durumuna küçültme, büyütme ve kapatma için işlevsellik kontrolleri sağlayan uygulama diyaloğunun uygulanmasını sağlar. Bu, üzerine başka bölümlerin ekleneceği kullanıcı arayüzünün temeli olacaktır. Eklenecek şu bölümler için: başlık alanı, metin alanı, liste görünüm alanı ve butonlar. Her biri bir kontrol olacak. Düğmeler, Button.mqh ekleme dosyasında açıklanan bir düğme kontrolü olarak uygulanacaktır.

ListViewArea.mqh ekleme dosyasında tanımlanan liste görünümü kontrolü, RSS Okuyucusunun liste görünümü alanı bölümünü oluşturmak için kullanılacaktır.

Düzenleme kontrolü, giriş alanı bölümünü oluşturmak için açıkça yeterli olacaktır, bu denetim Edit.mqh dosyasında tanımlanmıştır.

Başlık alanı ve metin alanı bölümleri, uygulanması söz konusu olduğunda benzersiz bir zorluk sunar. Sorun şu ki, her ikisinin de birkaç satırda görüntülenebilen metin desteğine sahip olması gerekiyor. MQL5'teki metin nesneleri yeni satır besleme karakterlerini tanımıyor. Başka bir sorun, bir metin nesnesinin bir satırında yalnızca sınırlı sayıda dize karakterinin görüntülenebilmesidir. Bu, yeterince uzun bir açıklama içeren bir metin nesnesi oluşturursanız nesnenin metin kesilerek görüntüleneceği, yalnızca belirli sayıda karakterin gösterileceği anlamına gelir. Deneme yanılma yoluyla karakter sınırının boşluklar ve noktalama işaretleri dahil 63 olduğunu öğrendim.

Bu sorunların üstesinden gelmek için her iki bölümü de değiştirilmiş liste görünümü kontrolleri olarak uygulamaya karar verdim. Başlık alanı bölümü için değiştirilmiş liste görünümü kontrolü kaydırılamaz olacak ve sabit sayıda liste öğesi (2) içerecektir. Her liste öğesi tıklanabilir veya seçilebilir olmayacak ve kontrolün fiziksel görünümü liste gibi görünmeyecek şekilde olacaktır. Bu 2 liste öğesi iki metin satırını temsil edecektir. Metin bir satıra sığmayacak kadar uzunsa buna göre bölünecek ve 2 satır metin olarak görüntülenecektir. Başlık alanı bölümünün kontrolü TitleArea.mqh dosyasında tanımlanacaktır.

Metin alanı bölümü için benzer bir yaklaşım uygulanacaktır, ancak bu sefer liste öğelerinin sayısı dinamik olacak ve değiştirilmiş liste görünümü kontrolü dikey olarak kaydırılabilir olacaktır. Bu kontrol TextArea.mqh dosyasında verilecektir.

Şimdiye kadar bahsedilen kütüphaneler, kullanıcı arayüzü ile ilgilenir. Bu uygulama için tartışılması gereken çok önemli bir kitaplık daha var. Bu, XML belgelerini ayrıştırmak için kullanılan kitaplıktır.


2.3. Kolay XML ayrıştırıcı

RSS belgesi bir XML dosyası olduğundan, liquinaut tarafından geliştirilen EasyXML - XML Ayrıştırıcı ve Kod Tabanında bulunan kitaplık uygulanır.

Kitaplık oldukça kapsamlıdır ve RSS Okuyucumuz için gereken hemen hemen tüm işlevleri içerir. Gerekli olduğunu düşündüğüm bazı ekstra özellikler eklemek için orijinal kitaplıkta bazı değişiklikler yaptım.

Bunlar küçük eklemelerdi. Bunlardan ilki, loadXmlFromUrlWebReq() adlı ekstra bir yöntemin eklenmesiydi. Bu yöntem, web isteklerini işlemek için WinInet kitaplığına dayanan loadXmlFromUrl() kullanımına bir alternatif sunar; loadXmlFromUrlWebReq(), İnternet'ten indirmeleri etkinleştirmek için yerleşik WebRequest() işlevini kullanır.

//+------------------------------------------------------------------+
//| load xml by given url using MQL5 webrequest function             |
//+------------------------------------------------------------------+
bool CEasyXml::loadXmlFromUrlWebReq(string pUrl)
  {
//---
   string cookie=NULL,headers;
   char post[],result[];
   int res;
//---
   string _url=pUrl;
   string sStream;
   res=WebRequest("GET",_url,cookie,NULL,5000,post,0,result,headers);
//--- check error
   if(res==-1)
     {
      Err=EASYXML_ERR_WEBREQUEST_URL;
      return(Error());
     }
//---success downloading file
   sStream=CharArrayToString(result,0,-1,CP_UTF8);
//---set up cach file
   if(blSaveToCache)
     {
      bool bResult=writeStreamToCacheFile(sStream);
      if(!bResult) Error(-1,false);
     }
//---
   return(loadXmlFromString(sStream));
  }

İkinci ekleme GetErrorMsg() yöntemiydi; bu, bir hata oluştuğunda çözümleyici tarafından hata mesajı çıktısının alınmasına izin verir.

string            GetErrorMsg(void){   return(ErrMsg);}

Son ekleme, easyxml ayrıştırıcısını test ederken bulduğum oldukça ciddi bir kusuru düzeltmek için yapıldı.

Kitaplığın XML stil sayfası bildirimlerini tanıyamadığını buldum. Kod, bir stil sayfası bildirimini öznitelikle karıştırıyor. Bu, kodun hiçbir zaman var olmayan karşılık gelen öznitelik değerini sürekli olarak aradığı için programın sonsuz bir döngüde takılıp kalmasına neden oldu.

Bu, skipProlog() yönteminde küçük bir değişiklikle kolayca düzeltildi.

//+------------------------------------------------------------------+
//| skip xml prolog                                                  |
//+------------------------------------------------------------------+
bool CEasyXml::skipProlog(string &pText,int &pPos)
  {
//--- skip xml declaration
   if(StringCompare(EASYXML_PROLOG_OPEN,StringSubstr(pText,pPos,StringLen(EASYXML_PROLOG_OPEN)))==0)
     {
      int iClose=StringFind(pText,EASYXML_PROLOG_CLOSE,pPos+StringLen(EASYXML_PROLOG_OPEN));

      if(blDebug) Print("### Prolog ###    ",StringSubstr(pText,pPos,(iClose-pPos)+StringLen(EASYXML_PROLOG_CLOSE)));

      if(iClose>0)
        {
         pPos=iClose+StringLen(EASYXML_PROLOG_CLOSE);
           } else {
         Err=EASYXML_INVALID_PROLOG;
         return(false);
        }
     }
//--- skip stylesheet declarations
   if(StringCompare(EASYXML_STYLESHEET_OPEN,StringSubstr(pText,pPos,StringLen(EASYXML_STYLESHEET_OPEN)))==0)
     {
      int iClose=StringFind(pText,EASYXML_STYLESHEET_CLOSE,pPos+StringLen(EASYXML_STYLESHEET_OPEN));

      if(blDebug) Print("### Prolog ###    ",StringSubstr(pText,pPos,(iClose-pPos)+StringLen(EASYXML_STYLESHEET_CLOSE)));

      if(iClose>0)
        {
         pPos=iClose+StringLen(EASYXML_STYLESHEET_CLOSE);
           } else {
         Err=EASYXML_INVALID_PROLOG;
         return(false);
        }
     }
//--- skip comments
   if(!skipWhitespaceAndComments(pText,pPos,"")) return(false);

//--- skip doctype
   if(StringCompare(EASYXML_DOCTYPE_OPEN,StringSubstr(pText,pPos,StringLen(EASYXML_DOCTYPE_OPEN)))==0)
     {
      int iClose=StringFind(pText,EASYXML_DOCTYPE_CLOSE,pPos+StringLen(EASYXML_DOCTYPE_OPEN));

      if(blDebug) Print("### DOCTYPE ###    ",StringSubstr(pText,pPos,(iClose-pPos)+StringLen(EASYXML_DOCTYPE_CLOSE)));

      if(iClose>0)
        {
         pPos=iClose+StringLen(EASYXML_DOCTYPE_CLOSE);
           } else {
         Err=EASYXML_INVALID_DOCTYPE;
         return(false);
        }
     }

//--- skip comments
   if(!skipWhitespaceAndComments(pText,pPos,"")) return(false);

   return(true);
  }

Bu soruna rağmen, liquinaut'tan hiçbir şey çıkarmayın, easyxml.mqh mükemmel bir araçtır.


2.4. Expert Advisor kodu

Uygulama için ihtiyaç duyulan tüm kütüphaneler açıklandığına göre artık bu bileşenleri bir araya getirerek CRssReader sınıfını tanımlamanın zamanı geldi.

Lütfen RSS Okuyucu Expert Advisor kodunun CRssReader sınıfının tanımıyla başlayacağını unutmayın.

//+------------------------------------------------------------------+
//|                                                    RssReader.mq5 |
//|                                                          Ufranco |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Ufranco"
#property link      "https://www.mql5.com"
#property version   "1.00"
#include <Controls\Dialog.mqh>
#include <Controls\Edit.mqh>
#include <Controls\Button.mqh>
#include <TitleArea.mqh>
#include <TextArea.mqh>
#include <ListViewArea.mqh>
#include <easyxml.mqh>
//+------------------------------------------------------------------+
//| defines                                                          |
//+------------------------------------------------------------------+
//--- indents and gaps
#define INDENT_LEFT                         (11)      // indent from left (with allowance for border width)
#define INDENT_TOP                          (11)      // indent from top (with allowance for border width)
#define INDENT_RIGHT                        (11)      // indent from right (with allowance for border width)
#define INDENT_BOTTOM                       (11)      // indent from bottom (with allowance for border width)
#define CONTROLS_GAP_X                      (5)       // gap by X coordinate
#define CONTROLS_GAP_Y                      (5)       // gap by Y coordinate

#define EDIT_HEIGHT                         (20)      // size by Y coordinate
#define BUTTON_WIDTH                        (150)     // size by X coordinate
#define BUTTON_HEIGHT                       (20)      // size by Y coordinate
#define TEXTAREA_HEIGHT                     (131)     // size by Y coordinate
#define LIST_HEIGHT                         (93)      // size by Y coordinate

Gerekli dosyaları ekleyerek başlıyoruz. Tanımlama yönergeleri, kontrollerin fiziksel parametrelerini piksel cinsinden ayarlamak için kullanılır.

INDENT_LEFT, INDENT_RIGHT, INDENT_TOP ve INDENT_DOWN, bir kontrol ile uygulama diyaloğunun kenarı arasındaki mesafeyi ayarlar.

  • CONTROLS_GAP_Y, iki kontrol arasındaki dikey mesafedir;
  • EDIT_HEIGHT, giriş alanını oluşturan Düzenleme kontrolünün yüksekliğini ayarlar;
  • BUTTON_WIDTH ve BUTTON_HEIGHT, tüm düğme kontrollerinin genişliğini ve yüksekliğini tanımlar;
  • TEXTAREA_HEIGHT, metin alanı bölümünün yüksekliğidir;
  • LIST_HEIGHT, liste görünümü kontrolünün yüksekliğini ayarlar.

Tanımlamalardan sonra CRssReader sınıfının tanımına başlıyoruz.

//+------------------------------------------------------------------+
//| Class CRssReader                                                 |
//| Usage: main class for the RSS application                        |
//+------------------------------------------------------------------+
class CRssReader : public CAppDialog
  {
private:
   int               m_shift;                    // index of first item tag
   string            m_rssurl;                   // copy of web address of last feed 
   string            m_textareaoutput[];         // array of strings prepared for output to the text area panel
   string            m_titleareaoutput[];        // array of strings prepared for output to title area panel
   CButton           m_button1;                  // the button object
   CButton           m_button2;                  // the button object      
   CEdit             m_edit;                     // input panel
   CTitleArea        m_titleview;                // the display field object
   CListViewArea     m_listview;                 // the list object
   CTextArea         m_textview;                 // text area object
   CEasyXml          m_xmldocument;              // xml document object
   CEasyXmlNode     *RssNode;                    // root node object
   CEasyXmlNode     *ChannelNode;                // channel node object
   CEasyXmlNode     *ChannelChildNodes[];        // array of channel child node objects

Daha önce belirtildiği gibi CRssReader, CAppDialog sınıfından devralır.

Sınıfın aşağıda verilen birkaç özel özelliği vardır:

  • m_shift - bu tamsayı türü değişken, ChannelChildnodes dizisindeki ilk öğe düğümünün indeksini depolar;
  • m_rssurl - girilen son URL'nin kopyasını tutan bir dize değeridir;
  • m_textareaoutput[] -bir dize dizisidir, her öğe belirli sayıda karakter içeren bir metin satırına karşılık gelir;
  • m_titleareaoutput[] - bu dize dizisi de önceki dize dizisiyle aynı amaca hizmet eder;
  • m_button1 ve m_button2, CButton türünde nesnelerdir;
  • m_listview, liste kontrolünü temsil eden bir nesnedir;
  • m_edit özelliği bir CEdit nesnesidir ve giriş alanını uygular;
  • m_titleview, başlık alanı görüntüleme alanı için bir nesnedir;
  • m_textview - metin alanı bölümünün nesnesi;
  • m_xmldocument bir xml belge nesnesidir;
  • RssNode, kök Düğüm nesnesidir;
  • ChannelNode, kanal düğümünün nesnesidir;
  • ChannelChildNodes dizisi, Channel etiketinin doğrudan alt öğelerine yönelik bir işaretçiler kümesidir.

Sınıfımızın yalnızca iki genel kullanıma açık yöntemi olacaktır.

public:
                     CRssReader(void);
                    ~CRssReader(void);
   //--- create
   virtual bool      Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);
   //--- chart event handler
   virtual bool      OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);

İlk yöntem Create(), uygulama diyaloğunun boyutunu ve başlangıç pozisyonunu ayarlar.

Ayrıca RSS Reader uygulamasının tüm denetimlerini başlatır, (sınıfımızın CAppDialog sınıfından devraldığını ve bu nedenle üst sınıfın ve atalarının genel yöntemlerinin CRssReader oluşumları tarafından çağrılabileceğini unutmayın).

//+------------------------------------------------------------------+
//| Create                                                           |
//+------------------------------------------------------------------+
bool CRssReader::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
  {
   if(!CAppDialog::Create(chart,name,subwin,x1,y1,x2,y2))
      return(false);
//--- create dependent controls
   if(!CreateEdit())
      return(false);
   if(!CreateButton1())
      return(false);
   if(!CreateButton2())
      return(false);
   if(!CreateTitleView())
      return(false);
   if(!CreateListView())
      return(false);
   if(!CreateTextView())
      return(false);
//--- succeed
   return(true);
  }

İkincisi, OnEvent() yöntemidir; işlev, belirli olayları karşılık gelen bir kontrole ve bir tanıtıcı işlevine atayarak etkileşimi etkinleştirir.

//+------------------------------------------------------------------+
//| Event Handling                                                   |
//+------------------------------------------------------------------+
EVENT_MAP_BEGIN(CRssReader)
ON_EVENT(ON_CHANGE,m_listview,OnChangeListView)
ON_EVENT(ON_END_EDIT,m_edit,OnObjectEdit)
ON_EVENT(ON_CLICK,m_button1,OnClickButton1)
ON_EVENT(ON_CLICK,m_button2,OnClickButton2)
EVENT_MAP_END(CAppDialog)


2.5. Kontrollerin başlatma yöntemleri

CreateEdit(), CreateButton1() ,CreateButton2(), CreateTitleView(), CreateListView() ve CreateTextView() korumalı yöntemler, karşılık gelen bir kontrolü başlatmak için ana Create() işlevi tarafından çağrılır.

protected:
   // --- creating controls
   bool              CreateEdit(void);
   bool              CreateButton1(void);
   bool              CreateButton2(void);
   bool              CreateTitleView(void);
   bool              CreateListView(void);
   bool              CreateTextView(void);

Bir kontrolün boyutu, pozisyonu ve özellikleri (yani yazı tipi, yazı boyutu, renk, kenarlık rengi, kenarlık türü) bu işlevlerin her birinde ayarlanır.

//+------------------------------------------------------------------+
//| Create the display field                                         |
//+------------------------------------------------------------------+
bool CRssReader::CreateEdit(void)
  {
//--- coordinates
   int x1=INDENT_LEFT;
   int y1=INDENT_TOP;
   int x2=ClientAreaWidth()-INDENT_RIGHT;
   int y2=y1+EDIT_HEIGHT;
//--- create
   if(!m_edit.Create(m_chart_id,m_name+"Edit",m_subwin,x1,y1,x2,y2))
      return(false);
   if(!m_edit.Text("Please enter the web address of an Rss feed"))
      return(false);
   if(!m_edit.ReadOnly(false))
      return(false);
   if(!Add(m_edit))
      return(false);
//--- succeed
   return(true);
  }
//+------------------------------------------------------------------+
//| Create button 1                                                  |
//+------------------------------------------------------------------+ 
bool CRssReader::CreateButton1(void)
  {
//--- coordinates
   int x1=INDENT_LEFT;
   int y1=INDENT_TOP+(EDIT_HEIGHT+CONTROLS_GAP_Y);
   int x2=x1+BUTTON_WIDTH;
   int y2=y1+BUTTON_HEIGHT;
//--- create
   if(!m_button1.Create(m_chart_id,m_name+"Button1",m_subwin,x1,y1,x2,y2))
      return(false);
   if(!m_button1.Text("Reset"))
      return(false);
   if(!m_button1.Font("Comic Sans MS"))
      return(false);
   if(!m_button1.FontSize(8))
      return(false);
   if(!m_button1.Color(clrWhite))
      return(false);
   if(!m_button1.ColorBackground(clrBlack))
      return(false);
   if(!m_button1.ColorBorder(clrBlack))
      return(false);
   if(!m_button1.Pressed(true))
      return(false);
   if(!Add(m_button1))
      return(false);
//--- succeed
   return(true);
  }
//+------------------------------------------------------------------+
//| Create button 2                                                  |
//+------------------------------------------------------------------+ 
bool CRssReader::CreateButton2(void)
  {
//--- coordinates
   int x1=(ClientAreaWidth()-INDENT_RIGHT)-BUTTON_WIDTH;
   int y1=INDENT_TOP+(EDIT_HEIGHT+CONTROLS_GAP_Y);
   int x2=ClientAreaWidth()-INDENT_RIGHT;
   int y2=y1+BUTTON_HEIGHT;
//--- create
   if(!m_button2.Create(m_chart_id,m_name+"Button2",m_subwin,x1,y1,x2,y2))
      return(false);
   if(!m_button2.Text("Update current feed"))
      return(false);
   if(!m_button2.Font("Comic Sans MS"))
      return(false);
   if(!m_button2.FontSize(8))
      return(false);
   if(!m_button2.Color(clrWhite))
      return(false);
   if(!m_button2.ColorBackground(clrBlack))
      return(false);
   if(!m_button2.ColorBorder(clrBlack))
      return(false);
   if(!m_button2.Pressed(true))
      return(false);
   if(!Add(m_button2))
      return(false);
//--- succeed
   return(true);
  }
//+------------------------------------------------------------------+
//| Create the display field                                         |
//+------------------------------------------------------------------+
bool CRssReader::CreateTitleView(void)
  {
//--- coordinates
   int x1=INDENT_LEFT;
   int y1=INDENT_TOP+(EDIT_HEIGHT+CONTROLS_GAP_Y)+BUTTON_HEIGHT+CONTROLS_GAP_Y;
   int x2=ClientAreaWidth()-INDENT_RIGHT;
   int y2=y1+(EDIT_HEIGHT*2);
   m_titleview.Current();
//--- create 
   if(!m_titleview.Create(m_chart_id,m_name+"TitleView",m_subwin,x1,y1,x2,y2))
     {
      Print("error creating title view");
      return(false);
     }
   else
     {
      for(int i=0;i<2;i++)
        {
         m_titleview.AddItem(" ");
        }
     }
   if(!Add(m_titleview))
     {
      Print("error adding title view");
      return(false);
     }
//--- succeed
   return(true);
  }
//+------------------------------------------------------------------+
//| Create the "ListView" element                                    |
//+------------------------------------------------------------------+
bool CRssReader::CreateListView(void)
  {

//--- coordinates
   int x1=INDENT_LEFT;
   int y1=INDENT_TOP+((EDIT_HEIGHT+CONTROLS_GAP_Y)*2)+20+TEXTAREA_HEIGHT+CONTROLS_GAP_Y+BUTTON_HEIGHT+CONTROLS_GAP_Y;
   int x2=ClientAreaWidth()-INDENT_RIGHT;
   int y2=y1+LIST_HEIGHT;
//--- create
   if(!m_listview.Create(m_chart_id,m_name+"ListView",m_subwin,x1,y1,x2,y2))
      return(false);
   if(!Add(m_listview))
      return(false);
//--- fill out with strings
   for(int i=0;i<20;i++)
      if(!m_listview.AddItem(" "))
         return(false);
//--- succeed
   return(true);
  }
//+------------------------------------------------------------------+
//| Create the display field                                         |
//+------------------------------------------------------------------+
bool CRssReader::CreateTextView(void)
  {
//--- coordinates
   int x1=INDENT_LEFT;
   int y1=INDENT_TOP+((EDIT_HEIGHT+CONTROLS_GAP_Y)*2)+20+BUTTON_HEIGHT+CONTROLS_GAP_Y;
   int x2=ClientAreaWidth()-INDENT_RIGHT;
   int y2=y1+TEXTAREA_HEIGHT;
   m_textview.Current();
//--- create 
   if(!m_textview.Create(m_chart_id,m_name+"TextArea",m_subwin,x1,y1,x2,y2))
     {
      Print("error creating text area view");
      return(false);
     }
   else
     {
      for(int i=0;i<1;i++)
        {
         m_textview.AddItem(" ");
        }
      m_textview.VScrolled(true);
      ChartRedraw();
     }
   if(!Add(m_textview))
     {
      Print("error adding text area view");
      return(false);
     }
//----success      
   return(true);
  }


2.6. RSS belgesi işleme yöntemleri

// --- rss document processing
   bool              LoadDocument(string filename);
   int               ItemNodesTotal(void);
   void              FreeDocumentTree(void);

2.6.1. LoadDocument()

Bu işlevin oynayacağı birkaç önemli rol vardır. Bunlardan en önemlisi web isteklerinin işlenmesidir. RSS dosyasını indirmek için loadXmlFromUrlWebReq() çağrılır.

Bu başarıyla tamamlanırsa işlev ikinci görevi olan RssNode, ChannelNode işaretçilerini başlatma ve ayrıca ChannelChildnodes dizisini doldurma görevine geçer. m_rssurl ve m_shift özelliklerinin ayarlandığı yer burasıdır. Bütün bunlar yapıldıktan sonra işlev doğru değerini verir.

RSS dosyası indirilemiyorsa, başlık alanı, liste görünümü alanı ve metin alanı bölümlerindeki tüm metinler temizlenir ve başlık çubuğunda bir durum mesajı görüntülenir. Bunu, metin alanı bölümünde bir hata mesajının çıktısı takip eder. Ardından işlev false verir.

//+------------------------------------------------------------------+
//|   load document                                                  |
//+------------------------------------------------------------------+
bool CRssReader::LoadDocument(string filename)
  {
   if(!m_xmldocument.loadXmlFromUrlWebReq(filename))
     {
      m_textview.ItemsClear();
      m_listview.ItemsClear();
      m_titleview.ItemsClear();
      CDialog::Caption("Failed to load Feed");
      if(!m_textview.AddItem(m_xmldocument.GetErrorMsg()))
         Print("error displaying error message");
      return(false);
     }
   else
     {
      m_rssurl=filename;
      RssNode=m_xmldocument.getDocumentRoot();
      ChannelNode=RssNode.FirstChild();
      if(CheckPointer(RssNode)==POINTER_INVALID || CheckPointer(ChannelNode)==POINTER_INVALID)
         return(false);
     }
   ArrayResize(ChannelChildNodes,ChannelNode.Children().Total());
   for(int i=0;i<ChannelNode.Children().Total();i++)
     {
      ChannelChildNodes[i]=ChannelNode.Children().At(i);
     }
   m_shift=ChannelNode.Children().Total()-ItemNodesTotal();
   return(true);
  }


2.6.2. ItemNodesTotal()

Bu yardımcı işlev, LoadDocument() yönteminde kullanılır. Kanal etiketinin alt öğeleri olan öğe düğümlerinin sayısı olan bir tamsayı değeri verir.

Öğe düğümü yoksa belge geçersiz bir RSS belgesi olur ve işlev 0 verir.

//+------------------------------------------------------------------+
//| function counts the number of item tags in document              |
//+------------------------------------------------------------------+
int CRssReader::ItemNodesTotal(void)
  {
   int t=0;
   for(int i=0;i<ChannelNode.Children().Total();i++)
     {
      if(ChannelChildNodes[i].getName()=="item")
        {
         t++;
        }
      else continue;
     }
   return(t);
  }

2.6.3. FreeDocumentTree()

Bu işlev, tüm CEasyXmlNode işaretçilerini sıfırlar.

Önce ChannelChildnodes dizisinin öğeleri, CARrayObj sınıfının Shutdown() yöntemi çağrılarak silinir. Dizi daha sonra tek bir ArrayFree() çağrısı ile serbest bırakılır.

Daha sonra kanal düğümünün işaretçisi silinir ve easyxml ayrıştırıcının belge ağacı temizlenir. Bu eylemler, RssNode ve ChannelNode işaretçilerinin kötü işaretçiler olmasına neden olur, bu nedenle her ikisine de NULL değeri atanır.

//+------------------------------------------------------------------+
//| free document tree and reset pointer values                      |
//+------------------------------------------------------------------+ 
void CRssReader::FreeDocumentTree(void)
  {
   ChannelNode.Children().Shutdown();
   ArrayFree(ChannelChildNodes);
   RssNode.Children().Shutdown();
   m_xmldocument.Clear();
   m_shift=0;
   RssNode=NULL;
   ChannelNode=NULL;
  }


2.7. Belge ağacından bilgi çıkarma yöntemleri

Bu işlevler, bir RSS belgesinden metin almak içindir.

//--- getters
   string            getChannelTitle(void);
   string            getTitle(CEasyXmlNode *Node);
   string            getDescription(CEasyXmlNode *Node);
   string            getDate(CEasyXmlNode *Node);

2.7.1. getChannelTitle()

Bu işlev, RSS belgesinin geçerli kanal başlığını alır.

Kanal düğüm işaretçisinin geçerliliğini kontrol ederek başlar. İşaretçi geçerliyse başlık etiketini arayan kanal düğümünün tüm doğrudan torunları arasında döngü yapar.

For döngüsü, arama yapılacak kanal düğümü alt öğelerinin sayısını sınırlamak için m_shift özelliğini kullanır. İşlev başarısız olursa NULL verir.

//+------------------------------------------------------------------+
//| get channel title                                                |
//+------------------------------------------------------------------+
string CRssReader::getChannelTitle(void)
  {
   string ret=NULL;
   if(!CheckPointer(ChannelNode)==POINTER_INVALID)
     {
      for(int i=0;i<m_shift;i++)
        {
         if(ChannelChildNodes[i].getName()=="title")
           {
            ret=ChannelChildNodes[i].getValue();
            break;
           }
         else continue;
        }
     }
//---return value
   return(ret);
  }


2.7.2. getTitle()

İşlev, girdi olarak bir öğe etiketine bir işaretçi alır ve bir başlık etiketi arayarak bu etiketin alt öğelerinin üzerinden geçer ve değerini verir.

getDescription() ve getDate() işlevleri aynı formatı izler ve benzer şekilde çalışır. Başarılı bir işlev çağrısı bir dize değeri verir, aksi takdirde çıktı olarak NULL verilir.

//+------------------------------------------------------------------+
//| display title                                                    |
//+------------------------------------------------------------------+
string CRssReader::getTitle(CEasyXmlNode *Node)
  {
   int k=Node.Children().Total();
   string n=NULL;
   for(int i=0;i<k;i++)
     {
      CEasyXmlNode*subNode=Node.Children().At(i);
      if(subNode.getName()=="title")
        {
         n=subNode.getValue();
         break;
        }
      else continue;
     }
   return(n);
  }
//+------------------------------------------------------------------+
//| display description                                              |
//+------------------------------------------------------------------+
string CRssReader::getDescription(CEasyXmlNode *Node)
  {
   int k=Node.Children().Total();
   string n=NULL;
   for(int i=0;i<k;i++)
     {
      CEasyXmlNode*subNode=Node.Children().At(i);
      if(subNode.getName()=="description")
        {
         n=subNode.getValue();
         break;
        }
      else continue;
     }
   return(n);
  }
//+------------------------------------------------------------------+
//| display date                                                     |
//+------------------------------------------------------------------+ 
string CRssReader::getDate(CEasyXmlNode *Node)
  {
   int k=Node.Children().Total();
   string n=NULL;
   for(int i=0;i<k;i++)
     {
      CEasyXmlNode*subNode=Node.Children().At(i);
      if(subNode.getName()=="pubDate")
        {
         n=subNode.getValue();
         break;
        }
      else continue;
     }
   return(n);
  }


2.8. Metni biçimlendirme yöntemleri

Bu işlevler, metin nesnelerinin sahip olduğu bazı sınırlamaların üstesinden gelmek için metni metin nesneleri olarak çıktıya hazırlamak içindir.

 //--- text formating 
   bool              FormatString(string v,string &array[],int n);
   string            removeTags(string _string);
   string            removeSpecialCharacters(string s_tring);
   int               tagPosition(string _string,int w);

2.8.1. FormatString()

Bu, bir RSS belgesinden çıkarılan metni uygulamaya çıkış için hazırlayan ana işlevdir.

Temel olarak bir dize giriş değeri alır ve metni "n" karakterlik satırlara böler. "n", tek bir metin satırındaki karakter sayısının tamsayı değeridir. Metindeki her "n" karakterden sonra kod, yeni bir satır besleme karakteri eklemek için uygun bir yer arar. Ardından tüm dize değeri işlenir ve yeni satır besleme karakterleri orijinal metne eklenir.

StringSplit() işlevi, her biri "n" karakter uzunluğunda olmayan bir dize dizisi oluşturmak için kullanılır. İşlev, bir bool değeri ve ayrıca çıktıya hazır bir dizi dize değeri verir.

//+------------------------------------------------------------------+
//| format string for output to text area panel                      |
//+------------------------------------------------------------------+
bool CRssReader::FormatString(string v,string &array[],int n)
  {
   ushort ch[],space,fullstop,comma,semicolon,newlinefeed;
   string _s,_k;
   space=StringGetCharacter(" ",0);
   fullstop=StringGetCharacter(".",0);
   comma=StringGetCharacter(",",0);
   semicolon=StringGetCharacter(";",0);
   newlinefeed=StringGetCharacter("\n",0);
   _k=removeTags(v);
   _s=removeSpecialCharacters(_k);
   int p=StringLen(_s);
   ArrayResize(ch,p+1);
   int d=StringToShortArray(_s,ch,0,-1);
   for(int i=1;i<d;i++)
     {
      int t=i%n;
      if(!t== 0)continue;
      else 
        {
         if(ch[(i/n)*n]==fullstop || ch[(i/n)*n]==semicolon || ch[(i/n)*n]==comma)
           {
            ArrayFill(ch,((i/n)*n)+1,1,newlinefeed);
           }
         else
           {
            for(int k=i;k>=0;k--)
              {
               if(ch[k]==space)
                 {
                  ArrayFill(ch,k,1,newlinefeed);
                  break;
                 }
               else continue;
              }
           }
        }
     }
   _s=ShortArrayToString(ch,0,-1);
   int s=StringSplit(_s,newlinefeed,array);
   if(!s>0)
     {return(false);}
// success 
   return(true);
  }


2.8.2. RemoveTags()

Bu işlev, çok sayıda RSS belgesinin XML düğümleri içinde HTML etiketleri içerdiğini fark ettikten sonra bir zorunluluk haline geldi.

Birçok RSS toplama uygulaması tarayıcıda çalıştığından, bazı RSS belgeleri bu şekilde yayınlanır.

İşlev, bir dize değeri alır ve metin içindeki etiketleri arar. Herhangi bir etiket bulunursa işlev metnin her karakteri arasında döngü yapar ve her açılış ve kapanış etiket karakterinin pozisyonunu 2 boyutlu a[][] dizisinde saklar. Bu dizi, etiketler arasındaki metni çıkarmak için kullanılır ve çıkarılan dize verilir. Etiket bulunamazsa giriş dizesi olduğu gibi verilir.

//+------------------------------------------------------------------+
//| remove tags                                                      |
//+------------------------------------------------------------------+
string CRssReader::removeTags(string _string)
  {
   string now=NULL;
   if(StringFind(_string,"<",0)>-1)
     {
      int v=0,a[][2];
      ArrayResize(a,2024);
      for(int i=0;i<StringLen(_string);i++)
        {
         int t=tagPosition(_string,i);
         if(t>0)
           {
            v++;
            a[v-1][0]=i;
            a[v-1][1]=t;
           }
         else continue;
        }
      ArrayResize(a,v);
      for(int i=0;i<v-1;i++)
        {
         now+=StringSubstr(_string,(a[i][1]+1),(a[i+1][0]-(a[i][1]+1)));
        }
     }
   else
     {
      now=_string;
     }
   return(now);
  }

Böyle bir belgenin kısmi bir örneği aşağıda gösterilmiştir.

<item>            
    <title>GIGABYTE X99-Gaming G1 WIFI Motherboard Review</title>
    <author>Ian Cutress</author>
    <description><![CDATA[ <p>The gaming motherboard range from a manufacturer is one with a lot of focus in terms of design and function due to the increase in gaming related PC sales. On the Haswell-E side of gaming, GIGABYTE is putting forward the X99-Gaming G1 WIFI at the top of its stack, and this is what we are reviewing today.&nbsp;</p>
<p align="center"><a href='http://dynamic1.anandtech.com/www/delivery/ck.php?n=a1f2f01f&amp;cb=582254849' target='_blank'><img src='http://dynamic1.anandtech.com/www/delivery/avw.php?zoneid=24&amp;cb=582254849&amp;n=a1f2f01f' border='0' alt='' /></a><img src="http://toptenreviews.122.2o7.net/b/ss/tmn-test/1/H.27.3--NS/0" height="1" width="1" border="0" alt="" /></p>]]></description>
    <link>http://www.anandtech.com/show/8788/gigabyte-x99-gaming-g1-wifi-motherboard-review</link>
        <pubDate>Thu, 18 Dec 2014 10:00:00 EDT</pubDate>
        <guid isPermaLink="false">tag:www.anandtech.com,8788:news</guid>
        <category><![CDATA[ Motherboards]]></category>                               
</item>  


2.8.3. removeSpecialCharacters()

Bu işlev, belirli dize sabitlerini doğru karakterle değiştirir.

Örneğin ampersan karakteri bazı xml belgelerinde "&" olarak gösterilebilir. Bu işlev, bu tür olayları değiştirmek için yerleşik StringReplace() işlevini kullanır.

//+------------------------------------------------------------------+
//| remove special characters                                        |
//+------------------------------------------------------------------+ 
string CRssReader::removeSpecialCharacters(string s_tring)
  {
   string n=s_tring;
   StringReplace(n,"&amp;","&");
   StringReplace(n,"&#39;","'");
   StringReplace(n,"&nbsp;"," ");
   StringReplace(n,"&ldquo;","\'");
   StringReplace(n,"&rdquo;","\'");
   StringReplace(n,"&quot;","\"");
   StringReplace(n,"&ndash;","-");
   StringReplace(n,"&rsquo;","'");
   StringReplace(n,"&gt;","");
   return(n);
  }


2.8.4. tagPosition()

Bu, removeTags() işlevinde çağrılan bir yardımcı işlevdir. Girdi olarak bir dize ve bir tamsayı değeri alır.

Girilen tamsayı değeri, dizedeki bir karakterin pozisyonunu temsil eder, işlev buradan bir açılış etiketi karakteri aramaya başlayacaktır, yani "<". Bir açılış etiketi bulunursa, işlev bir kapanış etiketi aramaya başlar ve ilgili kapanış etiketi karakterinin ">" konumunu çıktı olarak verir. Bulunan etiket yoksa, işlev -1 değerini verir.

//+------------------------------------------------------------------+
//| tag positions                                                    |
//+------------------------------------------------------------------+
int CRssReader::tagPosition(string _string,int w)
  {
   int iClose=-1;
   if(StringCompare("<",StringSubstr(_string,w,StringLen("<")))==0)
     {
      iClose=StringFind(_string,">",w+StringLen("<"));
     }

   return(iClose);
  }


2.9. Bağımsız kontrollerin olaylarını işleme yöntemleri

Bu işlevler, belirli bir denetimin yakalanan olaylarını işler.

//--- handlers of the dependent controls events
   void              OnChangeListView(void);
   void              OnObjectEdit(void);
   void              OnClickButton1(void);
   void              OnClickButton2(void);
  };

2.9.1. OnChangeListView()

Bu bir olay işleyici işlevidir ve uygulamanın liste görünümü alanı bölümündeki liste öğelerinden biri tıklandığında çağrılır.

İşlev, RSS belgesinde atıfta bulunulan bazı içerikler için açıklama özetinin görüntülenmesini sağlamaktan sorumludur.

İşlev, herhangi bir metnin metin alanı ve başlık alanı bölümlerini temizler, belge ağacından yeni verileri alır ve çıktı için hazırlar. Tüm bunlar yalnızca ChannelChildnodes dizisi boş değilse gerçekleşir.

//+------------------------------------------------------------------+
//| Event handler                                                    |
//+------------------------------------------------------------------+
void CRssReader::OnChangeListView(void)
  {
   int a=0,k=0,l=0;
   a=m_listview.Current()+m_shift;
   if(ArraySize(ChannelChildNodes)>a)
     {
      if(m_titleview.ItemsClear())
        {
         if(!FormatString(getTitle(ChannelChildNodes[a]),m_titleareaoutput,55))
           {
            return;
           }
         else
         if(ArraySize(m_titleareaoutput)>0)
           {
            for(l=0;l<ArraySize(m_titleareaoutput);l++)
              {
               m_titleview.AddItem(removeSpecialCharacters(m_titleareaoutput[l]));
              }
           }
        }
      if(m_textview.ItemsClear())
        {
         if(!FormatString(getDescription(ChannelChildNodes[a]),m_textareaoutput,35))
            return;
         else
         if(ArraySize(m_textareaoutput)>0)
           {
            for(k=0;k<ArraySize(m_textareaoutput);k++)
              {
               m_textview.AddItem(m_textareaoutput[k]);
              }
            m_textview.AddItem(" ");
            m_textview.AddItem("Date|"+getDate(ChannelChildNodes[a]));
           }
         else return;
        }
     }
  }


2.9.2. OnObjectEdit()

İşleyici işlevi, bir kullanıcı giriş alanına bir metin girmeyi bitirdiğinde çağrılır.

İşlev, LoadDocument() yöntemini çağırır. İndirme başarılı olursa metin tüm uygulamadan temizlenir. Ardından, başlık değiştirilir ve yeni içerik liste görünümü alanı bölümüne gönderilir.

//+------------------------------------------------------------------+
//| Event handler                                                    |
//+------------------------------------------------------------------+
void CRssReader::OnObjectEdit(void)
  {
   string f=m_edit.Text();
   if(StringLen(f)>0)
     {
      if(ArraySize(ChannelChildNodes)<1)
        {
         CDialog::Caption("Loading...");
         if(LoadDocument(f))
           {
            if(!CDialog::Caption(removeSpecialCharacters(getChannelTitle())))
               Print("error changing caption");
            if(m_textview.ItemsClear() && m_listview.ItemsClear() && m_titleview.ItemsClear())
              {
               for(int i=0;i<ItemNodesTotal()-1;i++)
                 {
                  if(!m_listview.AddItem(removeSpecialCharacters(IntegerToString(i+1)+"."+getTitle(ChannelChildNodes[i+m_shift]))))
                    {
                     Print("can not add item to listview area");
                     return;
                    }
                 }
              }
            else
              {
               Print("text area/listview area not cleared");
               return;
              }
           }
         else return;
        }
      else
        {
         FreeDocumentTree();
         CDialog::Caption("Loading new RSS Feed...");
         if(LoadDocument(f))
           {
            if(!CDialog::Caption(removeSpecialCharacters(getChannelTitle())))
               Print("error changing caption");
            if(m_textview.ItemsClear() && m_listview.ItemsClear() && m_titleview.ItemsClear())
              {
               for(int i=0;i<ItemNodesTotal()-1;i++)
                 {
                  if(!m_listview.AddItem(removeSpecialCharacters(IntegerToString(i+1)+"."+getTitle(ChannelChildNodes[i+m_shift]))))
                    {
                     Print("can not add item to listview area");
                     return;
                    }
                 }
              }
            else
              {
               Print("text area/listview area not cleared");
               return;
              }
           }
         else return;
        }
     }
   else return;
  }


2.9.3. OnClickButton1/2()

Bu işleyiciler, bir kullanıcı sıfırlamayı veya besleme güncellemelerini kontrol et düğmelerini tıkladığında çağrılır.

Sıfırlama düğmesine tıklamak, uygulama diyaloğunu Expert advisor ilk başlatıldığı zamanki durumuna yeniler.

"Besleme güncellemesini kontrol et" düğmesinin tıklanması LoadDocument() yükleme yönteminin geri çağrılmasına neden olur ve RSS besleme verileri indirilerek liste görünümü alanı bölümü yenilenir.

//+------------------------------------------------------------------+
//| Event handler  refresh the app dialogue                          |
//+------------------------------------------------------------------+   
void CRssReader::OnClickButton1(void)
  {
   if(ArraySize(ChannelChildNodes)<1)
     {
      if(!m_edit.Text("Enter the web address of an Rss feed"))
         Print("error changing edit text");
      if(!CDialog::Caption("RSSReader"))
         Print("error changing caption");
      if(m_textview.ItemsClear() && m_listview.ItemsClear() && m_titleview.ItemsClear())
        {
         for(int i=0;i<20;i++)
           {
            if(!m_listview.AddItem(" "))
               Print("error adding to listview");
           }
         m_listview.VScrolled(true);
         for(int i=0;i<1;i++)
           {
            m_textview.AddItem(" ");
           }
         m_textview.VScrolled(true);
         for(int i=0;i<2;i++)
           {
            m_titleview.AddItem(" ");
           }
         return;
        }
     }
   else
     {
      FreeDocumentTree();
      if(!m_edit.Text("Enter the web address of an Rss feed"))
         Print("error changing edit text");
      if(!CDialog::Caption("RSSReader"))
         Print("error changing caption");
      if(m_textview.ItemsClear() && m_listview.ItemsClear() && m_titleview.ItemsClear())
        {
         for(int i=0;i<20;i++)
           {
            if(!m_listview.AddItem(" "))
               Print("error adding to listview");
           }
         m_listview.VScrolled(true);
         for(int i=0;i<1;i++)
           {
            m_textview.AddItem(" ");
           }
         m_textview.VScrolled(true);
         for(int i=0;i<2;i++)
           {
            m_titleview.AddItem(" ");
           }
         return;
        }
     }
  }
//+------------------------------------------------------------------+
//| Event handler  update current feed                               |
//+------------------------------------------------------------------+ 
void CRssReader::OnClickButton2(void)
  {
   string f=m_rssurl;
   if(ArraySize(ChannelChildNodes)<1)
      return;
   else
     {
      FreeDocumentTree();
      CDialog::Caption("Checking for RSS Feed update...");
      if(LoadDocument(f))
        {
         if(!CDialog::Caption(removeSpecialCharacters(getChannelTitle())))
            Print("error changing caption");
         if(m_textview.ItemsClear() && m_listview.ItemsClear() && m_titleview.ItemsClear())
           {
            for(int i=0;i<ItemNodesTotal()-1;i++)
              {
               if(!m_listview.AddItem(removeSpecialCharacters(IntegerToString(i+1)+"."+getTitle(ChannelChildNodes[i+m_shift]))))
                 {
                  Print("can not add item to listview area");
                  return;
                 }
              }
           }
         else
           {
            Print("text area/listview area not cleared");
            return;
           }
        }
      else return;
     }
  }

Bu, CRssReader sınıfının tanımını tamamlar.


2.10. CRssReader sınıfı uygulaması

//+------------------------------------------------------------------+
//| Class CRssReader                                                 |
//| Usage: main class for the RSS application                        |
//+------------------------------------------------------------------+
class CRssReader : public CAppDialog
  {
private:
   int               m_shift;                   // index of first item tag
   string            m_rssurl;                  // copy of web address of last feed 
   string            m_textareaoutput[];        // array of strings prepared for output to the text area panel
   string            m_titleareaoutput[];       // array of strings prepared for output to title area panel
   CButton           m_button1;                 // the button object
   CButton           m_button2;                 // the button object      
   CEdit             m_edit;                    // input panel
   CTitleArea        m_titleview;               // the display field object
   CListViewArea     m_listview;                // the list object
   CTextArea         m_textview;                // text area object
   CEasyXml          m_xmldocument;             // xml document object
   CEasyXmlNode     *RssNode;                   // root node object
   CEasyXmlNode     *ChannelNode;               // channel node object
   CEasyXmlNode     *ChannelChildNodes[];       // array of channel child node objects

public:
                     CRssReader(void);
                    ~CRssReader(void);
   //--- create
   virtual bool      Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2);
   //--- chart event handler
   virtual bool      OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);

protected:
   // --- creating controls
   bool              CreateEdit(void);
   bool              CreateButton1(void);
   bool              CreateButton2(void);
   bool              CreateTitleView(void);
   bool              CreateListView(void);
   bool              CreateTextView(void);
   // --- rss document processing
   bool              LoadDocument(string filename);
   int               ItemNodesTotal(void);
   void              FreeDocumentTree(void);
   //--- getters
   string            getChannelTitle(void);
   string            getTitle(CEasyXmlNode *Node);
   string            getDescription(CEasyXmlNode *Node);
   string            getDate(CEasyXmlNode *Node);
   //--- text formating 
   bool              FormatString(string v,string &array[],int n);
   string            removeTags(string _string);
   string            removeSpecialCharacters(string s_tring);
   int               tagPosition(string _string,int w);
   //--- handlers of the dependent controls events
   void              OnChangeListView(void);
   void              OnObjectEdit(void);
   void              OnClickButton1(void);
   void              OnClickButton2(void);
  };
//+------------------------------------------------------------------+
//| Event Handling                                                   |
//+------------------------------------------------------------------+
EVENT_MAP_BEGIN(CRssReader)
ON_EVENT(ON_CHANGE,m_listview,OnChangeListView)
ON_EVENT(ON_END_EDIT,m_edit,OnObjectEdit)
ON_EVENT(ON_CLICK,m_button1,OnClickButton1)
ON_EVENT(ON_CLICK,m_button2,OnClickButton2)
EVENT_MAP_END(CAppDialog)
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CRssReader::CRssReader(void)
  {

  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CRssReader::~CRssReader(void)
  {
  }
//+------------------------------------------------------------------+
//| Create                                                           |
//+------------------------------------------------------------------+
bool CRssReader::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
  {
   if(!CAppDialog::Create(chart,name,subwin,x1,y1,x2,y2))
      return(false);
//--- create dependent controls
   if(!CreateEdit())
      return(false);
   if(!CreateButton1())
      return(false);
   if(!CreateButton2())
      return(false);
   if(!CreateTitleView())
      return(false);
   if(!CreateListView())
      return(false);
   if(!CreateTextView())
      return(false);
//--- succeed
   return(true);
  }
//+------------------------------------------------------------------+
//| Create the display field                                         |
//+------------------------------------------------------------------+
bool CRssReader::CreateEdit(void)
  {
//--- coordinates
   int x1=INDENT_LEFT;
   int y1=INDENT_TOP;
   int x2=ClientAreaWidth()-INDENT_RIGHT;
   int y2=y1+EDIT_HEIGHT;
//--- create
   if(!m_edit.Create(m_chart_id,m_name+"Edit",m_subwin,x1,y1,x2,y2))
      return(false);
   if(!m_edit.Text("Please enter the web address of an Rss feed"))
      return(false);
   if(!m_edit.ReadOnly(false))
      return(false);
   if(!Add(m_edit))
      return(false);
//--- succeed
   return(true);
  }
//+------------------------------------------------------------------+
//| Create button 1                                                  |
//+------------------------------------------------------------------+ 
bool CRssReader::CreateButton1(void)
  {
//--- coordinates
   int x1=INDENT_LEFT;
   int y1=INDENT_TOP+(EDIT_HEIGHT+CONTROLS_GAP_Y);
   int x2=x1+BUTTON_WIDTH;
   int y2=y1+BUTTON_HEIGHT;
//--- create
   if(!m_button1.Create(m_chart_id,m_name+"Button1",m_subwin,x1,y1,x2,y2))
      return(false);
   if(!m_button1.Text("Reset"))
      return(false);
   if(!m_button1.Font("Comic Sans MS"))
      return(false);
   if(!m_button1.FontSize(8))
      return(false);
   if(!m_button1.Color(clrWhite))
      return(false);
   if(!m_button1.ColorBackground(clrBlack))
      return(false);
   if(!m_button1.ColorBorder(clrBlack))
      return(false);
   if(!m_button1.Pressed(true))
      return(false);
   if(!Add(m_button1))
      return(false);
//--- succeed
   return(true);
  }
//+------------------------------------------------------------------+
//| Create button 2                                                  |
//+------------------------------------------------------------------+ 
bool CRssReader::CreateButton2(void)
  {
//--- coordinates
   int x1=(ClientAreaWidth()-INDENT_RIGHT)-BUTTON_WIDTH;
   int y1=INDENT_TOP+(EDIT_HEIGHT+CONTROLS_GAP_Y);
   int x2=ClientAreaWidth()-INDENT_RIGHT;
   int y2=y1+BUTTON_HEIGHT;
//--- create
   if(!m_button2.Create(m_chart_id,m_name+"Button2",m_subwin,x1,y1,x2,y2))
      return(false);
   if(!m_button2.Text("Update current feed"))
      return(false);
   if(!m_button2.Font("Comic Sans MS"))
      return(false);
   if(!m_button2.FontSize(8))
      return(false);
   if(!m_button2.Color(clrWhite))
      return(false);
   if(!m_button2.ColorBackground(clrBlack))
      return(false);
   if(!m_button2.ColorBorder(clrBlack))
      return(false);
   if(!m_button2.Pressed(true))
      return(false);
   if(!Add(m_button2))
      return(false);
//--- succeed
   return(true);
  }
//+------------------------------------------------------------------+
//| Create the display field                                         |
//+------------------------------------------------------------------+
bool CRssReader::CreateTitleView(void)
  {
//--- coordinates
   int x1=INDENT_LEFT;
   int y1=INDENT_TOP+(EDIT_HEIGHT+CONTROLS_GAP_Y)+BUTTON_HEIGHT+CONTROLS_GAP_Y;
   int x2=ClientAreaWidth()-INDENT_RIGHT;
   int y2=y1+(EDIT_HEIGHT*2);
   m_titleview.Current();
//--- create 
   if(!m_titleview.Create(m_chart_id,m_name+"TitleView",m_subwin,x1,y1,x2,y2))
     {
      Print("error creating title view");
      return(false);
     }
   else
     {
      for(int i=0;i<2;i++)
        {
         m_titleview.AddItem(" ");
        }
     }
   if(!Add(m_titleview))
     {
      Print("error adding title view");
      return(false);
     }
//--- succeed
   return(true);
  }
//+------------------------------------------------------------------+
//| Create the "ListView" element                                    |
//+------------------------------------------------------------------+
bool CRssReader::CreateListView(void)
  {

//--- coordinates
   int x1=INDENT_LEFT;
   int y1=INDENT_TOP+((EDIT_HEIGHT+CONTROLS_GAP_Y)*2)+20+TEXTAREA_HEIGHT+CONTROLS_GAP_Y+BUTTON_HEIGHT+CONTROLS_GAP_Y;
   int x2=ClientAreaWidth()-INDENT_RIGHT;
   int y2=y1+LIST_HEIGHT;
//--- create
   if(!m_listview.Create(m_chart_id,m_name+"ListView",m_subwin,x1,y1,x2,y2))
      return(false);
   if(!Add(m_listview))
      return(false);
//--- fill out with strings
   for(int i=0;i<20;i++)
      if(!m_listview.AddItem(" "))
         return(false);
//--- succeed
   return(true);
  }
//+------------------------------------------------------------------+
//| Create the display field                                         |
//+------------------------------------------------------------------+
bool CRssReader::CreateTextView(void)
  {
//--- coordinates
   int x1=INDENT_LEFT;
   int y1=INDENT_TOP+((EDIT_HEIGHT+CONTROLS_GAP_Y)*2)+20+BUTTON_HEIGHT+CONTROLS_GAP_Y;
   int x2=ClientAreaWidth()-INDENT_RIGHT;
   int y2=y1+TEXTAREA_HEIGHT;
   m_textview.Current();
//--- create 
   if(!m_textview.Create(m_chart_id,m_name+"TextArea",m_subwin,x1,y1,x2,y2))
     {
      Print("error creating text area view");
      return(false);
     }
   else
     {
      for(int i=0;i<1;i++)
        {
         m_textview.AddItem(" ");
        }
      m_textview.VScrolled(true);
      ChartRedraw();
     }
   if(!Add(m_textview))
     {
      Print("error adding text area view");
      return(false);
     }
//----success      
   return(true);
  }
//+------------------------------------------------------------------+
//|   load document                                                  |
//+------------------------------------------------------------------+
bool CRssReader::LoadDocument(string filename)
  {
   if(!m_xmldocument.loadXmlFromUrlWebReq(filename))
     {
      m_textview.ItemsClear();
      m_listview.ItemsClear();
      m_titleview.ItemsClear();
      CDialog::Caption("Failed to load Feed");
      if(!m_textview.AddItem(m_xmldocument.GetErrorMsg()))
         Print("error displaying error message");
      return(false);
     }
   else
     {
      m_rssurl=filename;
      RssNode=m_xmldocument.getDocumentRoot();
      ChannelNode=RssNode.FirstChild();
      if(CheckPointer(RssNode)==POINTER_INVALID || CheckPointer(ChannelNode)==POINTER_INVALID)
         return(false);
     }
   ArrayResize(ChannelChildNodes,ChannelNode.Children().Total());
   for(int i=0;i<ChannelNode.Children().Total();i++)
     {
      ChannelChildNodes[i]=ChannelNode.Children().At(i);
     }
   m_shift=ChannelNode.Children().Total()-ItemNodesTotal();
   return(true);
  }
//+------------------------------------------------------------------+
//| function counts the number of item tags in document              |
//+------------------------------------------------------------------+
int CRssReader::ItemNodesTotal(void)
  {
   int t=0;
   for(int i=0;i<ChannelNode.Children().Total();i++)
     {
      if(ChannelChildNodes[i].getName()=="item")
        {
         t++;
        }
      else continue;
     }
   return(t);
  }
//+------------------------------------------------------------------+
//| free document tree and reset pointer values                      |
//+------------------------------------------------------------------+ 
void CRssReader::FreeDocumentTree(void)
  {
   ChannelNode.Children().Shutdown();
   ArrayFree(ChannelChildNodes);
   RssNode.Children().Shutdown();
   m_xmldocument.Clear();
   m_shift=0;
   RssNode=NULL;
   ChannelNode=NULL;
  }
//+------------------------------------------------------------------+
//| get channel title                                                |
//+------------------------------------------------------------------+
string CRssReader::getChannelTitle(void)
  {
   string ret=NULL;
   if(!CheckPointer(ChannelNode)==POINTER_INVALID)
     {
      for(int i=0;i<m_shift;i++)
        {
         if(ChannelChildNodes[i].getName()=="title")
           {
            ret=ChannelChildNodes[i].getValue();
            break;
           }
         else continue;
        }
     }
//---return value
   return(ret);
  }
//+------------------------------------------------------------------+
//| display title                                                    |
//+------------------------------------------------------------------+
string CRssReader::getTitle(CEasyXmlNode *Node)
  {
   int k=Node.Children().Total();
   string n=NULL;
   for(int i=0;i<k;i++)
     {
      CEasyXmlNode*subNode=Node.Children().At(i);
      if(subNode.getName()=="title")
        {
         n=subNode.getValue();
         break;
        }
      else continue;
     }
   return(n);
  }
//+------------------------------------------------------------------+
//| display description                                              |
//+------------------------------------------------------------------+
string CRssReader::getDescription(CEasyXmlNode *Node)
  {
   int k=Node.Children().Total();
   string n=NULL;
   for(int i=0;i<k;i++)
     {
      CEasyXmlNode*subNode=Node.Children().At(i);
      if(subNode.getName()=="description")
        {
         n=subNode.getValue();
         break;
        }
      else continue;
     }
   return(n);
  }
//+------------------------------------------------------------------+
//| display date                                                     |
//+------------------------------------------------------------------+ 
string CRssReader::getDate(CEasyXmlNode *Node)
  {
   int k=Node.Children().Total();
   string n=NULL;
   for(int i=0;i<k;i++)
     {
      CEasyXmlNode*subNode=Node.Children().At(i);
      if(subNode.getName()=="pubDate")
        {
         n=subNode.getValue();
         break;
        }
      else continue;
     }
   return(n);
  }
//+------------------------------------------------------------------+
//| format string for output to text area panel                      |
//+------------------------------------------------------------------+
bool CRssReader::FormatString(string v,string &array[],int n)
  {
   ushort ch[],space,fullstop,comma,semicolon,newlinefeed;
   string _s,_k;
   space=StringGetCharacter(" ",0);
   fullstop=StringGetCharacter(".",0);
   comma=StringGetCharacter(",",0);
   semicolon=StringGetCharacter(";",0);
   newlinefeed=StringGetCharacter("\n",0);
   _k=removeTags(v);
   _s=removeSpecialCharacters(_k);
   int p=StringLen(_s);
   ArrayResize(ch,p+1);
   int d=StringToShortArray(_s,ch,0,-1);
   for(int i=1;i<d;i++)
     {
      int t=i%n;
      if(!t== 0)continue;
      else 
        {
         if(ch[(i/n)*n]==fullstop || ch[(i/n)*n]==semicolon || ch[(i/n)*n]==comma)
           {
            ArrayFill(ch,((i/n)*n)+1,1,newlinefeed);
           }
         else
           {
            for(int k=i;k>=0;k--)
              {
               if(ch[k]==space)
                 {
                  ArrayFill(ch,k,1,newlinefeed);
                  break;
                 }
               else continue;
              }
           }
        }
     }
   _s=ShortArrayToString(ch,0,-1);
   int s=StringSplit(_s,newlinefeed,array);
   if(!s>0)
     {return(false);}
// success 
   return(true);
  }
//+------------------------------------------------------------------+
//| remove special characters                                        |
//+------------------------------------------------------------------+ 
string CRssReader::removeSpecialCharacters(string s_tring)
  {
   string n=s_tring;
   StringReplace(n,"&amp;","&");
   StringReplace(n,"&#39;","'");
   StringReplace(n,"&nbsp;"," ");
   StringReplace(n,"&ldquo;","\'");
   StringReplace(n,"&rdquo;","\'");
   StringReplace(n,"&quot;","\"");
   StringReplace(n,"&ndash;","-");
   StringReplace(n,"&rsquo;","'");
   StringReplace(n,"&gt;","");
   return(n);
  }
//+------------------------------------------------------------------+
//| remove tags                                                      |
//+------------------------------------------------------------------+
string CRssReader::removeTags(string _string)
  {
   string now=NULL;
   if(StringFind(_string,"<",0)>-1)
     {
      int v=0,a[][2];
      ArrayResize(a,2024);
      for(int i=0;i<StringLen(_string);i++)
        {
         int t=tagPosition(_string,i);
         if(t>0)
           {
            v++;
            a[v-1][0]=i;
            a[v-1][1]=t;
           }
         else continue;
        }
      ArrayResize(a,v);
      for(int i=0;i<v-1;i++)
        {
         now+=StringSubstr(_string,(a[i][1]+1),(a[i+1][0]-(a[i][1]+1)));
        }
     }
   else
     {
      now=_string;
     }
   return(now);
  }
//+------------------------------------------------------------------+
//| tag positions                                                    |
//+------------------------------------------------------------------+
int CRssReader::tagPosition(string _string,int w)
  {
   int iClose=-1;
   if(StringCompare("<",StringSubstr(_string,w,StringLen("<")))==0)
     {
      iClose=StringFind(_string,">",w+StringLen("<"));
     }

   return(iClose);
  }
//+------------------------------------------------------------------+
//| Event handler                                                    |
//+------------------------------------------------------------------+
void CRssReader::OnChangeListView(void)
  {
   int a=0,k=0,l=0;
   a=m_listview.Current()+m_shift;
   if(ArraySize(ChannelChildNodes)>a)
     {
      if(m_titleview.ItemsClear())
        {
         if(!FormatString(getTitle(ChannelChildNodes[a]),m_titleareaoutput,55))
           {
            return;
           }
         else
         if(ArraySize(m_titleareaoutput)>0)
           {
            for(l=0;l<ArraySize(m_titleareaoutput);l++)
              {
               m_titleview.AddItem(removeSpecialCharacters(m_titleareaoutput[l]));
              }
           }
        }
      if(m_textview.ItemsClear())
        {
         if(!FormatString(getDescription(ChannelChildNodes[a]),m_textareaoutput,35))
            return;
         else
         if(ArraySize(m_textareaoutput)>0)
           {
            for(k=0;k<ArraySize(m_textareaoutput);k++)
              {
               m_textview.AddItem(m_textareaoutput[k]);
              }
            m_textview.AddItem(" ");
            m_textview.AddItem("Date|"+getDate(ChannelChildNodes[a]));
           }
         else return;
        }
     }
  }
//+------------------------------------------------------------------+
//| Event handler                                                    |
//+------------------------------------------------------------------+
void CRssReader::OnObjectEdit(void)
  {
   string f=m_edit.Text();
   if(StringLen(f)>0)
     {
      if(ArraySize(ChannelChildNodes)<1)
        {
         CDialog::Caption("Loading...");
         if(LoadDocument(f))
           {
            if(!CDialog::Caption(removeSpecialCharacters(getChannelTitle())))
               Print("error changing caption");
            if(m_textview.ItemsClear() && m_listview.ItemsClear() && m_titleview.ItemsClear())
              {
               for(int i=0;i<ItemNodesTotal()-1;i++)
                 {
                  if(!m_listview.AddItem(removeSpecialCharacters(IntegerToString(i+1)+"."+getTitle(ChannelChildNodes[i+m_shift]))))
                    {
                     Print("can not add item to listview area");
                     return;
                    }
                 }
              }
            else
              {
               Print("text area/listview area not cleared");
               return;
              }
           }
         else return;
        }
      else
        {
         FreeDocumentTree();
         CDialog::Caption("Loading new RSS Feed...");
         if(LoadDocument(f))
           {
            if(!CDialog::Caption(removeSpecialCharacters(getChannelTitle())))
               Print("error changing caption");
            if(m_textview.ItemsClear() && m_listview.ItemsClear() && m_titleview.ItemsClear())
              {
               for(int i=0;i<ItemNodesTotal()-1;i++)
                 {
                  if(!m_listview.AddItem(removeSpecialCharacters(IntegerToString(i+1)+"."+getTitle(ChannelChildNodes[i+m_shift]))))
                    {
                     Print("can not add item to listview area");
                     return;
                    }
                 }
              }
            else
              {
               Print("text area/listview area not cleared");
               return;
              }
           }
         else return;
        }
     }
   else return;
  }
//+------------------------------------------------------------------+
//| Event handler  refresh the app dialogue                          |
//+------------------------------------------------------------------+   
void CRssReader::OnClickButton1(void)
  {
   if(ArraySize(ChannelChildNodes)<1)
     {
      if(!m_edit.Text("Enter the web address of an Rss feed"))
         Print("error changing edit text");
      if(!CDialog::Caption("RSSReader"))
         Print("error changing caption");
      if(m_textview.ItemsClear() && m_listview.ItemsClear() && m_titleview.ItemsClear())
        {
         for(int i=0;i<20;i++)
           {
            if(!m_listview.AddItem(" "))
               Print("error adding to listview");
           }
         m_listview.VScrolled(true);
         for(int i=0;i<1;i++)
           {
            m_textview.AddItem(" ");
           }
         m_textview.VScrolled(true);
         for(int i=0;i<2;i++)
           {
            m_titleview.AddItem(" ");
           }
         return;
        }
     }
   else
     {
      FreeDocumentTree();
      if(!m_edit.Text("Enter the web address of an Rss feed"))
         Print("error changing edit text");
      if(!CDialog::Caption("RSSReader"))
         Print("error changing caption");
      if(m_textview.ItemsClear() && m_listview.ItemsClear() && m_titleview.ItemsClear())
        {
         for(int i=0;i<20;i++)
           {
            if(!m_listview.AddItem(" "))
               Print("error adding to listview");
           }
         m_listview.VScrolled(true);
         for(int i=0;i<1;i++)
           {
            m_textview.AddItem(" ");
           }
         m_textview.VScrolled(true);
         for(int i=0;i<2;i++)
           {
            m_titleview.AddItem(" ");
           }
         return;
        }
     }
  }
//+------------------------------------------------------------------+
//| Event handler  update current feed                               |
//+------------------------------------------------------------------+ 
void CRssReader::OnClickButton2(void)
  {
   string f=m_rssurl;
   if(ArraySize(ChannelChildNodes)<1)
      return;
   else
     {
      FreeDocumentTree();
      CDialog::Caption("Checking for RSS Feed update...");
      if(LoadDocument(f))
        {
         if(!CDialog::Caption(removeSpecialCharacters(getChannelTitle())))
            Print("error changing caption");
         if(m_textview.ItemsClear() && m_listview.ItemsClear() && m_titleview.ItemsClear())
           {
            for(int i=0;i<ItemNodesTotal()-1;i++)
              {
               if(!m_listview.AddItem(removeSpecialCharacters(IntegerToString(i+1)+"."+getTitle(ChannelChildNodes[i+m_shift]))))
                 {
                  Print("can not add item to listview area");
                  return;
                 }
              }
           }
         else
           {
            Print("text area/listview area not cleared");
            return;
           }
        }
      else return;
     }
  }

Artık Expert Advisor kodunda kullanılabilir.


2.11. Expert Advisor kodu

Uygulamanın tamamen etkileşimli olması amaçlandığından, Expert Advisor'ın girdi değişkenleri yoktur.

İlk önce CRssReader sınıfının bir örneği olan global bir değişken tanımlıyoruz. OnInit() işlevinde, ana Create() yöntemine yapılan bir çağrıyla uygulama diyaloğunu başlatıyoruz. Bu başarılı olursa bir üst sınıfın Run() yöntemi çağrılır.

OnDeinit() işlevinde, tüm uygulamayı silmek ve Expert Advisor'ı grafikten kaldırmak için üst sınıfın Destroy() yöntemi çağrılır.

OnChartEvent() işlevi, tüm olayların işlenmesini gerçekleştirecek olan CRssReader sınıfının bir üst yöntemine yapılan çağrıyı içerir.

//Expert Advisor code begins here
//+------------------------------------------------------------------+
//| Global Variables                                                 |
//+------------------------------------------------------------------+
CRssReader ExtDialog;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- create application dialog
   if(!ExtDialog.Create(0,"RSSReader",0,20,20,518,394))
      return(INIT_FAILED);
//--- run application
   ExtDialog.Run();
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   ExtDialog.Destroy(reason);
  }
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//---
   ExtDialog.ChartEvent(id,lparam,dparam,sparam);
  }

Ardından kodun derlenmesi gerekir ve program kullanıma hazır hale gelir.

RssReader.mq5 Expert Advisor bir grafiğe yüklendiğinde aşağıdaki gibi boş bir uygulama diyaloğu görünür:

Şek. 2. RssReader Expert Advisor'ın boş uygulama diyaloğunun ekran görüntüsü

Şek. 2. RssReader Expert Advisor'ın boş uygulama diyaloğunun ekran görüntüsü

Bir web adresi girin ve RSS içeriği aşağıdaki resimde gösterildiği gibi uygulama iletişim kutusuna yüklenecektir:

Şek. 3. Terminalde çalışan RssReader EA

Şek. 3. Terminalde çalışan RssReader EA

Programı çok çeşitli RSS beslemeleriyle test ettim. Gözlemlediğim tek sorun, çoğunlukla HTML belgelerinde bulunan karakterleri içeren RSS belgelerinin sonucu olan bazı istenmeyen karakterlerin görüntülenmesiyle ilgiliydi.

Ayrıca, uygulama çalışırken bir grafiğin dönemini değiştirmenin, EA'nın yeniden başlatılmasına neden olduğunu ve uygulama kontrollerinin düzgün çizilmemesine neden olabileceğini fark ettim.

Bu davranışı düzeltemedim, bu yüzden tavsiyem RSS Okuyucu programı çalışırken grafik dönemini değiştirmekten kaçınmanız.


Sonuç

nesne yönelimli programlama tekniklerini kullanarak MetaTrader 5 için tamamen etkileşimli bir RSS Okuyucu uygulamasının oluşturulmasını tamamladık.

Uygulamaya eklenebilecek çok daha fazla özellik var ve kullanıcı arayüzünün düzenlenebileceği daha birçok yol olduğuna eminim. Muhtemelen daha iyi uygulama GUI tasarım becerilerine sahip olanların uygulamayı geliştireceklerini ve yarattıklarını paylaşacaklarını umuyorum.

Not: Lütfen buradan indirebileceğiniz easyxml.mqh dosyasının Kod Tabanında bulunan dosyayla aynı olmadığını, makalede daha önce bahsedilen değişiklikleri içerdiğini unutmayın. Gerekli tüm içerikler RssReader.zip dosyasındadır.


MetaQuotes Ltd tarafından İngilizceden çevrilmiştir.
Orijinal makale: https://www.mql5.com/en/articles/1589

Ekli dosyalar |
easyxml.mqh (25.66 KB)
easyxmlnode.mqh (7.67 KB)
ListViewArea.mqh (19.89 KB)
TextArea.mqh (13.47 KB)
TitleArea.mqh (13.56 KB)
RssReader.mq5 (27.83 KB)
RssReader.zip (20.49 KB)
Fiyat Yönüne ve Hareket Hızına Dayalı Alım Satım Fikirleri Fiyat Yönüne ve Hareket Hızına Dayalı Alım Satım Fikirleri
Makale, fiyatların hareket yönü ve hızlarının analizine dayanan bir fikrin gözden geçirilmesini sağlar. Düşünülmekte olan stratejinin uygulanabilirliğini araştırmak için expert advisor olarak sunulan MQL4 dilinde biçimlendirmesini gerçekleştirdik. Ayrıca makalede verilen bir örneğin kontrolü, incelenmesi ve optimizasyonu ile en iyi parametreleri belirliyoruz.
MQL5 Cookbook: ОСО Talimatları MQL5 Cookbook: ОСО Talimatları
Her bir yatırımcının alım satım faaliyeti, talimatlar arasındaki ilişkiler de dahil olmak üzere çeşitli mekanizmalar ve karşılıklı ilişkiler içerir. Bu makale, OCO talimatlarının işlenmesi için bir çözüm önerir. Standart kitaplık sınıfları kapsamlı bir şekilde dahil edilir ve burada yeni veri türleri oluşturulur.
Piyasadan Ürün Satın Alma İpuçları. Adım Adım Rehber Piyasadan Ürün Satın Alma İpuçları. Adım Adım Rehber
Bu adım adım kılavuz, gerekli bir ürünü daha iyi anlamak ve aramak için ipuçları ve püf noktaları sağlar. Makale, uygun bir ürünü aramanın, istenmeyen ürünleri ayırmanın, ürün verimliliğini ve sizin için gerekliliğini belirlemenin farklı yöntemlerini çözmeye çalışıyor.
Teknik Analiz ve Piyasa Tahmini Yöntemleri Üzerine Teknik Analiz ve Piyasa Tahmini Yöntemleri Üzerine
Makale, görsel düşünme ve "kullanıma hazır" bir pazar görünümü ile birleştirilmiş iyi bilinen bir matematiksel yöntemin yeteneklerini ve potansiyelini göstermektedir. Bir yandan, yaratıcı zihinlerin alım satım paradigmasını yeniden gözden geçirmesini sağlayabildiği için geniş bir kitlenin dikkatini çekmeye hizmet eder. Öte yandan, analiz ve tahmin için çok çeşitli araçlarla ilgili alternatif geliştirmelere ve program kodu uygulamalarına yol açabilir.