English Русский 中文 Español Deutsch Português 한국어 Français Italiano Türkçe
CChartObject クラスに基づく新規GUIウィジェット設計と実装

CChartObject クラスに基づく新規GUIウィジェット設計と実装

MetaTrader 5インディケータ | 7 10月 2015, 16:29
969 0
investeo
investeo

はじめに

前稿『GUI インターフェースを使用した半自動Expert Advisor』を書いてのち、より複雑なインディケータやExpert Advisorsに新しい関数を伴うインターフェースを強化したいと思うようになりました。MQL5 標準ライブラリクラスを知ってから、新しいウィジェットを実装しました。

本稿ではGUIオブジェクトに MQL5 標準ライブラリ クラスを使用するプロセス、CChartObjectEdit クラスから派生した新しいクラスの実装法について述べます。派生クラスは CChartObjectProgressBar、 CChartObjectSpinner a、 CChartEditTableです。CChartEditTable クラスはオブジェクトの動的二次元配列を使い、これはMQL5にオブジェクトの動的二次元配列を実装する方法の動作例です。


1. CChartObject とその派生クラス

標準MQL5 ライブラリクラスを使用しなければ、 チャート上にオブジェクトを作成し保持するのにオブジェクト関数 を使う必要があります。

オブジェクトは ObjectCreate() 関数を用いて作成され、オブジェクトタイプはENUM_OBJECT 値としてObjectCreate() 関数に渡されます。 チャート上のすべてのオブジェクトは独自のプロパティを持ち、それは 整数ダブル値、または文字列 タイプです。プロパティはすべて設定され、専用の関数で読み出されます。: ObjectGetInteger()ObjectSetInteger()ObjectGetDouble()ObjectSetDouble()ObjectGetString()ObjectSetString()です。また与えられるチャートには、削除移動カウント オブジェクトもあります。

MQL5のOOP パラダイムにより、チャートオブジェクトの処理は CChartObject クラスとその派生クラスによって行われます。

CChartObject クラスはチャートに載せられるグラフィックオブジェクトの基本クラスです。以下で CChartObject の基本継承図を確認ください。

CChartObject クラスの継承図

図1 CChartObject クラスの継承図

見てのとおり、右下角に小さな三角印のついたクラスがいくつかあります。

これらはその他クラスの親クラスです。基本的に、派生クラスはオブジェクト上で処理を行う変数やメソッドを追加することで基本クラスの機能を高めます。また、オブジェクトを作成し、そのタイプを返すのに Create() メソッドと Type() メソッドでは相違があります。

例で見ていきます。 CChartObjectTrend クラスは以下の基本クラスです。: CChartObjectTrendByAngleCChartObjectChannelCChartObjectStdDevChannelCChartObjectRegressionCChartObjectPitchfork classes。

CChartObjectTrendOBJPROP_RAY_RIGHT および OBJPROP_RAY_LEFT のプロパティを持つオブジェクトの基本クラスで、以下のように定義されます。

class CChartObjectTrend : public CChartObject
  {
public:
   //--- methods of access to properties of the object
   bool              RayLeft() const;
   bool              RayLeft(bool new_sel);
   bool              RayRight() const;
   bool              RayRight(bool new_sel);
   //--- method of creating the object
   bool              Create(long chart_id,string name,int window,
                                datetime time1,double price1,datetime time2,double price2);
   //--- method of identifying the object
   virtual int       Type() const { return(OBJ_TREND); }
   //--- methods for working with files
   virtual bool      Save(int file_handle);
   virtual bool      Load(int file_handle);
  };

メソッドの違いを区別できるよう、定義にはコメントがふくまれています。

オブジェクトのプロパティにアクセスするメソッドは RayLeft() と RayRight() です。その実装はCChartObjectTrend オブジェクト上で処理を行う ObjectGetInteger() メソッドおよび ObjectSetInteger() メソッドを呼ぶことです。

bool CChartObjectTrend::RayLeft(bool new_ray)
  {
//--- checking
   if(m_chart_id==-1) return(false);
//---
   return(ObjectSetInteger(m_chart_id,m_name,OBJPROP_RAY_LEFT,new_ray));
  }

Create() メソッドはオブジェクトを作成し、チャートにアタッチする役割をします。

それは、パラメータの一つとして、OBJ_TREND を使って ObjectCreate() メソッドを呼びます。

