Tipos personalizados

A palavra-chave typedef em linguagem C++ permite criar tipos personalizados de dados, basta definir o nome do tipo de dados para um tipo de dados existente. Ao fazer isto, não é criado um novo tipo de dados, mas sim é definido um novo nome para o tipo existente. Graças ao uso de tipos personalizados, você pode tornar o programa mais flexível, basta suficiente alterar as instruções typedef usando os macros de substituição (#define). Usar os tipos personalizados também pode melhorar a legibilidade do código, uma vez que, para os tipos de dados padrão, você pode usar seus próprios nomes descritivos com ajuda de typedef. Formato geral para escrever instruções a fim de criar um tipo personalizado:

   typedef tipo novo_nome;

Aqui o elemento tipo representa qualquer tipo de dados válido, enquanto o elemento novo_nome é o nome novo para este tipo. É importante notar que o novo nome é definido apenas como um complemento para o nome existente do tipo e não para substituí-lo. Na linguagem MQL5, você pode criar um ponteiro para a função, usando typedef.

Ponteiro para a função

Ponteiro para a função geralmente é determinado pelo formato de registro

   typedef tipo_de_resultado_de_função (*Nome_de_tipo_de_função)(lista_de_tipos_de_parâmetros_de_entrada);

onde, após a palavra typedef, é definida a assinatura da função, isto é, o número e tipo de parâmetros de entrada, bem como o tipo de resultado a ser retornado pela função. Aqui está uma explicação de como criar e usar um ponteiro para uma função:

// --- declaramos o ponteiro para uma função que aceita dois parâmetros do tipo int
   typedef int (*TFunc)(int,int);
//--- TFunc é o tipo, e nós podemos declarar o ponteiro-variável para a função
   TFunc func_ptr; // ponteiro para a função
//--- declaramos as funções que correspondem à descrição TFunc
   int sub(int x,int y) { return(x-y); }  // / subtração de um número a partir de outro
   int add(int x,int y) { return(x+y); }  // adição de dois números
   int neg(int x)       { return(~x);  }  // inversão de bits na variável
//--- você pode armazenas o endereço da função na variável func_ptr, para chamá-la no futuro
   func_ptr=sub;
   Print(func_ptr(10,5));
   func_ptr=add;
   Print(func_ptr(10,5));
   func_ptr=neg;           // erro: neg não tem o tipo int (int,int)
   Print(func_ptr(10));    // erro: deve haver dois parâmetros

Neste exemplo, à variável func_ptr podem ser atribuídas as funções sub e add, uma vez que cada uma delas tem dois parâmetros de entrada do tipo int, conforme especificado na definição do ponteiro para a função TFunc. Aqui à função neg não pode ser atribuído o ponteiro func_ptr, uma vez que sua assinatura é diferente.

Organização dos modelos de eventos na interface personalizada

Usando os ponteiros para a função você pode facilmente construir a manipulação de eventos ao criar a interface personalizada. Mostraremos um exemplo a partir da seção CButton sobre como criar botões e adicionar neles uma função para processamento do carregamento do botão. Em primeiro lugar, definimos o ponteiro para a função TAction, ela será chamada pressionando um botão, e criaremos três funções em conformidade com a descrição TAction.

//--- criamos o tipo personalizado de função
typedef int(*TAction)(string,int);
//+------------------------------------------------------------------+
//|  Abre o arquivo                                                  |
//+------------------------------------------------------------------+
int Open(string name,int id)
  {
   PrintFormat("Função chamada %s (name=%s id=%d)",__FUNCTION__,name,id);
   return(1);
  }
//+------------------------------------------------------------------+
//|  Salva o arquivo                                                  |
//+------------------------------------------------------------------+
int Save(string name,int id)
  {
   PrintFormat("Função chamada %s (name=%s id=%d)",__FUNCTION__,name,id);
   return(2);
  }
//+------------------------------------------------------------------+
//|  Fecha o arquivo                                                  |
//+------------------------------------------------------------------+
int Close(string name,int id)
  {
   PrintFormat("Função chamada %s (name=%s id=%d)",__FUNCTION__,name,id);
   return(3);
  }
 

Logo realizamos a classe MyButton a partir do CButton, em que adicionamos o membro TAction que, por sua vez, é o ponteiro para a função.

//+------------------------------------------------------------------+
//| Criamos nossa classe de botão com a função de manipulador de eventos          |
//+------------------------------------------------------------------+
class MyButton: public CButton
  {
private:
   TAction           m_action;                    // manipulador de eventos para o gráfico
public:
                     MyButton(void){}
                    ~MyButton(void){}
   //--- construtor com indicação do texto do botão e ponteiro para a função a fim de manipular eventos
                     MyButton(string text, TAction act)
     {
      Text(text);
      m_action=act;
     }
   //--- definição de função que será chamada a partir do manipulador de eventos OnEvent()
   void              SetAction(TAction act){m_action=act;}
   //--- manipulador padrão de eventos de gráfico
   virtual bool      OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam) override
     {      
      if(m_action!=NULL & lparam==Id())
        { 
         //--- chamamos o manipulador próprio m_action() 
         m_action(sparam,(int)lparam);
         return(true);
        }
      else
      //--- retornamos o resultado da chamada do manipulador a partir da classe mão CButton
         return(CButton::OnEvent(id,lparam,dparam,sparam));
     }
  };

