English Русский 中文 Español Deutsch Português 한국어 Français Italiano Türkçe
MQL5 クックブック: インジケーターサブウィンドウコンソールーボタン

MQL5 クックブック: インジケーターサブウィンドウコンソールーボタン

MetaTrader 5 | 24 11月 2015, 14:48
1 990 0
Anatoli Kazharski
Anatoli Kazharski

イントロダクション

この記事では、ボタンコンソールでユーザーインターフェースを開発する例を紹介します。ユーザーにインタラクティヴィティ性を伝えるため、ボタンはカーソルが図上にある際に色を変えます。ボタンの上にカーソルがある状態で、ボタンの色は、わずかに暗くなり、ボタンがクリックされた時には、わずかにより暗くなります。さらに、ツールチップをそれぞれのボタンに加え、直感的なインターフェースを作成します。

この記事はその他のイベントも扱っています:マウス移動イベント、左マウスボタンの状態、オブジェクトへの左クリック、チャートのプロパティ修正イベントなどです。インジケーターサブウィンドウの全スペースを占めるボタンパネルを作成していきます。ボタンは、3行にそれぞれ4つのボタンが配置されています。

 

開発

MQL5では、ボタンは様々なグラフィカルオブジェクトを用いて作成されており、OBJ_BUTTON (ボタン), OBJ_BITMAP (ビットマップ)、OBJ_BITMAP_LABEL (ビットマップラベル) やOBJ_EDIT (編集)などです。

この記事では、OBJ_EDITを用いて、ボタンを作成します。この種類のオブジェクトは、読み取り専用になっています。明記するテキストを表示できるので役に立ちます。さらに、オブジェクトの角を尖がらせることもできます。

それでは、MQL5ウィザードを用いて、インジケーターを作成しましょう。インジケーターのソースコードは以下のようになります;

//+------------------------------------------------------------------+
//|                                                  TestButtons.mq5 |
//|                        Copyright 2013, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2013, MetaQuotes Software Corp."
#property link      "http://www.mql5.com"
#property version   "1.00"
//---
#property indicator_separate_window // Indicator is in the subwindow
#property indicator_plots 0         // No plotting series
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping

//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const int begin,
                const double &price[])
  {
//---

//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
//| Timer function                                                   |
//+------------------------------------------------------------------+
void OnTimer()
  {
//---

  }
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//---

  }
//+------------------------------------------------------------------+

今あるのは、何も描画されていない空のウィンドウです。タイマーの必要性は後ほど考察します。

関数を作成する際に使用される配列や、変数、定数を追加しましょう。すべての配列は二次元です。1次元は、ウィンドウの高さを超えるボタンの数を示し、二次元はウィンドウの幅を超える超えるボタン数を意味します。

//---
#define BUTTON_COLUMNS  4           // Number of buttons across the width
#define BUTTON_ROWS 3               // Number of buttons across the height
//+------------------------------------------------------------------+
//| Global parameters                                                |
//+------------------------------------------------------------------+
//--- Font
string            font_name="Calibri";
//--- Indicator subwindow properties
int               subwindow_number           =WRONG_VALUE;             // Subwindow number
int               subwindow_height           =0;                       // Subwindow height
string            subwindow_shortname        ="TestButtons";           // Short name of the indicator
string            prefix                     =subwindow_shortname+"_"; // Prefix for object names
int               chart_width                =0;                       // Chart width
int               chart_height               =0;                       // Chart height
int               chart_y_offset             =0;                       // Distance from the chart top to the subwindow
//--- Colors of button elements
color             background_color           =clrSteelBlue;            // Button color
color             font_color                 =clrWhite;                // Font color
color             hover_background_color     =C'38,118,166';           // Button color when the cursor goes over
color             clicked_background_color   =C'2,72,136';             // Clicked button color
//--- Text displayed on buttons
string button_texts[BUTTON_ROWS][BUTTON_COLUMNS]=
  {
     {"Button 01","Button 02","Button 03","Button 04"},
     {"Button 05","Button 06","Button 07","Button 08"},
     {"Button 09","Button 10","Button 11","Button 12"}
  };