bool CChartObjectTrend::Create(long chart_id,string name,int window,
                                   datetime time1,double price1,datetime time2,double price2)
  {
   bool result=ObjectCreate(chart_id,name,OBJ_TREND,window,time1,price1,time2,price2);
   if(result) result&=Attach(chart_id,name,window,2);
//---
   return(result);
  }

Save() メソッドおよび Load() メソッドは FileWriteInteger() 関数と FileLoadInteger() 関数を使うことで、ハードドライブ上のオブジェクトデータを格納しロードします。

bool CChartObjectTrend::Save(int file_handle)
  {
   bool result;
//--- checking
   if(file_handle<=0) return(false);
   if(m_chart_id==-1) return(false);
//--- writing
   result=CChartObject::Save(file_handle);
   if(result)
     {
      //--- writing value of the "Ray left" property
      if(FileWriteInteger(file_handle,(int) ObjectGetInteger(m_chart_id,m_name,
                                                        OBJPROP_RAY_LEFT),CHAR_VALUE)!=sizeof(char))
      return(false);
      //--- writing value of the "Ray right" property
      if(FileWriteInteger(file_handle,(int) ObjectGetInteger(m_chart_id,m_name, 
                                                                OBJPROP_RAY_RIGHT),CHAR_VALUE)!=sizeof(char))
       return(false);
     }
//---
   return(result);
  }

bool CChartObjectTrend::Load(int file_handle)
  {
   bool result;
//--- checking
   if(file_handle<=0) return(false);
   if(m_chart_id==-1) return(false);
//--- reading
   result=CChartObject::Load(file_handle);
   if(result)
     {
      //--- reading value of the "Ray left" property
      if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_RAY_LEFT,
                                                 FileReadInteger(file_handle,CHAR_VALUE)))return(false);
      //--- reading value of the "Ray right" property
      if(!ObjectSetInteger(m_chart_id,m_name,OBJPROP_RAY_RIGHT,
                                                 FileReadInteger(file_handle,CHAR_VALUE))) return(false);
     }
//---
   return(result);
  }

それではCChartObjectTrend から始めて、派生クラスをさっと見ていきます。

CChartObjectTrendByAngle クラスは Angle() プロパティ モディファイアを追加し、 OBJ_TRENDBYANGLE オブジェクトタイプを返します。

class CChartObjectTrendByAngle : public CChartObjectTrend
  {
public:
   //--- methods of access to properties of the object
   double            Angle() const;
   bool              Angle(double angle);
   //--- method of creating the object
   bool              Create(long chart_id,string name,int window,datetime time1,double price1,
                               datetime time2,double price2);
   //--- method of identifying the object
   virtual int       Type() { return(OBJ_TRENDBYANGLE); }
  };

CChartObjectChannel クラスは OBJ_CHANNEL オブジェクトタイプを返します。また、これはチャネルを処理するので、3つの 価格/日付ペアが Create() メソッドに渡されます。

class CChartObjectChannel : public CChartObjectTrend
  {
public:
   //--- method of creating the object
   bool              Create(long chart_id,string name,int window,datetime time1,double price1,
                               datetime time2,double price2,datetime time3,double price3);
   //--- method of identifying the object
   virtual int       Type() const { return(OBJ_CHANNEL); }
  };

CChartObjectStdDevChannel クラスは Deviations() プロパティ モディファイアや、さらにCreate() メソッドの偏差値パラメータを追加します。

class CChartObjectStdDevChannel : public CChartObjectTrend
  {
public:
   //--- methods of access to properties of the object
   double            Deviations() const;
   bool              Deviations(double deviation);
   //--- method of creating the object
   bool              Create(long chart_id,string name,int window,
                           datetime time1,datetime time2,double deviation);
   //--- method of identifying the object
   virtual int       Type() const { return(OBJ_STDDEVCHANNEL); }
   //--- methods for working with files
   virtual bool      Save(int file_handle);
   virtual bool      Load(int file_handle);
  };

CChartObjectRegression クラスは回帰トレンドラインを作成します。Create() メソッドおよび Type() メソッドのみが CChartObjectTrend クラスからオーバーライドされます。

