English Русский 中文 Español Deutsch Português
グラフィカルインタフェースX: Easy And Fast (簡単で手早い)ライブラリの更新(ビルド2)

グラフィカルインタフェースX: Easy And Fast (簡単で手早い)ライブラリの更新(ビルド2)

MetaTrader 5 | 14 9月 2016, 10:46
817 0
Anatoli Kazharski
Anatoli Kazharski

コンテンツ

はじめに

シリーズ第一弾のグラフィカルインタフェース I: ライブラリストラクチャの準備(チャプター 1)ではライブラリの目的が詳しく考察されました。各章の末尾には記事へのリンクの完全なリストがみられます。そこではまた、開発の現段階でのライブラリの完全版をダウンロードすることができます。ファイルはアーカイブと同じディレクトリに配置される必要があります。

シリーズの前回の記事の出版以来Easy And Fastライブラリにはいくつかの新機能が加わりました。ライブラリの構造とコードは部分的に最適化され、CPUの負荷が少し軽減されています。多くのコントロールクラスで繰り返して現れるメソッドはCElement基本クラスに移動されました。また、いくつかの小規模の視覚改善と修正も行われました。これらを詳しく考察していきましょう。

 

更新について

1. デフォルト配色が変更されました。今ではそれはどんなチャート背景にも準拠してほとんどが明るい色調です。デフォルト配色を使用すると、カスタムクラスでコントロール作成メソッドを開発する際に特性の最小量を指定することができます。 

以下のスクリーンショットは、明るい背景と暗い背景を持つMQLアプリケーションのグラフィカルインタフェースの例を示します。

 図1 明るい背景に対してデフォルト配色を使用したグラフィカルインターフェースの例

図1 明るい背景に対してデフォルト配色を使用したグラフィカルインターフェースの例


 図2 暗い背景に対してデフォルト配色を使用したグラフィカルインターフェースの例

図2 暗い背景に対してデフォルト配色を使用したグラフィカルインターフェースの例


 

2. マウスおよびマウスカーソルパラメータを格納するCMouseクラスの最初のバージョンを実装しました。より慎重に見てみましょう。

CMouseクラスは、すべてのライブラリファイルが位置する「<terminal directlory>\MQLX\Include\EasyAndFastGUI\Controls」にあるMouse.mqhファイルの中にあります。ここでは標準ライブラリのCChartクラスのインスタンスが必要です。CChart::SubwindowY() メソッドは、マウスカーソルが現在位置するサブウィンドウに相対した Y座標の計算のためにこのクラスで使わます。チャートへの結合はクラスコンストラクタ、 結合解除はデストラクタで行われます

CChartクラスはここでの基本クラスすべてによって利用可能です。よって、適切な変更が実装されました。 

//+------------------------------------------------------------------+
//|                                                        Mouse.mqh |
//|                        Copyright 2016, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#include <Charts\Chart.mqh>
//+------------------------------------------------------------------+
//| マウスパラメータを受け取るクラス                         |
//+------------------------------------------------------------------+
class CMouse
  {
private:
   //--- チャートを管理するクラスのインスタンス
   CChart            m_chart;
   //---
public:
                     CMouse(void);
                    ~CMouse(void);
  };
//+------------------------------------------------------------------+
//| コンストラクタ                                                   |
//+------------------------------------------------------------------+
CMouse::CMouse(void)
  {
//--- 現在のチャートIDを受け取る
   m_chart.Attach();
  }
//+------------------------------------------------------------------+
//| デストラクタ                                                       |
//+------------------------------------------------------------------+
CMouse::~CMouse(void)
  {
//--- チャートから取り離す
   m_chart.Detach();
  }

下記はほぼすべてのライブラリのクラスで使用されるマウスカーソルパラメータのリストです。

  • 現在のカーソル座標
  • カーソルが位置するサブウィンドウの番号
  • チャートでのカーソルのX座標に当たる時刻
  • チャートでのカーソルのY座標に当たるレベル
  • 左マウスボタンの状態(押されている/いない)

パラメータ値を格納したり受信するためのフィールドとメソッドはCMouseクラスボディで実装されています。 