//--- Object names
string button_object_names[BUTTON_ROWS][BUTTON_COLUMNS]=
  {
     {"button_01","button_02","button_03","button_04"},
     {"button_05","button_06","button_07","button_08"},
     {"button_09","button_10","button_11","button_12"}
  };
//--- Button widths
int button_widths[BUTTON_ROWS][BUTTON_COLUMNS];
//--- Button heights
int button_heights[BUTTON_ROWS][BUTTON_COLUMNS];
//--- X-coordinates
int button_x_distances[BUTTON_ROWS][BUTTON_COLUMNS];
//--- Y-coordinates
int button_y_distances[BUTTON_ROWS][BUTTON_COLUMNS];
//--- Button states
bool button_states[BUTTON_ROWS][BUTTON_COLUMNS]=
  {
     {true,false,false,false},
     {false,false,false,false},
     {false,false,false,false}
  };
//--- Button colors
color button_colors[BUTTON_ROWS][BUTTON_COLUMNS];

チャートをインジケーターにロードしている際、サイズや座標を計算したのち、配列はOnInit()関数のオブジェクトプロパティに初期化される必要が有ります。カーソル追跡をONにする必要が有ります。そして最後に、インジケーターサブウィンドウにボタンを追加します。利便性のため、これらのアクションは、以下にて一つずつ見ていく個別の関数にて実行されます。結果として、OnInit()関数コードは以下のようになります:

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Set the timer at 1-second intervals
   EventSetTimer(1);
//--- Add prefix to object names
   AddPrefix();
//--- Enable tracking of mouse events
   ChartSetInteger(0,CHART_EVENT_MOUSE_MOVE,true);
//--- Set the short name
   IndicatorSetString(INDICATOR_SHORTNAME,subwindow_shortname);
//--- Set subwindow properties
   SetSubwindowProperties();
//--- Set button properties
   SetButtonColors();      // Colors
   SetButtonCoordinates(); // Coordinates
   SetButtonSizes();       // Sizes
//--- Add the button panel
   AddButtonsPanel();
//--- Refresh the chart
   ChartRedraw();
//--- Everything completed successfully
   return(INIT_SUCCEEDED);
  }

AddPrefix()関数では、接頭辞、つまり、インジケーターのショートネームがそれぞれのグラフィカルオブジェクトの名前に追加されます。これは、チャート上で一つ以上のプログラムが稼働し、オブジェクト名をマッチさせている場合、オブジェクトの移動・削除・置換を除去する上で必要です。

//+------------------------------------------------------------------+
//| Adding prefix to all object names                                |
//+------------------------------------------------------------------+
void AddPrefix()
  {
//--- Add prefix to object names
   for(int i=0; i<BUTTON_COLUMNS; i++)
      for(int j=0; j<BUTTON_ROWS; j++)
         button_object_names[j][i]=prefix+button_object_names[j][i];
  }

計算に必要なチャートの属性は、SetSubwindowProperties()関数にて初期化されます:

//+------------------------------------------------------------------+
//| Setting subwindow properties                                     |
//+------------------------------------------------------------------+
void SetSubwindowProperties()
  {
//--- Indicator subwindow number
   subwindow_number=ChartWindowFind(0,subwindow_shortname);
//--- Subwindow width and height
   chart_width=(int)ChartGetInteger(0,CHART_WIDTH_IN_PIXELS);
   subwindow_height=(int)ChartGetInteger(0,CHART_HEIGHT_IN_PIXELS,subwindow_number);
  }

チャートの属性を取得した後、ボタンの色、座標値、サイズを決定するための計算を行います。これらのアクションは以下に提供されている3つの個別の関数にて実行されます:

//+------------------------------------------------------------------+
//| Setting button color                                             |
//+------------------------------------------------------------------+
void SetButtonColors()
  {
   for(int i=0; i<BUTTON_COLUMNS; i++)
     {
      for(int j=0; j<BUTTON_ROWS; j++)
        {
         //--- If the button is clicked
         if(button_states[j][i])
            button_colors[j][i]=clicked_background_color;
         //--- If the button is unclicked
         else
            button_colors[j][i]=background_color;
        }
     }
  }
