Recursos

Usando gráficos e som em programas MQL5

Programas em MQL5 permitem trabalhar com som e arquivos gráficos:

 

PlaySound()

Exemplo de chamada da função PlaySound():

//+------------------------------------------------------------------+
//| A função chama OrderSend() padrão e toca um som                  |
//+------------------------------------------------------------------+
void OrderSendWithAudio(MqlTradeRequest  &request, MqlTradeResult &result)
  {
  //--- envia uma solicitação para um servidor
   OrderSend(request,result);
   //--- se a solicitação for aceite, executa o som Ok.wav
   if(result.retcode==TRADE_RETCODE_PLACEDPlaySound("Ok.wav");
   //--- se falhar, toca um alarme a partir do arquivo timeout.wav
   else PlaySound("timeout.wav");
  }

O exemplo mostra como tocar sons a partir de arquivos 'Ok.wav' e 'timeout.wav', que estão incluídos no pacote do terminal padrão. Estes arquivos estão localizados na pasta terminal_directory\Sounds. Aqui, terminal_directory é uma pasta, a partir do qual o terminal de cliente da MetaTrader 5 é iniciado. A localização do diretório do terminal pode ser encontrado a partir de um programa MQL5 da seguinte forma:

//--- Pasta, na qual dados de terminal são armazenados
   string terminal_path=TerminalInfoString(TERMINAL_PATH);

Você pode usar arquivos de som não somente da pasta terminal_directory\Sounds, mas também de qualquer sub-pasta localizada em terminal_data_directory\MQL5. Você pode descobrir a localização do diretório de dados do terminal a partir do menu do terminal "Arquivo" -> "Abrir" dados do terminal ou usar um método de programa:

//--- Pasta, na qual dados de terminal são armazenados
   string terminal_data_path=TerminalInfoString(TERMINAL_DATA_PATH);

Por exemplo, se o arquivo de som 'Demo.wav' está localizado em terminal_data_directory\MQL5\Files, então a chamada de PlaySound() deveria ser escrita da seguinte forma:

//--- toca Demo.wav a partir da pasta terminal_directory_data\MQL5\Files\Demo.wav
   PlaySound("\\Files\\Demo.wav");

Observe que no comentário o caminho do arquivo está escrito usando uma barra invertida "\", e na função é usado "\\".

Ao se especificar o caminho, sempre use barras invertidas duplas como separador, porque uma única barra invertida é um controle de símbolo para o compilador ao lidar com constantes de cadeias de caracteres e constantes de caracteres no código fonte do programa.

Call PlaySound() function with NULL parameter to stop playback:

//--- Chamar o PlaySound() com parâmetro NULL interrompe a reprodução
   PlaySound(NULL);

 

ObjectCreate()

Exemplo de um Expert Advisor, que cria um rótulo gráfico (OBJ_BITMAP_LABEL) usando a função ObjectCreate().

string label_name="currency_label";        // nome do objeto OBJ_BITMAP_LABEL
string euro      ="\\Images\\euro.bmp";    // caminho do arquivo terminal_dara_directory\MQL5\Images\euro.bmp
string dollar    ="\\Images\\dollar.bmp";  // caminho do arquivo terminal_dara_directory\MQL5\Images\dollar.bmp
//+------------------------------------------------------------------+
//| Função de inicialização do Expert                                |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- cria um botão OBJ_BITMAP_LABEL, se ele já não tiver sido criado
   if(ObjectFind(0,label_name)<0)
     {
      //--- tenta criar objeto OBJ_BITMAP_LABEL
      bool created=ObjectCreate(0,label_name,OBJ_BITMAP_LABEL,0,0,0);
      if(created)
        {
         //--- vincula o botão ao canto superior esquerdo do gráfico
         ObjectSetInteger(0,label_name,OBJPROP_CORNER,CORNER_RIGHT_UPPER);
         //--- agora configura as propriedades do objeto
         ObjectSetInteger(0,label_name,OBJPROP_XDISTANCE,100);
         ObjectSetInteger(0,label_name,OBJPROP_YDISTANCE,50);
         //--- redefine o código do último erro para 0
         ResetLastError();
         //--- carrega uma figura para indicador o estado "Pressionado" do botão
         bool set=ObjectSetString(0,label_name,OBJPROP_BMPFILE,0,euro);
         //--- testa o resultado
         if(!set)
           {
            PrintFormat("Falha no download a partir do arquivo de imagem %s. Código de erro %d",euro,GetLastError());
           }
         ResetLastError();
         //--- carrega uma figura para indicador do estado "Não pressionado" do botão
         set=ObjectSetString(0,label_name,OBJPROP_BMPFILE,1,dollar);
         
         if(!set)
           {
            PrintFormat("Falha no download a partir do arquivo de imagem %s. Código de erro %d",dollar,GetLastError());
           }
         //--- envia um comando para um gráfico para reatualização, a fim de que o botão apareça imediatamente, sem um tick
         ChartRedraw(0);
        }
      else
        {
         //--- falha ao criar um objeto, notificar
         PrintFormat("Falha ao criar objeto OBJ_BITMAP_LABEL. Error code %d",GetLastError());
        }
     }
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Função de Desinicialização do Expert                             |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- exclui um objeto de um gráfico
   ObjectDelete(0,label_name);
  }