class CMouse
  {
private:
   //--- 座標
   int               m_x;
   int               m_y;
   //--- カーソルが位置するウィンドウの番号
   int               m_subwin;
   //--- X座標に当たる時刻
   datetime          m_time;
   //--- Y座標に当たるレベル(価格)
   double            m_level;
   //--- 左マウスボタンの状態(押されている/いない)
   bool              m_left_button_state;
   //---
public:
   //--- 座標を返す
   int               X(void)               const { return(m_x);                 }
   int               Y(void)               const { return(m_y);                 }
   //--- (1) カーソルが位置するウィンドウの番号 (2) tX座標に当たる時刻 
   //    (3) Y座標に当たるレベル(価格)を返す
   int               SubWindowNumber(void) const { return(m_subwin);            }
   datetime          Time(void)            const { return(m_time);              }
   double            Level(void)           const { return(m_level);             }
   //--- 左マウスボタンの状態(押されている/いない)を返す
   bool              LeftButtonState(void) const { return(m_left_button_state); }
  };

もちろんCHARTEVENT_MOUSE_MOVEイベントの発生を追跡するイベントハンドラも必要です。CMouseクラスフィールドはイベント処理ブロックで埋まっています。このコードはすでにすべてのコントロールのイベントハンドラで見てきました。今ではそれはCMouseクラスのみで存在し、コントロールクラスのコードはより直観的になっています。 また、マウスカーソルのパラメータは、今ではすべての要素とともに全体のパス内に一度だけ受信され、CPUの負荷が軽減されています。  

class CMouse
  {
   //--- イベントハンドラ
   void              OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
  };
//+------------------------------------------------------------------+
//| マウスカーソル移動イベントハンドラ                                  |
//+------------------------------------------------------------------+
void CMouse::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
//--- カーソル移動イベントハンドラ 
   if(id==CHARTEVENT_MOUSE_MOVE)
     {
      //--- マウスの左ボタンの座標と状態
      m_x                 =(int)lparam;
      m_y                 =(int)dparam;
      m_left_button_state =(bool)int(sparam);
      //--- カーソル位置を受け取る
      if(!::ChartXYToTimePrice(0,m_x,m_y,m_subwin,m_time,m_level))
         return;
      //--- 相対的なY座標を受け取る
      if(m_subwin>0)
         m_y=m_y-m_chart.SubwindowY(m_subwin);
     }
  }

CMouseクラスインスタンスはライブラリエンジン基本クラス(CWndContainer)で宣言されています。

//+------------------------------------------------------------------+
//| すべてのインターフェースオブジェクトを格納するクラス                          |
//+------------------------------------------------------------------+
class CWndContainer
  {
protected:
   //--- マウスパラメータを受け取るためのクラスインスタンス
   CMouse            m_mouse;
  };

CMouseクラスインスタンスはまた、その型のオブジェクトへのポインタを格納するCElement基本コントロールクラスでも宣言されていて、これはCWndContainerクラスで宣言されています。また、ポインタを保存し/受信するためのメソッドはここに配置されています。 

//+------------------------------------------------------------------+
//| 基本コントロールクラス                                               |
//+------------------------------------------------------------------+
class CElement
  {
protected:
   //--- マウスパラメータを受け取るためのクラスインスタンス
   CMouse           *m_mouse;
   //---
public:
   //--- マウスポインタを(1) 保存し (2) 返す
   void              MousePointer(CMouse &object)                   { m_mouse=::GetPointer(object);       }
   CMouse           *MousePointer(void)                       const { return(::GetPointer(m_mouse));      }
  };

ライブラリのグラフィカルインターフェースの作成時にはCMouseオブジェクトへのポインタは自動ですべてのコントロールに渡されます。このためにはCMouseオブジェクトはCWndContainer::AddToObjectsArray()メソッドに受け渡され、ここでは下のコードでみられるように、コントロールを構成するすべてのグラフィックオブジェクトへのポインタが共通の配列に送られます。 

//+------------------------------------------------------------------+
//| コントロールオブジェクトへのポインタを共通配列に追加する    |
//+------------------------------------------------------------------+
template<typename T>
void CWndContainer::AddToObjectsArray(const int window_index,T &object)
  {
   int total=object.ObjectsElementTotal();
   for(int i=0; i<total; i++)
      AddToArray(window_index,object.Object(i));
//--- マウスカーソルを基本コントロールクラスに保存する
   object.MousePointer(m_mouse);
  }

