グラフィカルインタフェ-スを備えたエキスパ-トアドバイザ:パネルの作成(第1部)

Anatoli Kazharski | 13 8月, 2018

目次

概論

algotradeが積極的に開発されているにもかかわらず、多くのトレーダーは依然として手動取引を好んでいます。しかし、ここでは、日常的な操作の自動化は避けることができないと思います。

この記事では、手動取引のためのマルチシンボルシグナルエキスパートアドバイザーの作成について説明します。一例として、端末標準配信のインジケータシグナルStochasticから見てみましょう。このコードは、グラフィカルインターフェイスを使用して独自のエキスパートを作成するために使用できます。他のインジケータに接続したり、特定の計算結果を使用して意思決定を行うことができます。

顧客からの注文を受け付けている人にとっては、この記事は、顧客にデモンストレーションするための技術的タスクの例として役立ちます。またこの例は、グラフィカルインタフェースを持つプログラムを理解できるプログラマーのために、プログラム仕様をコンパイルする時間を短縮するのに役立つかもしれません。

ここで詳細する問題をリストアップしましょう。

この記事は2つの部に分かれて掲載されます。この記事では、パネルの作成を見ていき、次の部では、その機能について説明します。

グラフィカルインタフェースの要素

エキスパートの開発は、ユーザーとのやりとりやデータの視覚化を実現するグラフィカルインターフェイスの構築から始まります。標準ライブラリの機能を使用してグラフィカルインタフェースを作成できますが、私の例ではEasyAndFastライブラリに基づいて実装されます。その豊富な機能により、グラフィック部分のリビジョンに気を取られることなく、プログラム自体の機能に集中することができます。

まず、グラフィカルインタフェースの一般的なスキームの概要を説明します。下の図は、GUIウィンドウに2つのタブのグループがあることを示しています。リストには、それらに配置する必要がある機能が表示されます。これは単純化された例であり、発注者と実行者は議論を行い、より詳細に作成することもできます。


図 1. 説明付きグラフィカルインターフェースの一般図。

多くのGUIコントロールがあります。したがって、最初に階層的な形式でそれらをリストアップします。

プログラムのメインクラス(CProgram)は、上記の要素のクラスのメソッドとインスタンスを宣言します。要素を作成するメソッドのコードは別のファイルに入れられ、MQLプログラムのクラスのファイルに接続します

//+------------------------------------------------------------------+
// |アプリケーションを作成するクラス                                      |
//+------------------------------------------------------------------+
class CProgram : public CWndEvents
  {
private:
   // --- ウィンドウ
   CWindow           m_window1;
   // --- ステータスバー
   CStatusBar        m_status_bar;
   // --- タブ
   CTabs             m_tabs1;
   // --- 入力フィールド
   CTextEdit         m_symb_filter;
   CTextEdit         m_lot;
   CTextEdit         m_up_level;
   CTextEdit         m_down_level;
   CTextEdit         m_chart_scale;
   // --- ボタン
   CButton           m_request;
   CButton           m_chart_shift;
   CButton           m_buy;
   CButton           m_sell;
   CButton           m_close_all;
   //--- コンボボックス
   CComboBox         m_timeframes;
   //--- チェックボックス
   CCheckBox         m_date_scale;
   CCheckBox         m_price_scale;
   CCheckBox         m_show_indicator;
   // --- 表
   CTable            m_table_positions;
   CTable            m_table_symb;
   //--- 標準チャート
   CStandardChart    m_sub_chart1;
   // --- 実行インジケータ
   CProgressBar      m_progress_bar;
   //---
public:
   // --- グラフィカルインタフェースを作成する
   bool              CreateGUI(void);
   //---
private:
   // --- フォーム
   bool              CreateWindow(const string text);
   // --- ステータスバー
   bool              CreateStatusBar(const int x_gap,const int y_gap);
   // --- タブ
   bool              CreateTabs1(const int x_gap,const int y_gap);
   // --- 入力フィールド
   bool              CreateSymbFilter(const int x_gap,const int y_gap,const string text);
   bool              CreateLot(const int x_gap,const int y_gap,const string text);
   bool              CreateUpLevel(const int x_gap,const int y_gap,const string text);
   bool              CreateDownLevel(const int x_gap,const int y_gap,const string text);
   bool              CreateChartScale(const int x_gap,const int y_gap,const string text);
   // --- ボタン
   bool              CreateRequest(const int x_gap,const int y_gap,const string text);
   bool              CreateChartShift(const int x_gap,const int y_gap,const string text);
   bool              CreateBuy(const int x_gap,const int y_gap,const string text);
   bool              CreateSell(const int x_gap,const int y_gap,const string text);
   bool              CreateCloseAll(const int x_gap,const int y_gap,const string text);
   //--- コンボボックス
   bool              CreateComboBoxTF(const int x_gap,const int y_gap,const string text);
   //--- チェックボックス
   bool              CreateDateScale(const int x_gap,const int y_gap,const string text);
   bool              CreatePriceScale(const int x_gap,const int y_gap,const string text);
   bool              CreateShowIndicator(const int x_gap,const int y_gap,const string text);
   // --- 表
   bool              CreatePositionsTable(const int x_gap,const int y_gap);
   bool              CreateSymbolsTable(const int x_gap,const int y_gap);
   //--- 標準チャート
   bool              CreateSubChart1(const int x_gap,const int y_gap);
   // --- 実行インジケータ
   bool              CreateProgressBar(const int x_gap,const int y_gap,const string text);
  };