//+------------------------------------------------------------------+
//| Setting X and Y coordinates for buttons                          |
//+------------------------------------------------------------------+
void SetButtonCoordinates()
  {
   int button_width=chart_width/BUTTON_COLUMNS;
   int button_height=subwindow_height/BUTTON_ROWS;
//---
   for(int i=0; i<BUTTON_COLUMNS; i++)
     {
      for(int j=0; j<BUTTON_ROWS; j++)
        {
         if(i==0)
            button_x_distances[j][i]=0;
         else
            button_x_distances[j][i]=(button_width*i)-i;
         //---
         if(j==0)
            button_y_distances[j][i]=0;
         else
            button_y_distances[j][i]=(button_height*j)-j;
        }
     }
  }
//+------------------------------------------------------------------+
//| Setting button width and height                                  |
//+------------------------------------------------------------------+
void SetButtonSizes()
  {
   int button_width=chart_width/BUTTON_COLUMNS;
   int button_height=subwindow_height/BUTTON_ROWS;
//---
   for(int i=0; i<BUTTON_COLUMNS; i++)
     {
      for(int j=0; j<BUTTON_ROWS; j++)
        {
         if(i==BUTTON_COLUMNS-1)
            button_widths[j][i]=chart_width-(button_width*(BUTTON_COLUMNS-1)-i);
         else
            button_widths[j][i]=button_width;
         //---
         if(j==BUTTON_ROWS-1)
            button_heights[j][i]=subwindow_height-(button_height*(BUTTON_ROWS-1)-j)-1;
         else
            button_heights[j][i]=button_height;
        }
     }
  }

そして、最後にAddButtonsPanel()関数はインジケーターサブウィンドウにボタンを追加します:

//+------------------------------------------------------------------+
//| Adding buttons to the indicator subwindow                        |
//+------------------------------------------------------------------+
void AddButtonsPanel()
  {
//--- Create buttons
   for(int i=0; i<BUTTON_COLUMNS; i++)
     {
      for(int j=0; j<BUTTON_ROWS; j++)
        {
         CreateButton(0,subwindow_number,button_object_names[j][i],button_texts[j][i],
                      CORNER_LEFT_UPPER,font_name,8,font_color,button_colors[j][i],clrNONE,
                      button_widths[j][i],button_heights[j][i],
                      button_x_distances[j][i],button_y_distances[j][i],2,true,button_texts[j][i]);
        }
     }
  }

補助関数のソースコードCreateButton()は、以下のようになります:

//+------------------------------------------------------------------+
//| Creating a button (graphical object of the Edit type)            |
//+------------------------------------------------------------------+
void CreateButton(long   chart_id,     // chart id
                  int    sub_window,   // (sub)window number
                  string object_name,  // object name
                  string text,         // displayed text
                  long   corner,       // chart corner
                  string font,         // font
                  int    font_size,    // font size
                  color  c_font,       // font color
                  color  c_background, // background color
                  color  c_border,     // border color
                  int    x_size,       // width
                  int    y_size,       // height
                  int    x_dist,       // X-coordinate
                  int    y_dist,       // Y-coordinate
                  long   zorder,       // Z-order
                  bool   read_only,    // Read Only flag
                  string tooltip)      // tooltip
  {
//--- If the object has been created successfully, set the remaining properties
   if(ObjectCreate(chart_id,object_name,OBJ_EDIT,subwindow_number,0,0))
     {
      ObjectSetString(chart_id,object_name,OBJPROP_TEXT,text);              // name
      ObjectSetInteger(chart_id,object_name,OBJPROP_CORNER,corner);         // chart corner
      ObjectSetString(chart_id,object_name,OBJPROP_FONT,font);              // font
      ObjectSetInteger(chart_id,object_name,OBJPROP_FONTSIZE,font_size);    // font size
      ObjectSetInteger(chart_id,object_name,OBJPROP_COLOR,c_font);          // font color
      ObjectSetInteger(chart_id,object_name,OBJPROP_BGCOLOR,c_background);  // background color
      ObjectSetInteger(chart_id,object_name,OBJPROP_BORDER_COLOR,c_border); // border color
      ObjectSetInteger(chart_id,object_name,OBJPROP_XSIZE,x_size);          // width
      ObjectSetInteger(chart_id,object_name,OBJPROP_YSIZE,y_size);          // height
      ObjectSetInteger(chart_id,object_name,OBJPROP_XDISTANCE,x_dist);      // X-coordinate
      ObjectSetInteger(chart_id,object_name,OBJPROP_YDISTANCE,y_dist);      // Y-coordinate
      ObjectSetInteger(chart_id,object_name,OBJPROP_SELECTABLE,false);      // object is not available for selection
      ObjectSetInteger(chart_id,object_name,OBJPROP_ZORDER,zorder);         // Z-order
      ObjectSetInteger(chart_id,object_name,OBJPROP_READONLY,read_only);    // Read Only text
      ObjectSetInteger(chart_id,object_name,OBJPROP_ALIGN,ALIGN_CENTER);    // align center
      ObjectSetString(chart_id,object_name,OBJPROP_TOOLTIP,tooltip);        // no tooltip if "\n"
     }
  }

