Discussão do artigo "Como criar um painel de informações para exibir dados em indicadores e Expert Advisors"
Obrigado por compartilhar.
Essa implementação da classe tem uma grande desvantagem se houver necessidade de herdá-la.
1. Não há construtor padrão, e o construtor paramétrico define parâmetros importantes por tamanho. Por exemplo, se você precisar calcular o tamanho do painel com base em seus parâmetros no descendente da classe, essa lógica terá de ser implementada fora da classe ou na classe, mas com o cálculo em uma função separada, o que, de certa forma, supera a lógica, pois a chamada do construtor paramétrico, sem o construtor padrão, estará na lista de inicialização. Talvez uma solução melhor seja mover a inicialização do construtor para uma função de classe.
2. A seção com parâmetros é declarada como privada, o que não permite que o descendente implemente, por exemplo, um esquema de cores diferente ou altere o tamanho do cabeçalho
3. Entendo que o trabalho não está concluído, mas algumas funções não estão implementadas, por exemplo, SetButtonClose(On/Off), SetButtonMinimize(On/Off).
Com a disponibilidade do código-fonte, não é um problema finalizá-lo, mas ainda assim...
Obrigado por compartilhar.
Essa implementação da classe tem uma grande desvantagem se houver necessidade de herdá-la.
1. Não há construtor padrão, e o construtor paramétrico define parâmetros importantes por tamanho. Por exemplo, se você precisar calcular o tamanho do painel com base em seus parâmetros no descendente da classe, essa lógica terá de ser implementada fora da classe ou na classe, mas com o cálculo em uma função separada, o que, de certa forma, supera a lógica, pois a chamada do construtor paramétrico, sem o construtor padrão, estará na lista de inicialização. Talvez uma solução melhor seja mover a inicialização do construtor para uma função de classe.
2. A seção com parâmetros é declarada como privada, o que não permite que o descendente implemente, por exemplo, um esquema de cores diferente ou altere o tamanho do cabeçalho
3. Sei que o trabalho não está concluído, mas algumas funções não estão implementadas, por exemplo, SetButtonClose(On/Off), SetButtonMinimize(On/Off).
Com a disponibilidade do código-fonte, não é um problema finalizá-lo, mas ainda assim...
O artigo é um tutorial. Nele, o painel cobre as necessidades mínimas.
1. O descendente tem seu próprio construtor, em sua lista de inicialização deve estar o construtor do pai. Nele, você especifica as dimensões necessárias.
2) Nem sequer pensei em esquemas de cores, bem como no tamanho do cabeçalho.
3. esses métodos são declarados na seção pública. É estranho que eles não estejam implementados. Lembro-me exatamente de que estava testando sua ativação/desativação.... Tive que reescrever essa classe do zero, de memória, porque sua primeira versão foi destruída pelo Windows quando ficou sem espaço no disco. Devo ter me esquecido de restaurá-las. Obrigado, vou corrigi-lo.
Sim, com a disponibilidade do código-fonte, todas as cartas estão nas mãos dos leitores. É esse o objetivo dos artigos de tutorial.
O artigo é instrutivo. Nele, o painel aborda as necessidades mínimas.
1. O descendente tem seu próprio construtor, sua lista de inicialização deve conter o construtor do pai. Nele, você especifica as dimensões necessárias.
2. nem sequer pensei em esquemas de cores), bem como o tamanho do cabeçalho.
3. esses métodos são declarados na seção pública. É estranho que eles não estejam implementados. Lembro-me exatamente de que estava testando sua ativação/desativação.... Tive que reescrever essa classe do zero, de memória, porque sua primeira versão foi destruída pelo Windows quando ficou sem espaço no disco. Devo ter me esquecido de restaurá-las. Obrigado, vou corrigi-lo.
Sim, com a disponibilidade do código-fonte, todas as cartas estão nas mãos dos leitores. É esse o objetivo dos artigos de tutorial.
1. Sim, mas simplesmente quando o construtor ancestral é chamado na lista de inicialização, o cálculo dos parâmetros a serem passados para ele deve ser movido para outro lugar. Especialmente se não for o mais primitivo.
Por exemplo, o cálculo da posição X, Y para a exibição inicial no canto inferior direito, o cálculo da altura dependendo do número esperado de linhas da tabela.... Isso exigirá 3 funções de classe adicionais, nem todas elas em um único trecho de código em seu construtor com a chamada subsequente do construtor ancestral. Parece mais uma muleta, embora funcione. Bem, não é um código muito bonito quando você pode tornar a arquitetura da classe mais adaptável a outras alterações. (É claro que essa é uma observação das anotações de um perfeccionista).
2. Pequenos enfeites tornam o produto mais qualitativo. Mas seu código em geral é bonito e suas soluções são interessantes, é agradável lê-lo.
3. Eu compreendo, a perda de dados é sempre muito desagradável, portanto, um backup confiável é tudo para nós.
Obrigado, estamos aguardando novos artigos.
Confira o novo artigo: Criando um painel para exibir dados em indicadores e EAs.
Autor: Artyom Trishkin
Obrigado pelo ótimo tutorial