さて、各コントロールクラスは、ライブラリ全体で単一のオブジェクトに格納されているマウスおよびカーソルのパラメータへのアクセスを有します。CWndEventsクラスのChartEvent() ハンドラで新しい値を受け取るためには、それにイベントの現在のパラメータを送ることによって CMouseオブジェクトハンドラが呼び出されるべきです。呼び出しはすべてのコントロールのイベントを処理する前に実行されるので、マウスおよびカーソルのパラメータの関連する値は繰り返した型変換を必要とすることなくすべてのコントロールによって利用可能で、クラスフィールドに値が代入され相対的な相対的なY座標が計算されます。

//+------------------------------------------------------------------+
//| プログラムイベントの処理                                     |
//+------------------------------------------------------------------+
void CWndEvents::ChartEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
//--- 配列が空の場合は終了する
//--- イベントパラメータフィールドの初期化

//--- マウスパラメータを受け取る
   m_mouse.OnEvent(id,lparam,dparam,sparam);

//--- カスタムイベント
//--- インターフェースのコントロールイベントをチェックする
//--- マウス移動イベント
//--- チャートプロパティ変更イベント
  }

CSimpleButtonコントロールコードハンドラの一部を例として使いましょう。下記に示されているのはCSimpleButton::OnEvent()メソッドの短縮版です。(1) 現在カーソルが位置するサブウィンドウの番号 (2) カーソル座標 (3) マウスの左マウスの状態を受け取るためのCMouse オブジェクトメソッドの呼び出しを含む文字列は黄色で強調表示されています・   

//+------------------------------------------------------------------+
//| イベントハンドラ                                                    |
//+------------------------------------------------------------------+
void CSimpleButton::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
//--- カーソル移動イベントを処理する
   if(id==CHARTEVENT_MOUSE_MOVE)
     {
      //--- コントロールが隠れている場合は終了する
      if(!CElement::IsVisible())
         return;
      //--- フォームがブロックされている場合は終了する
      if(m_wnd.IsLocked())
         return;
      //--- サブウィンドウ番号が一致しない場合は終了する
      if(CElement::m_subwin!=CElement::m_mouse.SubWindowNumber())
         return;
      //--- ボタンがブロックされている場合は終了する
      if(!m_button_state)
         return;
      //--- フォーカスを定義する
      CElement::MouseFocus(CElement::m_mouse.X()>X() && CElement::m_mouse.X()<X2() && 
                           CElement::m_mouse.Y()>Y() && CElement::m_mouse.Y()<Y2());
      //--- マウスのボタンが押されていない場合は終了する
      if(!CElement::m_mouse.LeftButtonState())
         return;
      //--- 
      ...
      return;
     }
//...
  }

すべてのライブラリのコントロールクラスで適切な変更が実装されました。  


3. コントロールのグラフィックオブジェクト名からコントロールのIDとインデックスを受けとるメソッドは、以前は多くのライブラリーコントロールクラスで繰り返されていました。繰り返しを防ぐために、これらのメソッドは今ではCElement基本クラスに移されました。  

//+------------------------------------------------------------------+
//| 基本コントロールクラス                                               |
//+------------------------------------------------------------------+
class CElement
  {
protected:
   //--- ボタン名からIDを受け取る
   int               IdFromObjectName(const string object_name);
   //--- メニューオプション名からインデックスを受け取る
   int               IndexFromObjectName(const string object_name);
  };

 

4. ウィンドウを折りたたむ/展開するためのボタンを有効にするメソッドとヘッダーテキストレベルの位置づけを有効にするクラスをCWindowクラスに追加しました。

//+------------------------------------------------------------------+
//| コントロールのためのフォームを作成するクラス                     |
//+------------------------------------------------------------------+
class CWindow : public CElement
  {
private:
   //--- ヘッダーテキストレベルのインデント
   int               m_label_x_gap;
   int               m_label_y_gap;
   //--- ウィンドウを折りたたむ/展開するためのボタンの存在
   bool              m_roll_button;
   //---
public:
   //--- テキストレベルのインデント
   void              LabelXGap(const int x_gap)                              { m_label_x_gap=x_gap;                }
   void              LabelYGap(const int y_gap)                              { m_label_y_gap=y_gap;                }
   //--- ツールヒントボタンを使う
   void              UseRollButton(void)                                     { m_roll_button=true;                 }
  };

 

5. ウィンドウポインタ(CWindow)の存在を確認するためにCElementクラスにCheckWindowPointer()メソッドを追加しました。 CheckPointer() システムメソッドを使ってこのメソッドにポインタ型を送り正しさを確認します。以前は、作成前に、同じコードがメインコントロール作成メソッド内でのすべてのコントロールクラスで繰り返されていました。CElement::CheckWindowPointer()メソッドはこの工程を簡易化し、コード量を削減してより多才化します。 