class CChartObjectRegression : public CChartObjectTrend
  {
public:
   //--- method of creating the object
   bool              Create(long chart_id,string name,int window,datetime time1,datetime time2);
   //--- method of identifying the object
   virtual int       Type() const { return(OBJ_REGRESSION); }
  };

CChartObjectPitchfork クラスはフォークタイプを処理します。また、Create() メソッドおよび Type() メソッドのみ変更されます。

class CChartObjectPitchfork : public CChartObjectTrend
  {
public:
   //--- method of creating the object
   bool              Create(long chart_id,string name,int window,datetime time1,double price1,
                               datetime time2,double price2,datetime time3,double price3);
   //--- method of identifying the object
   virtual int       Type() const { return(OBJ_CHANNEL); }
  };

すばやく見てみると、他のクラスを基にした新しいグラフィックオブジェクトクラスを書くときに適用する基本ルールを見出せます。

  • オブジェクト作成には Create() メソッドを変更
  • オブジェクトタイプを返すには Type() メソッドを変更
  • プロパティアクセス モディファイアを追加

すべてのルールを適用する必要はありません。クラスには新しいアクセス モディファイアを追加するか、新しい変数および/またはオブジェクトを追加するとよいでしょう。

先に進む前に、グラフィックオブジェクト上での CChartObject メソッドの使い方についてお話します。

ObjectSet メソッド系および ObjectGet メソッド系を使う代わりに、オブジェクトプロパティを使います。 CChartObject または派生オブジェクトを宣言すれば十分で、必要なプロパティを変更するメソッドを呼び出します。理解しやすいように通常ラベルの例を提供します。

以下を書く代わりに

void OnStart()
  {
//---
   string label_name="my_OBJ_LABEL_object";
   if(ObjectFind(0,label_name)<0)
     {
      Print("Object ",label_name," not found. Error code = ",GetLastError());
      ObjectCreate(0,label_name,OBJ_LABEL,0,0,0);           
      ObjectSetInteger(0,label_name,OBJPROP_XDISTANCE,200);
      ObjectSetInteger(0,label_name,OBJPROP_YDISTANCE,300);
      ObjectSetInteger(0,label_name,OBJPROP_COLOR,White);
      ObjectSetString(0,label_name,OBJPROP_TEXT,UP);
      ObjectSetString(0,label_name,OBJPROP_FONT,"Wingdings");
      ObjectSetInteger(0,label_name,OBJPROP_FONTSIZE,10);
      ObjectSetDouble(0,label_name,OBJPROP_ANGLE,-45);
      ObjectSetInteger(0,label_name,OBJPROP_SELECTABLE,false);
      ChartRedraw(0);                                      
     }
  }

OOP パラダイムを用いて実装することが可能です。

1. CChartObjectLabel オブジェクトを宣言します。

CChartObjectLabel ラベル

2. オブジェクト上で処理します。

int OnInit()
  {
//---
   label.Create(0, label_name, 0, 0);
   label.X_Distance(200);
   label.Y_Distance(300);
   label.Color(White);
   label.Description(UP);
   label.Font("Wingdings");
   label.FontSize(10);
   label.Angle(-45);
   label.Selectable(false);
//---
   return(0);
  }

ご覧のように、主な相違は文字列 label_ name 上で処理しないことです。

string label_name="my_OBJ_LABEL_object";

パラメータの一つである label_name によって関数 ObjectSetInteger()ObjectGetInteger()ObjectSetDouble()ObjectGetDouble() を呼びますが、 CChartObjectLabel オブジェクトを宣言し、そのメソッドを使用します。これはシンプルで覚えやすく実装するのに理論的であるだけでなく、書くスピードもアップします。

MQL5 コードエディタにより、オブジェクト インスタンスのあとに点(.)を入れることでコードを完了の機能をします。これで既定のプロパティを設定したり取得したりするのにどのOBJPROPプロパティを入れるか確認する目的でMQL5 ドキュメンテーション を何度も見る必要がなくなります。

同様に前述のCChartObjectTrend クラスにに対して、左ラインまたは右ラインを取得あるいは設定するには CChartObjectTrend オブジェクトを宣言し、RayRight() メソッドまたは RayLeft() メソッドを呼べば十分です。

CChartObjectTrend trendline;
trendline.RayRight(true); 


2. ProgressBar

最初に実装するウィジェットはProgressBar です。進捗バーは 0 ~ x パーセントで処理の進行を表示します。