//+------------------------------------------------------------------+
// |コントロール要素を作成するメソッド                                    |
//+------------------------------------------------------------------+
#include "CreateGUI.mqh"
//+------------------------------------------------------------------+

次に、GUIのアセンブリ、要素の作成方法、およびそのプロパティについて詳しく見ていきます。

GUIを構築する

さて、開発されたアプリケーションのグラフィカルインタフェースには、10種類の要素が使用されます。

このリストにはいくつかの要素がありますので、各グループを1つずつ見ていきましょう。同じ順序で、それらを作成する方法を紹介します。 

コントロール要素のフォーム

以下は、他のすべての要素が配置されるフォームを作成するためのメソッドコードです。始めにプログラムのGUI要素のリストにフォームを追加する必要があります。これを行うには、すCWndContainer :: AddWindow()メソッドを呼び出し、CWindow型の要素のオブジェクトを渡す必要があります。それから、フォームを作成する前に、このプロパティを設定します。以下のプロパティを設定します(以下のリストと同じ順番で)。

プロパティが設定されたら、フォーム作成メソッドCWindow :: CreateWindow()を呼び出し、ここに引き渡す必要があります。

//+------------------------------------------------------------------+
// |コントロールのフォームを作成します。                                  |
//+------------------------------------------------------------------+
bool CProgram::CreateWindow(const string caption_text)
  {
//--- ウィンドウの配列にウィンドウポインタを追加する
   CWndContainer::AddWindow(m_window1);
// ---プロパティ
   m_window1.XSize(750);
   m_window1.YSize(450);
   m_window1.FontSize(9);
   m_window1.IsMovable(true);
   m_window1.ResizeMode(true);
   m_window1.CloseButtonIsUsed(true);
   m_window1.CollapseButtonIsUsed(true);
   m_window1.TooltipsButtonIsUsed(true);
   m_window1.FullscreenButtonIsUsed(true);
// --- ツールチップを設定する
   m_window1.GetCloseButtonPointer().Tooltip("Close");
   m_window1.GetTooltipButtonPointer().Tooltip("Tooltips");
   m_window1.GetFullscreenButtonPointer().Tooltip("Fullscreen");
   m_window1.GetCollapseButtonPointer().Tooltip("Collapse/Expand");
// ---フォームを作成する
   if(!m_window1.CreateWindow(m_chart_id,m_subwin,caption_text,1,1))
      return(false);
//---
   return(true);
  }

GUIの新しい要素をコードに追加するたびに、プログラムをコンパイルし、その結果がどうなるかを確認することが望ましいです。 

図2  - コントロールのフォーム

図2. コントロールのフォーム

以下はすべての中間結果のスクリーンショットです。

ステータス文字列

ステータス行を作成するためのメソッドコードは、メイン要素の設定から始まります。そこから、それに結び付けられた要素のサイズに対する位置合わせと位置づけが計算されます。これにより、アプリケーションを開発するときの時間が節約されます。関連する要素のグループ全体を移動し、主なものの座標のみを変更することができます。要素をバインドするには、そのポインタをCElement :: MainPointer()メソッドに渡します。この例では、ステータスバーをフォームにバインドするので、メソッドにフォームオブジェクトを渡します