//+------------------------------------------------------------------+
//| 基本コントロールクラス                                               |
//+------------------------------------------------------------------+
class CElement
  {
protected:
   //--- フォームへのポインタの存在を確認する
   bool              CheckWindowPointer(ENUM_POINTER_TYPE pointer_type);
  };
//+------------------------------------------------------------------+
//| フォームへのポインタの存在を確認する                     |
//+------------------------------------------------------------------+
bool CElement::CheckWindowPointer(ENUM_POINTER_TYPE pointer_type)
  {
//--- フォームへのポインタが存在しない場合
   if(pointer_type==POINTER_INVALID)
     {
      //--- メッセージを生成する
      string message=__FUNCTION__+" > Before creating the control, the pointer to the form: "+ClassName()+"::WindowPointer(CWindow &object)" should be sent;
      //--- メッセージを端末のジャーナルに送る
      ::Print(message);
      //--- アプリケーションのグラフィカルインターフェースの作成に割り込む
      return(false);
     }
//--- ポインタ存在の属性を送る
   return(true);
  }

ここで単にCElement::CheckWindowPointer()メソッドを呼び出して、下記のコードでみられるように、コントロールが取り付けられるフォームへのポインタの存在を確認します(CSimpleButtonクラスでの単純なボタンの作成)。適切な変更は、すべてのライブラリのコントロールクラスで実装されました。 

//+------------------------------------------------------------------+
//| 「シンプルボタン」コントロールの作成                                |
//+------------------------------------------------------------------+
bool CSimpleButton::CreateSimpleButton(const long chart_id,const int subwin,const string button_text,const int x,const int y)
  {
//--- フォームへのポインタが存在しない場合は終了する
   if(!CElement::CheckWindowPointer(::CheckPointer(m_wnd)))
      return(false);
//--- 変数を初期化する
   m_id          =m_wnd.LastId()+1;
   m_chart_id    =chart_id;
   m_subwin      =subwin;
   m_x           =x;
   m_y           =y;
   m_button_text =button_text;
//--- エッジポイントからのインデント
   CElement::XGap(m_x-m_wnd.X());
   CElement::YGap(m_y-m_wnd.Y());
//--- ボタンを作成する
   if(!CreateButton())
      return(false);
//--- ダイアログウィンドウか最小化されたウィンドウの場合はコントロールを非表示にする
   if(m_wnd.WindowType()==W_DIALOG || m_wnd.IsMinimized())
      Hide();
//---
   return(true);
  }

 

6. コントロールが取り付けられているフォームの幅が変更した場合のコントロール幅の自動変更モードを CElement基本クラスに追加しました。このモードの設定にはCElement::AutoXResizeMode()メソッドが使われます。このモードでは、コントロールの右端はフォームの右端に固定されています。さらに、フォームの右端からのインデントの設定と受け取りのためのCElement::AutoXResizeRightOffset() メソッドを追加しました。 

//+------------------------------------------------------------------+
//| 基本コントロールクラス                                               |
//+------------------------------------------------------------------+
class CElement
  {
protected:
   //--- コントロール幅の自動変更モード
   bool              m_auto_xresize_mode;
   //--- コントロール幅自動変更モードでのフォームの右端からのインデント
   int               m_auto_xresize_right_offset;
   //---
public:
   //--- (1) コントロール幅自動変更モード (2) フォームの右端からのインデントの設定と受け取り
   bool              AutoXResizeMode(void)                    const { return(m_auto_xresize_mode);         }
   void              AutoXResizeMode(const bool flag)               { m_auto_xresize_mode=flag;            }
   int               AutoXResizeRightOffset(void)             const { return(m_auto_xresize_right_offset); }
   void              AutoXResizeRightOffset(const int offset)       { m_auto_xresize_right_offset=offset;  }
  };

デフォルトでは、コントロールの右端とフォームの右端の固定は無効になっていて(false)インデントは0に等しいです。初期化はCElementクラスコンストラクタで行われます(コードは下記参照)。 

//+------------------------------------------------------------------+
//| コンストラクタ                                                   |
//+------------------------------------------------------------------+
CElement::CElement(void) : m_auto_xresize_mode(false),
                           m_auto_xresize_right_offset(0)
  {
  }