Em seguida, criamos a classe derivada CControlsDialog a partir da CAppDialog, à qual adicionamos a matriz m_buttons para armazenas os botões do tipo MyButton,  bem como os métodos AddButton(MyButton &button) e CreateButtons().

//+------------------------------------------------------------------+
//| Classe CControlsDialog                                            |
//| Designação: painel gráfico para controle do aplicativo       |
//+------------------------------------------------------------------+
class CControlsDialog : public CAppDialog
  {
private:
   CArrayObj         m_buttons;                     // matriz de botões
public:
                     CControlsDialog(void){};
                    ~CControlsDialog(void){};
   //--- create
   virtual bool      Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2) override;
   //--- adição de botão
   bool              AddButton(MyButton &button){return(m_buttons.Add(GetPointer(button)));m_buttons.Sort();};
protected:
   //--- criação de botões 
   bool              CreateButtons(void);
  };
//+------------------------------------------------------------------+
//| Criação do objeto CControlsDialog no gráfico                      |
//+------------------------------------------------------------------+
bool CControlsDialog::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
  {
   if(!CAppDialog::Create(chart,name,subwin,x1,y1,x2,y2))
      return(false);
   return(CreateButtons());
//---
  }
//+------------------------------------------------------------------+
//| defines                                                          |
//+------------------------------------------------------------------+
//--- indents and gaps
#define INDENT_LEFT                         (11)      // indent from left (with allowance for border width)
#define INDENT_TOP                          (11)      // indent from top (with allowance for border width)
#define CONTROLS_GAP_X                      (5)       // gap by X coordinate
#define CONTROLS_GAP_Y                      (5)       // gap by Y coordinate
//--- for buttons
#define BUTTON_WIDTH                        (100)     // size by X coordinate
#define BUTTON_HEIGHT                       (20)      // size by Y coordinate
//--- for the indication area
#define EDIT_HEIGHT                         (20)      // size by Y coordinate
//+------------------------------------------------------------------+
//| Criação e adição de botões para o painel CControlsDialog           |
//+------------------------------------------------------------------+
bool CControlsDialog::CreateButtons(void)
  {
//--- cálculo de coordenadas de botões
   int x1=INDENT_LEFT;
   int y1=INDENT_TOP+(EDIT_HEIGHT+CONTROLS_GAP_Y);
   int x2;
   int y2=y1+BUTTON_HEIGHT;
//--- adicionamos os objetos dos botões juntamente com os ponteiros para as funções
   AddButton(new MyButton("Open",Open));
   AddButton(new MyButton("Save",Save));
   AddButton(new MyButton("Close",Close));
//--- criamos os botões graficamente
   for(int i=0;i<m_buttons.Total();i++)
     {
      MyButton *b=(MyButton*)m_buttons.At(i);
      x1=INDENT_LEFT+i*(BUTTON_WIDTH+CONTROLS_GAP_X);
      x2=x1+BUTTON_WIDTH;
      if(!b.Create(m_chart_id,m_name+"bt"+b.Text(),m_subwin,x1,y1,x2,y2))
        {
         PrintFormat("Failed to create button %s %d",b.Text(),i);
         return(false);
        }
      //--- adicionamos cada botão no recipiente CControlsDialog
      if(!Add(b))
         return(false);
     }
//--- succeed
   return(true);
  }

