Galeria de UIs escritas em MQL - página 69

 
Maxim Kuznetsov projeto?

Há um repositório de alguma coisa (que, na minha opinião, dificilmente pode ser chamado de código-fonte ) e documentação

Por que você está procurando por isso, procurando por isso e não consegue encontrar))). O projeto está nas páginas das ramificações, juntamente com as instruções de instalação. Não vou lhe dizer a página exata, role para trás.

A próxima versão será publicada no kodobase. Se você quiser, pode esperar um pouco.
 

Foi adicionada a capacidade de alterar programaticamente a cor dos quadros de elementos e associá-los a valores de parâmetros. Esse é um indicador informativo e útil que ajuda a perceber rapidamente o nível de risco dos valores inseridos. Ele se mostrou prático e claro. Além disso, no caso de exceder os limites definidos, são exibidas janelas de aviso.

Alguns exemplos:


Amanhã, veremos isso com exemplos e código.

 
Vamos começar em uma nova página.
 

Antes de continuar com o tópico da implementação da proteção escalonada dos limites dos parâmetros e dos avisos ao usuário, devemos mencionar outro tópico que o precede diretamente. Ou seja, a predefinição de parâmetros.

Começarei com o que é bem conhecido: a maioria dos programas MQL tem variáveis da categoria de entrada. Elas são declaradas em nível global e são visíveis em uma única janela de configurações. A janela aparece no início do programa e, dentro dela, o usuário pode alterar os valores iniciais das variáveis "externas", se houver necessidade. Mas antes disso, o usuário inicializa as variáveis externas dentro do programa. A questão é que as predefinições do programa não são universais, e é por isso que há uma categoria de variáveis que exigem a possibilidade de configuração a cada inicialização. Sabe-se também que qualquer tentativa de acessar manualmente as variáveis externas durante a execução do programa é impossível e requer uma reinicialização. Com uma interface gráfica, essa necessidade é eliminada. As configurações do programa podem ser abertas em tempo de execução.

Entretanto, ainda há a mesma necessidade de definir valores iniciais para os parâmetros do programa no início.

Se tivermos uma interface gráfica , não faz sentido declarar variáveis do tipo de entrada, porque não precisamos mais da janela de configurações padrão , mas a essência continua a mesma. Em vez de variáveis de entrada, precisamos definir valores iniciais para os parâmetros dos controles.

Na inicialização do programa, devemos chamar alguma função que defina os valores iniciais para nossas próprias janelas, e não para a janela padrão. Como opção, isso pode ser feito no construtor KIB, no estágio de construção da interface, quando os valores V_CURRENT são definidos, ou os estados ON/OFF, etc., mas agora é possível inicializar os elementos de forma programática. Agora é possível combinar a inicialização de elementos no construtor e no programa.

Portanto, precisamos de uma função especial chamada de OnInit() para fazer esse trabalho.

O que exatamente essa função fará:

  • Abrir as janelas necessárias no início do programa.
  • Definir valores nos controles de destino.

Como a função será chamada?

Eu a chamaria de Initialize(), mas qualquer pessoa pode criar sua própria variante.

Oprincipal é que essa função deve estar em qualquer Expert Advisor de interface. Ela pode ser comparada à função OnTick() de um Expert Advisor ou OnCalculate() de um indicador. É importante entender isso.


Que valor a função retornará?

A função terá o tipo void. Não há necessidade de retornar um valor. Quando chamada, ela abrirá as janelas necessárias, inicializará os parâmetros dos elementos e possivelmente predefinirá algumas propriedades. Isso é basicamente tudo. Teoricamente, é possível definir limites de parâmetros iniciais, mas acho que o controle de valores será implementado em uma função separada chamada em eventos de elementos do arquivo API e do timer. Provavelmente escreverei uma impressão das chamadas de controle na próxima versão.

*É importante levarem conta que, no momento, o conceito de Expert Advisors de interface está apenas sendo formado e muitas descobertas estão à nossa frente.