CreateButton()関数の最後のパラメーターに注意してください:マウスがグラフィカルオブジェクトの上を移動する際のツールチップの挙動を担当します。例えば、AddButtonsPanel()関数では、このパラメーターはbutton_texts配列から渡された値によって表されます:必要であれば、より詳しい記述で個別の配列を作成できます。

それでは、もしインジケーターをチャートに貼り付ければ、結果は以下のようになります;

図1. インジケーターサブウィンドウに追加されたボタン

図1. インジケーターサブウィンドウに追加されたボタン

現在、これらはインジケーターサブウィンドウにて調整されたオブジェクトでしかありません。ユーザーとのインタラクションはまだ実装されていません。これらのオブジェクトに息を吹き込みましょう。

まず、サブウィンドウのサイズが変更された際にそのサイズに沿って、ボタンのサイズを調整する機能を実装します。このために、二つの関数を追加で記述します - UpdateButtonCoordinates()ResizeButtons()です。ボタンの座標とサイズを設定します:

//+------------------------------------------------------------------+
//| Updating button coordinates                                      |
//+------------------------------------------------------------------+
void UpdateButtonCoordinates()
  {
//--- Set coordinates
   for(int i=0; i<BUTTON_COLUMNS; i++)
     {
      for(int j=0; j<BUTTON_ROWS; j++)
        {
         ObjectSetInteger(0,button_object_names[j][i],OBJPROP_XDISTANCE,button_x_distances[j][i]);
         ObjectSetInteger(0,button_object_names[j][i],OBJPROP_YDISTANCE,button_y_distances[j][i]);
        }
     }
  }
//+------------------------------------------------------------------+
//| Updating button sizes                                            |
//+------------------------------------------------------------------+
void ResizeButtons()
  {
//--- Set sizes
   for(int i=0; i<BUTTON_COLUMNS; i++)
     {
      for(int j=0; j<BUTTON_ROWS; j++)
        {
         ObjectSetInteger(0,button_object_names[j][i],OBJPROP_XSIZE,button_widths[j][i]);
         ObjectSetInteger(0,button_object_names[j][i],OBJPROP_YSIZE,button_heights[j][i]);
        }
     }
  }

チャートの属性の修正イベントとチャートのサイズ修正イベントのハンドリングを行うために、 CHARTEVENT_CHART_CHANGE識別子を使用する必要が有ります。以下にて、OnChartEvent()関数に追加する必要のあるコードがあります。

//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,           // event identifier
                  const long &lparam,     // parameter of the event of type long
                  const double &dparam,   // parameter of the event of type double
                  const string &sparam)   // parameter of the event of type string
  {
//--- Tracking the event of modifying the chart properties and resizing the chart
   if(id==CHARTEVENT_CHART_CHANGE)
     {
      //--- Set subwindow properties
      SetSubwindowProperties();
      //--- Set button coordinates
      SetButtonCoordinates();
      //--- Set button sizes
      SetButtonSizes();
      //--- Set new button coordinates
      UpdateButtonCoordinates();
      //--- Set new button sizes
      ResizeButtons();
      //--- Refresh the chart
      ChartRedraw(); return;
     }

  }