処理をより安定したものとするため、最大値を100までに制限せず、任意の正の整数値とします。進捗値に従いサイズを変える色つきの細長い表示が必要です。まず頭に浮かぶのが、長方形を2つ使うことですが、私は別の方法を選択しました。CChartObjectEdit オブジェクトを2つ使うのです。一つはもう一つの内側に配置しそれぞれ別の背景色にします。

これでコードを書くことや値を表示するため進捗バーの内側に入れるテキストを追加することが簡素化されます。必要に応じて進捗バーは水平、または垂直とするとよいでしょう。


2.1. ProgressBar の実装

CChartObjectEdit クラスからCChartObjectProgress クラスを派生させます。

値:m_value, m_min, m_max の値と制限を維持するためにプライベートな内部変数を追加しました。

進捗バーの方向は整数値で設定し、m_direction 変数で保持されます。色は m_color 変数により保持されます。ここで目的の値はないので、Type() メソッドが OBJ_EDIT 値を返します。クラス定義の中に CChartObjectEdit m_bar 変数があるのがわかります。これはm_valueに応じてサイズを変える内側のバーにあたります。その他の変数 m_name および m_chart は内部に m_bar 変数に対する値を保持します。

class CChartObjectProgressBar : public CChartObjectEdit
  {
private:
   int               m_value;
   int               m_min;
   int               m_max;
   int               m_direction;
   color             m_color;
   CChartObjectEdit  m_bar;
   string            m_name;
   long              m_chart_id;

public:
   int               GetValue();
   int               GetMin();
   int               GetMax();

   void              SetValue(int val);
   void              SetMin(int val);
   void              SetMax(int val);

   void              SetColor(color bgcol,color fgcol);
   bool              Create(long chart_id,string name,int window,int X,int Y,
                           int sizeX,int sizeY,int direction);

   //--- method of identifying the object
   virtual int       Type() const { return(OBJ_EDIT); }
};

Create() メソッドは ProgressBar オブジェクトを作成し、それをチャートにアタッチします。

縦向きのバーが描かれる場合、サイズ Y 変数から Y 変数が引き算されるのがおわかりでしょう。これは通常、上から下に CChartObjectEdit が描かれるところ、私は長方形の中で下から上に向かって描きたかったからです。

bool CChartObjectProgressBar::Create(long chart_id,string name,int window,int X,int Y,
                                          int sizeX,int sizeY,int direction=0)
  {
   bool result=ObjectCreate(chart_id,name,(ENUM_OBJECT)Type(),window,0,0,0);

   m_name=name;
   m_chart_id=chart_id;
   m_direction=direction;

   if(direction!=0)
     {
      Y=Y-sizeY;
     }

   ObjectSetInteger(chart_id,name,OBJPROP_BGCOLOR,White);
   ObjectSetInteger(chart_id,name,OBJPROP_COLOR,White);
   ObjectSetInteger(chart_id,name,OBJPROP_SELECTABLE,false);
   ObjectSetInteger(chart_id,name,OBJPROP_READONLY,true);

   result&=m_bar.Create(chart_id,name+"m_bar",window,X,Y,sizeX,sizeY);
   m_bar.Color(White);
   m_bar.ReadOnly(true);
   m_bar.Selectable(false);

//---
   if(result) result&=Attach(chart_id,name,window,1);
   result&=X_Distance(X);
   result&=Y_Distance(Y);
   result&=X_Size(sizeX);
   result&=Y_Size(sizeY);
//---
   return(result);
  }

SetColor() メソッドは両方の長方形の背景色および前景色を設定します。

void CChartObjectProgressBar::SetColor(color bgCol,color fgCol=White)
  {
   m_color=bgCol;
   m_bar.BackColor(m_color);
   m_bar.Color(fgCol);
  }

SetValue() メソッドは m_val value を設定し、内側の長方形のオブジェクトサイズを計算します。

サイズは横向きの場合と縦向きの場合で計算の仕方が異なります。