次に、ステータス行のプロパティを設定します。その中で私たちはユーザーの情報が表示される3つのポイントを作ります。 

プロパティが設定されたら、要素を作成します。これで作業の準備が整い、実行時にその段落のテキストを変更できます。この例ではテキストの最初の段落に『ヘルプが必要な場合、F1キーを押す』を設定します。  

メソッドの終わりに、作成した項目のインデックスをGUIエレメントの一般的なリストに保存する必要があります。これを行うには、CWndContainer :: AddToElementsArray()メソッドを呼び出し、フォームのインデックスと要素のオブジェクトを渡します。1つのフォームしかないので、インデックスは0になります。

//+------------------------------------------------------------------+
// | ステータス行を作成します。                                          |
//+------------------------------------------------------------------+
bool CProgram::CreateStatusBar(const int x_gap,const int y_gap)
  {
#define STATUS_LABELS_TOTAL 3
//--- ウィンドウにポインタを保存する
   m_status_bar.MainPointer(m_window1);
// ---プロパティ
   m_status_bar.AutoXResizeMode(true);
   m_status_bar.AutoXResizeRightOffset(1);
   m_status_bar.AnchorBottomWindowSide(true);
// --- いくつの部分が必要かを指定して、プロパティを設定します
   int width[STATUS_LABELS_TOTAL]={0,200,110};
   for(int i=0; i<STATUS_LABELS_TOTAL; i++)
      m_status_bar.AddItem(width[i]);
// --- コントロール要素を作成します
   if(!m_status_bar.CreateStatusBar(x_gap,y_gap))
      return(false);
// --- ステータスバーの項目にテキストを設定する
   m_status_bar.SetValue(0,"For Help, press F1");
// --- オブジェクトグループの一般配列にオブジェクトを追加します
   CWndContainer::AddToElementsArray(0,m_status_bar);
   return(true);
  }

EasyAndFastライブラリの残りの要素も同じ原則で作成されます。したがって、以下はエキスパートアドバイザーに使用する、指定プロパティのみを見ていきます。

図3  - ステータス行の追加

図3.ステータス行の追加

タブグループ

タブグループを作成するメソッドの中に、以下のプロパティを要素に設定します。

メソッドコードは次のとおりです。

//+------------------------------------------------------------------+
// |タブ1のグループを作成します。                                        |
//+------------------------------------------------------------------+
bool CProgram::CreateTabs1(const int x_gap,const int y_gap)
  {
#define TABS1_TOTAL 2
// ---ポインタをメインの要素に保存します
   m_tabs1.MainPointer(m_window1);
// ---プロパティ
   m_tabs1.IsCenterText(true);
   m_tabs1.PositionMode(TABS_TOP);
   m_tabs1.AutoXResizeMode(true);
   m_tabs1.AutoYResizeMode(true);
   m_tabs1.AutoXResizeRightOffset(3);
   m_tabs1.AutoYResizeBottomOffset(25);
// ---指定されたプロパティを持つタブを追加する
   string tabs_names[TABS1_TOTAL]={"Trade","Positions"};
   for(int i=0; i<TABS1_TOTAL; i++)
      m_tabs1.AddTab(tabs_names[i],100);
// --- コントロール要素を作成します
   if(!m_tabs1.CreateTabs(x_gap,y_gap))
      return(false);
// --- オブジェクトグループの一般配列にオブジェクトを追加します
   CWndContainer::AddToElementsArray(0,m_tabs1);
   return(true);
  }

図4  - タブのグループを追加する。

図4.タブのグループを追加する。

入力フィールド

例として、ユーザが通貨および/または通貨ペアを指定して表内のシンボルリストを作成できる入力フィールドを見ていきます。その主な要素はタブのグループになります。ここでは、この入力フィールドを表示するタブも指定する必要があります。これを行うには、 CTabs :: AddToElementsArray()メソッドを呼び出し、タブのインデックスと添付された要素のオブジェクトを渡します。

次に、この入力フィールドに設定されているプロパティを見ていきます。