もしインジケーターをチャートに追加すると、(もしくはインジケーターがすでにチャートにある状態で再度コンパイルすると)そのボタンは、チャートウィンドウかインジケーターサブウィンドウがサイズ変更されるとすぐに、自動的にサイズ変更し、再配置されます。

さらにカーソルがボタン上にある際のボタンの色の変化を実装します。しかし、関数コードを記述する前に、 CHARTEVENT_MOUSE_MOVE識別子にてイベントをハンドリングするプロセスを見てみましょう。

OnInit()関数では、すでにプログラムにマウス左ボタンの状態だけでなく、マウスのカーソルの移動を追跡するよう指示するStringを持っています。

//--- Enable tracking of mouse events
   ChartSetInteger(0,CHART_EVENT_MOUSE_MOVE,true);

これなしでは(もしくは、最後のパラメーター値がFalseであれば、)CHARTEVENT_MOUSE_MOVE識別子のついたイベントは、OnChartEvent()関数にて追跡されません。これは、すべてのプログラムにてそのようなイベントが追跡される必要がないので、とても役に立ちます。

マウスイベントの追跡がどのように作動するかを理解するために、一時的にOnChartEvent()関数にチャートの一致するコメントを表示する機能を追加します。

//--- Mouse movement and left-click tracking
   if(id==CHARTEVENT_MOUSE_MOVE)
     {
      Comment("id: ",CHARTEVENT_MOUSE_MOVE,"\n",
              "lparam (x): ",lparam,"\n",
              "dparam (y): ",dparam,"\n",
              "sparam (state of the mouse buttons): ",sparam
              );

もしチャートのマウスカーソルのを移動させたら、左上の角にてカーソルの現在の座標を見ることができます。左クリックした時、その変化はコメント行sparam (マウスボタンの状態)にて表示され、 One (1) はマウスボタンがクリックされたことを示し、zero (0) はクリックが終了したことを意味します。

もしマウスカーソルが位置しているサブウィンドウを知る必要があれば、ChartXYToTimePrice()関数を使用できます。座標を取得し、ウィンドウ・サブウィンドウ数、時刻、価格を返します(参照により渡された値に返します。)以下のコードをテストすることでご覧になれます:

//--- Mouse movement and left-click tracking
   if(id==CHARTEVENT_MOUSE_MOVE)
     {
      int      x      =(int)lparam; // X-coordinate
      int      y      =(int)dparam; // Y-coordinate
      int      window =WRONG_VALUE; // Number of the window where the cursor is located
      datetime time   =NULL;        // Time corresponding to the X-coordinate
      double   price  =0.0;         // Price corresponding to the Y-coordinate
      //--- Get the position of the cursor
      if(ChartXYToTimePrice(0,x,y,window,time,price))
        {
         Comment("id: ",CHARTEVENT_MOUSE_MOVE,"\n",
                 "x: ",x,"\n",
                 "y: ",y,"\n",
                 "sparam (state of the mouse buttons): ",sparam,"\n",
                 "window: ",window,"\n",
                 "time: ",time,"\n",
                 "price: ",DoubleToString(price,_Digits)
                 );
        }
      //---
      return;
     }

インジケーターのサブウィンドウの計算は、もし関連する座標が用いられれば簡単です。この場合、 Yー座標(価格軸)に関連します。関連する値を取得するために、チャートの上部からインジケーターサブウィンドウまでの距離を現在の値から引く必要があります。これは以下のように実行されます:

      //--- Get the position of the cursor
      if(ChartXYToTimePrice(0,x,y,window,time,price))
        {
         //--- Get the distance from the chart top to the indicator subwindow
         chart_y_offset=(int)ChartGetInteger(0,CHART_WINDOW_YDISTANCE,subwindow_number);
         //--- Convert the Y-coordinate to the relative value
         y-=chart_y_offset;
         Comment("id: ",CHARTEVENT_MOUSE_MOVE,"\n",
                 "x: ",x,"\n",
                 "y: ",y,"\n",
                 "sparam (state of the mouse buttons): ",sparam,"\n",
                 "window: ",window,"\n",
                 "time: ",time,"\n",
                 "price: ",DoubleToString(price,_Digits)
                 );
        }

y変数の値は、もしマウスカーソルがインジケーターサブウィンドウの上にある場合、0以下になり、カーソルがサブウィンドウ上を移動した際に0以上になります。

標準として、チャート上のカーソルの位置に関係なく、時間軸に沿ってチャートをスクロールできます。チャートのスクロールは必要であれば停止できます。カーソルがパネル上やカスタムコントロール上に位置する際に必要です。カーソルがインジケーターサブウィンドウにある際のチャートのスクロール停止とカーソルががサブウィンドウ外にある時の開始のためのコードは以下のようになります;

         //--- If the cursor is in the subwindow area, disable chart scrolling
         if(window==subwindow_number)
            ChartSetInteger(0,CHART_MOUSE_SCROLL,false);
         //--- Enable chart scrolling if the cursor moves out of the indicator subwindow area
         else
            ChartSetInteger(0,CHART_MOUSE_SCROLL,true);

さらに、カーソルが一致するボタンの上にある際のボタンの色を変える関数を書きましょうーChangeButtonColorOnHover():

//+------------------------------------------------------------------+
//| Changing the button color when the cursor hovers over the button |
//+------------------------------------------------------------------+
void ChangeButtonColorOnHover(int x,int y)
  {
   int x1,y1,x2,y2;
//--- Initialize the array of XY coordinates for buttons
   SetButtonCoordinates();
//--- Determine if the cursor is over any of the buttons
   for(int i=0; i<BUTTON_COLUMNS; i++)
     {
      for(int j=0; j<BUTTON_ROWS; j++)
        {
         //--- If this button is clicked, go to the next one
         if(button_states[j][i])
            continue;
         //--- Get the button boundaries
         x1=button_x_distances[j][i];
         y1=button_y_distances[j][i];
         x2=button_x_distances[j][i]+button_widths[j][i];
         y2=button_y_distances[j][i]+button_heights[j][i];
         //--- If the cursor is within the button area, set the new button color
         if(x>x1 && x<x2 && y>y1 && y<y2)
            ObjectSetInteger(0,button_object_names[j][i],OBJPROP_BGCOLOR,hover_background_color);
         //--- Otherwise set the standard color
         else
            ObjectSetInteger(0,button_object_names[j][i],OBJPROP_BGCOLOR,background_color);
        }
     }
  }

結果として、CHARTEVENT_MOUSE_MOVE識別子の中にて以下のソースコードがあります。

//--- Mouse movement and left-click tracking
   if(id==CHARTEVENT_MOUSE_MOVE)
     {
      int      x      =(int)lparam; // X-coordinate
      int      y      =(int)dparam; // Y-coordinate
      int      window =WRONG_VALUE; // Number of the window where the cursor is located
      datetime time   =NULL;        // Time corresponding to the X-coordinate
      double   price  =0.0;         // Price corresponding to the Y-coordinate
      //--- Get the position of the cursor
      if(ChartXYToTimePrice(0,x,y,window,time,price))
        {
         //--- Get the distance from the chart top to the indicator subwindow
         chart_y_offset=(int)ChartGetInteger(0,CHART_WINDOW_YDISTANCE,subwindow_number);
         //--- Convert the Y-coordinate to the relative value
         y-=chart_y_offset;
         //--- If the cursor is in the subwindow area, disable chart scrolling
         if(window==subwindow_number)
            ChartSetInteger(0,CHART_MOUSE_SCROLL,false);
         //--- Enable chart scrolling if the cursor moves out of the indicator subwindow area
         else
            ChartSetInteger(0,CHART_MOUSE_SCROLL,true);
         //--- Change the button color when the cursor is hovered over
         ChangeButtonColorOnHover(x,y);
        }
      //--- Refresh the chart
      ChartRedraw(); 
      return;
     }

もしボタン上にカーソルを移動させた場合、ボタンの色の変化をご覧になることができるか、標準の状態に戻ります。

現在、Button 01のみクリックされた際のボタンの色を持っています。その他のボタンをクリックしようとすると、レスポンスはなく、色の変更もありません。この場合に色の変更を実装するために、CHARTEVENT_OBJECT_CLICK識別子のあるイベントを使用する必要があります。

二つの関数を書いてみましょう;InitializeButtonStates()ChangeButtonColorOnClick()です。InitializeButtonStates()関数は、特定のボタンがクリックされたか否かをチェックし、その名前の接頭辞をチェックします。もしそのクリックイベントが認識されれば、ボタンの状態の配列(button_states) がループにて初期化され、関数がtrueを返します。

//+------------------------------------------------------------------+
//| Initializing button states in case of click                      |
//+------------------------------------------------------------------+
bool InitializeButtonStates(string clicked_object)
  {
//--- Get the indicator subwindow number
   subwindow_number=ChartWindowFind(0,subwindow_shortname);
//--- If a button in the indicator subwindow has been clicked
   if(ObjectFind(0,clicked_object)==subwindow_number && StringFind(clicked_object,prefix+"button_",0)>=0)
     {
      //--- Determine the clicked button
      for(int i=0; i<BUTTON_COLUMNS; i++)
        {
         for(int j=0; j<BUTTON_ROWS; j++)
           {
            //--- Determine the state of all buttons
            if(clicked_object==button_object_names[j][i])
               button_states[j][i]=true;
            else
               button_states[j][i]=false;
           }
        }
      //---
      return(true);
     }
//---
   return(false);
  }

この後、ChangeButtonColorOnClick()関数は、button_states配列の値に沿ってボタンの色を設定します。

//+------------------------------------------------------------------+
//| Changing the button color in case of click                       |
//+------------------------------------------------------------------+
void ChangeButtonColorOnClick()
  {
   for(int i=0; i<BUTTON_COLUMNS; i++)
     {
      for(int j=0; j<BUTTON_ROWS; j++)
        {
         //--- If the button has been clicked, it is set a distinctive color
         if(button_states[j][i])
            ObjectSetInteger(0,button_object_names[j][i],OBJPROP_BGCOLOR,clicked_background_color);
         //--- Set the standard color to the unclicked button
         else
            ObjectSetInteger(0,button_object_names[j][i],OBJPROP_BGCOLOR,background_color);
        }
     }
  }

すべてを作動させるために、ボタンのクリックのハンドリングをイベント追跡関数OnChartEvent()に追加してください:

//--- Tracking left mouse button clicks on a graphical object
   if(id==CHARTEVENT_OBJECT_CLICK)
     {
      //--- If the button has been clicked
      if(InitializeButtonStates(sparam))
        {
         //--- Set button colors
         ChangeButtonColorOnClick();
        }
      //--- Refresh the chart
      ChartRedraw();
      return;
     }

クリックされた際、ボタンは色を変更します。

まだいくつか紹介するべきポイントがあります。OnDeinit()関数では、サブウィンドウエリアのチャートのスクロールを可能にし、チャートからインジケーターを削除した際のマウスイベントの追跡を停止します。これは、もしイベント追跡を使用するいくつかのプログラムが同時にチャートで稼働している場合、重要になります。

//+------------------------------------------------------------------+
//| Deinitialization                                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   if(reason==REASON_REMOVE ||  // If the indicator has been deleted from the chart or
      reason==REASON_RECOMPILE) // the program has been recompiled
     {
      //--- Deactivate the timer
      EventKillTimer();
      //--- Delete the objects
      DeleteButtons();
      //--- Enable chart scrolling
      ChartSetInteger(0,CHART_MOUSE_SCROLL,true);
      //--- Disable tracking of mouse events
      ChartSetInteger(0,CHART_EVENT_MOUSE_MOVE,false);
      //--- Refresh the chart
      ChartRedraw();
     }
  }