void CChartObjectProgressBar::SetValue(int val)
  {
   if(m_direction==0) // horizontal ProgressBar
     {
      double sizex=(double)ObjectGetInteger(m_chart_id,m_name,OBJPROP_XSIZE,0);

      double stepSize=sizex/(m_max-m_min);

      m_value=val;
      m_bar.Create(m_bar.ChartId(),m_bar.Name(),m_bar.Window(),
                   m_bar.X_Distance(),m_bar.Y_Distance(),(int)MathFloor(stepSize*m_value),m_bar.Y_Size());
        } else {
      double sizey=(double)ObjectGetInteger(m_chart_id,m_name,OBJPROP_YSIZE,0);

      double stepSize=sizey/(m_max-m_min);
      m_value=val;
      m_bar.Create(m_bar.ChartId(),m_bar.Name(),m_bar.Window(),
                   m_bar.X_Distance(),(int)(this.Y_Distance()+sizey-MathFloor(stepSize*m_value)),
                   m_bar.X_Size(),(int)MathFloor(stepSize*m_value));

     }

   m_bar.Description(IntegerToString(m_value));
  }

2.2. ProgressBar のデモ

CChartObjectProgressBar クラスはもう実装済みなので、その動作を見てみることにします。

チャートに新しい進捗バーを配置するには、 CChartObjectProgressBar オブジェクトを宣言し、Create() と適切なプロパティメソッドを使うだけです。

progressBar.Create(0, "progressBar1", 0, 10, 10, 200, 40);
progressBar.SetColor(YellowGreen);
progressBar.SetMin(0);
progressBar.SetMax(100);
progressBar.SetValue(0);

私はチャートに 6 本の進捗バーを入れ、スクリーンで任意のオブジェクトがクリックされると値を変える デモ用Expert Advisor を書きました。

そのソースコード全貌とその他のデモは添付にあります。それでは下記の説明をご覧ください。


3. スピナー

スピナーウィジェットはフィールドとボタンを2つ持つウィジェットです。ボタンの一つをクリックすることで、編集フィールドの値をインクリメントまたはデクリメントするのに使われます。

オブジェクト設計中は整数値のみで操作をしたくありませんでしたので、ダブルタイプ値で操作するのに「スピナー」を作成しました。「スピナー」はまたステップサイズを定義する機能もあります。それは現在値をインクリメントまたはデクリメントする値です。また、それには越えてはいけない最小値および最大値もあります。


3.1. 「スピナー」の実装

MQL5 には CChartObjectEdit クラスおよび CChartObjectButton クラスがあり、それらはCChartObjectSpinner クラスとして一つに合成することが可能です。CChartObjectSpinner は CChartObjectEdit から派生し、プライベートメンバCChartObjectButton オブジェクトを2つ持ちます。

m_min および m_max メンバ変数に格納された最大、最小のm_value には制約があり、m_precision 変数が n番目の digit値への計算精度を格納します。必要なメソッドは値のアクセス用で、インクリメントとデクリメントのステップサイズを設定し、値を設定します。

class CChartObjectSpinner: public CChartObjectEdit
  {

private:
   double            m_value;
   double            m_stepSize;
   double            m_min;
   double            m_max;
   int               m_precision;
   string            m_name;
   long              m_chart_id;
   CChartObjectButton m_up,m_down;

public:
   double            GetValue();
   double            GetMin();
   double            GetMax();

   void              SetValue(double val);
   void              SetMin(double val);
   void              SetMax(double val);

   double            Inc();
   double            Dec();

   bool              Create(long chart_id,string name,int window,int X,int Y,
                               int sizeX,int sizeY,double val,double stepSize,int precision);

   //--- method of identifying the object
   virtual int       Type() const { return(OBJ_EDIT); }
   
  };

Create() メソッドは新しい CChartObjectSpinnerを作成し、それをチャートにアタッチします。

CChartObjectEdit の右側で作成される CChartObjectButtons が2つあります。それぞれ CChartObjectEdit 高さの半分の高さとなっています。

インクリメントボタンには '+' 記号があり、デクリメントボタンには '-' 記号があります。