要素タイプCTextEditは他のいくつかの要素で構成されています。したがって、プロパティを変更する必要がある場合は、そこへのポインタを取得できます。私達はいくつかのテキスト入力フィールドのプロパティ(CTextBox)を変更する必要があります。以下のコードリストで実装されているのと同じ順序でこれを見てい行きましょう。

デフォルトでは、入力フィールドのチェックボックスが有効になっています。これを行うには、 アイテムが作成された直後にアクティベートする必要があります

//+------------------------------------------------------------------+
// | 『Symbols filter』入力フィールドのチェックボックスを作成します。       |
//+------------------------------------------------------------------+
bool CProgram::CreateSymbolsFilter(const int x_gap,const int y_gap,const string text)
  {
// ---ポインタをメインの要素に保存します
   m_symb_filter.MainPointer(m_tabs1);
// ---タブに固定します
   m_tabs1.AddToElementsArray(0,m_symb_filter);
// ---プロパティ
   m_symb_filter.SetValue("USD"); // "EUR,USD" "EURUSD,GBPUSD" "EURUSD,GBPUSD,AUDUSD,NZDUSD,USDCHF"
   m_symb_filter.CheckBoxMode(true);
   m_symb_filter.AutoXResizeMode(true);
   m_symb_filter.AutoXResizeRightOffset(90);
   m_symb_filter.GetTextBoxPointer().XGap(100);
   m_symb_filter.GetTextBoxPointer().AutoXResizeMode(true);
   m_symb_filter.GetTextBoxPointer().AutoSelectionMode(true);
   m_symb_filter.GetTextBoxPointer().DefaultText("Example: EURUSD,GBP,NOK");
// --- コントロール要素を作成します
   if(!m_symb_filter.CreateTextEdit(text,x_gap,y_gap))
      return(false);
// --- チェックボックスをオンにする
   m_symb_filter.IsPressed(true);
// --- オブジェクトグループの一般配列にオブジェクトを追加します
   CWndContainer::AddToElementsArray(0,m_symb_filter);
   return(true);
  }

テキスト入力フィールドに加えて、グラフィカルインタフェースに数字のフィールドがあります。例えば、入力フィールドLot(ポジションを開くときのボリューム)です。このタイプの入力フィールドでは、他のプロパティを指定する必要があります。

このメソッドのコードは次のとおりです。

//+------------------------------------------------------------------+
// | 入力フィールド "Lot"を作成します。                                 |
//+------------------------------------------------------------------+
bool CProgram::CreateLot(const int x_gap,const int y_gap,const string text)
  {
// ---ポインタをメインの要素に保存します
   m_lot.MainPointer(m_tabs1);
// ---タブに固定します
   m_tabs1.AddToElementsArray(0,m_lot);
// ---プロパティ
   m_lot.XSize(80);
   m_lot.MaxValue(1000);
   m_lot.MinValue(0.01);
   m_lot.StepValue(0.01);
   m_lot.SetDigits(2);
   m_lot.SpinEditMode(true);
   m_lot.SetValue((string)0.1);
   m_lot.GetTextBoxPointer().XSize(50);
   m_lot.GetTextBoxPointer().AutoSelectionMode(true);
   m_lot.GetTextBoxPointer().AnchorRightWindowSide(true);
// --- コントロール要素を作成します
   if(!m_lot.CreateTextEdit(text,x_gap,y_gap))
      return(false);
// --- オブジェクトグループの一般配列にオブジェクトを追加します
   CWndContainer::AddToElementsArray(0,m_lot);
   return(true);
  }

図5  - 入力フィールドの追加。

図5.入力フィールドを追加。

画像はあまり論理的に見えませんが、他の要素を追加すると、すべてが適切に機能しています。

ボタン

私たちのエキスパートアドバイザーのグラフィカルインターフェイスにいくつかのボタンを追加します。最も多くの特性を持つもの、すなわち、SELLポジションを開くためのボタンを考えてみましょう。

同じようなプロパティがBUYボタンでも変更され、指定した背景色のみが異なります。

