English Русский 中文 Español Deutsch 日本語 Português Français Italiano Türkçe
MQL5 Coobook: 지표 하위 창 컨트롤 - 버튼

MQL5 Coobook: 지표 하위 창 컨트롤 - 버튼

MetaTrader 5 | 3 9월 2021, 11:10
66 0
Anatoli Kazharski
Anatoli Kazharski

소개

이 글에서는 버튼 컨트롤이 있는 사용자 인터페이스를 개발하는 예를 고려할 것입니다. 사용자에게 상호 작용에 대한 아이디어를 전달하기 위해 커서가 버튼 위에 있을 때 버튼의 색상이 변경됩니다. 버튼 위에 커서가 있으면 버튼 색상이 약간 어두워지고 버튼을 클릭하면 훨씬 더 어두워집니다. 또한 각 버튼에 툴팁을 추가하여 직관적인 인터페이스를 만듭니다.

이 글에서는 마우스 이동 이벤트, 마우스 왼쪽 버튼의 상태, 개체를 마우스 왼쪽 버튼으로 클릭 및 차트 속성 수정 이벤트와 같은 일부 이벤트도 다룹니다. 지표 하위 창의 전체 공간을 차지하는 버튼 패널을 만들 것입니다. 설명을 위해 버튼은 각 행에 4개의 버튼이 있는 3개의 행으로 정렬됩니다.

 

개발

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)
  {
//---

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

우리가 지금 가지고 있는 것은 플로팅 시리즈가 없는 빈 창입니다. 타이머의 필요성은 잠시 후에 논의될 것입니다.

이제 함수를 만드는 데 사용할 상수, 변수 및 배열을 추가해 보겠습니다. 모든 배열은 2차원입니다. 첫 번째 치수는 창 높이의 버튼 수를 나타내고 두 번째 치수는 창 너비의 버튼 수를 나타냅니다.

//---
#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() 함수의 개체 속성으로 초기화되어야 합니다. 커서 추적도 활성화해야 합니다. 마지막으로 지표 하위 창에 버튼을 추가해야 합니다. 편의를 위해 이러한 작업은 별도의 기능에서 수행되며 아래에서 하나씩 살펴보겠습니다. 결과적으로 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);
  }

차트 속성을 얻은 후 버튼 색상, 좌표 값 및 크기를 결정하기 위한 계산을 수행할 수 있습니다. 이러한 모든 작업은 아래에 제공된 세 가지 개별 기능에서 수행됩니다.

//+------------------------------------------------------------------+
//| 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() 함수에는 프로그램이 마우스 커서 움직임과 왼쪽 마우스 버튼의 상태를 추적하도록 지시하는 문자열이 이미 있습니다.

//--- 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(마우스 버튼의 상태)에 표시됩니다. 여기서 1(1)은 마우스 버튼을 클릭하고 0(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 변수의 값은 마우스 커서가 지표 하위 창 위에 있으면 음수이고 커서가 하위 창 영역 위로 이동하면 양수입니다.

기본적으로 차트의 커서 위치에 관계없이 시간 척도를 따라 차트를 스크롤할 수 있습니다. 그러나 필요한 경우 차트 스크롤을 비활성화할 수 있습니다. 커서가 패널이나 사용자 정의 컨트롤 위에 있을 때 주로 필요합니다. 커서가 지표 하위 창에 있을 때 차트 스크롤을 비활성화하고 커서가 하위 창 밖으로 이동할 때 활성화하는 코드는 예를 들어 다음과 같을 수 있습니다.

         //--- 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;
     }

이제 버튼 위로 커서를 이동하면 버튼 색상이 변경/정상으로 돌아오는 것을 볼 수 있습니다.

현재 버튼 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 소프트웨어 사를 통해 러시아어가 번역됨.
원본 기고글: https://www.mql5.com/ru/articles/750

파일 첨부됨 |
testbuttons.mq5 (20.47 KB)
MQL5 Coobook: 지표 하위 창 컨트롤 - 스크롤바 MQL5 Coobook: 지표 하위 창 컨트롤 - 스크롤바
계속해서 다양한 컨트롤을 탐색하고 이번에는 스크롤바에 주의를 기울이겠습니다. "MQL5 Cookbook: 지표 하위 창 컨트롤 - 버튼"라는 제목의 이전 글와 마찬가지로 모든 작업은 지표 하위 창에서 수행됩니다. OnChartEvent() 함수의 이벤트 작업에 대한 자세한 설명을 제공하는 위에서 언급한 글을 잠시 읽어보십시오. 설명을 위해 이번에는 MQL5 리소스를 사용하여 얻을 수 있는 모든 금융 상품 속성의 큰 목록에 대한 세로 스크롤 바를 만듭니다.
MQL5 Coobook: 단일 창에서 여러 시간 프레임 모니터링 MQL5 Coobook: 단일 창에서 여러 시간 프레임 모니터링
MetaTrader 5에는 분석을 위해 21개의 시간 프레임이 있습니다. 기존 차트에 배치하고 기호, 시간 프레임 및 기타 속성을 바로 설정할 수 있는 특수 차트 개체를 활용할 수 있습니다. 이 글에서는 이러한 차트 그래픽 개체에 대한 자세한 정보를 제공합니다. 하위 창에서 동시에 여러 차트 개체를 설정할 수 있는 컨트롤(버튼)이 있는 지표를 만듭니다. 또한 차트 개체는 하위 창에 정확하게 맞고 기본 차트 또는 터미널 창의 크기가 조정될 때 자동으로 조정됩니다.
MQL5 Coobook: MQL5에서 다중 기호 변동성 지표 개발 MQL5 Coobook: MQL5에서 다중 기호 변동성 지표 개발
이 글에서는 다중 기호 변동성 지표의 개발을 고려해볼 것입니다. 다중 기호 지표의 개발은 이 글에서 명확히 하는 데 도움이 되는 초보 MQL5 개발자에게 몇 가지 어려움을 줄 수 있습니다. 다중 기호 지표 개발 과정에서 발생하는 주요 문제는 현재 기호에 대한 다른 기호 데이터의 동기화, 일부 지표 데이터의 부족 및 주어진 시간 프레임의 '참' 바에 대한 시작 식별과 관련이 있습니다. 이 모든 문제는 글에서 면밀히 고려해보겠습니다.
MQL5 Coobook: MetaTrader 5 거래 이벤트에 대한 소리 알림 MQL5 Coobook: MetaTrader 5 거래 이벤트에 대한 소리 알림
이 글에서는 Expert Advisor의 파일에 사운드 파일을 포함하여 거래 이벤트에 사운드 알림을 추가하는 것과 같은 문제를 고려할 것입니다. 파일이 포함된다는 사실은 사운드 파일이 Expert Advisor 내부에 위치한다는 것을 의미합니다. 따라서 Expert Advisor의 컴파일된 버전(*.ex5)을 다른 사용자에게 제공할 때 사운드 파일도 제공하고 저장해야 하는 위치를 설명할 필요가 없습니다.