Gallery of UIs written in MQL - page 69

 

Before continuing with the topic of implementing staggered parameter boundary protection and user warnings, we should mention another topic that directly precedes it. Namely, parameter presetting.

I will start with the well-known: most MQL programmes have variables of the input category. They are declared at the global level and are visible in a single settings window. The window appears at the start of the programme and inside it the user can change the initial values of "external" variables, if such a need arises. But before that, the user initialises the external variables inside the program. The point is that programme presets are not universal, and that's why there is a category of variables that require the possibility of setting at each startup. It is also known that any attempt to manually access external variables during programme execution is impossible and requires a reboot. With a graphical interface, this necessity is eliminated. The programme settings can be opened at runtime.

However, there is still the same necessity to set initial values to the programme parameters at the start.

If we have a graphical interface , there is no sense in declaring variables of the input type , because we no longer need the standard settings window , but the essence remains the same. Instead of input variables, we must set initial values to the parameters of controls.

At the initialisation of the program we should call some function that sets initial values to our own windows, not the standard window. As an option, this can be done in the KIB-constructor, at the stage of interface building, when V_CURRENT values are set, or ON/OFF states, etc., but now it is possible to initialise elements programmatically. Now it is possible to combine initialisation of elements in the constructor and in the program.

Therefore, we need a special function called from OnInit() to do this job.

What exactly this function will do:

  • Open the required windows at the start of the programme.
  • Set values in the target controls.

What will the function be called?

I would call it Initialize(), but anyone can come up with their own variant.

Themain thing is that this function must be in any interface Expert Advisor. It can be compared to the OnTick() function of an Expert Advisor or OnCalculate() of an indicator. It is important to understand this.


What value will the function return?

The function will have the void type . There is no need to return a value. When called, it will open the necessary windows, initialise the parameters of elements, and possibly preset some properties. That's basically all. Theoretically, you can set initial parameter bounds in it, but I think that the value control will be implemented in a separate function called on element events from the API file and from the timer. I will probably write a printout of control calls in the next version.

*It is important totake into account that at the moment the concept of interface Expert Advisors is just being formed and many discoveries are ahead of us.


Here is an example of the initialising function of an interface Expert Advisor in the context of the current demo project:

1. Function call:

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int _OnInit()
  {
   //------------------------------------------------
   //Initializing program interface:
   //------------------------------------------------
   Initialize();
   //------------------------------------------------


2. Function implementation:

void Initialize()   
{
   //------------------------------------------------
   //Opening the windows:
   //------------------------------------------------
   //1. "Main Parameters". 

    w_14_Main_Parameters();
   //------------------------------------------------

   //------------------------------------------------
   //2. "Input parameters".

   w_10_Input_parameters();
   //------------------------------------------------

   //------------------------------------------------
   //3. "Setting example 1"

   w_6_Settings_example_1();
   //------------------------------------------------


  //------------------------------------------------
  //Initializing the elements:
  //------------------------------------------------
  
   w6_d_p5_S_EDIT_Spin_the_value(55);

   w6_i_p3_H_SLIDER_Roll_the_value(55);

   w14_i_p3_V_SLIDER_Vertical_slider(55);

   w14_s_p4_EDIT_Max("100");

   w14_s_p4_EDIT_Min("0");

   w14_s_p4_EDIT_Selected("55");

   w15_i_p2_P_BAR_P1(55);

   w15_s_p4_VALUE_V1("55");
  //------------------------------------------------
}


So far, I see the structure of the function as follows. A very simple function. It opens windows and sends the required values to the element parameters. It is possible to change the initialisation of elements and opening of windows in places, because opening windows will immediately show the required values of elements without additional redrawing. However, these are minor things.


Then let's move on to the main topic: implementation of step-by-step protection of parameters.

 

14.realisation of step protection of parameter boundaries:

  • 1. Writing logic for controlling settings in preset boundaries and creating a warning system.
  • 2. Thefirst warning: the user receives a signal in the form of changing the colour of parts of the elements responsible for settings.(Let's link the colour of text, bases, frames andslider bar to the value boundaries).
  • 3. Second warning: opening of a dialogue box with a risk notification and a suggestion to return to the original settings.(Let's test the actual possibility to return to the previous settings when clicking on the "Cancel" button.)
  • 4. third warning: opening of a warning window blocking further change of settings and requiring manual confirmation of the user.(Let's check the blocking of windows and elements when the warning window appears).

//------------------------------------------------------------------------------------------------------------

Writing the logic of controlling the settings within the preset limits, and creating a warning system:

  • The first part of the implementation is to set the initial values of the parameters of the selected elements and open the required windows. To do this, we will write the Initialise() function and put its call in the _OnInit() function.
  • The second part of the implementation - let's open the API file and write the connection of elements. In the case of each element in the common chain, we will write calls and passing the value to the other target elements. For example: on the event of the field with buttons we call the horizontal slider and pass the value to it. Then, when the event comes to the slider case, we pass it back to the field with buttons, and additionally to the vertical slider. The latter, in its turn, passes the value to the input fields near itself and to the progress bar window.... All in all, there will be seven main elements in the chain that pass the value in several directions. Here they are:"Settings example 1" with elements"Spin the value" and"Roll the value","Main parameters" with elements"V_SLIDER", field"Selected" and"Percent", and"Processing the data..." with elements VALUE and P_BAR .
  • Part Three: Test the connection.
  • Fourth part: Let's write a function of parametres control with a conditional name: void Risk_management_group_1(). Its task is to signal the user about approaching the boundaries of dangerous values within this group of elements, and to warn when exceeding the allowed limits. The function will accept values from related elements and pass them through the set filters inside the conditions. We will implement the warning through appropriate risk levels of text and frame colour changes and send it to all elements of the chain. In parallel, we will call blocking windows that do not allow the user to continue the action without additional confirmation.
  • Fifth part: let's test the work of the function.

//-----------------------------------------------------------------------------

Let's proceed:

1. Set the initial values of the parameters of the selected elements and open the necessary windows. To do this, let's write theInitialise() function and call it in the _OnInit() function.

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int _OnInit()
  {
   //------------------------------------------------
   //Initializing program interface:
   //------------------------------------------------
   Initialize();
   //------------------------------------------------
void Initialize()   
{
   //------------------------------------------------
   //Opening the windows:
   //------------------------------------------------
   //1. "Main Parameters". 
    w_14_Main_Parameters();

   //2. "Input parameters".
   w_10_Input_parameters();

   //3. "Setting example 1"
   w_6_Settings_example_1();

   //------------------------------------------------
  //Initializing the elements:
  //------------------------------------------------
   w6_d_p5_S_EDIT_Spin_the_value(55);
   w6_i_p3_H_SLIDER_Roll_the_value(55);
   w14_i_p3_V_SLIDER_Vertical_slider(55);
   w14_s_p4_EDIT_Max("100");
   w14_s_p4_EDIT_Min("0");
   w14_s_p4_EDIT_Selected("55");
   w15_i_p2_P_BAR_P1(55);
   w15_s_p4_VALUE_V1("55");
  //------------------------------------------------
}

Result: The required windows are opened and initial values are set to the target elements.


2. Open the API file and write the connection of elements. In the case of each element, write calls and passing the value to the other target elements in the chain:

case Settings_example_1___Spin_the_value:
  
               //------------------------------------------------------------------------------------------------------
               //What to do when the value is set?
               //------------------------------------------------------------------------------------------------------
               //Min value:  NOT SET  |   Max value:  NOT SET  |   V_step:  1.7  |   Default value:  468.99  |  Digits: 3
               //------------------------------------------------------------------------------------------------------
               w6_i_p3_H_SLIDER_Roll_the_value((int)value);

               //------------------------------------------------------------------------------------------------------
               //Your comment:
               //------------------------------------------------------------------------------------------------------
               break;
case Settings_example_1___Roll_the_value:
  
               //------------------------------------------------------------------------------------------------------
               //What to do when the slider's handle is moved?
               //------------------------------------------------------------------------------------------------------
               //Min value:  0  |   Max value:  100  |   V_step:  1  |   Default value:  55  |  Digits: Integer value
               //------------------------------------------------------------------------------------------------------
               //Transferring the value:
               w14_i_p3_V_SLIDER_Vertical_slider((int)value);

               w6_d_p5_S_EDIT_Spin_the_value((double)value);
               //------------------------------------------------------------------------------------------------------
               //Your comment:
               //------------------------------------------------------------------------------------------------------
               break;
case Main_Parameters___Vertical_slider:
  
               //------------------------------------------------------------------------------------------------------
               //What to do when the slider's handle is moved?
               //------------------------------------------------------------------------------------------------------
               //Min value:  0  |   Max value:  100  |   V_step:  1  |   Default value:  50  |  Digits: Integer value
               //------------------------------------------------------------------------------------------------------
               {
                //----------------------------------------------------- 
                //Transferring value to other destinations:
                //----------------------------------------------------- 
                w14_s_p4_EDIT_Percent(value);
                //-----------------------------------------------------
                w14_s_p4_EDIT_Selected(value);
                //-----------------------------------------------------
                w15_i_p2_P_BAR_P1((int)value);
                //-----------------------------------------------------
                w15_s_p4_VALUE_V1(value);
                //-----------------------------------------------------
                w6_i_p3_H_SLIDER_Roll_the_value((int)value);
                //-----------------------------------------------------
                w6_d_p5_S_EDIT_Spin_the_value((double)value);
                //-----------------------------------------------------
                w8_s_p4_CELL_Account_balance__Value(value);
                //------------------------------------------------------------------------------------------------------
                //Your comment:
                //------------------------------------------------------------------------------------------------------
               }
               break;


3. Test the connection:

Result: element values are connected as intended.



4. Write a function to control the parameters of our group of elements: void Risk_management_group_1().

void Risk_management_group_1(string value)
{
 uint Color = 0;
 //--------------------
 static uint This_color;
 static bool User_warned, Last_warning;
 //------------------------------------------------------------
 //Setting limit colors:
 //------------------------------------------------------------
 if((int)value < 25)                      Color = clrLightGreen;
 //------------------------------------------------------------
 if((int)value >= 25 && (int)value < 50)  Color = clrLimeGreen;
 //------------------------------------------------------------
 if((int)value >= 50 && (int)value < 70)  Color = clrGreen;
 //------------------------------------------------------------
 if((int)value >= 70 && (int)value < 85)  Color = clrDarkGreen;
 //------------------------------------------------------------
 if((int)value >= 85 && (int)value < 90)  Color = clrBrown;
 //------------------------------------------------------------
 if((int)value >= 90 && (int)value < 95)  Color = C'170,0,0';
 //------------------------------------------------------------
 if((int)value >= 95 && (int)value <=100) Color = clrRed;
 //------------------------------------------------------------  

 //------------------------------------------------------------ 
 //Changing colors when the limits are passed:
 //------------------------------------------------------------
 if(This_color != Color)
   {
    w14_s_p4_EDIT_Percent((string)Color, p4_COLOR_base); 
    //-----------------------------------------------------
    w14_s_p4_EDIT_Selected((string)Color, p4_COLOR_base); 
    //-----------------------------------------------------
    w15_i_p2_P_BAR_P1(Color, p2_COLOR_bar);
    w15_i_p2_P_BAR_P1(Color, p2_COLOR_frame);
    w15_s_p4_VALUE_V1((string)Color, p4_COLOR_frame);
                   
    w8_s_p4_CELL_Account_balance__Value((string)Color, p4_COLOR_text);
    w8_s_p4_CELL_Account_balance__Value((string)Color, p4_COLOR_frame);
    //-----------------------------------------------------
    w14_i_p3_V_SLIDER_Vertical_slider(Color,p3_COLOR_bar);
    //-----------------------------------------------------
    w15_s_p4_VALUE_V1((string)Color, p4_COLOR_text);
    //-----------------------------------------------------
    w6_i_p3_H_SLIDER_Roll_the_value(Color,p3_COLOR_bar);
    //-----------------------------------------------------
    w6_d_p5_S_EDIT_Spin_the_value((double)Color, p5_COLOR_text);
    //-----------------------------------------------------
    w6_d_p5_S_EDIT_Spin_the_value((double)Color, p5_COLOR_frame);
    //-----------------------------------------------------
    w14_i_p1_BUTTON_BUY_OFF(Color, p1_N_COLOR_frame);
    w14_i_p1_BUTTON_BUY_OFF(Color, p1_A_COLOR_frame);
    //-----------------------------------------------------
    w14_i_p1_BUTTON_SELL_OFF(Color, p1_N_COLOR_frame);
    w14_i_p1_BUTTON_SELL_OFF(Color, p1_A_COLOR_frame);
    //-----------------------------------------------------
    w7_s_p4_EDIT_Comment_1(Color, p4_COLOR_frame);
    //-----------------------------------------------------
    This_color = Color;
    //-----------------------------------------------------
   }   
 //-----------------------------------------------------
 //Opening warning window 1:
 //-----------------------------------------------------
 if((int)value >= 85 && (int)value < 95 && !User_warned)
   { 
    //---------------------------------
    //Opening dialog window:
    //---------------------------------
    w_13_Risky_managment(); 
    //---------------------------------
    //Setting flag of warning 1:
    //---------------------------------
    User_warned = true;
    //---------------------------------
   }
 //-----------------------------------------------------
 if((int)value < 85)User_warned = false;
 //-----------------------------------------------------
 //Opening warning window 2:
 //-----------------------------------------------------
 if((int)value >= 96 && !Last_warning)
   { 
    //---------------------------------
    //Calling blocking window:
    //---------------------------------
    w_17_Last_warning();
    //---------------------------------
    //Setting flag of warning 2:
    //---------------------------------
    Last_warning = true;
    //---------------------------------
   }
 //-----------------------------------------------------
 if((int)value < 95)Last_warning = false;                
 //-----------------------------------------------------                 
}

Call the Risk_management_group_1() function from the _OnInit() function:

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int _OnInit()
  {
   //------------------------------------------------
   //Initializing program interface:
   //------------------------------------------------
   Initialize();
   //----------------------------------------------------------
   //Checking default value of the parameters in the group:  
   //----------------------------------------------------------
   Risk_management_group_1();
   //----------------------------------------------------------
 

Result: works as intended, but when entering a value in the input field, the warning window does not reset the entered value when it appears(requires improvement).

(*Also - setting the frame colour was added in the update, but is missing in the current version).


 

The next task is to consider cancelling the entered parameters by pressing the "Cancel" button.

This is a very difficult task, but I have already partially implemented it. I will try to restore the previous functionality.

 
In addition to the colour indication, I am now implementing flashing of frames, texts and bases. I think it will be ready tomorrow. Next, cancellation of entered values with the Cancel button.

The problem is that when entering values into elements, they are immediately received by the kernel and passed to the API file, which logically causes the processing of custom code. It is necessary to delay accepting values in windows with confirmation buttons before they arrive in parameters and link it to clicking on "Ok" or "Confirm" (or "Apply").

But also, it is necessary to return to the elements the previous values before the changes, if the user clicks on the cancellation button (Cancel).

This is a very interesting problem and its solution immediately raises the practical usefulness of the interface to a new level. Fortunately, for the most part, the goal was achieved long ago. It's just amazing how many interesting things were already implemented 4 years ago.

I think I'll accomplish the task in a week and further, I'll get serious about tables.
 

In the last breakdown I showed how to apply colour indication of risk and open blocking windows at the crossing of set parameter limits. However, two problems that I did not expect were discovered.

1. The risk management function opens the first warning window when a dangerous level is crossed, but if you keep the cursor pressed on the element at that moment, the value continues to grow and reaches the next conditional level. - Critical.

2. When the critical value is crossed, the last warning window opens, but it does not stop the value from changing either if the user continues to hold the left mouse button.

3. If the user releases the mouse button and wants to close the warning windows, he cannot do it. To be more precise, he couldn't. The reason is that the two blocking windows start blocking each other. When one of the blocking windows is open, it is easily closed, but when two windows are open at the same time, nothing else in the interface can work. The programme goes into a stupor, although it still works.

The image below shows how this happened:

 

Then, I fixed the mutual locking problems of the settings windows and now the windows do not interfere with each other. They perform the locking function together without conflicting with each other.


Now I need to make it so that the warning window will automatically stop changes to the parameter value, even if the left mouse button is pressed and the item is active.

 
Today I will publish a continuation of the topic of colour indication of parameter values - flashing of elements. The task turned out to be a bit more complicated than I thought, so I delayed on it. In the end, the solution justified the time spent. In my opinion, at any rate.
 
You can understand that.
 
Jin Rong Xia #:
You can understand that.
Yes, I can understand you. The translator's working well.