A criação e configuração do objeto gráfico de nome currency_label são executados na função OnInit(). Os caminhos para os arquivos gráficos são definidos nas variáveis globais euro e dollar, uma barra invertida dupla é usada como separador:

string euro      ="\\Images\\euro.bmp";    // caminho do arquivo terminal_dara_directory\MQL5\Images\euro.bmp
string dollar    ="\\Images\\dollar.bmp";  // caminho do arquivo terminal_dara_directory\MQL5\Images\dollar.bmp

Os arquivos estão localizados na pasta terminal_data_directory\MQL5\Images.

O Objeto OBJ_BITMAP_LABEL é na realizada um botão, que exibe uma das duas imagens, dependendo do estado do botão (pressionado ou não pressionado): euro.bmp ou dollar.bmp.

Propriedades do objeto the OBJ_BITMAP_LABEL

O tamanho do botão com uma interface gráfico é automaticamente ajustada para o tamanho da figura. A imagem é alterada por um clique do botão esquerdo do mouse sob o objeto OBJ_BITMAP_LABEL ("Disable selection" deve estar definida nas propriedades). O objeto OBJ_BITMAP é criado da mesma forma - ele é usado para criar o pano de fundo com um imagem necessária.

O valor da propriedade OBJPROP_BMPFILE, que é responsável pela aparência dos objetos OBJ_BITMAP e OBJ_BITMAP_LABEL, e pode ser alterado dinamicamente. Isso permite criar várias interfaces interativas de usuário para programas MQL5.

 

Inclusão de recursos em arquivos executáveis durante compilação de programas MQL5 #

Um programa mql5 pode precisar de um monte de diferentes recursos baixáveis na forma de arquivos de imagem e som. A fim de eliminar a necessidade de transferir todos estes arquivos ao mover um arquivo executável em MQL5, a diretriz do compilador #resource deve ser usada:

 #resource path_to_resource_file

O comando #resource diz ao compilador que o recurso no caminho especificado path_to_resource_file deve ser incluído dentro do arquivo executável EX5. Assim, todos os sons e imagens necessários podem ser alocados diretamente dentro de um arquivo EX5, de modo que não exista necessidade de transferir separadamente os arquivos nele usados, caso você queira executar o programa em um terminal diferente. Qualquer arquivo EX5 pode conter recursos, e qualquer programa EX5 pode usar recursos de um outro programa EX5.

Os arquivo em formato BMP e WAV são automaticamente comprimidos antes de serem incluídos em um arquivo EX5. Isso significa que além de criar programas completos em MQL5, o uso de recursos também permite reduzir o tamanho total dos arquivos necessários ao usar gráficos e sons, quando comparado com a forma usual de escrever um programa MQL5.

O arquivo de recurso não deve exceder 16 Mb.

 

Busca por recursos específicos pelo compilador

Um recurso é inserido usando o comando #resorce "<path to the resource file>"

 #resource "<path_to_resource_file>"

