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,0),ArrayRange(euro,1),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