Eu o modifiquei para uma aparência escura e, além disso, estou procurando alterar as cores do título e dos dados também
Também criei uma função para adicionar texto de maneira fácil
void DrawData(int cell, string title, string data, color clr ) { dashboard.DrawText(title, dashboard.CellX(cell,0)+2, dashboard.CellY(cell,0)+2, clr); dashboard.DrawText(data, dashboard.CellX(cell,1)+2, dashboard.CellY(cell,1)+2,90, clr); ChartRedraw(ChartID()); }
mas estou achando difícil mudar as cores desses textos, não tenho certeza do que está errado, pois as cores parecem opacas, aqui está a função DrawText modificada
//+------------------------------------------------------------------+ //| Exibir uma mensagem de texto nas coordenadas especificadas //+------------------------------------------------------------------+ void CDashboard::DrawText(const string text,const int x,const int y,const color clr,const int width=WRONG_VALUE,const int height=WRONG_VALUE) { //--- Declare variáveis para registrar a largura e a altura do texto nelas int w=width; int h=height; //--- Se a largura e a altura do texto passado para o método tiverem valores zero, //--- então todo o espaço de trabalho é completamente limpo usando a cor transparente if(width==0 && height==0) this.m_workspace.Erase(0x00FFFFFF); //--- Caso contrário else { //--- Se a largura e a altura passadas tiverem valores padrão (-1), obteremos sua largura e altura do texto if(width==WRONG_VALUE && height==WRONG_VALUE) this.m_workspace.TextSize(text,w,h); //--- caso contrário, else { //--- se a largura passada para o método tiver o valor padrão (-1) - obtenha a largura do texto, ou //--- se a largura passada para o método tiver um valor maior que zero, use a largura passada para o método, ou //--- se a largura passada para o método tiver um valor zero, use o valor 1 para a largura w=(width ==WRONG_VALUE ? this.m_workspace.TextWidth(text) : width>0 ? width : 1); //--- se a altura passada para o método tiver um valor padrão (-1), obtenha a altura do texto, ou //--- se a altura passada para o método tiver um valor maior que zero, use a altura passada para o método, ou //--- se a altura passada para o método tiver um valor zero, use o valor 1 para a altura h=(height==WRONG_VALUE ? this.m_workspace.TextHeight(text) : height>0 ? height : 1); } //--- Preencher o espaço de acordo com as coordenadas especificadas e a largura e altura resultantes com uma cor transparente (apagar a entrada anterior) this.m_workspace.FillRectangle(x,y,x+w,y+h,0x00FFFFFF); } //--- Exibir o texto no espaço livre do texto anterior e atualizar o espaço de trabalho sem redesenhar a tela this.m_workspace.TextOut(x,y,text,::ColorToARGB(clr,this.m_alpha)); this.m_workspace.Update(false); }
Arpit T # :
//--- Exiba o texto no espaço livre do texto anterior e atualize o espaço de trabalho sem redesenhar a tela this .m_workspace. TextOut (x,y,text,:: ColorToARGB (clr, this .m_alpha )); this .m_workspace.Update( false );
A cor destacada é a transparência do próprio painel, não do texto. Para o texto, é melhor definir a transparência (ou melhor, a opacidade) para o valor padrão de 255 - texto completamente opaco. Mas você pode "brincar" com o valor da opacidade inserindo valores numéricos regulares de 0 a 255 em vez de this.m_alpha. 0 é uma cor totalmente transparente, 255 é uma cor totalmente opaca.
A cor destacada é a transparência do próprio painel, não do texto. Para o texto, é melhor definir a transparência (ou melhor, a opacidade) para o valor padrão de 255 - texto completamente opaco. Mas você pode "brincar" com o valor da opacidade inserindo valores numéricos regulares de 0 a 255 em vez de this.m_alpha. 0 é uma cor totalmente transparente, 255 é uma cor totalmente opaca.
Obrigado, agora está tudo bem