O comprimento da constante string <path_to_resource_file> não de exceder 63 caracteres.

O compilador busca por um recurso no caminho especificado na seguinte ordem:

  • se o separador barra invertida "\" (escrito como "\\") é colocado no começo do caminho, ele busca pelo recurso referente ao diretório terminal_data_directory\MQL5\,
  • se não houver barra invertida, ele busca pelo recurso referente à localização do arquivo de recurso, na qual o recurso foi escrito.

O caminho do recurso não pode conter as sub-cadeias "..\\" e ":\\".

Exemplos de inclusão de recurso:

//--- correct specification of resources
#resource "\\Images\\euro.bmp" // euro.bmp está localizado em terminal_data_directory\MQL5\Images\
#resource "picture.bmp"        // picture.bmp está localizado no mesmo diretoria que o arquivo fonte
#resource "Resource\\map.bmp"  // O recurso está localizado em source_file_directory\Resource\map.bmp
 
//--- especificação incorreta de recursos
#resource ":picture_2.bmp"     // não deve conter ":"
#resource "..\\picture_3.bmp"  // não deve conter ".."
#resource "\\Files\\Images\\Folder_First\\My_panel\\Labels\\too_long_path.bmp" //mais que 63 símbolos

 

Uso de Recursos

Nome de recurso

Após um recurso ser declarado usando a diretiva #resource, ele pode ser usado em qualquer parte de um programa. O nome do recurso é seu caminho sem uma barra invertida no começo da linha, que define o caminho do recurso. Para usar seu próprio recurso no código, o sinal especial "::" deve ser adicionado antes do nome do recurso.

Exemplos:

//--- exemplos de especificação de recurso e seus nomes em comentários
#resource "\\Images\\euro.bmp"          // nome do recurso - Images\euro.bmp
#resource "picture.bmp"                 // nome do recurso - picture.bmp
#resource "Resource\\map.bmp"           // nome do recurso - Resource\map.bmp
#resource "\\Files\\Pictures\\good.bmp" // nome do recurso - Files\Pictures\good.bmp
#resource "\\Files\\Demo.wav";          // nome do recurso - Files\Demo.wav"
#resource "\\Sounds\\thrill.wav";       // nome do recurso - Sounds\thrill.wav"
...                                  
 
//--- utilização dos recursos
ObjectSetString(0,bitmap_name,OBJPROP_BMPFILE,0,"::Images\\euro.bmp");
...
ObjectSetString(0,my_bitmap,OBJPROP_BMPFILE,0,"::picture.bmp");
...
set=ObjectSetString(0,bitmap_label,OBJPROP_BMPFILE,1,"::Files\\Pictures\\good.bmp");
...
PlaySound("::Files\\Demo.wav");
...
PlaySound("::Sounds\\thrill.wav");

Deve se notar que ao definir imagens a partir de um recurso para os objetos OBJ_BITMAP e OBJ_BITMAP_LABEL, o valor da propriedade OBJPROP_BMPFILE não pode ser modificado manualmente. Por exemplo, para criar OBJ_BITMAP_LABEL nós usados euro.bmp e dollar.bmp.

#resource "\\Images\\euro.bmp";    // euro.bmp está localizado em terminal_data_directory\MQL5\Images\
#resource "\\Images\\dollar.bmp";  // dollar.bmp está localizado em terminal_data_directory\MQL5\Images\

Ao visualizar as propriedades deste objeto, veremos que as propriedades BitMap File (On) e BitMap File (Off) são esmaecidas e não podem ser alteradas manualmente:

using_resource

 

Usando os recursos em outros programas MQL5

Existe uma outra vantagem no uso de recurso — em qualquer programa MQL5, os recursos de um outro arquivo EX5 podem ser usados. Assim, os recursos de um arquivo EX5 podem ser usados em muitos outros programas MQL5.

A fim de usar um nome de recurso de um outro arquivo, ele deve ser especificado como <path_EX5_file_name>::<resource_name>. Por exemplo, suponha que o script Draw_Triangles_Script.mq5 contém um recurso para uma imagem no arquivo triangle.bmp:

 #resource "\\Files\\triangle.bmp"