Agora podemos escrever o programa usando o painel de controle CControlsDialog, no qual são criados 3 botões "Open", "Save" e "Close". Ao pressionar o botão, é chamada a função correspondente que está escrita como um ponteiro para a função TAction.

//--- declaramos o objeto no nível global para criá-lo automaticamente ao inciar o programa
CControlsDialog MyDialog;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- agora criamos o objeto no gráfico
   if(!MyDialog.Create(0,"Controls",0,40,40,380,344))
      return(INIT_FAILED);
//--- executamos o aplicativo
   MyDialog.Run();
//--- inicialização bem-sucedida do aplicativo
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- destroy dialog
   MyDialog.Destroy(reason);
  }
//+------------------------------------------------------------------+
//| Expert chart event function                                      |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,         // event ID  
                  const long& lparam,   // event parameter of the long type
                  const double& dparam, // event parameter of the double type
                  const string& sparam) // event parameter of the string type
  {
//--- para os eventos do gráfico, chamamos o manipulador a partir da classe mãe (neste caso, CAppDialog)
   MyDialog.ChartEvent(id,lparam,dparam,sparam);
  }

A aparência do aplicativo em execução e os resultados dos botões pressionados são mostrados na imagem.

panel_buttons

 

Código-fonte completo do programa

//+------------------------------------------------------------------+
//|                                                Panel_Buttons.mq5 |
//|                        Copyright 2017, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
 
#property copyright "Copyright 2017, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property description "Painel com vários botões CButton"
#include <Controls\Dialog.mqh>
#include <Controls\Button.mqh>
//+------------------------------------------------------------------+
//| defines                                                          |
//+------------------------------------------------------------------+
//--- indents and gaps
#define INDENT_LEFT                         (11)      // indent from left (with allowance for border width)
#define INDENT_TOP                          (11)      // indent from top (with allowance for border width)
#define CONTROLS_GAP_X                      (5)       // gap by X coordinate
#define CONTROLS_GAP_Y                      (5)       // gap by Y coordinate
//--- for buttons
#define BUTTON_WIDTH                        (100)     // size by X coordinate
#define BUTTON_HEIGHT                       (20)      // size by Y coordinate
//--- for the indication area
#define EDIT_HEIGHT                         (20)      // size by Y coordinate
 
//--- criamos o tipo personalizado de função
typedef int(*TAction)(string,int);
//+------------------------------------------------------------------+
//|  Abre o arquivo                                                  |
//+------------------------------------------------------------------+
int Open(string name,int id)
  {
   PrintFormat("Função chamada %s (name=%s id=%d)",__FUNCTION__,name,id);
   return(1);
  }
//+------------------------------------------------------------------+
//|  Salva o arquivo                                                  |
//+------------------------------------------------------------------+
int Save(string name,int id)
  {
   PrintFormat("Função chamada %s (name=%s id=%d)",__FUNCTION__,name,id);
   return(2);
  }
//+------------------------------------------------------------------+
//|  Fecha o arquivo                                                  |
//+------------------------------------------------------------------+
int Close(string name,int id)
  {
   PrintFormat("Função chamada %s (name=%s id=%d)",__FUNCTION__,name,id);
   return(3);
  }