//+------------------------------------------------------------------+
// | 『SELL』ボタンを作成します。                                        |
//+------------------------------------------------------------------+
bool CProgram::CreateSell(const int x_gap,const int y_gap,const string text)
  {
// ---ポインタをメインの要素に保存する
   m_sell.MainPointer(m_tabs1);
// ---タブに固定します
   m_tabs1.AddToElementsArray(0,m_sell);
// ---プロパティ
   m_sell.XSize(80);
   m_sell.IsCenterText(true);
   m_sell.BackColor(C'255,51,51');
   m_sell.BackColorHover(C'255,100,100');
   m_sell.BackColorPressed(C'195,0,0');
   m_sell.LabelColor(clrWhite);
   m_sell.LabelColorHover(clrWhite);
   m_sell.LabelColorPressed(clrWhite);
   m_sell.BorderColor(clrBlack);
   m_sell.BorderColorHover(clrBlack);
   m_sell.BorderColorPressed(clrBlack);
// --- コントロール要素を作成します
   if(!m_sell.CreateButton(text,x_gap,y_gap))
      return(false);
// --- データベース内の要素へのポインタを追加する
   CWndContainer::AddToElementsArray(0,m_sell);
   return(true);
  }

図6  - ボタンを追加する。

図6. ボタンを追加する。

ドロップダウンリスト付きコンボボックス

時間枠を変更するために、ドロップダウンリストを持つコンボボックスを作成します。設定するプロパティをリストアップしましょう。

次に、リスト内の各項目に値が割り当てられ、いくつかのプロパティがリストへのポインタによって設定されます。

このコンボボックスを作成するためのメソッドコードを次に示します。

//+------------------------------------------------------------------+
// | 時間枠を選択するためのコンボボックスを作成します。                     |
//+------------------------------------------------------------------+
bool CProgram::CreateComboBoxTF(const int x_gap,const int y_gap,const string text)
  {
// --- リスト内のアイテムの総数
#define ITEMS_TOTAL2 21
// --- パネルオブジェクトを渡す
   m_timeframes.MainPointer(m_tabs1);
// ---タブに固定します
   m_tabs1.AddToElementsArray(0,m_timeframes);
// ---プロパティ
   m_timeframes.XSize(115);
   m_timeframes.ItemsTotal(ITEMS_TOTAL2);
   m_timeframes.AnchorRightWindowSide(true);
   m_timeframes.GetButtonPointer().XSize(50);
   m_timeframes.GetButtonPointer().AnchorRightWindowSide(true);
// --- コンボボックスのリストにアイテムの値を保存する
   string items_text[ITEMS_TOTAL2]={"M1","M2","M3","M4","M5","M6","M10","M12","M15","M20","M30","H1","H2","H3","H4","H6","H8","H12","D1","W1","MN"};
   for(int i=0; i<ITEMS_TOTAL2; i++)
      m_timeframes.SetValue(i,items_text[i]);
// --- リストポインタを取得する
   CListView *lv=m_timeframes.GetListViewPointer();
// --- リストのプロパティを設定する
   lv.LightsHover(true);
   lv.SelectItem(18);
// --- コントロール要素を作成します
   if(!m_timeframes.CreateComboBox(text,x_gap,y_gap))
      return(false);
// --- データベース内の要素へのポインタを追加する
   CWndContainer::AddToElementsArray(0,m_timeframes);
   return(true);
  }

図7  - コンボボックスを追加する。

図7. コンボボックスを追加する。

チェックボックス

チェックボックスは最も簡単な要素です。これは2つの特性を指定すれば十分です。

要素を作成した後、 プログラムでチェックボックスをオンにすることができます。

//+------------------------------------------------------------------+
// | 『Date scale』チェックボックスを作成します。                   |
//+------------------------------------------------------------------+
bool CProgram::CreateDateScale(const int x_gap,const int y_gap,const string text)
  {
//--- ウィンドウにポインタを保存する
   m_date_scale.MainPointer(m_tabs1);
// ---タブに固定します
   m_tabs1.AddToElementsArray(0,m_date_scale);
// ---プロパティ
   m_date_scale.XSize(70);
   m_date_scale.AnchorRightWindowSide(true);
// --- コントロール要素を作成します
   if(!m_date_scale.CreateCheckBox(text,x_gap,y_gap))
      return(false);
// ---チェックボックスを有効にする
   m_date_scale.IsPressed(true);
// --- オブジェクトグループの一般配列にオブジェクトを追加します
   CWndContainer::AddToElementsArray(0,m_date_scale);
   return(true);
  }