Aqui está um exemplo da função de inicialização de um Expert Advisor de interface no contexto do projeto de demonstração atual:

1. Chamada de função:

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


2. implementação da função:

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


Até o momento, vejo a estrutura da função da seguinte forma. Uma função muito simples. Ela abre janelas e envia os valores necessários para os parâmetros do elemento. É possível alterar a inicialização de elementos e a abertura de janelas em alguns lugares, porque a abertura de janelas mostrará imediatamente os valores necessários dos elementos sem redesenho adicional. No entanto, essas são questões menores.


Vamos então passar ao tópico principal: implementação da proteção passo a passo dos parâmetros.

 

14.Realização da proteção por etapas dos limites dos parâmetros:

  • 1. Escrever a lógica para controlar as configurações nos limites predefinidos e criar um sistema de aviso.
  • 2. Oprimeiro aviso: o usuário recebe um sinal na forma de alteração da cor de partes dos elementos responsáveis pelas configurações.(Vamos vincular a cor do texto, das bases, dos quadros e da barradeslizante aos limites de valor).
  • 3. Segundo aviso: abertura de uma caixa de diálogo com uma notificação de risco e uma sugestão para retornar às configurações originais.(Vamos testar a possibilidade real de retornar às configurações anteriores ao clicar no botão "Cancelar").
  • 4. Terceiro aviso: abertura de uma janela de aviso que bloqueia a alteração adicional das configurações e exige a confirmação manual do usuário.(Vamos verificar o bloqueio de janelas e elementos quando a janela de aviso for exibida).

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

Escrever a lógica de controle das configurações dentro dos limites predefinidos e criar um sistema de aviso:

  • A primeira parte da implementação é definir os valores iniciais dos parâmetros dos elementos selecionados e abrir as janelas necessárias. Para fazer isso, escreveremos a função Initialise() e colocaremos sua chamada na função _OnInit().
  • A segunda parte da implementação - vamos abrir o arquivo API e escrever a conexão dos elementos. No caso de cada elemento da cadeia comum, escreveremos chamadas e passaremos o valor para os outros elementos de destino. Por exemplo: no evento do campo com botões, chamamos o controle deslizante horizontal e passamos o valor para ele. Em seguida, quando o evento chega ao caso do controle deslizante, nós o passamos de volta para o campo com botões e, adicionalmente, para o controle deslizante vertical. Esse último, por sua vez, passa o valor para os campos de entrada próximos a ele e para a janela da barra de progresso.... Ao todo, haverá sete elementos principais na cadeia que passam o valor em várias direções. Aqui estão eles:"Settings example 1" (Exemplo de configurações 1) com os elementos"Spin the value" (Giraro valor) e"Roll the value"(Rolar o valor),"Main parameters" (Parâmetros principais) com os elementos"V_SLIDER"(V_SLIDER), campo"Selected"(Selecionado) e"Percent"(Porcentagem), e"Processing the data..."(Processando os dados...) com os elementos VALUE e P_BAR .
  • Terceira parte: testar a conexão.
  • Quarta parte: vamos escrever uma função de controle de parâmetros com um nome condicional: void Risk_management_group_1(). Sua tarefa é sinalizar ao usuário sobre a aproximação dos limites de valores perigosos dentro desse grupo de elementos e avisar quando exceder os limites permitidos. A função aceitará valores de elementos relacionados e os passará pelos filtros definidos dentro das condições. Implementaremos o aviso por meio de níveis de risco apropriados de mudanças de texto e cor do quadro e o enviaremos a todos os elementos da cadeia. Em paralelo, chamaremos janelas de bloqueio que não permitem que o usuário continue a ação sem confirmação adicional.
  • Quinta parte: vamos testar o funcionamento da função.

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

Vamos prosseguir:

1. defina os valores iniciais dos parâmetros dos elementos selecionados e abra as janelas necessárias. Para fazer isso, vamos escrever a funçãoInitialise() e chamá-la na função _OnInit().