//+------------------------------------------------------------------+
//| Criamos nossa classe de botão com a função de manipulador de eventos          |
//+------------------------------------------------------------------+
class MyButton: public CButton
  {
private:
   TAction           m_action;                    // manipulador de eventos para o gráfico
public:
                     MyButton(void){}
                    ~MyButton(void){}
   //--- construtor com indicação do texto do botão e ponteiro para a função a fim de manipular eventos
                     MyButton(string text,TAction act)
     {
      Text(text);
      m_action=act;
     }
   //--- definição de função que será chamada a partir do manipulador de eventos OnEvent()
   void              SetAction(TAction act){m_action=act;}
   //--- manipulador padrão de eventos de gráfico
   virtual bool      OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam) override
     {
      if(m_action!=NULL & lparam==Id())
        {
         //--- chamamos o manipulador próprio
         m_action(sparam,(int)lparam);
         return(true);
        }
      else
      //--- retornamos o resultado da chamada do manipulador a partir da classe mão CButton
         return(CButton::OnEvent(id,lparam,dparam,sparam));
     }
  };
//+------------------------------------------------------------------+
//| Classe CControlsDialog                                            |
//| Designação: painel gráfico para controle do aplicativo       |
//+------------------------------------------------------------------+
class CControlsDialog : public CAppDialog
  {
private:
   CArrayObj         m_buttons;                     // matriz de botões
public:
                     CControlsDialog(void){};
                    ~CControlsDialog(void){};
   //--- create
   virtual bool      Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2) override;
   //--- adição de botão
   bool              AddButton(MyButton &button){return(m_buttons.Add(GetPointer(button)));m_buttons.Sort();};
protected:
   //--- criação de botões 
   bool              CreateButtons(void);
  };
//+------------------------------------------------------------------+
//| Criação do objeto CControlsDialog no gráfico                      |
//+------------------------------------------------------------------+
bool CControlsDialog::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
  {
   if(!CAppDialog::Create(chart,name,subwin,x1,y1,x2,y2))
      return(false);
   return(CreateButtons());
//---
  }
//+------------------------------------------------------------------+
//| Criação e adição de botões para o painel CControlsDialog           |
//+------------------------------------------------------------------+
bool CControlsDialog::CreateButtons(void)
  {
//--- cálculo de coordenadas de botões
   int x1=INDENT_LEFT;
   int y1=INDENT_TOP+(EDIT_HEIGHT+CONTROLS_GAP_Y);
   int x2;
   int y2=y1+BUTTON_HEIGHT;
//--- adicionamos os objetos dos botões juntamente com os ponteiros para as funções
   AddButton(new MyButton("Open",Open));
   AddButton(new MyButton("Save",Save));
   AddButton(new MyButton("Close",Close));
//--- criamos os botões graficamente
   for(int i=0;i<m_buttons.Total();i++)
     {
      MyButton *b=(MyButton*)m_buttons.At(i);
      x1=INDENT_LEFT+i*(BUTTON_WIDTH+CONTROLS_GAP_X);
      x2=x1+BUTTON_WIDTH;
      if(!b.Create(m_chart_id,m_name+"bt"+b.Text(),m_subwin,x1,y1,x2,y2))
        {
         PrintFormat("Failed to create button %s %d",b.Text(),i);
         return(false);
        }
      //--- adicionamos cada botão no recipiente CControlsDialog
      if(!Add(b))
         return(false);
     }
//--- succeed
   return(true);
  }
//--- declaramos o objeto no nível global para criá-lo automaticamente ao inciar o programa
CControlsDialog MyDialog;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- agora criamos o objeto no gráfico
   if(!MyDialog.Create(0,"Controls",0,40,40,380,344))
      return(INIT_FAILED);
//--- executamos o aplicativo
   MyDialog.Run();
//--- inicialização bem-sucedida do aplicativo
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- destroy dialog
   MyDialog.Destroy(reason);
  }
//+------------------------------------------------------------------+
//| Expert chart event function                                      |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,         // event ID  
                  const long& lparam,   // event parameter of the long type
                  const double& dparam, // event parameter of the double type
                  const string& sparam) // event parameter of the string type
  {
//--- para os eventos do gráfico, chamamos o manipulador a partir da classe mãe (neste caso, CAppDialog)
   MyDialog.ChartEvent(id,lparam,dparam,sparam);
  }

 

Veja também

Variáveis, Funções