フォーム幅を変更するCWindow::ChangeWindowWidth() メソッドは以前にすでにCWindowクラスに作成されました。 ここでは、モードが有効になっている場合は、グラフィカルインターフェースが指標サブウィンドウに実装されている場合にのみフォームの幅が自動的に変更されます。 言葉を変えると、チャートウィンドウの幅はフォームのイベントハンドラでCHARTEVENT_CHART_CHANGEイベントによって変えられ、フォームの幅が変更されます。 

//--- チャートプロパティ変更イベント
   if(id==CHARTEVENT_CHART_CHANGE)
     {
      //--- ボタンが離された場合
      if(m_clamping_area_mouse==NOT_PRESSED)
        {
         //--- チャートウィンドウサイズを受け取る
         SetWindowProperties();
         //--- 座標を直す
         UpdateWindowXY(m_x,m_y);
        }
      //--- モードが有効な場合はサイズを変える
      if(CElement::AutoXResizeMode())
         ChangeWindowWidth(m_chart.WidthInPixels()-2);
      //---
      return;
     }

ライブラリのイベントIDリストには ON_WINDOW_CHANGE_SIZEが新しく追加されました。このIDは、フォームサイズ変更メッセージを生成するために使用されます。 

//+------------------------------------------------------------------+
//|                                                      Defines.mqh |
//|                        Copyright 2015, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
...
//--- イベントID
#define ON_WINDOW_CHANGE_SIZE     (3)  // ウィンドウサイズを変更する
...

このようなメッセージの生成はCWindow::ChangeWindowWidth()メソッドに追加されました。このメソッドの簡略版を以下に示します。 

//+------------------------------------------------------------------+
//| ウィンドウ幅を変更する                                          |
//+------------------------------------------------------------------+
void CWindow::ChangeWindowWidth(const int width)
  {
//--- 幅が変更していない場合は終了する
//--- 背景とヘッダ幅を更新する
//--- 座標とすべてのボタンのインデントを更新する
//    Closeボタン
//--- Unfoldボタン
//--- Foldボタン
//--- ツールヒントボタン(有効な場合)

//--- ウィンドウサイズ変更メッセージ
   ::EventChartCustom(m_chart_id,ON_WINDOW_CHANGE_SIZE,(long)CElement::Id(),0,””);
  }

メッセージはライブラリエンジン( CWndEventsクラス)で処理されます。 CElement基本コントロールクラスにChangeWidthByRightWindowSide()仮想メソッドを追加しました。 多数の派生クラスでのメソッド実装を変更しました(コントロール幅の変更が必要なところで)。  

//+------------------------------------------------------------------+
//| 基本コントロールクラス                                               |
//+------------------------------------------------------------------+
class CElement
  {
public:
   //--- 幅をウィンドウの右端から変える
   virtual void      ChangeWidthByRightWindowSide(void) {}
  };

ON_WINDOW_CHANGE_SIZEイベントの到着後、適切なモードが有効な場合はコントロールの幅はCWndEventsクラスで変更できます。CWndEvents::OnWindowChangeSize()メソッドはこのために実装されました。 

//+------------------------------------------------------------------+
//| イベント処理クラス                                             |
//+------------------------------------------------------------------+
class CWndEvents : public CWndContainer
  {
private:
   //--- ウィンドウサイズの変更を処理する
   bool              OnWindowChangeSize(void);
  };
//+------------------------------------------------------------------+
//| ON_WINDOW_CHANGE_SIZEイベント                                      |
//+------------------------------------------------------------------+
bool CWndEvents::OnWindowChangeSize(void)
  {
//--- 「Change control size(コントロールサイズ変更)」シグナルの場合
   if(m_id!=CHARTEVENT_CUSTOM+ON_WINDOW_CHANGE_SIZE)
      return(false);
//--- アクティブウィンドウのインデックス
   int awi=m_active_window_index;
//--- ウィンドウIDが一致した場合
   if(m_lparam!=m_windows[awi].Id())
      return(true);
//--- フォーム以外のすべてのコントロールの幅を変える
   int elements_total=CWndContainer::ElementsTotal(awi);
   for(int e=0; e<elements_total; e++)
     {
      if(m_wnd[awi].m_elements[e].ClassName()=="CWindow")
         continue;
      //---
      if(m_wnd[awi].m_elements[e].AutoXResizeMode())
         m_wnd[awi].m_elements[e].ChangeWidthByRightWindowSide();
     }
//---
   return(true);
  }