図8  - チェックボックスを追加する。

図8. チェックボックスを追加する。

GUIには2つのテーブルがあります。生成された記号と、ポジションを開くためのシグナルのリストを視覚化するものを見ていきます。これは最初のタブに配置されます。まず、配列の宣言と初期化を行い、表のプロパティを設定します。以下のプロパティを設定します。

ヘッダーのテキストは、表の作成後に指定することができます。

//+------------------------------------------------------------------+
// |シンボルテーブルを作成します。                                       |
//+------------------------------------------------------------------+
bool CProgram::CreateSymbolsTable(const int x_gap,const int y_gap)
  {
#define COLUMNS1_TOTAL 2
#define ROWS1_TOTAL    1
// ---ポインタをメインの要素に保存します
   m_table_symb.MainPointer(m_tabs1);
// ---タブに固定します
   m_tabs1.AddToElementsArray(0,m_table_symb);
// --- 列幅の配列
   int width[COLUMNS1_TOTAL]={95,58};
// --- 列内のテキスト整形配列
   ENUM_ALIGN_MODE align[COLUMNS1_TOTAL]={ALIGN_LEFT,ALIGN_RIGHT};
// --- X軸に沿った列のテキストインデントの配列
   int text_x_offset[COLUMNS1_TOTAL]={5,5};
// ---プロパティ
   m_table_symb.XSize(168);
   m_table_symb.TableSize(COLUMNS1_TOTAL,ROWS1_TOTAL);
   m_table_symb.ColumnsWidth(width);
   m_table_symb.TextAlign(align);
   m_table_symb.TextXOffset(text_x_offset);
   m_table_symb.ShowHeaders(true);
   m_table_symb.SelectableRow(true);
   m_table_symb.ColumnResizeMode(true);
   m_table_symb.IsZebraFormatRows(clrWhiteSmoke);
   m_table_symb.AutoYResizeMode(true);
   m_table_symb.AutoYResizeBottomOffset(2);
// --- コントロール要素を作成します
   if(!m_table_symb.CreateTable(x_gap,y_gap))
      return(false);
// --- ヘッダーのタイトルを設定する
   m_table_symb.SetHeaderText(0,"Symbol");
   m_table_symb.SetHeaderText(1,"Values");
// --- オブジェクトグループの一般配列にオブジェクトを追加します
   CWndContainer::AddToElementsArray(0,m_table_symb);
   return(true);
  }

2番目の表には、開いているポジションのいくつかのプロパティが表示されます。その10個の列には次のデータが表示されます。

2番目の表では、次のプロパティも設定する必要があります。

最初の列のセルに表示されている画像は、ボタンをクリックすると指定されたシンボル上で、ヘッジアカウントの場合はポジションまたはすべてのポジションを閉じることができます。 

//+------------------------------------------------------------------+
// | アイテムのテーブルを作成します。                                     |
//+------------------------------------------------------------------+
bool CProgram::CreatePositionsTable(const int x_gap,const int y_gap)
  {
...
// ---プロパティ
   m_table_positions.TableSize(COLUMNS2_TOTAL,ROWS2_TOTAL);
   m_table_positions.ColumnsWidth(width);
   m_table_positions.TextAlign(align);
   m_table_positions.TextXOffset(text_x_offset);
   m_table_positions.ImageXOffset(image_x_offset);
   m_table_positions.ImageYOffset(image_y_offset);
   m_table_positions.ShowHeaders(true);
   m_table_positions.IsSortMode(true);
   m_table_positions.SelectableRow(true);
   m_table_positions.ColumnResizeMode(true);
   m_table_positions.IsZebraFormatRows(clrWhiteSmoke);
   m_table_positions.AutoXResizeMode(true);
   m_table_positions.AutoYResizeMode(true);
   m_table_positions.AutoXResizeRightOffset(2);
   m_table_positions.AutoYResizeBottomOffset(2);
...
   return(true);
  }

図9  - 最初のタブに表を追加する。

図9. 最初のタブに表を追加する。

図10  -  2番目のタブに表を追加する。

図10. 2番目のタブに表を追加する。

メインプログラムファイルのテーブルを操作する方法について(CProgram)、私は次の記事の項目で記載したいと思います。

標準チャート

