
"Yeni Başlayanlar" için MQL: Nesne Sınıfları Nasıl Tasarlanır ve Oluşturulur?
Nesne Yönelimli Programlamaya Giriş (OOP)
"Yeni Başlayanlar"ın soruları: Prosedürel programlama konusunda yalnızca çok muğlak bir anlayışa sahip olarak, OOP'de uzmanlaşmak ve bunu otomatik alım satım stratejileri yazarken kullanmak mümkün müdür? Veya bu iş sıradan bir kullanıcıyı aşıyor mu?
Genel olarak, bir MQL5 Expert Advisor'ı veya göstergesi yazmak için nesne yönelimli programlama dilini nesne yönelimli programlama prensiplerini takip etmeden kullanmak mümkündür. Geliştirmelerinizde yeni teknolojilerin kullanımı zorunlu değildir. En basit olduğunu düşündüğünüz yolu seçin. Ayrıca, OOP'nin daha fazla uygulanması, oluşturduğunuz alım satım robotlarının karlılığını garanti edemez.
Ancak, yeni (nesne yönelimli) bir yaklaşıma geçiş, dış değişikliklere tepki verecek ve piyasa ile senkronize olacak olan Expert Advisor'larına alım satım stratejilerinin daha karmaşık uyarlanabilir matematiksel modellerini uygulamak için yer açar.
OOP'nin dayandığı teknolojilere bir göz atalım:
- Olaylar
- Nesne sınıfları
Olaylar, OOP'nin ana temelidir. Programın tüm mantığı, sürekli gelen olayların işlenmesi üzerine kuruludur. Bunlara uygun tepkiler, nesne sınıflarında tanımlanır ve açıklanır. Diğer bir deyişle, bir sınıf nesnesi, olayların akışını yakalayarak ve işleyerek çalışır.
İkinci temel, sırasıyla "üç sütuna" dayanan nesneler sınıfıdır:
- Kapsülleme - Bir "kara kutu" prensibine dayalı sınıfın korunması: Nesne olaylara tepki verir, ancak gerçek uygulaması bilinmemektedir.
- Devralma - "Üst" sınıfının tüm özelliklerini ve yöntemlerini korurken mevcut olandan yeni bir sınıf oluşturma imkanı.
- Çok Biçimlilik - Devralınan bir yöntemin bir "alt öğe" sınıfındaki uygulamasını değiştirme yeteneği.
Temel kavramlar, en iyi şekilde Expert Advisor kodunda gösterilir.
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() // OnInit event processing { return(0); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) // OnDeInit event processing { } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() // OnTick event processing { } //+------------------------------------------------------------------+ //| Expert Timer function | //+------------------------------------------------------------------+ void OnTimer() // OnTimer event processing { } //+------------------------------------------------------------------+ //| Expert Chart event function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, // OnChartEvent event processing const long &lparam, const double &dparam, const string &sparam) { }
class CNew:public CObject { private: int X,Y; void EditXY(); protected: bool on_event; //events processing flag public: // Class constructor void CNew(); // OnChart event processing method virtual void OnEvent(const int id, const long &lparam, const double &dparam, const string &sparam); };
private: int X,Y; void EditXY();
class CNew: public CObject
// OnChart event processing method virtual void OnEvent(const int id, const long &lparam, const double &dparam, const string &sparam);
Bu yöntemin sanal değiştiricisi, OnEvent işleyicisinin geçersiz kılınabileceği anlamına gelir fakat bu durumda yöntemin adı, üst sınıfınınkiyle aynı kalır.
2. Sınıfları Tasarlama
OOP'nin en önemli avantajlarından biri genişletilebilir olmasıdır; bu, mevcut sistemin herhangi bir değişiklik yapmadan yeni bileşenlerle çalışabileceği anlamına gelir. Bu aşamada yeni bileşenler eklenebilir.
MQL5 için MasterWindows sınıflarının görsel tasarım programını oluşturarak tasarım sürecini göz önünde bulundurun.
2.1. Aşama I: Proje Taslağı
Tasarım süreci, bir kağıda kurşun kalemle çizilmiş bir taslak ile başlar. Bu, programlamadaki en zorlu ve heyecan verici anlardan biridir. Yalnızca program ve kullanıcı (arayüz) arasındaki iletişimi değil, aynı zamanda veri işlemenin düzenlenmesini de dikkate almalıyız. Bu işlem bir günden uzun sürebilir. Arayüzle başlamak en iyisidir; zira (bazı durumlarda, örneğimizde olduğu gibi) bir algoritma yapılandırırken tanımlayıcı hale gelebilir.
Oluşturulan programın iletişiminin düzenlenmesi için, Windows uygulama penceresine benzer bir form kullanacağız (Şekil 1'deki taslağa bakınız). Bu, çizgiler içerir ve bu çizgiler sırayla hücrelerden ve grafik nesnelerinin hücrelerinden oluşur. Ve böylece, daha kavramsal tasarım aşamasında, programın yapısını ve nesnelerin sınıflandırılmasını görmeye başlarız.
Şekil 1. Sınıf oluşturucusunun formu (taslak)
Formda yeterince fazla sayıda satır ve hücre (alan) ile, bunlar yalnızca iki tür grafik nesnesinden oluşturulur: OBJ_EDIT ve OBJ_BUTTON. Böylece programın oluşturduğu görsel görünümü, yapıyı ve temel nesneleri belirlediğimizde, tasarımın taslağının hazır olduğunu ve bir sonraki aşamaya geçme zamanının geldiğini varsayabiliriz.
2.2 Aşama II: Temel Sınıfı Tasarlama
Şimdiye kadar bu tür üç sınıf vardır ve daha sonra daha fazlası eklenebilir (gerekirse):
- CCell sınıfı hücresi,
- CRow sınıf satırı; CCell sınıfının hücrelerinden oluşur,
- CWin sınıf penceresi; CRow sınıfının satırlarından oluşur.
Şimdi doğrudan programlama sınıflarına geçebiliriz, ancak... Henüz çok önemli bir görevi çözmemiz gerekiyor; sınıfların nesneleri arasında veri alışverişi. Bu amaçlar için, MQL5'in dili, olağan değişkenlerin yanı sıra, yeni bir tür - yapı içerir. Elbette tasarımın bu aşamasında bağlantıların tamamını göremiyoruz ve bunları hesaplamak oldukça zor. Bu nedenle, proje ilerledikçe sınıfların ve yapıların açıklamasını kademeli olarak dolduracağız. Ayrıca, OOP'nin prensipleri yalnızca bunu engellemekle kalmaz, aslında tam tersi - teknolojiyi veya programlamayı teşvik eder.
WinCell Yapısı:
struct WinCell { color TextColor; // text color color BGColor; // background color color BGEditColor; // background color while editing ENUM_BASE_CORNER Corner; // anchor corner int H; // cell height int Corn; // displacement direction (1;-1) };
Dinamik dizilerin dizelerini ve nesnelerini içermeyen yapılar basit yapı olarak adlandırılır. Bu tür yapıların değişkenleri, farklı yapılar olsalar dahi birbirlerine serbestçe kopyalanabilir. Yerleşik yapı tam olarak bu türdendir. Etkililiğini daha sonra değerlendireceğiz.
CCell temel sınıfı:
//+------------------------------------------------------------------+ //| CCell base class | //+------------------------------------------------------------------+ class CCell { private: protected: bool on_event; // event processing flag ENUM_OBJECT type; // cell type public: WinCell Property; // cell property string name; // cell name //+---------------------------------------------------------------+ // Class constructor void CCell(); virtual // Draw method void Draw(string m_name, int m_xdelta, int m_ydelta, int m_bsize); virtual // Event processing method void OnEvent(const int id, const long &lparam, const double &dparam, const string &sparam); };
CRow temel sınıfı:
//+------------------------------------------------------------------+ //| CRow base class | //+------------------------------------------------------------------+ class CRow { protected: bool on_event; // event processing flag public: string name; // row name WinCell Property; // row property //+---------------------------------------------------------------+ // Class constructor void CRow(); virtual // Draw method void Draw(string m_name, int m_xdelta, int m_ydelta, int m_bsize); virtual // Event processing method void OnEvent(const int id, const long &lparam, const double &dparam, const string &sparam); };
CWin temel sınıfı:
//+------------------------------------------------------------------+ //| Base CWin class (WINDOW) | //+------------------------------------------------------------------+ class CWin { private: void SetXY(int m_corner); //Coordinates protected: bool on_event; // event processing flag public: string name; // window name int w_corner; // window corner int w_xdelta; // vertical delta int w_ydelta; // horizontal detla int w_xpos; // X coordinate int w_ypos; // Y coordinate int w_bsize; // Window width int w_hsize; // Window height int w_h_corner; // hide mode corner WinCell Property; // Property //--- CRowType1 STR1; // CRowType1 CRowType2 STR2; // CRowType2 CRowType3 STR3; // CRowType3 CRowType4 STR4; // CRowType4 CRowType5 STR5; // CRowType5 CRowType6 STR6; // CRowType6 //+---------------------------------------------------------------+ // Class constructor void CWin(); // Set window properties void SetWin(string m_name, int m_xdelta, int m_ydelta, int m_bsize, int m_corner); virtual // Draw window method void Draw(int &MMint[][3], string &MMstr[][3], int count); virtual // OnEventTick handler void OnEventTick(); virtual // OnChart event handler method void OnEvent(const int id, const long &lparam, const double &dparam, const string &sparam); };
Açıklamalar ve öneriler:
- Tüm temel sınıflar (bu projedeki) olayları işleme yöntemlerini içerir. Bunlar, zincir boyunca olayları yakalamak ve iletmek için gereklidir. Olayları almak ve göndermek için bir mekanizma olmadan, program (veya modül) etkileşimini kaybeder.
- Bir temel sınıf geliştirirken, onu minimum sayıda yöntemle oluşturmaya çalışın. Ardından, oluşturulan nesnelerin işlevselliğini artıracak olan "azalan" sınıflarda bu sınıfın çeşitli uzantılarını uygulayın.
- Başka bir sınıfın dahili verilerine doğrudan başvuru kullanmayın!
2.3. Aşama III: Çalışma Projesi
Bu noktada programın adım adım oluşturulmasına başlıyoruz. Destekleyici çerçeveden başlayarak, işlevsel bileşenlerini artıracağız ve içerikle dolduracağız. Bu esnada işin doğruluğunu izleyeceğiz, optimize edilmiş bir kodla hata ayıklama uygulayacağız ve ortaya çıkan hataları takip edeceğiz.
Burada duralım ve hemen hemen her program için çalışacak olan çerçeve oluşturma teknolojisini göz önünde bulunduralım. Bunun için temel gereklilik hemen çalışır durumda olmasıdır (hatasız derleyin ve yürütme sırasında çalıştırın). Dil tasarımcıları bununla ilgilendiler; çerçeve olarak MQL5 Sihirbazı tarafından oluşturulan Expert Advisor şablonunu kullanmanızı tavsiye ediyorlar.
Örnek olarak, bu şablona ait kendi sürümümüzü ele alalım:
1) Program = Expert Advisor
//+------------------------------------------------------------------+ //| MasterWindows.mq5 | //| Copyright DC2008 | //| http://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "DC2008" #property link "http://www.mql5.com" #property version "1.00" //--- include files with classes #include <ClassMasterWindows.mqh> //--- Main module declaration CMasterWindows MasterWin; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- Launch of the main module MasterWin.Run(); return(0); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- Deinitialization of the main module MasterWin.Deinit(); } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- call OnTick event handler of main module MasterWin.OnEventTick(); } //+------------------------------------------------------------------+ //| Expert Event function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //--- call OnChartEvent handler of main module MasterWin.OnEvent(id,lparam,dparam,sparam); }
Bu, Expert Advisor'ın tamamlanmış kodudur. Proje boyunca herhangi bir ek bir değişiklik yapılmasına gerek yoktur!
2) Ana modül = sınıf
Projenin ana ve yardımcı modüllerinin tamamı buradan geliştirilmeye başlayacak. Bu yaklaşım, karmaşık çok modüllü projelerin programlanmasını ve olası hataların aranmasını kolaylaştırır. Ama bunları bulması çok zordur. Bazen bulunması zor "hataları" aramaktansa yeni bir proje yazmak daha kolay ve hızlıdır.
//+------------------------------------------------------------------+ //| ClassMasterWindows.mqh | //| Copyright DC2008 | //| http://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "DC2008" #property link "http://www.mql5.com" //+------------------------------------------------------------------+ //| Main module: CMasterWindows class | //+------------------------------------------------------------------+ class CMasterWindows { protected: bool on_event; // event processing flag public: // Class constructor void CMasterWindows(); // Method of launching the main module (core algorithm) void Run(); // Deinitialization method void Deinit(); // OnTick event processing method void OnEventTick(); // OnChartEvent event processing method void OnEvent(const int id, const long &lparam, const double &dparam, const string &sparam); };
Aşağıda, sınıfın ana yöntemlerinin kabataslak bir başlangıç açıklaması yer almaktadır.
//+------------------------------------------------------------------+ //| CMasterWindows class constructor | //+------------------------------------------------------------------+ void CMasterWindows::CMasterWindows() { //--- class members initialization on_event=false; // disable events processing } //+------------------------------------------------------------------+ //| Метод запуска главного модуля (основной алгоритм) | //+------------------------------------------------------------------+ void CMasterWindows::Run() { //--- Main functional of the class: runs additional modules ObjectsDeleteAll(0,0,-1); Comment("MasterWindows for MQL5 © DC2008"); //--- on_event=true; // enable events processing } //+------------------------------------------------------------------+ //| Deinitialization method | //+------------------------------------------------------------------+ void CMasterWindows::Deinit() { //--- ObjectsDeleteAll(0,0,-1); Comment(""); } //+------------------------------------------------------------------+ //| OnTick() event processing method | //+------------------------------------------------------------------+ void CMasterWindows::OnEventTick() { if(on_event) // event processing is enabled { //--- } } //+------------------------------------------------------------------+ //| OnChartEvent() event processing method | //+------------------------------------------------------------------+ void CMasterWindows::OnEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { if(on_event) // event processing is enabled { //--- } }
3) Temel ve türetilmiş sınıfların kitaplığı
Kitaplık herhangi bir sayıda türetilmiş sınıf içerebilir ve bunları temel sınıfla (varsa) birlikte dahil edilen ayrı dosyalarda gruplandırmak en iyisidir. Bu şekilde, gerekli değişiklikleri ve eklemeleri yapmak ve hataları aramak daha kolay olacaktır.
Artık, programın çerçevesine sahibiz. O halde onu test edelim ve doğru çalışıp çalışmadığını görelim: Derleyin ve çalıştırın. Test başarılı olursa projeyi ek modüllerle doldurmaya başlayabiliriz.
Türetilmiş sınıfların bağlantısıyla ve hücrelerle başlayalım:
Sınıf adı | Resim |
---|---|
CCellText sınıfı | ![]() |
CCellEdit sınıfı | ![]() |
CCellButton sınıfı | ![]() |
CCellButtonType sınıfı | ![]() |
Tablo 1. Hücre sınıfları kitaplığı
Tek bir türetilmiş CCellButtonType sınıfının oluşturulmasına ayrıntılı bir şekilde göz atalım. Bu sınıf, çeşitli türlerde düğmeler oluşturur.
//+------------------------------------------------------------------+ //| CCellButtonType class | //+------------------------------------------------------------------+ class CCellButtonType:public CCell { public: ///Class constructor void CCellButtonType(); virtual ///Draw method void Draw(string m_name, int m_xdelta, int m_ydelta, int m_type); }; //+------------------------------------------------------------------+ //| CCellButtonType class constructor | //+------------------------------------------------------------------+ void CCellButtonType::CCellButtonType() { type=OBJ_BUTTON; on_event=false; //disable events processing } //+------------------------------------------------------------------+ //| CCellButtonType class Draw method | //+------------------------------------------------------------------+ void CCellButtonType::Draw(string m_name, int m_xdelta, int m_ydelta, int m_type) { //--- creating an object with specified name if(m_type<=0) m_type=0; name=m_name+".Button"+(string)m_type; if(ObjectCreate(0,name,type,0,0,0,0,0)==false) Print("Function ",__FUNCTION__," error ",GetLastError()); //--- object properties initializartion ObjectSetInteger(0,name,OBJPROP_COLOR,Property.TextColor); ObjectSetInteger(0,name,OBJPROP_BGCOLOR,Property.BGColor); ObjectSetInteger(0,name,OBJPROP_CORNER,Property.Corner); ObjectSetInteger(0,name,OBJPROP_XDISTANCE,m_xdelta); ObjectSetInteger(0,name,OBJPROP_YDISTANCE,m_ydelta); ObjectSetInteger(0,name,OBJPROP_XSIZE,Property.H); ObjectSetInteger(0,name,OBJPROP_YSIZE,Property.H); ObjectSetInteger(0,name,OBJPROP_SELECTABLE,0); if(m_type==0) // Hide button { ObjectSetString(0,name,OBJPROP_TEXT,CharToString(MIN_WIN)); ObjectSetString(0,name,OBJPROP_FONT,"Webdings"); ObjectSetInteger(0,name,OBJPROP_FONTSIZE,12); } if(m_type==1) // Close button { ObjectSetString(0,name,OBJPROP_TEXT,CharToString(CLOSE_WIN)); ObjectSetString(0,name,OBJPROP_FONT,"Wingdings 2"); ObjectSetInteger(0,name,OBJPROP_FONTSIZE,8); } if(m_type==2) // Return button { ObjectSetString(0,name,OBJPROP_TEXT,CharToString(MAX_WIN)); ObjectSetString(0,name,OBJPROP_FONT,"Webdings"); ObjectSetInteger(0,name,OBJPROP_FONTSIZE,12); } if(m_type==3) // Plus button { ObjectSetString(0,name,OBJPROP_TEXT,"+"); ObjectSetString(0,name,OBJPROP_FONT,"Arial"); ObjectSetInteger(0,name,OBJPROP_FONTSIZE,10); } if(m_type==4) // Minus button { ObjectSetString(0,name,OBJPROP_TEXT,"-"); ObjectSetString(0,name,OBJPROP_FONT,"Arial"); ObjectSetInteger(0,name,OBJPROP_FONTSIZE,13); } if(m_type==5) // PageUp button { ObjectSetString(0,name,OBJPROP_TEXT,CharToString(PAGE_UP)); ObjectSetString(0,name,OBJPROP_FONT,"Wingdings 3"); ObjectSetInteger(0,name,OBJPROP_FONTSIZE,8); } if(m_type==6) // PageDown button { ObjectSetString(0,name,OBJPROP_TEXT,CharToString(PAGE_DOWN)); ObjectSetString(0,name,OBJPROP_FONT,"Wingdings 3"); ObjectSetInteger(0,name,OBJPROP_FONTSIZE,8); } if(m_type>6) // empty button { ObjectSetString(0,name,OBJPROP_TEXT,""); ObjectSetString(0,name,OBJPROP_FONT,"Arial"); ObjectSetInteger(0,name,OBJPROP_FONTSIZE,13); } on_event=true; //enable events processing } //+------------------------------------------------------------------+
Gerekli açıklamalar:
- Sınıf oluşturucusuna olayların işlenmesine bir yasak getiriyoruz. Bu, nesneyi çalışmaya hazırlamak ve gelen olayların dikkat dağıtıcı unsurlarını ortadan kaldırmak için gereklidir. Gerekli tüm işlemler tamamlandıktan sonra, bu işlemeye izin vereceğiz; nesne tam olarak çalışmaya başlayacaktır.
- Çizim yöntemi, dahili verileri kullanır ve harici verileri alır. Bu nedenle, istisnai durumları önlemek için veriler önce uyumluluk açısından test edilmeli ve ancak bundan sonra işlenmelidir. Ancak bu özel durumda bu testi yapmayacağız. Peki neden? Sınıf nesnesinin bir asker olduğunu ve askerlerin komutanlarının planlarını bilmeleri gerekmediğini düşünün. Görevleri, alınan komutları analiz edip bağımsız kararlar almak yerine, komutanlarının emirlerini açık, hızlı ve titiz bir şekilde yerine getirmektir. Bu nedenle, sınıfıyla çalışmaya başlamadan önce tüm harici verilere uyulmalıdır.
Şimdi tüm hücre kitaplığını test etmeliyiz. Bunu yapmak için aşağıdaki kodu ana modüle (geçici olarak, test amaçlı) ekleyecek ve Expert Advisor'ı çalıştıracağız.
//--- include file with classes #include <ClassUnit.mqh> //+------------------------------------------------------------------+ //| Main module: CMasterWindows class | //+------------------------------------------------------------------+ class CMasterWindows { protected: bool on_event; // events processing flag WinCell Property; // cell property CCellText Text; CCellEdit Edit; CCellButton Button; CCellButtonType ButtonType; public: // Class constructor void CMasterWindows(); // Main module run method (core algorithm) void Run(); // Deinitialization method void Deinit(); // OnTick event processing method void OnEventTick(); // OnChart event processing method void OnEvent(const int id, const long &lparam, const double &dparam, const string &sparam); }; //+------------------------------------------------------------------+ //| Main module run method (core algorithm) | //+------------------------------------------------------------------+ void CMasterWindows::Run() { //--- core algorithm - it launches additional modules ObjectsDeleteAll(0,0,-1); Comment("MasterWindows for MQL5 © DC2008"); //--- Text field Text.Draw("Text",50,50,150,"Text field"); //--- Edit field Edit.Draw("Edit",205,50,150,"default value",true); //--- LARGE BUTTON Button.Draw("Button",50,80,200,"LARGE BUTTON"); //--- Hide button ButtonType.Draw("type0",50,100,0); //--- Close button ButtonType.Draw("type1",70,100,1); //--- Return button ButtonType.Draw("type2",90,100,2); //--- Plus button ButtonType.Draw("type3",110,100,3); //--- Minus button ButtonType.Draw("type4",130,100,4); //--- None button ButtonType.Draw("type5",150,100,5); //--- None button ButtonType.Draw("type6",170,100,6); //--- None button ButtonType.Draw("type7",190,100,7); //--- on_event=true; // enable events processing }
Ve ortaya çıkan sınıflar için olayları aktarmayı unutmamalıyız! Bu yapılmazsa, projeleri işlemek çok zor hatta imkansız hale gelebilir.
//+------------------------------------------------------------------+ //| CMasterWindows class OnChart event processing method | //+------------------------------------------------------------------+ void CMasterWindows::OnEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { if(on_event) // event processing is enabled { //--- process events for the cell class objects Text.OnEvent(id,lparam,dparam,sparam); Edit.OnEvent(id,lparam,dparam,sparam); Button.OnEvent(id,lparam,dparam,sparam); ButtonType.OnEvent(id,lparam,dparam,sparam); } }
Sonuç olarak, hücre sınıfları kitaplığının nesneleri için mevcut tüm seçenekleri görüyoruz.
Şekil 2. Hücre sınıfları kitaplığı
Nesnelerin çalışma verimliliğini ve olaylara tepkilerini test edelim:
- Düzenleme alanına "varsayılan" yerine farklı değişkenler giriyoruz. Değerler değişirse test başarılı olmuş demektir.
- Düğmelere basıyoruz; düğmeler tekrar basılana kadar basılı durumda kalır. Ancak bu, tatmin edici bir tepki değildir. Düğmeye bir kez bastıktan sonra otomatik olarak eski haline dönmesi için düğmeye ihtiyacımız var. Ve işte burada OOP'nin gücünü - devralma olasılığını - gösterebiliriz. Programımız bir düzineden fazla düğme kullanıyor olabilir ve her biri için istenen işlevlerin ayrı ayrı eklenmesine gerek yoktur. CCell temel sınıfını değiştirmek yeterlidir ve türetilmiş sınıfların tüm nesneleri mucizevi bir şekilde düzgün çalışmaya başlayacaktır!
//+------------------------------------------------------------------+ //| CCell class OnChart event processing method | //+------------------------------------------------------------------+ void CCell::OnEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { if(on_event) // event processing is enabled { //--- button click event if(id==CHARTEVENT_OBJECT_CLICK && StringFind(sparam,".Button",0)>0) { if(ObjectGetInteger(0,sparam,OBJPROP_STATE)==1) { //--- if button stays pressed Sleep(TIME_SLEEP); ObjectSetInteger(0,sparam,OBJPROP_STATE,0); ChartRedraw(); } } } }
Böylece sınıf hücrelerinin kitaplığı test edilir ve projeye bağlanır.
Bir sonraki adım, bir satır kitaplığı eklemektir:
Sınıf adı | Resim |
---|---|
CRowType1 sınıfı (0) | ![]() |
CRowType1 sınıfı (1) | ![]() |
CRowType1 sınıfı (2) | ![]() |
CRowType1 sınıfı (3) | ![]() |
CRowType2 sınıfı | ![]() |
CRowType3 sınıfı | ![]() |
CRowType4 sınıfı | ![]() |
CRowType5 sınıfı | ![]() |
CRowType6 sınıfı | ![]() |
Tablo 2. Satır sınıfları kitaplığı
ve aynı şekilde test ediyoruz. Tüm testlerden sonra bir sonraki aşamaya geçiyoruz.
2.4 Aşama IV: Projeyi Oluşturma
Bu noktada, gerekli tüm modüller oluşturulmuş ve test edilmiştir. Şimdi projeyi oluşturmaya başlayalım. İlk önce bir basamak oluşturuyoruz: Pencerenin şekli Şekil 1'deki gibi olmalıdır, daha sonra onu işlevsellikle dolduruyoruz; yani tüm öğelerin ve modüllerin gelen olaylara programlanmış tepkileri.
Bunu yapmak için hazır bir program çerçevesine ve ana modülün hazırlanmasına sahibiz. O halde bununla başlayalım. Bu, CWin temel sınıfının "alt öğe" sınıflarından biridir; bu nedenle "üst" sınıfın tüm genel yöntemleri ve alanları devralma yoluyla kendisine iletilmiştir. Dolayısıyla, birkaç yöntemi geçersiz kılmamız gerekiyor; yeni bir CMasterWindows sınıfı hazırdır:
//--- include files with classes #include <ClassWin.mqh> #include <InitMasterWindows.mqh> #include <ClassMasterWindowsEXE.mqh> //+------------------------------------------------------------------+ //| CMasterWindows class | //+------------------------------------------------------------------+ class CMasterWindows:public CWin { protected: CMasterWindowsEXE WinEXE; // executable module public: void Run(); // Run method void Deinit(); // Deinitialization method virtual // OnChart event processing method void OnEvent(const int id, const long &lparam, const double &dparam, const string &sparam); }; //+------------------------------------------------------------------+ //| CMasterWindows class deinitialization method | //+------------------------------------------------------------------+ void CMasterWindows::Deinit() { //---(delete all objects) ObjectsDeleteAll(0,0,-1); Comment(""); } //+------------------------------------------------------------------+ //| CMasterWindows class Run method | //+------------------------------------------------------------------+ void CMasterWindows::Run() { ObjectsDeleteAll(0,0,-1); Comment("MasterWindows for MQL5 © DC2008"); //--- creating designer window and launch executable object SetWin("CWin1",1,30,250,CORNER_RIGHT_UPPER); Draw(Mint,Mstr,21); WinEXE.Init("CWinNew",30,18); WinEXE.Run(); } //+------------------------------------------------------------------+ //| CMasterWindows class event processing method | //+------------------------------------------------------------------+ void CMasterWindows::OnEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { if(on_event) // event processing is enabled { //--- Close button click in the main window if(id==CHARTEVENT_OBJECT_CLICK && StringFind(sparam,"CWin1",0)>=0 && StringFind(sparam,".Button1",0)>0) { ExpertRemove(); } //--- OnChart event processing for all objects STR1.OnEvent(id,lparam,dparam,sparam); STR2.OnEvent(id,lparam,dparam,sparam); STR3.OnEvent(id,lparam,dparam,sparam); STR4.OnEvent(id,lparam,dparam,sparam); STR5.OnEvent(id,lparam,dparam,sparam); STR6.OnEvent(id,lparam,dparam,sparam); WinEXE.OnEvent(id,lparam,dparam,sparam); } }
Ana modül kendi başına oldukça küçüktür; zira uygulama penceresinin oluşturulmasından başka hiçbir şeyden sorumlu değildir. Ardından kontrolü, en ilginç şeyin (gelen olaylara tepkinin) gerçekleştiği yürütülebilir WinEXE modülüne iletir.
Daha önce nesneler arasında veri alışverişi için basit bir WinCell yapısı oluşturduk; şimdi bu yaklaşımın tüm avantajları netlik kazanıyor. Yapının tüm üyelerini kopyalama işlemi çok rasyonel ve kompakttır:
STR1.Property = Property; STR2.Property = Property; STR3.Property = Property; STR4.Property = Property; STR5.Property = Property; STR6.Property = Property;
Bu aşamada, sınıf tasarımının ayrıntılı değerlendirmesini sonlandırabilir ve yeni sınıflar oluşturma sürecini önemli ölçüde hızlandıran yapılandırmaların görsel teknolojisine geçebiliriz.
3. Sınıfların görsel tasarımı
MQL5 için görsel MasterWindows tasarımı modunda bir sınıf çok daha hızlı oluşturulabilir ve daha kolay görselleştirilebilir:Şekil 3. Görsel tasarım süreci
Geliştiriciden gerekli olan tek şey, MasterWindows formunu kullanarak pencere formunu çizmek ve ardından yalnızca planlanan olaya tepkiyi belirlemektir. Kodun kendisi otomatik olarak oluşturulur. Hepsi bu kadar! Proje tamamlandı.
Expert Advisor'ın yanı sıra CMasterWindows sınıfının oluşturulan bir kodunun bir örneği Şekil 4'te gösterilmiştir (...\MQL5\Files klasöründe bir dosya oluşturulur):
//****** Project (Expert Advisor): project1.mq5 //+------------------------------------------------------------------+ //| Code has been generated by MasterWindows Copyright DC2008 | //| http://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "DC2008" //--- include files with classes #include <ClassWin.mqh> int Mint[][3]= { {1,0,0}, {2,100,0}, {1,100,0}, {3,100,0}, {4,100,0}, {5,100,0}, {6,100,50}, {} }; string Mstr[][3]= { {"New window","",""}, {"NEW1","new1",""}, {"NEW2","new2",""}, {"NEW3","new3",""}, {"NEW4","new4",""}, {"NEW5","new5",""}, {"NEW6","new6",""}, {} }; //+------------------------------------------------------------------+ //| CMasterWindows class (main unit) | //+------------------------------------------------------------------+ class CMasterWindows:public CWin { private: long Y_hide; // Window shift vertical in hide mode long Y_obj; // Window shift vertical long H_obj; // Window shift horizontal public: bool on_hide; // HIDE mode flag CArrayString units; // Main window lines void CMasterWindows() {on_event=false; on_hide=false;} void Run(); // Run method void Hide(); // Hide method void Deinit() {ObjectsDeleteAll(0,0,-1); Comment("");} virtual void OnEvent(const int id, const long &lparam, const double &dparam, const string &sparam); }; //+------------------------------------------------------------------+ //| CMasterWindows class Run method | //+------------------------------------------------------------------+ void CMasterWindows::Run() { ObjectsDeleteAll(0,0,-1); Comment("Code has been generated by MasterWindows for MQL5 © DC2008"); //--- creating main window and launch executable module SetWin("project1.Exp",50,100,250,CORNER_LEFT_UPPER); Draw(Mint,Mstr,7); } //+------------------------------------------------------------------+ //| CMasterWindows class Hide method | //+------------------------------------------------------------------+ void CMasterWindows::Hide() { Y_obj=w_ydelta; H_obj=Property.H; Y_hide=ChartGetInteger(0,CHART_HEIGHT_IN_PIXELS,0)-Y_obj-H_obj;; //--- if(on_hide==false) { int n_str=units.Total(); for(int i=0; i<n_str; i++) { long y_obj=ObjectGetInteger(0,units.At(i),OBJPROP_YDISTANCE); ObjectSetInteger(0,units.At(i),OBJPROP_YDISTANCE,(int)y_obj+(int)Y_hide); if(StringFind(units.At(i),".Button0",0)>0) ObjectSetString(0,units.At(i),OBJPROP_TEXT,CharToString(MAX_WIN)); } } else { int n_str=units.Total(); for(int i=0; i<n_str; i++) { long y_obj=ObjectGetInteger(0,units.At(i),OBJPROP_YDISTANCE); ObjectSetInteger(0,units.At(i),OBJPROP_YDISTANCE,(int)y_obj-(int)Y_hide); if(StringFind(units.At(i),".Button0",0)>0) ObjectSetString(0,units.At(i),OBJPROP_TEXT,CharToString(MIN_WIN)); } } //--- ChartRedraw(); on_hide=!on_hide; } //+------------------------------------------------------------------+ //| CMasterWindows class OnChartEvent event processing method | //+------------------------------------------------------------------+ void CMasterWindows::OnEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { if(on_event // event handling is enabled && StringFind(sparam,"project1.Exp",0)>=0) { //--- call of OnChartEvent handlers STR1.OnEvent(id,lparam,dparam,sparam); STR2.OnEvent(id,lparam,dparam,sparam); STR3.OnEvent(id,lparam,dparam,sparam); STR4.OnEvent(id,lparam,dparam,sparam); STR5.OnEvent(id,lparam,dparam,sparam); STR6.OnEvent(id,lparam,dparam,sparam); //--- creating graphic object if(id==CHARTEVENT_OBJECT_CREATE) { if(StringFind(sparam,"project1.Exp",0)>=0) units.Add(sparam); } //--- edit [NEW1] in Edit STR1 if(id==CHARTEVENT_OBJECT_ENDEDIT && StringFind(sparam,".STR1",0)>0) { //--- event processing code } //--- edit [NEW3] : Plus button STR3 if(id==CHARTEVENT_OBJECT_CLICK && StringFind(sparam,".STR3",0)>0 && StringFind(sparam,".Button3",0)>0) { //--- event processing code } //--- edit [NEW3] : Minus button STR3 if(id==CHARTEVENT_OBJECT_CLICK && StringFind(sparam,".STR3",0)>0 && StringFind(sparam,".Button4",0)>0) { //--- event processing code } //--- edit [NEW4] : Plus button STR4 if(id==CHARTEVENT_OBJECT_CLICK && StringFind(sparam,".STR4",0)>0 && StringFind(sparam,".Button3",0)>0) { //--- event processing code } //--- edit [NEW4] : Minus button STR4 if(id==CHARTEVENT_OBJECT_CLICK && StringFind(sparam,".STR4",0)>0 && StringFind(sparam,".Button4",0)>0) { //--- event processing code } //--- edit [NEW4] : Up button STR4 if(id==CHARTEVENT_OBJECT_CLICK && StringFind(sparam,".STR4",0)>0 && StringFind(sparam,".Button5",0)>0) { //--- event processing code } //--- edit [NEW4] : Down button STR4 if(id==CHARTEVENT_OBJECT_CLICK && StringFind(sparam,".STR4",0)>0 && StringFind(sparam,".Button6",0)>0) { //--- event processing code } //--- [new5] button click STR5 if(id==CHARTEVENT_OBJECT_CLICK && StringFind(sparam,".STR5",0)>0 && StringFind(sparam,".Button",0)>0) { //--- event processing code } //--- [NEW6] button click STR6 if(id==CHARTEVENT_OBJECT_CLICK && StringFind(sparam,".STR6",0)>0 && StringFind(sparam,"(1)",0)>0) { //--- event processing code } //--- [new6] button click STR6 if(id==CHARTEVENT_OBJECT_CLICK && StringFind(sparam,".STR6",0)>0 && StringFind(sparam,"(2)",0)>0) { //--- event processing code } //--- button click [] STR6 if(id==CHARTEVENT_OBJECT_CLICK && StringFind(sparam,".STR6",0)>0 && StringFind(sparam,"(3)",0)>0) { //--- event processing code } //--- Close button click in the main window if(id==CHARTEVENT_OBJECT_CLICK && StringFind(sparam,".Button1",0)>0) { ExpertRemove(); } //--- Hide button click in the main window if(id==CHARTEVENT_OBJECT_CLICK && StringFind(sparam,".Button0",0)>0) { Hide(); } } } //--- Main module declaration CMasterWindows MasterWin; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- launch main module MasterWin.Run(); return(0); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- main module deinitialization MasterWin.Deinit(); } //+------------------------------------------------------------------+ //| Expert Event function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //--- call OnChartEvent event handler MasterWin.OnEvent(id,lparam,dparam,sparam); }
Bunun başlatılmasıyla, aşağıdaki tasarlanmış pencereyi görürüz:
Şekil 4. Expert Advisor projesi1 - sınıfların görsel tasarımının sonucu
Sonuç
- Sınıflar aşama aşama tasarlanmalıdır. Görev modüllere ayrılarak her biri için ayrı bir sınıf oluşturulur. Modüller, sırayla, türetilmiş veya temel sınıfların mikro modüllerine ayrılır.
- Temel sınıfları yerleşik yöntemlerle aşırı yüklememeye çalışın; bunların sayısı minimum düzeyde tutulmalıdır.
- Kod otomatik olarak oluşturulduğu için görsel tasarım ortamının kullanıldığı sınıfların tasarımı bir "yeni başlayan" için dahi çok basittir.
Eklerin konumu:
- masterwindows.mq5 - ...\MQL5\Experts\
- klasörde kalan - ...\MQL5\Include\
MetaQuotes Ltd tarafından Rusçadan çevrilmiştir.
Orijinal makale: https://www.mql5.com/ru/articles/53





- Ücretsiz alım-satım uygulamaları
- İşlem kopyalama için 8.000'den fazla sinyal
- Finansal piyasaları keşfetmek için ekonomik haberler
Gizlilik ve Veri Koruma Politikasını ve MQL5.com Kullanım Şartlarını kabul edersiniz