メソッドはCWndEvents::ChartEventCustom()ライブラリイベントを処理するメインメソッドで呼び出されます。 

//+------------------------------------------------------------------+
//| CHARTEVENT_CUSTOMイベント                                        |
//+------------------------------------------------------------------+
void CWndEvents::ChartEventCustom(void)
  {
//--- フォームを折りたたむシグナル
//--- フォームを展開するシグナル

//--- コントロールサイズを変更するシグナル
   if(OnWindowChangeSize())
      return;

//--- 初期からコンテキストメニューを非表示にするためのシグナル
//--- コンテキストメニューをすべて非表示にするシグナル
//--- ダイアログウィンドウを開くシグナル
//--- ダイアログウィンドウを閉じるシグナル
//--- 指定されたフォームでのコントロールの色をリセットするシグナル
//--- マウスの左クリックの優先順位をリセットするシグナル
//--- マウスの左クリックの優先順位を元に戻すシグナル
  }

現在、コントロールが取り付けられているフォーム幅に相対してコントロール幅を変更するChangeWidthByRightWindowSide()メソッドは下記のクラスに存在します。

  • CTabs – シンプルなタブ
  • CIconTabs – 画像付きのタブ
  • CStatusBar – ステータスバー
  • CMenuBar – メインメニュー
  • CLabelsTable – テキストレベルテーブル
  • CTable – 編集ボックステーブル
  • CCanvasTable – レンダーテーブル
  • CProgressBar – プログレスバー
  • CTreeView – ツリービュー
  • CFileNavigator – ファイルナビゲータ
  • CLineGraph – 線チャート

CLabelsTable型のコントロールのメソッドコードは下に例として表示されています。 

//+------------------------------------------------------------------+
//| マージンの右端によって幅を変更する              |
//+------------------------------------------------------------------+
void CLabelsTable::ChangeWidthByRightWindowSide(void)
  {
//--- 座標
   int x=0;
//--- サイズ
   int x_size=0;
//--- テーブル背景の新しいサイズを計算して設定する
   x_size=m_wnd.X2()-m_area.X()-m_auto_xresize_right_offset;
   CElement::XSize(x_size);
   m_area.XSize(x_size);
   m_area.X_Size(x_size);
//--- 縦スクロールバーの新しい座標を計算して設定する
   x=m_area.X2()-m_scrollv.ScrollWidth();
   m_scrollv.XDistance(x);
//--- 横スクロールバーの新しい座標を計算して設定する
   x_size=CElement::XSize()-m_scrollh.ScrollWidth()+1;
   m_scrollh.ChangeXSize(x_size);
//--- オブジェクトの位置を更新する
   Moving(m_wnd.X(),m_wnd.Y());
  }


7. 作成後にプログラムでタブを切り替える機能を追加しました。SelectTab()メソッドがCTabsおよびCIconTabsクラスで実装されました。下のコードはCTabsクラスのメソッドを例として示します。

//+------------------------------------------------------------------+
//| タブ作成クラス                                          |
//+------------------------------------------------------------------+
class CTabs : public CElement
  {
public:
   //--- 指定されたタブを強調表示する
   void              SelectTab(const int index);
  };
//+------------------------------------------------------------------+
//| タブを強調表示する                                                |
//+------------------------------------------------------------------+
void CTabs::SelectTab(const int index)
  {
   for(int i=0; i<m_tabs_total; i++)
     {
      //--- タブが選択された場合
      if(index==i)
        {
         //--- 座標
         int x=0;
         int y=0;
         //--- サイズ
         int x_size=0;
         int y_size=0;
         //--- 強調表示されたタブインデックスを保存する
         SelectedTab(index);
         //--- 色を設定する
         m_tabs[i].Color(m_tab_text_color_selected);
         m_tabs[i].BackColor(m_tab_color_selected);
         //--- タブの位置に相対した計算
         CalculatingPatch(x,y,x_size,y_size);
         //--- 値を更新する
         m_patch.X_Size(x_size);
         m_patch.Y_Size(y_size);
         m_patch.XGap(x-m_wnd.X());
         m_patch.YGap(y-m_wnd.Y());
         //--- オブジェクトの位置を更新する
         Moving(m_wnd.X(),m_wnd.Y());
        }
      else
        {
         //--- アクティブでないタブの色を設定する
         m_tabs[i].Color(m_tab_text_color);
         m_tabs[i].BackColor(m_tab_color);
        }
     }
//--- 強調表示されたタブのコントロールのみを表示する
   ShowTabElements();
  }

 