プログラムのグラフィカルオブエクトの削除のための関数;

//+------------------------------------------------------------------+
//| Deleting all buttons                                             |
//+------------------------------------------------------------------+
void DeleteButtons()
  {
   for(int i=0; i<BUTTON_COLUMNS; i++)
      for(int j=0; j<BUTTON_ROWS; j++)
         DeleteObjectByName(button_object_names[j][i]);
  }
//+------------------------------------------------------------------+
//| Deleting the object by name                                      |
//+------------------------------------------------------------------+
void DeleteObjectByName(string object_name)
  {
//--- If such object exists
   if(ObjectFind(0,object_name)>=0)
     {
      //--- If an error occurred when deleting, print the relevant message
      if(!ObjectDelete(0,object_name))
         Print("Error ("+IntegerToString(GetLastError())+") when deleting the object!");
     }
  }

そして最後に、このプログラムにタイマーが必要な理由を紹介します。例えば、もし一つ以上のプログラムがチャート内で稼働し、個々のプログラムがマウスイベントを追跡する必要がある場合、チャート上からその内の一つが削除された時に、追跡がOnDeinit() 関数にてすべてのプログラムにおいて停止されます。したがって、代替物としてマウスイベントの追跡が行われているかを知るため毎秒毎のチェックを行う必要があるのです。