void DrawData(int cell, string title, string data, color clr ) { dashboard.DrawText(title, dashboard.CellX(cell,0)+2, dashboard.CellY(cell,0)+2, clr); dashboard.DrawText(data, dashboard.CellX(cell,1)+2, dashboard.CellY(cell,1)+2,90, clr); ChartRedraw(ChartID()); }
O código destacado estava causando problemas, eu o removi e tudo ficou bem.
trabalho bem feito, o escuro é bonito
Agradecimentos
Aqui está o construtor modificado para o visual escuro no dashboard.mqh, se você quiser usar esse tema
//+------------------------------------------------------------------+ //| Construtor| //+------------------------------------------------------------------+ CDashboard::CDashboard(const uint id,const int x,const int y, const int w,const int h,const int wnd=-1) : m_id(id), m_chart_id(::ChartID()), m_program_type((ENUM_PROGRAM_TYPE)::MQLInfoInteger(MQL_PROGRAM_TYPE)), m_program_name(::MQLInfoString(MQL_PROGRAM_NAME)), m_wnd(wnd==-1 ? GetSubWindow() : wnd), m_chart_w((int)::ChartGetInteger(m_chart_id,CHART_WIDTH_IN_PIXELS,m_wnd)), m_chart_h((int)::ChartGetInteger(m_chart_id,CHART_HEIGHT_IN_PIXELS,m_wnd)), m_mouse_state(MOUSE_STATE_NOT_PRESSED), m_x(x), m_y(::ChartGetInteger(m_chart_id,CHART_SHOW_ONE_CLICK) ? (y<79 ? 79 : y) : y), m_w(w), m_h(h), m_x_dock(m_x), m_y_dock(m_y), m_header(true), m_butt_close(true), m_butt_minimize(true), m_butt_pin(true), m_header_h(18), //--- Implementação do cabeçalho do painel m_header_alpha(255), m_header_alpha_c(m_header_alpha), m_header_back_color(clrBlack), m_header_back_color_c(m_header_back_color), m_header_fore_color(clrSnow), m_header_fore_color_c(m_header_fore_color), m_header_border_color(clrSnow), m_header_border_color_c(m_header_border_color), m_title("Dashboard"), m_title_font("Calibri"), m_title_font_size(-100), //--- botão fechar m_butt_close_back_color(clrBlack), m_butt_close_back_color_c(m_butt_close_back_color), m_butt_close_fore_color(clrSnow), m_butt_close_fore_color_c(m_butt_close_fore_color), //--- botão de recolher/expandir m_butt_min_back_color(clrBlack), m_butt_min_back_color_c(m_butt_min_back_color), m_butt_min_fore_color(clrSnow), m_butt_min_fore_color_c(m_butt_min_fore_color), //--- botão de pino m_butt_pin_back_color(clrBlack), m_butt_pin_back_color_c(m_butt_min_back_color), m_butt_pin_fore_color(clrSnow), m_butt_pin_fore_color_c(m_butt_min_fore_color), //--- Implementação do painel m_alpha(255), m_alpha_c(m_alpha), m_fore_alpha(255), m_fore_alpha_c(m_fore_alpha), m_back_color(clrBlack), m_back_color_c(m_back_color), m_fore_color(clrSnow), m_fore_color_c(m_fore_color), m_border_color(clrSnow), m_border_color_c(m_border_color), m_font("Calibri"), m_font_size(-100), m_minimized(false), m_movable(true) { //--- Defina a permissão para que o gráfico envie mensagens sobre eventos de movimentação e pressão dos botões do mouse, //--- eventos de rolagem do mouse, bem como criação/exclusão de objetos gráficos ::ChartSetInteger(this.m_chart_id,CHART_EVENT_MOUSE_MOVE,true); ::ChartSetInteger(this.m_chart_id,CHART_EVENT_MOUSE_WHEEL,true); ::ChartSetInteger(this.m_chart_id,CHART_EVENT_OBJECT_CREATE,true); ::ChartSetInteger(this.m_chart_id,CHART_EVENT_OBJECT_DELETE,true); //--- Defina os nomes das variáveis terminais globais para armazenar as coordenadas do painel, o estado recolhido/expandido e a fixação this.m_name_gv_x=this.m_program_name+"_id_"+(string)this.m_id+"_"+(string)this.m_chart_id+"_X"; this.m_name_gv_y=this.m_program_name+"_id_"+(string)this.m_id+"_"+(string)this.m_chart_id+"_Y"; this.m_name_gv_m=this.m_program_name+"_id_"+(string)this.m_id+"_"+(string)this.m_chart_id+"_Minimize"; this.m_name_gv_u=this.m_program_name+"_id_"+(string)this.m_id+"_"+(string)this.m_chart_id+"_Unpin"; //--- Se uma variável global não existir, crie-a e escreva o valor atual, //--- caso contrário - leia o valor da variável global do terminal para ela //--- Coordenada X if(!::GlobalVariableCheck(this.m_name_gv_x)) ::GlobalVariableSet(this.m_name_gv_x,this.m_x); else this.m_x=(int)::GlobalVariableGet(this.m_name_gv_x); //--- Coordenada Y if(!::GlobalVariableCheck(this.m_name_gv_y)) ::GlobalVariableSet(this.m_name_gv_y,this.m_y); else this.m_y=(int)::GlobalVariableGet(this.m_name_gv_y); //--- Recolhido/expandido if(!::GlobalVariableCheck(this.m_name_gv_m)) ::GlobalVariableSet(this.m_name_gv_m,this.m_minimized); else this.m_minimized=(int)::GlobalVariableGet(this.m_name_gv_m); //--- Recolhido/não recolhido if(!::GlobalVariableCheck(this.m_name_gv_u)) ::GlobalVariableSet(this.m_name_gv_u,this.m_movable); else this.m_movable=(int)::GlobalVariableGet(this.m_name_gv_u); //--- Defina os sinalizadores para o tamanho do painel que excede o tamanho da janela do gráfico this.m_higher_wnd=this.HigherWnd(); this.m_wider_wnd=this.WiderWnd(); //--- Se o recurso gráfico do painel for criado, if(this.m_canvas.CreateBitmapLabel(this.m_chart_id,this.m_wnd,"P"+(string)this.m_id,this.m_x,this.m_y,this.m_w,this.m_h,COLOR_FORMAT_ARGB_NORMALIZE)) { //--- definir a fonte da tela e preencher a tela com a cor transparente this.m_canvas.FontSet(this.m_title_font,this.m_title_font_size,FW_BOLD); this.m_canvas.Erase(0x00FFFFFF); } //--- caso contrário - relata ao diário a criação malsucedida de um objeto else ::PrintFormat("%s: Error. CreateBitmapLabel for canvas failed",(string)__FUNCTION__); //--- Se um espaço de trabalho de um recurso gráfico for criado, if(this.m_workspace.CreateBitmapLabel(this.m_chart_id,this.m_wnd,"W"+(string)this.m_id,this.m_x+1,this.m_y+this.m_header_h,this.m_w-2,this.m_h-this.m_header_h-1,COLOR_FORMAT_ARGB_NORMALIZE)) { //--- definir a fonte para a área de trabalho e preenchê-la com a cor transparente this.m_workspace.FontSet(this.m_font,this.m_font_size); this.m_workspace.Erase(0x00FFFFFF); } //--- caso contrário - relata ao diário a criação malsucedida de um objeto else ::PrintFormat("%s: Error. CreateBitmapLabel for workspace failed",(string)__FUNCTION__); }
Olá.
Dessa forma.
CDashboard *dashboard = NULL; uma variável de ponteiro para um futuro novo objeto da classe, criado dinamicamente, é declarada e imediatamente inicializada com o valor NULL.
E apenas uma instância da classe é declarada dessa forma:
CDashboard dashboard;
Mas, nesse caso, não é possível declarar e criar uma instância dessa forma: a classe não tem um construtor sem parâmetros formais.
Portanto, ao declarar uma instância dessa forma, você deve especificar todos os parâmetros necessários do objeto da classe, que devem ser passados para o construtor da classe:
CDashboard dashboard(InpUniqID, InpPanelX, InpPanelY, 200, 250);
------------------------
No exemplo de trabalho com a classe, primeiro é criado um ponteiro vazio para o objeto futuro no indicador e, em seguida, em OnInit(), é criado um objeto de painel, em que o ponteiro para o objeto criado é gravado na variável do ponteiro:
//--- Criar objeto de painel dashboard=new CDashboard(InpUniqID,InpPanelX,InpPanelY,200,250); if(dashboard==NULL) { Print("Error. Failed to create dashboard object"); return INIT_FAILED; }
Em seguida, em OnDeinit(), o objeto é excluído da memória usando esse ponteiro:
//--- Se o objeto do painel existir - exclua-o if(dashboard!=NULL) delete dashboard;
Se simplesmente criássemos um novo objeto com o operador new sem gravar o ponteiro do objeto criado em uma variável, não poderíamos excluí-lo depois, o que resultaria em um vazamento de memória.
Portanto, em resumo, no exemplo do artigo
- declare um ponteiro de variável para o objeto de classe futuro e inicialize-o com o valor NULL,
- criamos um novo objeto de classe e gravamos o ponteiro para ele na variável de painel criada anteriormente,
- ao acessar o objeto criado, usamos a variável ponteiro e um ponto ( dashboard.AnyMethod() )
- no final do trabalho, exclua o objeto de classe criado dinamicamente pelo ponteiro para ele.
Se a instância necessária da classe (dashboard CDashboard) tivesse sido criada imediatamente, não seriam necessários ponteiros para ela - ela teria sido acessada da mesma forma usando o operador "point". E não haveria necessidade de excluí-lo quando o trabalho estivesse concluído - o subsistema do terminal faz isso sozinho. Mas essa seria a única instância da classe no programa.
A criação dinâmica permite que você crie novos objetos da classe necessária em tempo real e faça referência a eles por meio de um ponteiro. É por isso que a criação dinâmica de um objeto de classe foi usada no exemplo. Simplificado, sem cobrir alguns pontos.
- 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
Novo artigo Como criar um painel de informações para exibir dados em indicadores e Expert Advisors foi publicado:
Neste artigo, veremos como criar uma classe de painel de informações para usá-la em indicadores e Expert Advisors. Este é um artigo introdutório a uma pequena série de artigos com modelos para integrar e usar indicadores padrão em Expert Advisors. Começaremos com a criação de um painel, que é um análogo da janela de dados do MetaTrader 5.
Hoje vamos começar criando um painel que pode exibir os dados especificados pelo desenvolvedor. Esse painel será útil para a apresentação visual dos dados no gráfico e durante a depuração visual, quando for mais prático observar os dados no painel do que localizá-los no depurador. Por exemplo, nos casos em que a depuração da estratégia depende dos valores de alguns valores de dados, mas não da depuração do código no depurador.
Faremos o painel como um protótipo da janela de dados no terminal e o preencheremos com os mesmos dados:
Figura 1- Janela de dados e painel de informações
Nosso painel personalizado nos permitirá adicionar a ele qualquer quantidade de dados necessária, rotulá-los (por um título) e exibir/atualizar as leituras do código do nosso programa.
O painel pode ser: movido pelo gráfico com o mouse, fixado no local necessário do gráfico e recolhido/expandido. Quanto à colocação dos dados no painel, será possível exibir uma tabela com um número especificado de linhas e colunas. Os dados dessa tabela podem ser impressos no log (coordenadas X e Y de cada célula da tabela) e obtidos via programação - para especificar o número de linhas e colunas onde esses dados devem estar - ou simplesmente imprimir as coordenadas no log e, a partir delas, escrever as necessárias em seu código. Esse primeiro método é mais conveniente por causa de sua total automação. O painel também terá um botão de fechamento ativo, mas delegamos seu processamento ao programa de controle, pois somente o desenvolvedor do programa deve decidir como reagir ao pressionar o botão de fechamento. Quando o botão for clicado, um evento personalizado será enviado ao manipulador de eventos do programa, que o desenvolvedor poderá manipular como achar adequado e pretender.
Autor: Artyom Trishkin