Então seu nome, para uso no script em si, se assemelhará a "Files\triangle.bmp", e a fim de usá-lo, "::" deve ser adicionado ao nome do recurso.

//--- usando o curso no script
ObjectSetString(0,my_bitmap_name,OBJPROP_BMPFILE,0,"::Files\\triangle.bmp");

A fim de usar o mesmo recurso a partir de um outro programa, por exemplo, a partir de um Expert Advisor, precisamos adicionar ao nome do recurso o caminho para o arquivo EX5 correspondente ao terminal_data_directory\MQL5\ e o nome arquivo EX5 do script - Draw_Triangles_Script.ex5. Suponha que o script está localizado na pasta padrão terminal_data_directory\MQL5\Scripts\, então o chamado deve ser escrito da seguinte forma:

//--- usando um recurso de um script em um EA
ObjectSetString(0,my_bitmap_name,OBJPROP_BMPFILE,0,"\\Scripts\\Draw_Triangles_Script.ex5::Files\\triangle.bmp");

Se o caminho para o arquivo executável não for especificado ao chamar o recurso de um outro EX5, o arquivo executável é procurado na mesma pasta que contém o programa que chama o recurso. Isso significa que se um Expert Advisor chamar um recurso de Draw_Triangles_Script.ex5 sem especificar o caminho, como abaixo:

//--- chama recurso de script em um EA sem especificar o caminho
ObjectSetString(0,my_bitmap_name,OBJPROP_BMPFILE,0,"Draw_Triangles_Script.ex5::Files\\triangle.bmp");

então o arquivo será procurado na pasta terminal_data_directory\MQL5\Experts\, caso o Expert Advisor esteja localizado em terminal_data_directory\MQL5\Experts\.

 

Trabalhando com indicadores personalizados que estão conectados como recursos

O funcionamento de programas MQL5 pode exigir um ou mais indicadores personalizados, eles podem ser incluídos no código do programa executável MQL5. A inclusão de indicadores como recursos simplifica a distribuição de programas.

Exemplo de conexão e utilização do indicador personalizado SampleIndicator.ex5, localizado na pasta: diretório_de_dados_do_terminal\MQL5\Indicators\:

//+------------------------------------------------------------------+
//|                                                     SampleEA.mq5 |
//|                        Copyright 2013, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#resource "\\Indicators\\SampleIndicator.ex5"
int handle_ind;
//+------------------------------------------------------------------+
//| Função de inicialização do Expert                                |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   handle_ind=iCustom(_Symbol,_Period,"::Indicators\\SampleIndicator.ex5");
   if(handle_ind==INVALID_HANDLE)
     {
      Print("Expert: iCustom call: Error code=",GetLastError());
      return(INIT_FAILED);
     }
//---
   return(INIT_SUCCEEDED);
  }

Os casos em que o indicador personalizado, na função OnInit(), cria uma ou mais cópias de si mesmo exigem uma análise separada. Lembre-se que para usar um recurso a partir de um programa mql5, é preciso especificá-lo no formato: <caminho_do_nome_do_arquivo_EX5>::<nome_do_recurso>.

Por exemplo, se o indicador SampleIndicator.ex5 estiver incluído no Expert Advisor SampleEA.ex5 como um recurso, então o caminho para si mesmo será especificado ao chamar iCustom() na função de inicialização do indicador personalizado, isso será da seguinte forma: "\\Experts\\SampleEA.ex5::Indicators\\SampleIndicator.ex5". Se for definido explicitamente o caminho, o indicador personalizado SampleIndicator.ex5 será firmemente ligado ao Advisor SampleEA.ex5 e perderá a capacidade de trabalhar de forma independente.

O caminho para si mesmo pode ser obtido utilizando a função GetRelativeProgramPath(), a seguir, um exemplo de utilização:

//+------------------------------------------------------------------+
//|                                              SampleIndicator.mq5 |
//|                        Copyright 2013, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property indicator_separate_window
#property indicator_plots 0
int handle;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- maneira errada para especificar uma referência para si próprio
//--- string path="\\Experts\\SampleEA.ex5::Indicators\\SampleIndicator.ex5";   
//--- maneira correta para obter uma referência a si mesmo
  string path=GetRelativeProgramPath();