シンボルでデータを視覚化は、CStandardChart型要素が行います。デフォルトでは、毎日の時間枠にEURUSDチャートが表示されます。ここには以下の要素があります。

必要に応じて、水平方向に並べられたグラフの配列を作成することができます。これを行うには、 CStandardChart :: AddSubChart()メソッドを使用して、チャートのシンボルと時間枠を引数として渡します。しかしこの場合、チャートは1つだけ必要で、シンボルと時間枠は他のコントロールを使用して切り替えます。

//+------------------------------------------------------------------+
// | 標準グラフ1を作成する                                              |
//+------------------------------------------------------------------+
bool CProgram::CreateSubChart1(const int x_gap,const int y_gap)
  {
//--- ウィンドウにポインタを保存する
   m_sub_chart1.MainPointer(m_tabs1);
// --- タブ1に固定する
   m_tabs1.AddToElementsArray(0,m_sub_chart1);
// ---プロパティ
   m_sub_chart1.XScrollMode(true);
   m_sub_chart1.AutoXResizeMode(true);
   m_sub_chart1.AutoYResizeMode(true);
   m_sub_chart1.AutoXResizeRightOffset(125);
   m_sub_chart1.AutoYResizeBottomOffset(2);
// ---チャートを追加する
   m_sub_chart1.AddSubChart("EURUSD",PERIOD_D1);
// --- コントロール要素を作成します
   if(!m_sub_chart1.CreateStandardChart(x_gap,y_gap))
      return(false);
// --- オブジェクトグループの一般配列にオブジェクトを追加します
   CWndContainer::AddToElementsArray(0,m_sub_chart1);
   return(true);
  }

図11  - チャートを追加する。

図11. チャートを追加する。

進捗インジケータ

ユーザがプログラムが現在何をしているのかを理解するために、グラフィカルインタフェースに進捗インジケータを追加します。以下は、この例のプロパティです(コードと同じ順序)。

以下では、進行状況インジケータの使用例を示します。

//+------------------------------------------------------------------+
// |進行状況バーを作成します。                                           |
//+------------------------------------------------------------------+
bool CProgram::CreateProgressBar(const int x_gap,const int y_gap,const string text)
  {
// ---ポインタをメインの要素に保存します
   m_progress_bar.MainPointer(m_status_bar);
// ---プロパティ
   m_progress_bar.YSize(17);
   m_progress_bar.BarYSize(14);
   m_progress_bar.BarXGap(0);
   m_progress_bar.BarYGap(1);
   m_progress_bar.LabelXGap(5);
   m_progress_bar.LabelYGap(2);
   m_progress_bar.PercentXGap(5);
   m_progress_bar.PercentYGap(2);
   m_progress_bar.IsDropdown(true);
   m_progress_bar.Font("Consolas");
   m_progress_bar.BorderColor(clrSilver);
   m_progress_bar.IndicatorBackColor(clrWhiteSmoke);
   m_progress_bar.IndicatorColor(clrLightGreen);
   m_progress_bar.AutoXResizeMode(true);
   m_progress_bar.AutoXResizeRightOffset(2);
// ---要素を作成する
   if(!m_progress_bar.CreateProgressBar(text,x_gap,y_gap))
      return(false);
// --- データベース内の要素へのポインタを追加する
   CWndContainer::AddToElementsArray(0,m_progress_bar);
   return(true);
  }

私たちのエキスパートアドバイザーのグラフィカルインターフェイスで使用されるすべてのコントロールを紹介しました。現時点では、これは単なるグラフィカルシェルです。しかし、私たちは元の考え方に従ってこのすべての作業をするために必要なすべての方法を書いていきます。

EasyAndFastライブラリの更新

EasyAndFast内のCTableクラス内でCTable :: SortData()パブリックメソッドが完成しました。さて、第2引数として、表のソート方向(オプション)を指定することができます。以前は、CTable :: SortData()メソッドの再呼び出しは、現在のものとは逆の方向にソートを開始しました。また、現在のソート方向とソートされた列のインデックスを取得するメソッドが追加されました。ここでは、表がユーザによって手動で(ヘッダをクリックすることによって)ソートされ、表内のデータが同じ順序で更新されていない場合、現在のソート方向を見つけ出してそれを復元することができます。 