//+------------------------------------------------------------------+
//| Timer function                                                   |
//+------------------------------------------------------------------+
void OnTimer()
  {
//--- Check whether tracking of mouse events is enabled
   CheckChartEventMouseMove();

  }

CheckChartEventMouseMove()関数コードは以下に提供されています;

CHARTEVENT_CHART_CHANGE識別子のあるイベントをチェックする上で十分です。

結果として得たものをデモンストレーションするビデオを以下にてご覧になれます:

 

結論

それではまとめましょう。TestButtons.mq5インジケーターは、この記事に添付されており、ダウンロードできます。さらなる開発により、この例はより面白いメニューに成長させることができます。例えば、ユーザーは特定のボタンをクリックすることで関連する価格にジャンプすることができます。ボタン数は必要であれば増やすことができます。

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

添付されたファイル |
testbuttons.mq5 (20.47 KB)
MQL5 クックブック:MetaTrader 5トレードイベントへの音声通知 MQL5 クックブック:MetaTrader 5トレードイベントへの音声通知
本稿では Expert Advisor のファイルに音声ファイルをインクルードすること、それによりトレードイベントに音声通知を追加するなどの問題を考察します。事実、ファイルのインクルードが意味するところは Expert Advisor内に音声ファイルを入れるということです。よってコンパイルされた Expert Advisor (*.ex5) バージョンを他のユーザーに提供する際、音声ファイルは提供せずそれがどこの保存されるか説明する必要があるのです。
MQL5 クックブック: インジケーターサブウィンドウコンソールースクロールバー MQL5 クックブック: インジケーターサブウィンドウコンソールースクロールバー
様々なコントロールを試してみましょう。今回はスクロールバーを紹介します。「MQL5クックブック:インジケーターサブウィンドウコンソールーボタン」という以前の記事のように、すべての処理がインジケーターサブウィンドウにて実行されます。OnChartEvent()関数にてイベントを扱う詳しい詳細を提供しているので、上記の記事を読んでみてください。この点はこの記事においても言及されます。今回はMQL5リソースを用いて取得される金融商品情報の大きなリストのための垂直スクロールバーを作成します。
MQL5 Cookbook:指定の基準に基づく Expert Advisor 最適化結果の保存方法 MQL5 Cookbook:指定の基準に基づく Expert Advisor 最適化結果の保存方法
MQL5 プログラミングに関するシリーズを続けます。今回、われわれは Expert Advisor のパラメータ最適化の最中に各最適化パスの結果を取得する方法を見ていきます。外部パラメータに指定された条件が満たされれば対応するパス値がファイルに書き込まれることを確認できるよう実装が行われます。検証値以外にもそのような結果をもたらしたパラメータも保存します。
MQL5 クックブック: MQL5でのマルチシンボルボラティリティインジケーターの開発 MQL5 クックブック: MQL5でのマルチシンボルボラティリティインジケーターの開発
この記事では、マルチシンボルボラティリティインジケーターを紹介します。マルチシンボルインジケーターの開発は、MQL5開発初心者にとっていくつか難しい点があります。マルチシンボルインジケーターの開発中に生じる主要な問題は、現在のシンボルに関連したその他のシンボルのデータの同期化、いくつかのインジケーターデータの欠如、特定のタイムフレーム間の初めの「本当の」バーの特定などに関連します。これらの問題は、この記事にて詳しく焦点が当てられます。