//--- indicator buffers mapping
   handle=iCustom(_Symbol,_Period,path,0,0);
   if(handle==INVALID_HANDLE)
     {
      Print("Indicator: iCustom call: Error code=",GetLastError());
      return(INIT_FAILED);
     }
   else Print("Indicator handle=",handle);
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| GetRelativeProgramPath                                           |
//+------------------------------------------------------------------+
string GetRelativeProgramPath()
  {
   int pos2;
//--- obtemos o caminho absoluto para o programa
   string path=MQLInfoString(MQL_PROGRAM_PATH);
//--- encontramos a posição da sub-cadeia de caracteres "\MQL5\"
   int    pos =StringFind(path,"\\MQL5\\");
//--- sub-cadeia não encontrada - erro
   if(pos<0)
      return(NULL);
//--- ignoramos o diretório "\MQL5"
   pos+=5;
//--- ignoramos '\' extras
   while(StringGetCharacter(path,pos+1)=='\\')
      pos++;
//--- se se tratar de um recurso, retornamos o caminho em relação ao diretório MQL5
   if(StringFind(path,"::",pos)>=0)
      return(StringSubstr(path,pos));
//--- encontramos o delimitador para o primeiro sub-diretório em MQL5 (por exemplo, MQL5\Indicators)
//--- se ele não existir, retornamos o caminho em relação ao diretório MQL5
   if((pos2=StringFind(path,"\\",pos+1))<0)
      return(StringSubstr(path,pos));
//--- retornamos o caminho em relação ao sub-diretório (например, MQL5\Indicators)
   return(StringSubstr(path,pos2+1));
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const int begin,        
                const double& price[])
  {
//--- Valor de retorno do prev_calculated para a próxima chamada
   return(rates_total);
  }

 

Variáveis de recurso #

Os recursos podem ser declarados usando as variáveis de recurso, e tratá-los como se fossem uma variável do tipo apropriado. Formato do declaração:

#resource caminho_para_o_arquivo_do_recurso as tipo_de_variável_de_recurso nome_de_variável_de_recurso

Exemplos de declaração:

#resource "data.bin" as int ExtData[]             // declaração de matriz de tipo numérico, que contém dados a partir do arquivo data.bin
#resource "data.bin" as MqlRates ExtData[]        // declaração de matriz de estruturas simples, que contém dados a partir do arquivo data.bin
//--- cadeias de caracteres
#resource "data.txt" as string ExtCode            // declaração de cadeias de caracteres que contêm dados do arquivo data.txt (são suportadas codificações ANSI, UTF-8 e UTF-16.)
//--- recursos gráficos
#resource "image.bmp" as bitmap ExtBitmap[]       // declaração de matriz unidimensional, que contém em si a varredura a partir do arquivo BMP, tamanho da matriz = height * width
#resource "image.bmp" as bitmap ExtBitmap2[][]    // declaração de matriz bidimensional, que contém em si a varredura a partir do arquivo BMP, tamanho da matriz [height][width]

Ao utilizar tal declaração, os dados deste recurso podem ser tratados por intermédio de uma variável, o endereçamento automático via "::<rsource name>" não funciona.

#resource "\\Images\\euro.bmp" as bitmap euro[][]
#resource "\\Images\\dollar.bmp"
//+------------------------------------------------------------------+
//|  Função de criação de objeto OBJ_BITMAP_LABEL usando o recurso|
//+------------------------------------------------------------------+
void Image(string name,string rc,int x,int y)
  {
   ObjectCreate(0,name,OBJ_BITMAP_LABEL,0,0,0);
   ObjectSetInteger(0,name,OBJPROP_XDISTANCE,x);
   ObjectSetInteger(0,name,OBJPROP_YDISTANCE,y);
   ObjectSetString(0,name,OBJPROP_BMPFILE,rc);
  }