bool CChartObjectSpinner::Create(long chart_id,string name,int window,int X,int Y,
                                     int sizeX,int sizeY,double val=0.0,double stepSize=1.0,int precision=8)
  {
   bool result=ObjectCreate(chart_id,name,(ENUM_OBJECT)Type(),window,0,0,0);

   m_name=name;
   m_chart_id=chart_id;
   m_value=val;
   m_stepSize=stepSize;
   m_precision=precision;

   ObjectSetInteger(chart_id,name,OBJPROP_BGCOLOR,White);
   ObjectSetInteger(chart_id,name,OBJPROP_COLOR,Black);
   ObjectSetInteger(chart_id,name,OBJPROP_SELECTABLE,false);
   ObjectSetInteger(chart_id,name,OBJPROP_READONLY,true);

   result&=m_up.Create(chart_id, name+"_up", window, X+sizeX, Y, 15, sizeY/2);
   result&=m_down.Create(chart_id, name+"_down", window, X+sizeX, Y+sizeY/2, 15, sizeY/2);
   m_up.Description("+");
   m_down.Description("-");
   ObjectSetString(chart_id,name,OBJPROP_TEXT,0,(DoubleToString(m_value,precision)));

//---
   if(result) result&=Attach(chart_id,name,window,1);
   result&=X_Distance(X);
   result&=Y_Distance(Y);
   result&=X_Size(sizeX);
   result&=Y_Size(sizeY);
//---
   return(result);
  }

SetValue() メソッドはプライベート変数 m_value を<m_min, m_max>の範囲内のダブル値に設定します。

void CChartObjectSpinner::SetValue(double val)
  {
   if(val>=m_min && val<=m_max) m_value=val;
   this.Description(DoubleToString(m_value));
  }

Inc() メソッドは与えられたステップサイズにより値をインクリメントしますが、m_max 値以上にはなりません。

与えられた精度とダブル値を比較するのに NormalizeDouble() 関数を使う必要があったことにご注意ください。

double CChartObjectSpinner::Inc(void)
  {
   if(NormalizeDouble(m_max-m_value-m_stepSize,m_precision)>0.0) m_value+=m_stepSize;
   else m_value=m_max;
   this.Description(DoubleToString(m_value, m_precision));
   m_up.State(false);
   return m_value;
  }

Dec() メソッドは与えられたステップサイズにより値をデクリメントしますが、m_min 値以下にはなりません。

double CChartObjectSpinner::Dec(void)
  {
   if(NormalizeDouble(m_value-m_stepSize-m_min,m_precision)>0.0)
      m_value-=m_stepSize; else m_value=m_min;
   this.Description(DoubleToString(m_value,m_precision));
   m_down.State(false);

   return m_value;
  }


3.2. スピナーのデモ

「スピナー」オブジェクトを検証するときがやってきました。それを使用するには CChartObjectSpinner オブジェクトを宣言し、メソッド Create()、 SetMin()、 SetMax() を使うだけです。

spinner.Create(0, "spinner1", 0, 10, 10, 200, 40, 0.0, 0.4);
   spinner.SetMin(0);
   spinner.SetMax(100);

私は「スピナー」ウィジェットを3つ使い、「スピナー」ボタンのどれかが押されると値を加えるデモを準備しました。

これは OnChartEvent() 関数内部で行われます。

void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//--- Check the event by pressing a mouse button
   if(id==CHARTEVENT_OBJECT_CLICK)
     {
     
     if (sparam=="spinner1_up") spinner.Inc();
     if (sparam=="spinner1_down") spinner.Dec();
     if (sparam=="spinner2_up") spinner2.Inc();
     if (sparam=="spinner2_down") spinner2.Dec();
     if (sparam=="spinner3_up") spinner3.Inc();
     if (sparam=="spinner3_down") spinner3.Dec();
     
     label.Description(DoubleToString(NormalizeDouble(spinner.GetValue()+spinner2.GetValue()+spinner3.GetValue(),10),10));
   
   ChartRedraw();
     }
  }

添付のデモを参照ください。


4. CChartObjectEditTable

複数時間枠 (MTF) Expert Advisors の多くには、個別に時間枠を表示するインディケータ値があります。

書く時間枠は色の異なる長方形や正方形の二次元テーブル形式で表示される異なるインディケータ設定を持つことがあります。私は CChartObjectEditTable クラスを作成し、そのようなオブジェクトの汎用的な2Dテーブルをデザインしました。オブジェクトの2D動的配列を使用しているので、このクラスは行列の任意量を保持することが可能です。

設計中、私はそれぞれのセル色を個別に定義し、すべてのセルに異なるテキスト文字列を入れる機能を追加することにしました。セルサイズは同一ですが、高さと幅、またセル間のスペースは定義したいと思いました。


4.1. CChartObjectEditTable の実装

