「サル」でもわかるMQL:オブジェクトクラスの設計 構築方法
オブジェクト指向プログラミング(OOP)への入門
「初心者」の方の質問:手続き型プログラミングへの曖昧な理解のまま、OOPをマスターし、自動トレーディング戦略の作成を行うことができるのでしょうか?この作業は普通のユーザーには難しすぎるものでしょうか?
一般的に、オブジェクト指向プログラミング の規則を使用せずとも、MQL5エキスパートアドバイザーやインジケーターの作成にオブジェクト指向プログラミング言語を用いることができます。開発において新しい技術の使用は必須ではありません。あなたの思う最も簡単な方法を選択してください。また、OOPのアプリケーションは、あなたの作成する取引システムの収益性を保証することはできません。
しかしながら、(オブジェクト指向の)新しい手法への移行は、トレーディング戦略のより複雑な数学的モデルを、市場の動き、外部環境の変化に応じるエキスパートアドバイザーに適応させるための基盤を築くことができます。
それでは、OOPの基礎となる技術を見てみましょう。
- イベント
- オブジェクトクラス
イベントはOOPの主要な基礎となる部分です。プログラム全体のロジックは、断続的に到来するイベントへの処理に基づいています。それらイベントに対する適切な対応は、オブジェクトクラス内に定義され、記述されます。つまり、クラスオブジェクトは、イベントの流れを捕まえ、処理することにより稼働します。
次に基礎となるものとして、オブジェクトクラスがあり、それは「3本の柱」で成り立ちます。
- カプセル化 - クラスの保護が「ブラックボックス」の理論に基づきます:オブジェクトはイベントに応答しますが、実際の実行処理は知られずに保たれます。
- 継承 - 既存のクラスから新しいクラスを、「親クラス」の属性やメソッドを保持しながら作成することです。
- 多相性 - 「孫」クラスにおける継承されたメソッドの実行内容を変化することができることです。
基礎的なコンセプトは、エキスパートアドバイザーコードで最も詳しく紹介されています。
//+------------------------------------------------------------------+ //| 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);
このメソッドの 仮想(virtual) 修飾子は、OnEventハンドラが再定義できることを意味しますが、この場合のメソッド名は親クラスと同じ名前で保持されます。
2. クラスの設計
OOPの重要な利点の一つに、拡張性があります - つまり、既存のシステムが変更せずにも新しいコンポーネントを扱うことができるということです。新しいコンポーネントをこのステージにて追加することができます。
MQL5のMsterWindowsクラスの視覚的デザインのプログラム作成により、設計の手順を考察してください。
2.1. ステージ1:プロジェクトの原案
設計のプロセスは、紙にペンで下書きを書くことから始まります。これは、プログラミングにおいて最も困難で楽しい瞬間の一つです。プログラムとユーザー間の対話だけではなく、データ処理の構造も考慮する必要があります。このプロセスは1日以上かかることもあります。基本的にはインターフェースから始めることが最も良いと思います。というのも、アルゴリスムの構築の際に、それが定義となることがあるからです。(ここでの例でもいくつかそのようになるケースがあります。)
作成したプログラウのダイアログの構築のため、Windowsアプリケーションウィンドウに類似したフォームを使用します。(図1の下書きをご覧ください)複数の行や、セルとグラッフィクオブジェクトのセルを持ちます。そして、概念設計のステージでは、プログラムの構造や、オブジェクトの分類などを紹介致します。
図1. クラスのコンストラクター(下書き)
かなり多くの数の行やセル(フィールド)を用いられた、ニ種類のグラフィックオブジェクトにより成り立っています。OBJ_EDIT と OBJ_BUTTON の二つです。従って、視覚的な外見や構造、プログラムに作成される基礎的なオブジェクトを決定すれば、設計の下書きは完成し、次のステージへ移ることができます。
2.2 ステージ2:ベースクラスの設計
今のところ3つのクラスがあり、今後(必要であれば)さらに追加していくことができます。
- セルクラス CCell
- セルのクラスであるCCellから成り立つ、行クラスCRow
- 行クラスのCRowから成り立つ、ウィンドウクラスのCWin
直接プログラミングクラスに進むことができますが、重要なタスクである、クラスのオブジェクト間でのデータの取り交わしを行う必要があります。そのために、MQL5言語は、基本的な変数に加えて、新しいタイプ - ストラクチャーというものを持っています。もちろん、このステージにおいて、全ての接続部分を見ることや、計算を行うことはできません。そのため、プロジェクトを進めつつ、クラスやストラクチャーの記述を埋めていきたいと思います。さらに、OOPの原則は、この仕組みを阻害するというのではなく、むしろ逆で、技術やプログラミングを促進するものです。
WinCell ストラクチャー:
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) };
Stringや動的配列オブジェクトを持たないストラクチャーをシンプルストラクチャーと呼びます。異なるストラクチャー同士でも、そのようなストラクチャーの変数は、互いに自由にコピーされることができます。構築されたストラクチャーはこのような形です。効果の測定は後ほど行います。
ベースクラス CCell:
//+------------------------------------------------------------------+ //| 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:
//+------------------------------------------------------------------+ //| 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:
//+------------------------------------------------------------------+ //| 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); };
説明と推奨:
- 全てのベースクラスは、イベント処理用のメソッドを持っています。順に沿ってイベントを受け持ち、伝達する必要があるのです。イベントを受け取り、送信する仕組みがなければ、プログラム(もしくはモジュール)はインタラクティビティを失うこととなります。
- ベースクラスの開発時には、最小数のメソッドで作成してみてください。そして、作成されたオブジェクトの機能性を向上させる「派生」クラスの中で様々な拡張を実行してみてください。
- 別のクラスの内部データへの直接の呼び出しは控えてください。
2.3. ステージ3:ワーキングプロジェクト
ここでは、プログラムの作成をステップごとに始めていきます。サポート用フレームワークから始め、機能コンポーネントを増やし、内容を記述します。この際、作業の正誤をチェックし、デバッギングを行い、表示されるエラーを追っていきます。
ここでひとまず作業を中断し、ほとんど全てのプログラムで作動するフレームワークの作成技術について考察してみましょう。主に重要な箇所は - (エラーなくコンパイルし稼働するなど)ただちに作動しうるという点です。言語設計者は、この点に注意し、MQL5ウィザードにて生成されるフレームワークとしてのエキスパートアドバイザーテンプレートを使用することを推奨しています。
例として、以下のテンプレートをみてみましょう。
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); }
こちらがエキスパートアドバイザーの完成版のコードです。このプロジェクトにおいて、さらなる追加変更は必要ではありません。
2) メインモジュール = クラス
全ての主要な、また補助的なプロジェクトのモジュールは、ここからその開発を始めます。この手法は、複雑なマルチモジュールプロジェクトのプログラミングを容易にし、起こりうるエラーを検索します。しかし、その発見は容易ではありません。時折、わかりにくい「バグ」を見つだすよりも、新しいプロジェクトを作成した方が容易く、早いこともしばしばあります。
//+------------------------------------------------------------------+ //| 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); };
クラスの主要なメソッドの冒頭の記述が以下になります。
//+------------------------------------------------------------------+ //| 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)基礎的な派生クラスのライブラリ
ライブラリは、派生クラスをいくつでも持つことができ、個別のファイルにグループ化するのに最適です。このように、エラーの検索と同様、必要な変更や追加をより簡単に行えます。
そして、やっとプログラムのフレームワークを持つことができます。テストし、正しく動作するか確認しましょう:(コンパイルと実行)もしテストが成功であれば、追加モジュールをプロジェクトに追加していきます。
派生クラスの接続を開始し、セルからスタートしましょう:
Nameクラス | イメージ |
---|---|
CCellText クラス | |
CCellEdit クラス | |
CCellButton クラス | |
CCellButtonType クラス |
表 1. セルクラスのライブラリ
CCellButtonTypeの派生クラスの作成を詳しく見てみましょう。このクラスは様々なボタンを作成します。
//+------------------------------------------------------------------+ //| 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 } //+------------------------------------------------------------------+
必要な説明;
- イベント処理の禁止令のクラスコンストラクターへの導入を行います。これは、作動する上でのオブジェクトを準備し、イベントの乱れを除去するために必要なことです。必要な動作の完成ののち、処理を進め、オブジェクトは完全に機能し始めます。
- drawメソッドは、内部データを使用し、外部データを受け取ります。従って、コンプライアンスのためまず初めにデータはテストされ、例外の状況を避けるため処理される必要があります。しかし、この特定のケースにおいてこのテストを行いません。それはどうしてでしょうか?クラスオブジェクトは一人の兵士であり、必ずしも将軍の計画を知る必要はないことを想像してみてください。彼らの仕事は、簡潔に、また、迅速に、厳密に指揮官の命令を遂行し、与えられた命令を分析し、独自の判断を下してはなりません。従って、全ての外部データは、クラスを扱う前に全てコンパイルされる必要があります。
そして、セルの全ライブラリをテストする必要があります。このためには、以下のコードをメインモジュールを(一時的にテストのため)挿入し、エキスパートアドバイザーを稼働してくみましょう。
//--- 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 }
そして、結果として生じるクラスにイベントを移すことを忘れてはいけません。もしこれが行われなければ、プロジェクトのハンドリングは困難、または、不可能になります。
//+------------------------------------------------------------------+ //| 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); } }
結果として、セルクラスのライブラリのオブジェクトにおける使用可能なオブションを全て見ることができます。
図 2. セルクラスのライブラリ
作動効率とイベントへのオブジェクトの反応をテストしてみましょう:
- 「デフォルト」の代わりに、編集フィールドの異なる変数をみてみます。もし変数が変化している場合、テストは成功です。
- ボタンを押し、またボタンが押されるまで、押された状態で維持されます。しかし、これは満足のいく反応ではありません。一度押した後、ボタンが元の状態に自動的に戻って来る必要があります。そして、これは、OOPの力、継承の可能性を紹介することができるところです。私たちのプログラムは、いくつかのボタンを使用し、個別にそれぞれに対して望んだ機能を追加する必要はありません。CCellベースクラスを変更するだけで十分であり、すべての派生クラスのオブジェクトは、適切に動き始めるのです!
//+------------------------------------------------------------------+ //| 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(); } } } }
そして、セルクラスのライブラリは、テストされ、プロジェクトに接続されます。
次のステップは、行ライブラリの追加です:
Nameクラス | イメージ |
---|---|
CRowType1(0) クラス | |
CRowType1 (1) クラス | |
CRowType1 (2) クラス | |
CRowType1 (3) クラス | |
CRowType2 クラス | |
CRowType3 クラス | |
CRowType4 クラス | |
CRowType5 クラス | |
CRowType6 クラス |
表 2. 行クラスのライブラリ
同様にテストを行います。すべてのテストの後、次のステージに進みます。
2.4ステージ4: プロジェクトの構築
この地点にて、すべての必要なモジュールは作成され、テストされました。それでは、プロジェクトの構築に進みます。まず、図1のウィンドウの形ようなのカスケードを作成し、すべての要素とイベントへのモジュールのプログラムされた応答、つまり、機能性を追加します。
そのために、プログラムの完成されているフレームとメインモジュールの準備品があります。それでは始めましょう。「子」クラスの一つ、Cwinベースクラスがあります。従って、すべてのパブリックメソッドや「親」クラスのフィールドは継承により、そのクラスに渡されます。それゆえ、いくつかのメソッドを再定義すれば、新しいCMasterWindowsクラスの準備完了です。
//--- 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); } }
アプリケーションウィンドウの作成のみを担っているので、メインモジュールはそれ自体かなり小さいです。次に、興味深い、イベントの発生への反応が見られる、実行可能WinEXEモジュールにコントロールを渡します。
以前に、WinCellストラクチャーをオブジェクト間のデータの受け渡しのために作成しました。今、この手法のすべての利点があきらかになります。ストラクチャーのすべてのメンバのコピーのプロセスは合理的であり、簡潔です
STR1.Property = Property; STR2.Property = Property; STR3.Property = Property; STR4.Property = Property; STR5.Property = Property; STR6.Property = Property;
このステージでは、クラスの設計の詳しい考察は終え、新規クラスの作成手順を早める、構築技術に移ります。
3. クラスのビジュアル設計
クラスはより早く構築されることができ、MQL5のMasterWindowsデザインにて、より簡単に視覚化することができます。
図 3. ビジュアル設計のプロセス
開発者に求められているのは、MasterWindowsフォームを用い、ウィンドウのフォームを描き、計画されたイベントの反応を決定することです。コード自体は自動で生成されます。そして終了です!プロジェクトの完成です。
エキスパートアドバイザーとともに、CMasterWindowsクラスの生成されたコードの例は図4にて示されています。(ファイルは、..\MQL5\Filesに作成されます。)
//****** 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); }
これを作動させると、以下の設計されたウィンドウを見ることができます。
図4. エキスパートアドバイザープロジェクト1ークラスのビジュアル設計の結果
結論
- ステージごとにクラスは設計される必要があります。タスクをモジュールごとに分解し、個別のクラスがそれぞれのために作成されます。モジュールは、派生クラスやベースクラスのより小さなモジュールへ分解されます。
- 内蔵のメソッドでベースクラスを再定義してはいけません。これらの数は最小で留める必要があります。
- ビジュアル設計の環境を使用したクラスの設計は、とても簡単であり、「サル」向けでもあります。というのも、コードは自動生成されるからです。
付属物の位置:
- masterwindows.mq5 - ...\MQL5\Experts\
- remaining in the folder - ...\MQL5\Include\
MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/53
- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索