//+------------------------------------------------------------------+
//| Função de início do programa script                              |
//+------------------------------------------------------------------+
void OnStart()
  {
//--- imprimimos os tamanhos da imagem [width, height], que é armazenada na variável de recurso euro
   Print(ArrayRange(euro,1),", ",ArrayRange(euro,0));
//--- alteramos a imagem no euro - desenhamos uma faixa horizontal no meio
   for(int x=0;x<ArrayRange(euro,1);x++)
      euro[ArrayRange(euro,1)/2][x]=0xFFFF0000;
//--- criamos o recurso gráfico usando a variável de recurso
   ResourceCreate("euro_icon",euro,ArrayRange(euro,1),ArrayRange(euro,0),0,0,ArrayRange(euro,1),COLOR_FORMAT_ARGB_NORMALIZE);
//--- criamos objeto do rótulo gráfico Euro, para o qual colocamos a imagem a partir do recurso euro_icon
   Image("Euro","::euro_icon",10,40);
//--- outro modo de utilizar o recurso, nós não podemos desenhar nele
   Image("USD","::Images\\dollar.bmp",15+ArrayRange(euro,1),40);
//--- a maneira direta de endereçamento para o recurso euro.bmp não está disponível, uma vez que ele já está declarado através da variável de recurso euro
   Image("E2","::Images\\euro.bmp",20+ArrayRange(euro,1)*2,40); // acontece o erro de tempo de execução
  }

Resultado de execução do script, estão criados apenas dois objetos OBJ_BITMAP_LABEL de três. Ao mesmo tempo, na imagem do primeiro objeto, nós vemos uma linha vermelha no meio.

res_variables

Uma vantagem importante do uso de recursos é que os arquivos de recurso - antes de serem incluídos num arquivo EX5 executável e compilados - são comprimidos automaticamente. Assim, o uso de variáveis ​​de recurso permite não só empacotar diretamente os dados necessários num arquivo EX5 executável, mas também reduzir o número e o tamanho total dos arquivos em comparação com o método convencional de escrita de programas MQL5.

A utilização de variáveis de recurso é particularmente útil para publicar produtos no Mercado.

Características

  • Ο tipo especial de variável de recurso bitmap informa ao compilador que o recurso é uma representação gráfica. Essas variáveis recebem o tipo uint.
  • A matriz-variável de recurso de tipo bitmap pode ter duas dimensões, neste caso, o tamanho da matriz será definido como [altura_de_imagem][largura_de_imagem]. No caso de uma matriz unidimensional, o número de elementos será definido como o produto de altura_de_imagem*largura_de_imagem.
  • Ao carregar imagens de 24 bits, para todos os pixels da imagem de componente de canal-alfa, define-se como 255.
  • Ao carregar imagens de 32 bits, para todos os pixels da imagem de componente de canal-alfa, define-se como 255.
  • Após carregar uma imagem de 32 bits com canal-alfa não acontece nenhuma manipulação de pixels.
  • O tamanho do arquivo de recurso não pode ser maior do que 128 MB.
  • Para arquivos de sequência de caracteres, a codificação de BOM (cabeçalho) é detectada automaticamente. Se não houver nenhum BOM, a codificação será determinada pelo conteúdo. São suportados arquivos codificados em ANSI, UTF-8 e UTF-16. Todas as cadeias de caracteres são convertidas para Unicode.

Programas em OpenCL

A utilização de variáveis - de sequências de caracteres - de recurso pode facilitar muito a escrita de alguns programas. Por exemplo, você pode escrever o código de um programa OpenCL num arquivo CL separado e, em seguida, incluir esse arquivo - como uma cadeia de caracteres - nos recursos de seu programa MQL5.

#resource "seascape.cl" as string cl_program
...
int context;
if((cl_program=CLProgramCreate(context,cl_program)!=INVALID_HANDLE)
  {
   //--- executa ações futuras com o programa OpenCL
  }

Neste exemplo, sem a utilização de uma variável de recursocl_program, você teria de descrever esse código como uma variável de cadeia grande.

Veja Também

ResourceCreate(), ResourceSave(), PlaySound(), ObjectSetInteger(), ChartApplyTemplate(), Funções de Arquivo