CChartObjectEditTable クラスにはオブジェクトの二次元配列に対する CArrayObj ポインター、m_rows と m_columnsメンバー変数にはテーブルの行と列の数があります。

テーブル内の全 CChartObjectEdit オブジェクトの接頭辞を持つ m_baseName メンバ変数があります。メソッドGetColor()、 SetColor()、GetText()、SetText() は必要なセルに色とテキスト値を設定、取得します。Delete() メソッドは Create() メソッドによって作成されるオブジェクトをすべて削除します。

class CChartObjectEditTable
  {

private:
   CArrayObj        *array2D;
   int               m_rows;
   int               m_cols;
   string            m_baseName;

public:

   bool              Create(long chart_id,string name,int window,int rows,int cols,int startX,int startY,
                                int sizeX,int sizeY,color Bg,int deltaX,int deltaY);
   bool              Delete();
   bool              SetColor(int row,int col,color newColor);
   color             GetColor(int row,int col);
   bool              SetText(int row,int col,string newText);
   string            GetText(int row,int col);


  };

Create() メソッドは CChartObjectEdit オブジェクトの二次元動的テーブルを作成します。

MQL5にオブジェクトの2D 配列を作成する方法を見ます。まず 2D 配列に対するポインターを宣言し、CArrayObj() オブジェクトの数を配列に書き込みます。配列内に配列を作成するということです。すべての配列はテーブルの列を持つとみなされます。

各コラムには行が含まれ、それは CChartObjectEdit オブジェクトを持ちます。オブジェクトはそれぞれ表示する単独セルです。

bool CChartObjectEditTable::Create(long chart_id,string name,int window,int rows=1,int cols=1,
                                       int startX=0,int startY=0,int sizeX=15,int sizeY=15,
                                  color Bg=White,int deltaX=5,int deltaY=5)
  {
   m_rows=rows;
   m_cols=cols;
   m_baseName=name;
   int i=0,j=0;

   array2D=new CArrayObj();
   if (array2D==NULL) return false;
   
   for(j=0; j<m_cols; j++)
     {
      CArrayObj *new_array=new CArrayObj();
      if (array2D==NULL) return false;
   
      array2D.Add(new_array);
      for(i=0; i<m_rows; i++)
        {
         CChartObjectEdit *new_edit=new CChartObjectEdit();

         new_edit.Create(chart_id, name+IntegerToString(i)+":"+IntegerToString(j), window, 
                         startX+j*(sizeX+deltaX), startY+i*(sizeY+deltaY), sizeX, sizeY);
         new_edit.BackColor(Bg);
         new_edit.Color(White);
         new_edit.Selectable(false);
         new_edit.ReadOnly(true);
         new_edit.Description("");
         new_array.Add(new_edit);
        }
     }

   return true;
  }

SetColor() メソッドはセルの色を設定します。まずコラム配列を探し、次にコラム配列の n番目のエレメントを見つけます。

そして、BackColor() メソッドを呼ぶことで、エレメントの色値が代わります。

bool CChartObjectEditTable::SetColor(int row,int col,color newColor)
  {
   CArrayObj *sub_array;
   CChartObjectEdit *element;

   if((row>=0 && row<m_rows) && (col>=0 && col<m_cols))
     {
      if(array2D!=NULL)
        {
         sub_array=array2D.At(col);
         element=(CChartObjectEdit*)sub_array.At(row);
         element.BackColor(newColor);

         return true;
        }
     }

   return false;
  }

GetColor() メソッドは SetColor() メソッドとしてセルを検索するアルゴリズムと同じですが、それは既定のあらゆるセルの色値を返します。

color CChartObjectEditTable::GetColor(int row,int col)
  {
   CArrayObj *sub_array;
   CChartObjectEdit *element;

   if((row>=0 && row<m_rows) && (col>=0 && col<m_cols))
     {
      if(array2D!=NULL)
        {
         sub_array=array2D.At(col);
         element=(CChartObjectEdit*)sub_array.At(row);
         return element.BackColor();
        }
     }

   return NULL;
  }

SetText() メソッドはエレメントを見つけ、Description() メソッドを呼ぶことでそのテキスト値を設定します。