//+------------------------------------------------------------------+
// | 描画された表を作成するクラス                                        |
//+------------------------------------------------------------------+
class CTable : public CElement
  {
public:
...
   // --- 指定した列でデータをソートする
   void              SortData(const uint column_index=0,const int direction=WRONG_VALUE);
   // ---(1)現在のソート方向、(2)ソートされた配列のインデックス
   int               IsSortDirection(void)             const { return(m_last_sort_direction);    }
   int               IsSortedColumnIndex(void)         const { return(m_is_sorted_column_index); }
...
  };
//+------------------------------------------------------------------+
// | 指定した列ごとにデータをソートする                                                |
//+------------------------------------------------------------------+
void CTable::SortData(const uint column_index=0,const int direction=WRONG_VALUE)
  {
// ---表の外に出ると終了する
   if(column_index>=m_columns_total)
      return;
// --- ソートを開始するインデックス
   uint first_index=0;
// ---最後のインデックス
   uint last_index=m_rows_total-1;
// ---ユーザーの方向制御なし
   if(direction==WRONG_VALUE)
     {
      // ---最初の時間は昇順にソートされ、その後は逆の方向にソートされます
      if(m_is_sorted_column_index==WRONG_VALUE || column_index!=m_is_sorted_column_index || m_last_sort_direction==SORT_DESCEND)
         m_last_sort_direction=SORT_ASCEND;
      else
         m_last_sort_direction=SORT_DESCEND;
     }
   else
     {
      m_last_sort_direction=(ENUM_SORT_MODE)direction;
     }
// --- 最後にソートされたデータ列のインデックスを記憶する
   m_is_sorted_column_index=(int)column_index;
// --- ソート
   QuickSort(first_index,last_index,column_index,m_last_sort_direction);
  }

もう一つの小さな追加CKeysクラスのCKeys :: KeySymbolメソッドに追加されました。以前は、テンキーパッド(キーボードの右側にある個別のキーブロック)は処理されていませんでした。ここでは、キーボードのこのセクションから数字と特殊文字を入力できます。

//+------------------------------------------------------------------+
// | 押されたキーの文字を返します。                                                  |
//+------------------------------------------------------------------+
string CKeys::KeySymbol(const long key_code)
  {
   string key_symbol="";
// ---スペースを入力する必要がある場合( "Space"キー)
   if(key_code==KEY_SPACE)
     {
      key_symbol=" ";
     }
// ---アルファベット文字または(2)数字キー文字、または(3)特殊文字を入力する必要がある場合
   else if((key_code>=KEY_A && key_code<=KEY_Z) ||
           (key_code>=KEY_0 && key_code<=KEY_9) ||
           (key_code>=KEY_NUMLOCK_0 && key_code<=KEY_NUMLOCK_SLASH) ||
           (key_code>=KEY_SEMICOLON && key_code<=KEY_SINGLE_QUOTE))
     {
      key_symbol=::ShortToString(::TranslateKey((int)key_code));
     }
// ---シンボルを返す
   return(key_symbol);
  }

CTableCKeysクラスの新バージョンは記事の最後でダウンロードすることができます。

まとめ

この記事の第一部を読んでいただきました。ここでは、私たちは多大な労力を要することなく、複雑なプログラムのためのグラフィカルなインタフェースを作成する方法を分析しました。あなたはこのプログラムを開発して、あなた自身の目的のためにそれを使い続けることができます。この記事の第2部では、グラフィカルインターフェイスの使い方、最も重要な機能の記入方法を紹介します。 

以下から記事で紹介したコードをより詳しく知ったりテストを行うために、自分のPCにファイルをダウンロードすることができます。

ファイル名 コメント
MQL5\Experts\TradePanel\TradePanel.mq5 グラフィカルインターフェイスによる手動取引のエキスパートアドバイザー
MQL5\Experts\TradePanel\Program.mqh プログラムクラスファイル
MQL5\Experts\TradePanel\CreateGUI.mqh Program.mqhファイルのプログラムクラスからグラフィカルインターフェイスを作成するための実装方法を含むファイル
MQL5\Include\EasyAndFastGUI\Controls\Table.mqh 更新したCTableクラス
MQL5\Include\EasyAndFastGUI\Keys.mqh 更新したCKeysクラス