8. 入力ボックステーブル(CTable)の行を再びクリックして選択を解除する機能を追加しました。

9. 「column_row_text」形式を持った文字列は、セル編集モードが無効な場合にテーブルセル(CTable)がクリックされたときに生成されたイベントで文字列パラメータ(sparam)として送られます。

10. マウスボタンのクリック領域を定義するための列挙とメソッドを修正しました。今ではすべてのコントロールで左マウスボタンクリック領域を追跡するにはENUM_MOUSE_STATE列挙が使われます。

11. 指標タイプのアプリケーションでのファイル名の長さの制限のため、ライブラリ内のリソースとして使用されるいくつかの画像ファイルの名前を変更しました。

12. また、いくつかの小規模な視覚改善と修正が行われました。検出されたエラーのいくつかはMetaTrader 4でのみ見られます。 


更新版を検証するためのアプリケーション

それでは、上記の更新のすべての検証を可能にするアプリケーションを開発してみましょう。「エキスパート」と「指標」の2つのアプリケーションバージョンを作成します 。指標のグラフィカルインターフェイスはチャートサブウィンドウに配置されるためウィンドウ幅のチャートウィンドウ幅への自動フィッティングの検証だけではなく、要素が取り付けられているウィンドウに合わせてその幅を調整するかの検証も可能です。 

現在存在するコントロールの種類はすべて、本格的なテストのためにグラフィカルインタフェースで実装される必要があります。できるだけスペース効率を上げるために、コントロールは別々のタブ(CTabs)に配置されます。コントロールのリストがかなり大きいので、作成メソッドの実装は別のファイルに配置するのが妥当でしょう。そのファイルをMainWindow.mqhと名付けましょう。これは、他のプロジェクトファイルが位置するフォルダに保存されます。以下のコードが示すように、これはカスタムクラスのボディの直後に接続される必要があります

//+------------------------------------------------------------------+
//|                                                      Program.mqh |
//|                        Copyright 2015, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#include <EasyAndFastGUI\Controls\WndEvents.mqh>
//+------------------------------------------------------------------+
//| アプリケーション作成クラス                               |
//+------------------------------------------------------------------+
class CProgram : public CWndEvents
  {

//...

  };
//+------------------------------------------------------------------+
//| コントロールを作成する                                                  |
//+------------------------------------------------------------------+
#include "MainWindow.mqh"

Program.mqhMainWindow.mqhと関連付けられるべきです。 

//+------------------------------------------------------------------+
//|                                                   MainWindow.mqh |
//|                        Copyright 2015, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#include "Program.mqh"

Program.mqhファイルでは、 すべてのコントロール作成メソッドが呼び出されるプログラムのグラフィカルインタフェースを作成するためのメインファイルのみを残すことが合理的です。 

テストアプリケーションのグラフィカルインターフェイスには合計で8つのタブが含まれます。下のスクリーンショットは、コントロールの位置を示します。1番目のタブは、(ボタングループを含む)すべてのボタンの種類と垂直スクロールバー付きのリストを含みます。「Simple Button 3」には2つのモードがあります。有効にされた場合、プロセスの実行をシミュレートするプログレスバーコントロールが見えるようになります。  

 図3 1番目のタブのグラフィカルインタフェースのコントロールのグループ

図3 1番目のタブのグラフィカルインタフェースのコントロールのグループ


「Simple Button 3」が有効にされると、ステータスバー領域にプログレスバーが表示されます(下記のスクリーンショットを参照)。

 図4 プログレスバーコントロール

図4 プログレスバーコントロール


2~4番目のタブには異なる種類のテーブルが含まれます。

 図5 2番目のタブのグラフィカルインターフェースのコントロールのグループ

図5 2番目のタブのグラフィカルインターフェースのコントロールのグループ

 

 図6。3番目のタブのグラフィカルインターフェースのコントロールのグループ

図6。3番目のタブのグラフィカルインターフェースのコントロールのグループ

 

図7 4番目のタブのグラフィカルインターフェースのコントロールのグループ 

図7 4番目のタブのグラフィカルインターフェースのコントロールのグループ


5番目のタブには折れ線グラフのコントロールが含まれます。操作に使われるメソッドはCProgramクラスで宣言されて実装されています。CProgram::OnTimerEvent()タイマーはランダムなシリーズを300ミリ秒ごとに生成します。

 図8 5番目のタブのグラフィカルインターフェースのコントロールのグループ

