
Promova seus projetos de desenvolvimento utilizando bibliotecas EX5
Introdução
Um leitor sofisticado não precisa de uma explicação sobre o propósito de esconder implementações de função e de classe em bibliotecas. Aqueles de vocês que estão ativamente a procura de novas ideias talvez queiram saber que a ocultação dos detalhes de implementação de classes/funções em um arquivo .ex5 vai permitir que você compartilhe seus algoritmos experientes com outros desenvolvedores, defina projetos comuns e promova-os na Internet.
E enquanto a equipe MetaQuotes não mede esforços para viabilizar a possibilidade de herança direta de classes de biblioteca ex5, vamos implementá-la agora.
Índice
1. Funções Importar e Exportar
2. Exportação da implementação escondida de uma classe
3. Inicialização de variáveis em arquivo .ex5
4. Herança de classes de exportação
5. Publicação de bibliotecas ex5
1. Funções Importar e Exportar
Este é um método de base subjacente à exportação de classes. Há três coisas importantes a serem levadas em consideração para suas funções estarem disponíveis nos outros programas:
- O arquivo a ser criado deve ter a extensão .mq5 (não .mqh) para ser compilado em arquivo .ex5;
- O arquivo deve conter diretivas de pré-processador de biblioteca #property;
- A palavra-chave "export" (exportar) deverá ser colocada após os cabeçalhos das funções exportadas requeridas
Example 1. Let us create a function to be used in other programs //--- library.mq5 #property library int libfunc (int a, int b) export { int c=a+b; Print("a+b="+string(с)); return(с); }
Após a compilação deste arquivo, você obterá o arquivo library.ex5 de onde libfunc possa então ser utilizada em um outro programa.
O processo de importação de funções é também muito simples. é executado utilizando a diretiva de pré-processador #import.
Example 2. We will use the export function libfunc() in our script //--- uses.mq5 #import "library.ex5" int libfunc(int a, int b); #import void OnStart() { libfunc(1, 2); }
Mantenha em mente que o compilador procurará por arquivos .ex5 na pasta MQL5\Libraries. Então se library.ex5 não for localizado na pasta, você terá que especificar o nome do caminho relativo.
Ex.:
#import "..\Include\MyLib\library.ex5" // the file is located in the MQL5\Include\MyLib folder #import "..\Experts\library.ex5" // the file is located in the MQL5\Experts\ folder
Para seu uso futuro, funções podem ser importadas não apenas no arquivo de destino .mq5 mas também em arquivos .mqh.
Além de ilustrar a aplicação prática, deixe-nos usar alguns gráficos.
Vamos criar uma biblioteca de funções para exportar. Estas funções exibirão objetos gráficos, como Button (botão), Edit (editar), Label (etiqueta) e Rectangle Label (etiqueta retângulo) em um gráfico, excluir os objetos a partir do gráfico e redefinir os parâmetros de cor do gráfico.
Isso pode ser mostrado através de esquema conforme a seguir:
O arquivo completo Graph.mq5 pode ser encontrado no final do artigo. Aqui daremos apenas um exemplo modelo da função de desenho Editar.
//+------------------------------------------------------------------+ //| SetEdit | //+------------------------------------------------------------------+ void SetEdit(long achart,string name,int wnd,string text,color txtclr,color bgclr,color brdclr, int x,int y,int dx,int dy,int corn=0,int fontsize=8,string font="Tahoma",bool ro=false) export { ObjectCreate(achart,name,OBJ_EDIT,wnd,0,0); ObjectSetInteger(achart,name,OBJPROP_CORNER,corn); ObjectSetString(achart,name,OBJPROP_TEXT,text); ObjectSetInteger(achart,name,OBJPROP_COLOR,txtclr); ObjectSetInteger(achart,name,OBJPROP_BGCOLOR,bgclr); ObjectSetInteger(achart,name,OBJPROP_BORDER_COLOR,brdclr); ObjectSetInteger(achart,name,OBJPROP_FONTSIZE,fontsize); ObjectSetString(achart,name,OBJPROP_FONT,font); ObjectSetInteger(achart,name,OBJPROP_XDISTANCE,x); ObjectSetInteger(achart,name,OBJPROP_YDISTANCE,y); ObjectSetInteger(achart,name,OBJPROP_XSIZE,dx); ObjectSetInteger(achart,name,OBJPROP_YSIZE,dy); ObjectSetInteger(achart,name,OBJPROP_SELECTABLE,false); ObjectSetInteger(achart,name,OBJPROP_READONLY,ro); ObjectSetInteger(achart,name,OBJPROP_BORDER_TYPE,0); ObjectSetString(achart,name,OBJPROP_TOOLTIP,""); }
A importação das funções requeridas e seu uso serão implementados no arquivo de destino Spiro.mq5:
Example 3. Using imported functions //--- Spiro.mq5 – the target file of the Expert Advisor //--- importing some graphics functions #import "Graph.ex5" void SetLabel(long achart, string name, int wnd, string text, color clr, int x, int y, int corn=0, int fontsize=8, string font="Tahoma"); void SetEdit(long achart, string name, int wnd, string text, color txtclr, color bgclr, color brdclr, int x, int y, int dx, int dy, int corn=0, int fontsize=8, string font="Tahoma", bool ro=false); void SetButton(long achart, string name, int wnd, string text, color txtclr, color bgclr, int x, int y, int dx, int dy, int corn=0, int fontsize=8, string font="Tahoma", bool state=false); void HideChart(long achart, color BackClr); #import //--- prefix for chart objects string sID; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ void OnInit() { HideChart(0, clrWhite); sID="spiro."; DrawParam(); } //+------------------------------------------------------------------+ //| DrawParam | //+------------------------------------------------------------------+ void DrawParam() { color bgclr=clrWhite, clr=clrBlack; //--- bigger radius SetLabel(0, sID+"stR.", 0, "R", clr, 10, 10+3); SetEdit(0, sID+"R.", 0, "100", clr, bgclr, clr, 40, 10, 50, 20); //--- smaller radius SetLabel(0, sID+"str.", 0, "r", clr, 10, 35+3); SetEdit(0, sID+"r.", 0, "30", clr, bgclr, clr, 40, 35, 50, 20); //--- distance to the center SetLabel(0, sID+"stD.", 0, "D", clr, 10, 60+3); SetEdit(0, sID+"D.", 0, "40", clr, bgclr, clr, 40, 60, 50, 20); //--- drawing accuracy SetLabel(0, sID+"stA.", 0, "Alfa", clr, 10, 85+3); SetEdit(0, sID+"A.", 0, "0.04", clr, bgclr, clr, 40, 85, 50, 20); //--- drawing accuracy SetLabel(0, sID+"stN.", 0, "Rotor", clr, 10, 110+3); SetEdit(0, sID+"N.", 0, "10", clr, bgclr, clr, 40, 110, 50, 20); //--- draw button SetButton(0, sID+"draw.", 0, "DRAW", bgclr, clr, 39, 135, 51, 20); }
Seguindo a execução do Expert Advisor, os objetos aparecerão no gráfico:
Como pode ser visto, o processo de exportação e importação de funções não é nada difícil, mas certifique-se de ler sobre certas limitações na Ajuda: exportação, importação.
2. Exportação da implementação escondida de uma classe
Visto que as classes no MQL5 não podem ser exportadas diretamente até o momento, teremos de recorrer a um método um tanto sofisticado. é baseado em funções de polimorfismo e virtuais. Por falar nisso, não é a classe em si que é retornada a partir do módulo ex5, mas um objeto criado pela mesma. Vamos chamá-lo de objeto de implementação oculto.
A essência do método é dividir a classe necessária em duas, para que a declaração de funções e variáveis seja aberta para acesso público e seus detalhes de implementação fiquem ocultos em um arquivo.ex5 fechado.
Isso pode ser simplesmente exemplificado conforme a seguir. Há a classe CSpiro que gostaríamos de compartilhar com outros desenvolvedores sem revelar detalhes de implementação. Vamos supor que ela contenha funções de variáveis, construtoras, destruidoras e de trabalho.
Para exportar a classe, devemos fazer o seguinte:
- Criar um clone da classe descendente CSpiro. Vamos chamá-lo ISpiro (a primeira letra C é substituída por um I, como derivado da palavra "interface")
- Deixe todas as variáveis e funções fictícias na classe inicial CSpiro.
- Os detalhes da implementação da função deve formar uma nova classe ISpiro.
- Adicione a isso a função de exportação que irá criar uma instância da ISpiro fechada.
- Observação! Todas as funções necessárias deverão ter o prefixo virtual
Como resultado, temos dois arquivos:
Example 4. Hiding of the class implementation in the ex5 module //--- Spiro.mqh – public file, the so called header file //+------------------------------------------------------------------+ //| Class CSpiro | //| Spirograph draw class | //+------------------------------------------------------------------+ class CSpiro { public: //--- prefix of the chart objects string m_sID; //--- offset of the chart center int m_x0,m_y0; //--- color of the line color m_clr; //--- chart parameters double m_R,m_r,m_D,m_dAlfa,m_nRotate; public: //--- constructor CSpiro() { }; //--- destructor ~CSpiro() { }; virtual void Init(int ax0,int ay0,color aclr,string asID) { }; virtual void SetData(double aR,double ar,double aD,double adAlpha,double anRotate) { }; public: virtual void DrawSpiro() { }; virtual void SetPoint(int x,int y) { }; };
Por favor, observe que todas as classes de função são declaradas com a palavra-chave virtual.
//--- ISpiro.mq5 – hidden implementation file #include "Spiro.mqh" //--- importing some functions #import "..\Experts\Spiro\Graph.ex5" void SetPoint(long achart,string name,int awnd,int ax,int ay,color aclr); void ObjectsDeleteAll2(long achart=0,int wnd=-1,int type=-1,string pref="",string excl=""); #import CSpiro *iSpiro() export { return(new ISpiro); } //+------------------------------------------------------------------+ //| Сlass ISpiro | //| Spirograph draw class | //+------------------------------------------------------------------+ class ISpiro : public CSpiro { public: ISpiro() { m_x0=0; m_y0=0; }; ~ISpiro() { ObjectsDeleteAll(0,0,-1); }; virtual void Init(int ax0,int ay0,color aclr,string asID); virtual void SetData(double aR,double ar,double aD,double adAlpha,double anRotate); public: virtual void DrawSpiro(); virtual void SetPoint(int x,int y); }; //+------------------------------------------------------------------+ //| Init | //+------------------------------------------------------------------+ void ISpiro::Init(int ax0,int ay0,color aclr,string asID) { m_x0=ax0; m_y0=ay0; m_clr=aclr; m_sID=asID; m_R=0; m_r=0; m_D=0; } //+------------------------------------------------------------------+ //| SetData | //+------------------------------------------------------------------+ void ISpiro::SetData(double aR,double ar,double aD,double adAlpha,double anRotate) { m_R=aR; m_r=ar; m_D=aD; m_dAlfa=adAlpha; m_nRotate=anRotate; } //+------------------------------------------------------------------+ //| DrawSpiro | //+------------------------------------------------------------------+ void ISpiro::DrawSpiro() { if(m_r<=0) { Print("Error! r==0"); return; } if(m_D<=0) { Print("Error! D==0"); return; } if(m_dAlfa==0) { Print("Error! Alpha==0"); return; } ObjectsDeleteAll2(0,0,-1,m_sID+"pnt."); int n=0; double a=0; while(a<m_nRotate*2*3.1415926) { double x=(m_R-m_r)*MathCos(a)+m_D*MathCos((m_R-m_r)/m_r*a); double y=(m_R-m_r)*MathSin(a)-m_D*MathSin((m_R-m_r)/m_r*a); SetPoint(int(m_x0+x),int(m_y0+y)); a+=m_dAlfa; } ChartRedraw(0); } //+------------------------------------------------------------------+ //| SetPoint | //+------------------------------------------------------------------+ void ISpiro::SetPoint(int x,int y) { Graph::SetPoint(0,m_sID+"pnt."+string(x)+"."+string(y),0,x,y,m_clr); } //+------------------------------------------------------------------+
Como pode ser visto, a classe escondida foi implementada no arquivo .mq5 e contém o comando de pré-processador #property library. Assim, todas as regras estabelecidas na seção anterior foram observadas.
Observe também o operador de resolução de escopo para a função SetPoint. Ele é tanto declarado na biblioteca Graph quanto na classe CSpiro. Para que o compilador chame a função desejada, especificamos explicitamente usando a ação :: e damos o nome do arquivo.
Graph::SetPoint(0, m_sID+"pnt."+string(x)+"."+string(y), 0, x, y, m_clr);
Podemos agora incluir o arquivo de cabeçalho e importar a sua implementação em nosso Expert Advisor resultante.
Isso pode ser mostrado através de esquema conforme a seguir:
Example 5. Using export objects //--- Spiro.mq5 - the target file of the Expert Advisor //--- importing some functions #import "Graph.ex5" void SetLabel(long achart, string name, int wnd, string text, color clr, int x, int y, int corn=0, int fontsize=8, string font="Tahoma"); void SetEdit(long achart, string name, int wnd, string text, color txtclr, color bgclr, color brdclr, int x, int y, int dx, int dy, int corn=0, int fontsize=8, string font="Tahoma", bool ro=false); void SetButton(long achart, string name, int wnd, string text, color txtclr, color bgclr, int x, int y, int dx, int dy, int corn=0, int fontsize=8, string font="Tahoma", bool state=false); void HideChart(long achart, color BackClr); #import //--- including the chart class #include <Spiro.mqh> //--- importing the object #import "ISpiro.ex5" CSpiro *iSpiro(); #import //--- object instance CSpiro *spiro; //--- prefix for chart objects string sID; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ void OnInit() { HideChart(0, clrWhite); sID="spiro."; DrawParam(); //--- object instance created spiro=iSpiro(); //--- initializing the drawing spiro.Init(250, 200, clrBlack, sID); //--- setting the calculation parameters spiro.SetData(100, 30, 40, 0.04, 10); //--- drawing spiro.DrawSpiro(); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { delete spiro; // deleting the object }
Como resultado, você será capaz de alterar os parâmetros de objeto no gráfico e traçar o gráfico do objeto:
3. Inicialização de variáveis em arquivo .ex5
é frequente o caso em que a sua ISuperClass utiliza variáveis do arquivo incluso globals.mqh. Estas variáveis podem ser inclusas em um modo semelhante para serem usadas em outros arquivos.
Ex.:
Example 6. Public include file //--- globals.mqh #include <Trade\Trade.mqh> //--- instance of the trade function object extern CTrade *_trade;
A única instância do objeto _trade é inicializada em seu programa, mas ela é usada na classe escondida ISuperClass.
Para este propósito, um ponteiro para o objeto que você criou deve ser passado a partir da classe ISuperClass para o arquivo .ex5.
é facilmente feito quando o objeto é recebido do arquivo .ex5, conforme abaixo:
Example 7. Initialization of variables upon creation of the object //--- ISuperClass.mq5 –hidden implementation file #property library CSuperClass *iSuperClass(CTrade *atrade) export { //--- saving the pointer _trade=atrade; //--- returning the object of the hidden implementation of ISuperClass of the open CSuperClass class return(new ISuperClass); } //... the remaining code
Assim, todas as variáveis necessárias são inicializadas após o recebimento do objeto em seu módulo.
Na verdade, pode haver um grande número de variáveis globais públicas, que podem ser de diferentes tipos. Para aqueles que não estão dispostos a alterar o cabeçalho da função iSuperClass o tempo todo, é melhor que criem uma classe especial agregando todas as variáveis e funções globais para trabalhar com ela.
Example 8. Public include file //--- globals.mqh #include <Trade\Trade.mqh> //--- trade "object" extern CTrade *_trade; //--- name of the Expert Advisor of the system extern string _eaname; //+------------------------------------------------------------------+ //| class __extern | //+------------------------------------------------------------------+ class __extern // all extern parameters for passing between the ex5 modules are accumulated here { public: //--- the list of all public global variables to be passed //--- trade "object" CTrade *trade; //--- name of the Expert Advisor of the system string eaname; public: __extern() { }; ~__extern() { }; //--- it is called when passing the parameters into the .ex5 file void Get() { trade=_trade; eaname=_eaname; }; // getting the variables //--- it is called in the .ex5 file void Set() { _trade=trade; _eaname=eaname; }; // setting the variables }; //--- getting the variables and pointer for passing the object into the .ex5 file __extern *_GetExt() { _ext.Get(); return(GetPointer(_ext)); } //--- the only instance for operation extern __extern _ext;O arquivo ISuperClass.mq5 será implementado da seguinte forma:
Example 9. //--- ISuperClass.mq5 –hidden implementation file #property library CSuperClass *iSuperClass(__extern *aext) export { //--- taking in all the parameters aext.Set(); //--- returning the object return(new ISuperClass); } //--- ... the remaining code
A chamada de função será agora transformada em uma forma simplificada e o que é mais importante, extensível.
Example 10. Using export objects in the presence of public global variables //--- including global variables (usually located in SuperClass.mqh) #include "globals.mqh" //--- including the public header class #include "SuperClass.mqh" //--- getting the hidden implementation object #import "ISuperClass.ex5" CSuperClass *iSuperClass(); #import //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { //--- creating the hidden implementation object providing for the passing of all parameters CSuperClass *sc=iSuperClass(_GetExt()); //--- ... the remaining code }
4. Herança de classes de exportação
Você já deve ter entendido que esta forma de exportar objetos implica que a herança simples e direta esteja fora de questão. A exportação do objeto de implementação oculto sugere que o objeto em si seja a última conexão da cadeia de herança e o que pode ser usado em última análise.
No caso geral, você pode criar uma "simulação" da herança escrevendo uma classe intermediária adicional. E aqui, precisaremos naturalmente de polimorfismo e virtualidade.
Example 11. Emulation of inheritance of hidden classes //--- including the public header class #include "SuperClass.mqh" //--- getting the hidden implementation object #import "ISuperClass.ex5" CSuperClass *iSuperClass(); #import class _CSuperClass { public: //--- instance of the hidden implementation object CSuperClass *_base; public: //--- constructor _CSuperClass() { _base=iSuperClass(_GetExt()); }; //--- destructor ~_CSuperClass() { delete _base; }; //--- further followed by all functions of the base CSuperClass class //--- working function called from the hidden implementation object virtual int func(int a, int b) { _base.func(a,b); }; };
O único problema aqui é o acesso a variáveis de CSuperClass. Como pode ser visto, elas não estão presentes na declaração da descendente e estão localizadas na variável _base. Normalmente, não afeta a capacidade de utilização, desde que exista uma classe de cabeçalho SuperClass.mqh.
Naturalmente, se você estiver focado principalmente em funções experientes, você não tem que criar um padrão adaptador de ISuperClass com relação a elas com antecedência. Bastará exportar estas funções experientes e deixar que os desenvolvedores externos criem suas próprias classes de padrões adaptadores que então serão fáceis de herdar.
- Exportação de funções independentes de classe
- Arquivos de cabeçalho .mqh e suas implementações .ex5
- Inicialização de variáveis nos arquivos .ex5
5. Publicação de bibliotecas ex5
Em novembro de 2011, a MetaQuotes começou a fornecer acesso a um armazenamento de arquivos. Mais sobre isso pode ser encontrado no anúncio.
Este armazenamento de arquivos permite que você armazene seus desenvolvimentos e, o que é mais importante, fornece acesso a isso para outros desenvolvedores. Esta ferramenta permitirá que você publique facilmente novas versões dos seus arquivos para garantir acesso rápido a eles pelos desenvolvedores que possam estar utilizando esses arquivos.
Além do mais, o website da empresa fornece a oportunidade de oferecer-lhe suas próprias bibliotecas no Mercado em uma base comercial sem custo nenhum.
Conclusão
Você já sabe como criar bibliotecas ex5 com a exportação de suas funções ou objetos de classe e pode aplicar seus conhecimentos na prática. Todos estes recursos permitem estabelecer uma cooperação mais estreita com outros desenvolvedores: trabalhar em projetos comuns, promovê-los no Mercado ou fornecer acesso às funções de biblioteca ex5.
Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/362





- Aplicativos de negociação gratuitos
- 8 000+ sinais para cópia
- Notícias econômicas para análise dos mercados financeiros
Você concorda com a política do site e com os termos de uso