Discussion of article "MQL5 Cookbook: Indicator Subwindow Controls - Buttons" - page 7

 
TheXpert:
Are you so sure your article is perfect?

I am very pleased that you read it.

I will be happy to answer all questions in the appropriate thread.

===

So that there are no unnecessary misconceptions, I have nothing against Anatoly! Kudos to him for the article! But it is necessary to answer the questions...

 
DC2008:

Excuse me, am I distracting you by any chance from writing another tutorial or recipe?

If not, let's continue discussing your article about control in the indicator subwindow. So, you offer a mass solution (or an idea) how to make a convenient menu in an indicator. Good, the purpose of the article is very worthy! But how can a "beginner" programmer use all this arsenal? Where to place custom functions? Demonstrate it by example. And at the same time explain what you need to fix in the code to use, for example, 5 buttons? Consider it a beginner's question.

No, you're not. I'm not writing anything yet. I have to rest at least one day a year. Just resting is not interesting, especially not for a long time. )

It's not a mass decision and I didn't write about it. Let's not attribute something that did not happen. It was already voiced at the beginning of the discussion that this is not a universal solution, but a special case. In my opinion, it is a good example for a beginner to practice. And not to get a ready-made solution for free and run, mouth open in a wide smile, to meet the sun. ) Do you understand? I would like such a simple and clear example at the very beginning of learning programming. Especially when this is the first programming language in your life and before that your whole life's activity was in a completely different field, in no way connected with it.

In order to make 5 buttons, in this case, we need to change the size of arrays and exclude unnecessary elements when declaring arrays for the names of objects-buttons, displayed text in buttons and button states.

There is an array of button states, so the same principle can be used to check which button is pressed and instead of just changing the colour of the button, perform some other (user required) action. This can be, for example, trading functions (and not only): deleting all pending orders, closing all positions, etc. The ideas are endless. And if there are no ideas, then you have chosen the wrong kind of activity. )

In order to implement this, you need to create another array, which will be initialised with identifiers of a custom enumeration (which also needs to be created), for example, with the name ENUM_SCRIPT. And the identifiers will then be called, for example: SCRIPT_01 =0, SCRIPT_02 =2, etc. Also in the loop, when checking whether the button on the panel is pressed, you will need to determine which identifier is bound to the pressed button and the current state of the button, and then pass the corresponding function to the programme for execution.

I will not show a sample code on purpose. Let it be a homework for beginners. )

Документация по MQL5: Стандартные константы, перечисления и структуры / Торговые константы / Свойства ордеров
Документация по MQL5: Стандартные константы, перечисления и структуры / Торговые константы / Свойства ордеров
  • www.mql5.com
Стандартные константы, перечисления и структуры / Торговые константы / Свойства ордеров - Документация по MQL5
 

I made the changes like you said:

//--- Displayed text in buttons
string button_texts[BUTTON_ROWS][BUTTON_COLUMNS]=
  {
     {"Button 01","Button 02","Button 03","Button 04"},
     {"Button 05"}
  };
//--- Object names
string button_object_names[BUTTON_ROWS][BUTTON_COLUMNS]=
  {
     {"button_01","button_02","button_03","button_04"},
     {"button_05"}
  };
....
bool button_states[BUTTON_ROWS][BUTTON_COLUMNS]=
  {
     {true,false,false,false},
     {false}
  };

And this is what I got on the screen:

How do I fix it? (I'm a beginner)

 
DC2008:

I made the changes like you said:

And this is what I got on the screen:

How do I fix it? (I'm a beginner)

Like this:

#define  BUTTON_COLUMNS 5 // Number of buttons by width
#define  BUTTON_ROWS    1 // Number of buttons by height
...
//--- Displayed text in buttons
string button_texts[BUTTON_ROWS][BUTTON_COLUMNS]=
  {
     {"Button 01","Button 02","Button 03","Button 04","Button 05"}
  };
//--- Object names
string button_object_names[BUTTON_ROWS][BUTTON_COLUMNS]=
  {
     {"button_01","button_02","button_03","button_04","button_05"}
  };
...
//--- Button states
bool button_states[BUTTON_ROWS][BUTTON_COLUMNS]=
  {
     {true,false,false,false,false}
  };
 

Oh, great! It works.

But I don't understand how to connect my functions to the buttons. Show me an example.

 
DC2008:

Oh, great! It works.

But I don't understand how to connect my functions to the buttons. Show me an example.

Well, let's continue the game of "beginner" started by you. )

At what point are you stuck? Show an attempt at how understood at the current point. Create an enumeration with five identifiers and an array whose elements need to be assigned those identifiers.

 
bool fun_states[BUTTON_ROWS][BUTTON_COLUMNS]=
  {
     {true,false,false,false,false}
  };
enum ENUM_SCRIPT
  {
   SCRIPT_01 =0,
   SCRIPT_02 =1,
   SCRIPT_03 =2,
   SCRIPT_04 =3,
   SCRIPT_05 =4,
  };
void F1()
  {Print("F1");}
bool F2()
  {Print("F2");return(false);}
int F3()
  {Print("F3");return(0);}
double F4()
  {Print("F4");return(0.1);}
color F5()
  {Print("F5");return(clrAliceBlue);}

So what do we do next?

 
DC2008:

So what do we do next?

This is the kind of array you need:

//--- Scripts
ENUM_SCRIPT buttons_scripts[NUMBER_BUTTONS_HEIGHT][NUMBER_BUTTONS_WIDTH]=
  {
     {SCRIPT_01,SCRIPT_02,SCRIPT_03,SCRIPT_04,SCRIPT_05}
  };

Then you need to write a function like this:

//+------------------------------------------------------------------+
//|| Executing scripts |
//+------------------------------------------------------------------+
void ScriptOn()
  {
   for(int i=0; i<NUMBER_BUTTONS_WIDTH; i++)
     {
      for(int j=0; j<NUMBER_BUTTONS_HEIGHT; j++)
        {
         //--- If this button is pressed, we will run the corresponding script
         if(buttons_state[j][i])
           {
            if(buttons_scripts[j][i]==SCRIPT_01)
              {
               F1();
               return;
              }
            //---
            if(buttons_scripts[j][i]==SCRIPT_02)
              {
               F2();
               return;
              }
            //---
            if(buttons_scripts[j][i]==SCRIPT_03)
              {
               F3();
               return;
              }
            //---
            if(buttons_scripts[j][i]==SCRIPT_04)
              {
               F4();
               return;
              }
            //---
            if(buttons_scripts[j][i]==SCRIPT_05)
              {
               F5();
               return;
              }
           }
        }
     }
  }

...and place this function in this part of the code:

//--- Tracking left mouse button clicks on a graphical object
   if(id==CHARTEVENT_OBJECT_CLICK)
     {
      //--- If you click on the button
      if(InitializeButtonStates(sparam))
        {
         //--- Set the colours for the buttons
         ChangeButtonColorOnClick();
         //--- Run the script
         ScriptOn();
        }
      //--- Update the chart
      ChartRedraw();
      return;
     }

And then you can think about how to optimise the code, if you need to. :)

 
tol64:

That's how I have it done.

The programme that has tracking enabled at startup turns it off when unloading. And the programme, which remains on the chart and needs tracking, checks if it is enabled, and if it is disabled, it enables it.

It is desirable to give your variant on the examples of Expert Advisor and indicator code from my post on the previous page to exclude ambiguity of statements.

There is no need to constantly check if someone has disabled tracking of mouse events. To be more precise, if you want to protect yourself from any situation at all, you can check it, but I think it's too much.

Maybe we should suggest developers to generate CHARTEVENT_CHART_CHANGE when CHART_EVENT_MOUSE_MOVE changes? Then it would be possible to elegantly restore the necessary setting when the Expert Advisor is running.

So far, I have this variant:

#property copyright "Copyright 2013, komposter"
#property link      "http://www.komposter.me/"
#property version   "1.00"
#property indicator_chart_window

input   bool    EnableMouseDetect = false; // true - work with mouse tracking, false - without it

bool PrevState = false;

//+------------------------------------------------------------------+
//| Custom indicator initialisation function |
//+------------------------------------------------------------------+
int OnInit()
{
        if ( EnableMouseDetect )
        {
                //--- Get the current state
                PrevState = (bool)ChartGetInteger(0,CHART_EVENT_MOUSE_MOVE);
                //--- Enable mouse event tracking
                if ( PrevState == false ) ChartSetInteger(0,CHART_EVENT_MOUSE_MOVE,true);
        }

        return(0);
}

//+------------------------------------------------------------------+
//| Deinitialisation function of the expert |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
        if ( EnableMouseDetect )
        {
                //--- Disable mouse event tracking
                if ( PrevState == false )
                {
                        ChartSetInteger(0,CHART_EVENT_MOUSE_MOVE,false);
                        ChartRedraw(); // Without this line, tracking is disabled only when a tick arrives. Is this the way it's designed?
                }
        }
}

//+------------------------------------------------------------------+
//| OnTick|
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                     const int prev_calculated,
                     const datetime& time[],
                     const double& open[],
                     const double& high[],
                     const double& low[],
                     const double& close[],
                     const long& tick_volume[],
                     const long& volume[],
                     const int& spread[])
       {
        
        return(rates_total);
       }
//+------------------------------------------------------------------+
//| ChartEvent function|
//+------------------------------------------------------------------+
void OnChartEvent(const int    id,
                  const long   &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//--- Tracking mouse movement and left mouse button presses
   if(id==CHARTEVENT_MOUSE_MOVE)
     {
      static int count=1;
      Print("CHARTEVENT_MOUSE_MOVE; EXPERT; ",count);
      count++;
     }
  }
//+------------------------------------------------------------------+

I made one indicator, but with a parameter: run with EnableMouseDetect = true - controls tracking, false - just prints the number of events, if tracking is enabled.


------------------
Now I've thought about it some more, and I have to agree - this option won't work. If you run first one programme that tracks the mouse (it will enable tracking), then the second one (it will see what is already enabled), and then delete the first one, it will disable tracking, and the second one will be left with nothing. I.e. we need to come up with some kind of semaphore to signal that tracking is needed.

And in light of the research conducted here (about the load on the processor) in such crutches is not necessary.

So I propose to vote my proposal to the developers, and the topic can be closed.

 
ChartRedraw(); // Without this line, tracking is disabled only when a tick arrives. Is this the way it's designed?
MT5 has asynchronous updating of chart properties. I.e. the fact that we set a property does not mean that the terminal immediately picked it up. The ChartRedraw() function is used to have all properties re-read by the terminal. You can also use the ChartGet... ObjectGet, in this case the properties will also be re-read.
Документация по MQL5: Операции с графиками / ChartRedraw
Документация по MQL5: Операции с графиками / ChartRedraw
  • www.mql5.com
Операции с графиками / ChartRedraw - Документация по MQL5