//+------------------------------------------------------------------+
//| 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");
  //------------------------------------------------
}

Resultado: As janelas necessárias são abertas e os valores iniciais são definidos para os elementos de destino.


2) Abra o arquivo API e escreva a conexão dos elementos. No caso de cada elemento, escreva chamadas e passe o valor para os outros elementos de destino na cadeia:

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. Teste a conexão:

Resultado: os valores dos elementos estão conectados como pretendido.



4. Escreva uma função para controlar os parâmetros do nosso grupo de elementos: 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;                
 //-----------------------------------------------------                 
}

Chame a função Risk_management_group_1() a partir da função _OnInit():

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

Resultado: funciona como pretendido, mas ao inserir um valor no campo de entrada, a janela de aviso não redefine o valor inserido quando aparece(requer aprimoramento).

(*Além disso, a configuração da cor do quadro foi adicionada na atualização, mas não está presente na versão atual).


 

A próxima tarefa é considerar o cancelamento dos parâmetros inseridos pressionando o botão "Cancel".

Essa é uma tarefa muito difícil, mas eu já a implementei parcialmente. Tentarei restaurar a funcionalidade anterior.

 
Além da indicação de cores, agora estou implementando o piscar de quadros, textos e bases. Acho que isso estará pronto amanhã. Em seguida, o cancelamento dos valores inseridos com o botão Cancelar.

O problema é que, ao inserir valores nos elementos, eles são imediatamente recebidos pelo kernel e passados para o arquivo de API, o que logicamente causa o processamento do código personalizado. É necessário atrasar a aceitação de valores em janelas com botões de confirmação antes que eles cheguem aos parâmetros e vincular isso ao clique em "Ok" ou "Confirmar" (ou "Aplicar").

Mas também é necessário retornar aos elementos os valores anteriores antes das alterações, se o usuário clicar no botão de cancelamento (Cancel).

Esse é um problema muito interessante e sua solução eleva imediatamente a utilidade prática da interface a um novo patamar. Felizmente, em sua maior parte, o objetivo foi alcançado há muito tempo. É incrível a quantidade de coisas interessantes que já foram implementadas há 4 anos.

Acho que realizarei a tarefa em uma semana e, depois, levarei as tabelas a sério.
 

No último detalhamento, mostrei como aplicar a indicação colorida de risco e abrir janelas de bloqueio ao cruzar os limites dos parâmetros definidos. Entretanto, dois problemas que eu não esperava foram descobertos.

1. A função de gerenciamento de risco abre a primeira janela de aviso quando um nível perigoso é ultrapassado, mas se você mantiver o cursor pressionado sobre o elemento nesse momento, o valor continua a crescer e atinge o próximo nível condicional. - Crítico.

2. Quando o valor crítico é ultrapassado, a última janela de aviso é aberta, mas isso também não impede que o valor mude se o usuário continuar a manter pressionado o botão esquerdo do mouse.

3 Se o usuário soltar o botão do mouse e quiser fechar as janelas de aviso, ele não poderá fazê-lo. Mais precisamente, ele não poderá fechar as janelas de aviso. Para ser mais preciso, ele não pode. O motivo é que as duas janelas de bloqueio começam a bloquear uma à outra. Quando uma das janelas de bloqueio está aberta, ela pode ser facilmente fechada, mas quando duas janelas estão abertas ao mesmo tempo, nada mais na interface pode funcionar. O programa entra em um estado de estupor, embora ainda funcione.

A imagem abaixo mostra como isso aconteceu:

 

Em seguida, corrigi os problemas de travamento mútuo das janelas de configurações e agora as janelas não interferem umas nas outras. Elas executam a função de bloqueio juntas sem entrar em conflito umas com as outras.


Agora preciso fazer com que a janela de aviso interrompa automaticamente as alterações no valor do parâmetro, mesmo que o botão esquerdo do mouse seja pressionado e o item esteja ativo.