bool CChartObjectEditTable::SetText(int row,int col,string newText)
  {
   CArrayObj *sub_array;
   CChartObjectEdit *element;

   if((row>=0 && row<m_rows) && (col>=0 && col<m_cols))
     {
      if(array2D!=NULL)
        {
         sub_array=array2D.At(col);
         element=(CChartObjectEdit*)sub_array.At(row);
         element.Description(newText);

         return true;
        }
     }

   return false;
  }

Delete() メソッドは Create() メソッドによって作成されるオブジェクトをすべて削除します。

最初にすべてのコラム配列を消去し、その次にメモリから array2D オブジェクトを削除します。

bool CChartObjectEditTable::Delete(void)
  {
   for(int j=0; j<m_cols; j++)
     {
      CArrayObj *column_array=array2D.At(j);
      column_array.Clear();
      delete column_array;
     }
   delete array2D;
   return true;
  }


4.2. CChartObjectEditTable のデモ

CChartObjectEditTable ウィジェットを使うために、 CChartEditTable オブジェクトを宣言し、何行、何列の表にするか指示するパラメータを伴うCreate() メソッドを使用します。

プロパティ モディファイアを使用することで、簡単にセルの色とテキストを変更することができます。

table.Create(0,"t",0,1,10,10,10,15,15,Yellow);
table.SetColor(2,2,Red);
table.SetText(2,2,"2");

CChartObjectEditTable オブジェクトを使用した機能を示すスクリプトを用意しましたので参照ください。

スクリプトのソースコードは添付にあります。


おわりに

本稿では、CChartObject クラスから派生した新しいチャートウィジェットの作成手順についてお話し、実際にそれを導入しました。

実装されたウィジェットの使用手順はひじょうに簡単でコード数行ですみます。

ウィジェット使用にあたっては Expert AdvisorのChartObjectsExtControls.mqh ファイル、またはインディケータコードをインクルードしてください。

MetaQuotes Ltdにより英語から翻訳されました。
元の記事: https://www.mql5.com/en/articles/196

添付されたファイル |
progressbarea.mq5 (3.67 KB)
spinnerdemoea.mq5 (2.83 KB)
edittabledemo.mq5 (4.15 KB)
MetaTrader 5での並列計算 MetaTrader 5での並列計算
人類の歴史において時間は高価値であり、われわれはそれを無駄に費やさないよう努力しています。本稿では、マルチ コア プロセッサのコンピュータをご使用の場合、お手元のExpert Advisor の動作スピードを上げる方法について述べていきます。また、提案のメソッド実装には MQL5以外の言語知識は必要とされません。
定義済みリスクおよびRRレシオに基づく半自動化ドラッグドロップExpert Advisor連携構築 定義済みリスクおよびRRレシオに基づく半自動化ドラッグドロップExpert Advisor連携構築
すべての取引を自動で行うトレーダーもいれば、複数インディケータのアウトプットを基にして自動と手動のミックスで取引を実行するトレーダーもいます。後者のグループの一員として、私はリスクと利益をチャートから直接、動的に評価するための連携ツールが必要でした。本稿は、定義済みの資本リスクおよびR/Rレシオを連携する半自動化Expert Advisorを実装する方法を提供します。EA パネル実行中には、 Expert Advisor リスク、R/R、ロットサイズ パラメータが変更可能です。
チャネルの描画 : 内見および外観 チャネルの描画 : 内見および外観
マーケット分析および移動平均後トレードを判断するのにチャネルはもっとも人気あるツールだと言っても過言ではないでしょう。チャネルとそのコンポーネントを使用するトレード戦略の多くを深く掘り下げず、数学的基本とインディケータの実用的実装について語っていきたいと思います。それはクライアント端末画面の3つの極値によって判断されるチャネルを描くものです。
初心者のためのMQL5のカスタムインディケーター 初心者のためのMQL5のカスタムインディケーター
初めての人にはどんな新しいテーマも複雑で学ぶのが難しいように見えます。知っているテーマはシンプルでわかりやすく感じます。しかし、だれもが母国語さえも最初から勉強しなければならないことを単に忘れがちです。自分のトレーディングストラテジーを策定する上で幅広い可能性を提供するMQL5プログラミング言語でもそれは同じです。- 基本的な考えを最もシンプルな例から学びましょう。本記事ではテクニカルインディケーター とMetaTrader 5 クライアントターミナルの相互作用をシンプルなカスタムインディケーター SMAの例を用いて考えます。