図8 5番目のタブのグラフィカルインターフェースのコントロールのグループ


6番目と7番目のタブは、ツリービューとファイルナビゲーターだけでなく、様々な種類のコンボボックス、入力フィールドとチェックボックスを含みます。

 図9 6番目のタブのグラフィカルインターフェースのコントロールのグループ

図9 6番目のタブのグラフィカルインターフェースのコントロールのグループ

 

図10 7番目のタブのグラフィカルインターフェースのコントロールのグループ 

図10 7番目のタブのグラフィカルインターフェースのコントロールのグループ


7番目のタブには、カレンダー、ドロップダウンカレンダー、スライダー、デュアルスライダー、セパレータとカラーパレットのボタンのコントロールが含まれています。

 図11 8番目のタブのグラフィカルインターフェースのコントロールのグループ

図11 8番目のタブのグラフィカルインターフェースのコントロールのグループ


カラーパレットウィンドウをメインチャートウィンドウで作成したい場合は、作成メソッドで、フォームとそれに取り付けられるコントロールの両方にゼロインデックスを与えます。ここでは、フォームにはコントロールは1つだけ(カラーパレット)取り付けられています。下のスクリーンショットが最終結果を示します。

 図12 メインチャートウィンドウでのカラーパレットコントロール

図12 メインチャートウィンドウでのカラーパレットコントロール


前述したように、検証には、同じグラフィカルインターフェースを持つもう1つのアプリケーション(エキスパート)も作成されました。

 図13 エキスパートアプリケーションの検証

図13 エキスパートアプリケーションの検証


両アプリケーションタイプ(エキスパートと指標)はMetaTrader 4MetaTrader 5の2つのプラットフォームのために実装されました。すべての必要なファイルは以下に添付されています。

 

 


おわりに

開発の現段階では、以下の図に示されたような結果が得られるはずです。

 図14 開発の現段階でのライブラリの構造

図14 開発の現段階でのライブラリの構造


興味をもったユーザの皆さんからの要求によって多数の修正と更新が実装されてきました。何かを欠いているか、アプリケーションを開発する際にライブラリに関連するバグを検出したら、記事へのコメント欄または個人的なメッセージを経由してコメントをお書きください。 喜んでお力になります。私はすでにライブラリーの次のバージョン(ビルド3)に取り組んでいます。ビルド3には多数の追加機能が存在し、ライブラリの新しいレベルが達成されています。 

本稿に記載されているテストアプリケーションに加えて、下記のアーカイブにはシリーズの以前の記事すべてからのテストEAと指標の更新されたバージョンが含まれています。

MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/2634

添付されたファイル |
キャンバスクラスの学習。アンチエイリアスと影 キャンバスクラスの学習。アンチエイリアスと影
キャンバスクラスのアンチエイリアシングアルゴリズムは、アンチエイリアスが使用されているすべての構造の基本です。この記事では、アルゴリズムがどのように動作するかについて扱い、可視化に関連する例を示します。また、グラフィックオブジェクトの描画の色合いをカバーし、キャンバス上の図形を描画するために開発された詳細なアルゴリズムがあります。数値解析ライブラリALGLIBは、計算に使用します。
グラフィカルインタフェースIX:プログレスバーと折れ線グラフコントロール(チャプター2) グラフィカルインタフェースIX:プログレスバーと折れ線グラフコントロール(チャプター2)
第九部の第2章はプログレスバーと折れ線グラフに専念されます。いつものように、これらのコントロールがカスタムMQLアプリケーションでどのように使用できるかを明らかにする詳細な実施例が存在します。
トレーディングロボットのためのFalseトリガー保護 トレーディングロボットのためのFalseトリガー保護
取引システムの収益は、ロジックのアルゴリズムの品質にだけでなく、ロジックや金融商品のダイナミクスの解析の精度により、決定されます。Falseトリガーは、取引ロボットのメイン・ロジックを低品質なものにします。指定された問題を解決する方法は、この記事で考慮されています。
MQLのソケットの使用およびシグナルプロバイダになる方法 MQLのソケットの使用およびシグナルプロバイダになる方法
現代の情報社会はソケットの存在なしに成り立つでしょうか?1982年に登場し現在までほぼ変わることなく、ソケットは私達の為に毎秒動いています。これは私達が暮らすマトリックスの神経終末ネットワークのベースです。