
Criando um painel administrativo de negociação em MQL5 (Parte III): Expansão das classes incorporadas para gerenciamento de temas (II)
Conteúdo:
- Introdução
- Classes no MQL5
- Adição de métodos de gerenciamento de temas em (CDialog, CEdit e CButton)
- Gerenciamento de temas da classe CButton
- Gerenciamento de temas da classe CEdit
- Configuração do painel administrativo para troca de temas
- Código final e resultados
- Considerações finais
Introdução
Podemos modificar e criar novas classes de bibliotecas para MQL5. No entanto, como as bibliotecas incorporadas são utilizadas em conjunto pela plataforma, quaisquer alterações feitas nesses arquivos podem tanto melhorar quanto prejudicar as funções atuais da plataforma. Em um artigo recente, discutimos brevemente a manipulação de cores da classe raiz Dialog para modificar a aparência do nosso painel. Embora nosso botão de troca de tema tenha conseguido alterar a cor do texto, ele não modificou a aparência do painel nem a cor de fundo do botão.
Com a diversificação, finalmente identificamos métodos para integrar com segurança as funções de alteração de tema às classes disponíveis. Após a implementação bem-sucedida dessas alterações, ajustamos o algoritmo do painel administrativo para se adequar às novas funções integradas.
Alteração de tema bem-sucedida
Este artigo é dedicado à criação de um painel visualmente atraente, apresentado à direita. As cores exibidas no tema foram baseadas na minha percepção pessoal sobre escolhas de cores durante o desenvolvimento. Elas podem ser otimizadas no código conforme as preferências de outros usuários. É importante destacar os componentes-chave do nosso programa que contribuem para a funcionalidade geral do painel.
Vou listá-los abaixo:
- Cor do texto
- Cor do botão
- Bordas
- Cor de fundo
Essas são as características mais visíveis do nosso programa. Quando iniciamos a troca de tema, cada componente deve responder alterando suas propriedades de exibição para refletir as cores desejadas, definidas no código. Ao final do artigo, vou tentar transmitir a você as habilidades necessárias para modificar e expandir as classes disponíveis ao trabalhar com interfaces.
Classes no MQL5.
Para que tanto iniciantes quanto usuários experientes possam compreender o conteúdo, gostaria de começar com o conceito de classes utilizado no MQL5. Abaixo estão definições e conceitos-chave que nos ajudarão a entender como as classes funcionam nesse ambiente de programação.
Classes:
Classes são a base da programação orientada a objetos (POO) no MQL5, permitindo que desenvolvedores agrupem variáveis relacionadas (atributos) e funções (métodos) em um único bloco para representar conceitos e comportamentos complexos dentro do programa.
Destacam-se:
- Atributos: variáveis que armazenam o estado ou dados dos objetos da classe.
- Métodos: funções que definem o comportamento ou ações dos objetos da classe.
Breve descrição das principais características de uma classe:
- Encapsulamento em uma classe implica na união dos dados (variáveis) e métodos (funções) que operam sobre esses dados, garantindo sua proteção contra acessos externos e uso indevido.
- Herança permite que uma classe herde propriedades e métodos de outra classe, promovendo a reutilização de código e a criação de uma estrutura hierárquica.
- Polimorfismo permite a redefinição de métodos, possibilitando que subclasses forneçam implementações específicas para métodos já definidos nas suas classes pai.
- Abstração simplifica a modelagem de sistemas complexos ao focar apenas nos dados e métodos relevantes, ocultando os detalhes desnecessários do usuário.
Localização dos arquivos de cabeçalho MQL5
Utilizei um trecho típico de código-fonte de classe MQL5 para nos ajudar a entender claramente as classes e suas estruturas do ponto de vista prático. Observe o trecho de código abaixo. A estrutura dele eu explico logo abaixo em formato de tabela.
//Basic parts of a class. class CDialog : public CWndContainer { public: // Constructor and Destructor (Methods) CDialog(void); // Constructor ~CDialog(void); // Destructor // Public Methods (Functions) virtual bool Create(const long chart, const string name, const int subwin, const int x1, const int y1, const int x2, const int y2); virtual bool OnEvent(const int id, const long &lparam, const double &dparam, const string &sparam); string Caption(void) const; bool Caption(const string text); bool Add(CWnd *control); // Add control by pointer bool Add(CWnd &control); // Add control by reference virtual bool Save(const int file_handle); virtual bool Load(const int file_handle); void UpdateThemeColors(bool darkTheme); protected: // Attributes (Variables) bool m_panel_flag; // Panel visibility flag bool m_minimized; // Minimized state flag CWnd m_caption; // Caption control CWnd m_client_area; // Client area control CRect m_norm_rect; // Normal (non-minimized) rectangle CRect m_min_rect; // Minimized rectangle CWnd m_white_border; // White border control // Protected Methods (Internal functions) virtual bool CreateWhiteBorder(void); virtual bool CreateBackground(void); virtual bool CreateCaption(void); virtual bool CreateButtonClose(void); virtual bool CreateClientArea(void); virtual void OnClickCaption(void); virtual void OnClickButtonClose(void); virtual bool OnDialogDragStart(void); virtual bool OnDialogDragProcess(void); virtual bool OnDialogDragEnd(void); };
Esta tabela apresenta uma visão geral dos atributos disponíveis no trecho de código acima e sua descrição.
Atributos (propriedades) | Descrição |
---|---|
bool m_panel_flag; | Flag que indica se o painel está visível. |
bool m_minimized; | Flag que indica se a janela de diálogo está minimizada |
CWnd m_caption; | Gerenciamento do texto do rótulo. |
CWnd m_client_area; | Gerenciamento da área cliente onde estão os demais elementos. |
CRect m_norm_rect; | Coordenadas para o estado normal (não minimizado). |
CRect m_min_rect; | Coordenadas para o estado minimizado. |
CWnd m_white_border; | Gerenciamento da borda branca ao redor da janela de diálogo. |
Esta tabela resume os métodos utilizados no exemplo de classe.
Métodos | Descrição |
---|---|
CDialog(void) | Construtor que inicializa o diálogo. |
~CDialog(void) | Destrutor para limpeza de recursos. |
Create(...) | Cria a janela de diálogo e seus elementos de controle. |
OnEvent(...) | Processa eventos do gráfico para o diálogo. |
Caption(void) | Retorna o texto atual do rótulo. |
Caption(const string text) | Define o texto do rótulo. |
Add(CWnd *control) | Adiciona um elemento de controle à área cliente via ponteiro. |
Add(CWnd &control) | Adiciona um elemento de controle à área cliente por referência. |
Save(const int file_handle) | Salva o estado do diálogo em um arquivo. |
Load(const int file_handle) | Carrega o estado do diálogo de um arquivo. |
UpdateThemeColors(bool darkTheme) | Atualiza as cores do tema (claro ou escuro). |
CreateWhiteBorder(void) | Cria a borda branca da janela de diálogo. |
CreateBackground(void) | Cria o fundo da janela de diálogo. |
CreateCaption(void) | Cria a área do rótulo. |
CreateButtonClose(void) | Cria o botão de fechar. |
CreateClientArea(void) | Cria a área cliente. |
OnClickCaption(void) | rocessa o evento de clique no cabeçalho. |
OnClickButtonClose(void) | Processa o evento de clique no botão de fechar. |
OnDialogDragStart(void) | Processa o início do evento de arrastar a janela de diálogo. |
OnDialogDragProcess(void) | Gerencia o processo de arrastar a janela de diálogo. |
OnDialogDragEnd(void) | Processa o evento de finalização do arrasto da janela de diálogo. |
Vamos agora analisar brevemente uma das classes principais que utilizamos em nosso programa abaixo.
Adição de métodos de gerenciamento de temas em (CDialog, CEdit e CButton)
Espero que agora tenhamos uma compreensão mais clara dos métodos que precisamos implementar para realizar a troca de temas. A biblioteca Dialog já contém as funcionalidades básicas necessárias, e nosso próximo passo será incluir os métodos adicionais necessários.
Métodos de gerenciamento de temas em CDialog:
CDialog:
A classe CDialog no MQL5 é responsável pela criação e gerenciamento de janelas de diálogo gráficas personalizadas ou painéis na plataforma MetaTrader 5. Ela permite que desenvolvedores criem janelas de diálogo contendo componentes de interface de usuário, como cabeçalhos, áreas cliente, bordas e botões de fechar. A classe lida com interações do usuário, como cliques e arrastes da janela de diálogo, além de permitir a atualização dinâmica do tema (por exemplo, troca entre tema claro e escuro). Também fornece métodos para salvar e carregar o estado da janela de diálogo, garantindo a preservação de seu tamanho, posição e status de minimização. Podem ser adicionados controles como botões e campos de texto à janela de diálogo, tornando-a uma ferramenta versátil para criar interfaces interativas e visualmente atrativas em aplicações de trading.
Na classe CDialog, introduzimos o método responsável pela atualização dinâmica do tema. Esse método cuida da atualização visual do diálogo com base em se o tema escuro (darkTheme) está ativado ou não. Veja como esse método foi implementado e como ele se relaciona com os demais componentes da classe CDialog. Vou explicar em duas etapas. No entanto, você pode pular a primeira etapa caso não pretenda definir as cores.
Etapa 1: Definição das cores do tema
É necessário definir as cores para que o programa saiba quais são as alternativas quando o tema for trocado. Nesta implementação, nosso método utiliza definições específicas de cores tanto para temas escuros quanto para temas claros. Elas podem ser constantes predefinidas ou constantes passadas por parâmetros.
// Theme colors that can be defined elsewhere in our program const color DARK_THEME_BG = clrBlack; const color DARK_THEME_BORDER = clrGray; const color LIGHT_THEME_BG = clrWhite; const color LIGHT_THEME_BORDER = clrSilver;
Etapa 2: Método de atualização das cores do tema
Essa função verifica se o darkTheme está ativado (true ou false) e aplica as cores correspondentes aos componentes principais: a borda branca (m_white_border) é atualizada com as cores de fundo e da borda; o fundo (m_background) altera as cores de fundo e da borda; o cabeçalho (m_caption) altera as cores do texto e do fundo da barra de título; e a área cliente (m_client_area) aplica as mudanças de cor à área cliente. Por fim, a função chama Redraw() para garantir que a nova temática seja aplicada visualmente sem recriar os objetos. Se você passou direto para o segundo passo, as definições de cores destacadas não funcionarão, e será necessário especificar a cor diretamente, como ClrBlack ou ClrBlue e assim por diante.
//+------------------------------------------------------------------+ //| Method for dynamic theme updates | //+------------------------------------------------------------------+ void CDialog::UpdateThemeColors(bool darkTheme) { color backgroundColor = darkTheme ? DARK_THEME_BG : LIGHT_THEME_BG; color borderColor = darkTheme ? DARK_THEME_BORDER : LIGHT_THEME_BORDER; // Update White Border colors m_white_border.ColorBackground(backgroundColor); m_white_border.ColorBorder(borderColor); // Update Background colors m_background.ColorBackground(backgroundColor); m_background.ColorBorder(borderColor); // Update Caption colors (optional for text-based themes) m_caption.Color(darkTheme ? clrWhite : clrBlack); m_caption.ColorBackground(backgroundColor); // Update Client Area colors m_client_area.ColorBackground(backgroundColor); m_client_area.ColorBorder(borderColor); // Redraw the controls to reflect the theme changes Redraw(); }
Gerenciamento de temas da classe CButton
Usando a mesma terminologia mencionada acima, adicionamos os métodos SetTextColor, SetBackgroundColor e SetBorderColor à classe CButton. Esses métodos nos permitem definir as cores do texto, do fundo e da borda do botão, respectivamente. A seguir, temos um trecho de código que demonstra a implementação desses métodos.
//--- theme methods void SetTextColor(color clr) { m_button.Color(clr); } void SetBackgroundColor(color clr) { m_button.BackColor(clr); } void SetBorderColor(color clr) { m_button.BorderColor(clr); }
Programa CButton padrão do MQL5
//+------------------------------------------------------------------+ //| Button.mqh | //| Copyright 2000-2024, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #include "WndObj.mqh" #include <ChartObjects\ChartObjectsTxtControls.mqh> //+------------------------------------------------------------------+ //| Class CButton | //| Usage: control that is displayed by | //| the CChartObjectButton object | //+------------------------------------------------------------------+ class CButton : public CWndObj { private: CChartObjectButton m_button; // chart object public: CButton(void); ~CButton(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); //--- state bool Pressed(void) const { return(m_button.State()); } bool Pressed(const bool pressed) { return(m_button.State(pressed)); } //--- properties bool Locking(void) const { return(IS_CAN_LOCK); } void Locking(const bool flag); protected: //--- handlers of object settings virtual bool OnSetText(void) { return(m_button.Description(m_text)); } virtual bool OnSetColor(void) { return(m_button.Color(m_color)); } virtual bool OnSetColorBackground(void) { return(m_button.BackColor(m_color_background)); } virtual bool OnSetColorBorder(void) { return(m_button.BorderColor(m_color_border)); } virtual bool OnSetFont(void) { return(m_button.Font(m_font)); } virtual bool OnSetFontSize(void) { return(m_button.FontSize(m_font_size)); } //--- internal event handlers virtual bool OnCreate(void); virtual bool OnShow(void); virtual bool OnHide(void); virtual bool OnMove(void); virtual bool OnResize(void); //--- íîâûå îáðàáîò÷èêè virtual bool OnMouseDown(void); virtual bool OnMouseUp(void); }; //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CButton::CButton(void) { m_color =CONTROLS_BUTTON_COLOR; m_color_background=CONTROLS_BUTTON_COLOR_BG; m_color_border =CONTROLS_BUTTON_COLOR_BORDER; } //+------------------------------------------------------------------+ //| Destructor | //+------------------------------------------------------------------+ CButton::~CButton(void) { } //+------------------------------------------------------------------+ //| Create a control | //+------------------------------------------------------------------+ bool CButton::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2) { //--- call method of the parent class if(!CWndObj::Create(chart,name,subwin,x1,y1,x2,y2)) return(false); //--- create the chart object if(!m_button.Create(chart,name,subwin,x1,y1,Width(),Height())) return(false); //--- call the settings handler return(OnChange()); } //+------------------------------------------------------------------+ //| Locking flag | //+------------------------------------------------------------------+ void CButton::Locking(const bool flag) { if(flag) PropFlagsSet(WND_PROP_FLAG_CAN_LOCK); else PropFlagsReset(WND_PROP_FLAG_CAN_LOCK); } //+------------------------------------------------------------------+ //| Create object on chart | //+------------------------------------------------------------------+ bool CButton::OnCreate(void) { //--- create the chart object by previously set parameters return(m_button.Create(m_chart_id,m_name,m_subwin,m_rect.left,m_rect.top,m_rect.Width(),m_rect.Height())); } //+------------------------------------------------------------------+ //| Display object on chart | //+------------------------------------------------------------------+ bool CButton::OnShow(void) { return(m_button.Timeframes(OBJ_ALL_PERIODS)); } //+------------------------------------------------------------------+ //| Hide object from chart | //+------------------------------------------------------------------+ bool CButton::OnHide(void) { return(m_button.Timeframes(OBJ_NO_PERIODS)); } //+------------------------------------------------------------------+ //| Absolute movement of the chart object | //+------------------------------------------------------------------+ bool CButton::OnMove(void) { //--- position the chart object return(m_button.X_Distance(m_rect.left) && m_button.Y_Distance(m_rect.top)); } //+------------------------------------------------------------------+ //| Resize the chart object | //+------------------------------------------------------------------+ bool CButton::OnResize(void) { //--- resize the chart object return(m_button.X_Size(m_rect.Width()) && m_button.Y_Size(m_rect.Height())); } //+------------------------------------------------------------------+ //| Handler of click on the left mouse button | //+------------------------------------------------------------------+ bool CButton::OnMouseDown(void) { if(!IS_CAN_LOCK) Pressed(!Pressed()); //--- call of the method of the parent class return(CWnd::OnMouseDown()); } //+------------------------------------------------------------------+ //| Handler of click on the left mouse button | //+------------------------------------------------------------------+ bool CButton::OnMouseUp(void) { //--- depress the button if it is not fixed if(m_button.State() && !IS_CAN_LOCK) m_button.State(false); //--- call of the method of the parent class return(CWnd::OnMouseUp()); } //+------------------------------------------------------------------+
CButton com método de gerenciamento de temas embutido:
Observe a seção destacada.
//+------------------------------------------------------------------+ //| Button.mqh | //| Copyright 2000-2024, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #include "WndObj.mqh" #include <ChartObjects\ChartObjectsTxtControls.mqh> //+------------------------------------------------------------------+ //| Class CButton | //| Usage: control that is displayed by | //| the CChartObjectButton object | //+------------------------------------------------------------------+ class CButton : public CWndObj { private: CChartObjectButton m_button; // chart object public: CButton(void); ~CButton(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); //--- state bool Pressed(void) const { return(m_button.State()); } bool Pressed(const bool pressed) { return(m_button.State(pressed)); } //--- properties bool Locking(void) const { return(IS_CAN_LOCK); } void Locking(const bool flag); //--- theme methods void SetTextColor(color clr) { m_button.Color(clr); } void SetBackgroundColor(color clr) { m_button.BackColor(clr); } void SetBorderColor(color clr) { m_button.BorderColor(clr); } protected: //--- handlers of object settings virtual bool OnSetText(void) { return(m_button.Description(m_text)); } virtual bool OnSetColor(void) { return(m_button.Color(m_color)); } virtual bool OnSetColorBackground(void) { return(m_button.BackColor(m_color_background)); } virtual bool OnSetColorBorder(void) { return(m_button.BorderColor(m_color_border)); } virtual bool OnSetFont(void) { return(m_button.Font(m_font)); } virtual bool OnSetFontSize(void) { return(m_button.FontSize(m_font_size)); } //--- internal event handlers virtual bool OnCreate(void); virtual bool OnShow(void); virtual bool OnHide(void); virtual bool OnMove(void); virtual bool OnResize(void); virtual bool OnMouseDown(void); virtual bool OnMouseUp(void); }; //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CButton::CButton(void) { m_color =CONTROLS_BUTTON_COLOR; m_color_background=CONTROLS_BUTTON_COLOR_BG; m_color_border =CONTROLS_BUTTON_COLOR_BORDER; } //+------------------------------------------------------------------+ //| Destructor | //+------------------------------------------------------------------+ CButton::~CButton(void) { } //+------------------------------------------------------------------+ //| Create a control | //+------------------------------------------------------------------+ bool CButton::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2) { //--- call method of the parent class if(!CWndObj::Create(chart,name,subwin,x1,y1,x2,y2)) return(false); //--- create the chart object if(!m_button.Create(chart,name,subwin,x1,y1,Width(),Height())) return(false); //--- call the settings handler return(OnChange()); } //+------------------------------------------------------------------+ //| Locking flag | //+------------------------------------------------------------------+ void CButton::Locking(const bool flag) { if(flag) PropFlagsSet(WND_PROP_FLAG_CAN_LOCK); else PropFlagsReset(WND_PROP_FLAG_CAN_LOCK); } //+------------------------------------------------------------------+ //| Create object on chart | //+------------------------------------------------------------------+ bool CButton::OnCreate(void) { //--- create the chart object by previously set parameters return(m_button.Create(m_chart_id,m_name,m_subwin,m_rect.left,m_rect.top,m_rect.Width(),m_rect.Height())); } //+------------------------------------------------------------------+ //| Display object on chart | //+------------------------------------------------------------------+ bool CButton::OnShow(void) { return(m_button.Timeframes(OBJ_ALL_PERIODS)); } //+------------------------------------------------------------------+ //| Hide object from chart | //+------------------------------------------------------------------+ bool CButton::OnHide(void) { return(m_button.Timeframes(OBJ_NO_PERIODS)); } //+------------------------------------------------------------------+ //| Absolute movement of the chart object | //+------------------------------------------------------------------+ bool CButton::OnMove(void) { //--- position the chart object return(m_button.X_Distance(m_rect.left) && m_button.Y_Distance(m_rect.top)); } //+------------------------------------------------------------------+ //| Resize the chart object | //+------------------------------------------------------------------+ bool CButton::OnResize(void) { //--- resize the chart object return(m_button.X_Size(m_rect.Width()) && m_button.Y_Size(m_rect.Height())); } //+------------------------------------------------------------------+ //| Handler of click on the left mouse button | //+------------------------------------------------------------------+ bool CButton::OnMouseDown(void) { if(!IS_CAN_LOCK) Pressed(!Pressed()); //--- call of the method of the parent class return(CWnd::OnMouseDown()); } //+------------------------------------------------------------------+ //| Handler of click on the left mouse button | //+------------------------------------------------------------------+ bool CButton::OnMouseUp(void) { //--- depress the button if it is not fixed if(m_button.State() && !IS_CAN_LOCK) m_button.State(false); //--- call of the method of the parent class return(CWnd::OnMouseUp()); } //+------------------------------------------------------------------+
Gerenciamento de temas da classe CEdit
Este é um dos principais componentes do nosso projeto, responsável pelo campo de entrada de mensagens. Por padrão, nosso painel e seus componentes possuem fundo branco com texto preto em primeiro plano. Ao clicar no botão de troca de tema, a cor do texto em primeiro plano muda para branco. No entanto, durante o desenvolvimento, percebi que a cor do campo de entrada permanecia inalterada, o que às vezes fazia com que ele se confundisse com o texto ao alternar entre os temas. Por isso, precisamos adicionar um método na classe CEdit para lidar com a troca de temas e garantir que o campo de entrada de texto esteja em conformidade com os objetivos visuais do nosso tema.
A classe CEdit padrão já inclui métodos para definir cores (OnSetColor, OnSetColorBackground e OnSetColorBorder). Podemos usar esses métodos para atualizar a aparência do objeto CEdit ao alterar o tema. Aplicamos novos métodos de troca de tema, por exemplo, adicionando os métodos SetTextColor, SetBackgroundColor e SetBorderColor na classe CEdit. Esses métodos atualizam as cores correspondentes e chamam os métodos existentes (OnSetColor, OnSetColorBackground, OnSetColorBorder) para aplicar as alterações ao objeto gráfico.
//+------------------------------------------------------------------+ //| Set text color | //+------------------------------------------------------------------+ bool CEdit::SetTextColor(const color clr) { m_color = clr; return(OnSetColor()); } //+------------------------------------------------------------------+ //| Set background color | //+------------------------------------------------------------------+ bool CEdit::SetBackgroundColor(const color clr) { m_color_background = clr; return(OnSetColorBackground()); } //+------------------------------------------------------------------+ //| Set border color | //+------------------------------------------------------------------+ bool CEdit::SetBorderColor(const color clr) { m_color_border = clr; return(OnSetColorBorder()); }
Abaixo, vamos revisar o código-fonte original não editado da classe CEdit e, em seguida, apresentar o programa com suporte ao gerenciamento de temas, que está logo abaixo dele.
CEdit padrão do MQL5:
//+------------------------------------------------------------------+ //| Edit.mqh | //| Copyright 2000-2024, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #include "WndObj.mqh" #include <ChartObjects\ChartObjectsTxtControls.mqh> //+------------------------------------------------------------------+ //| Class CEdit | //| Usage: control that is displayed by | //| the CChartObjectEdit object | //+------------------------------------------------------------------+ class CEdit : public CWndObj { private: CChartObjectEdit m_edit; // chart object //--- parameters of the chart object bool m_read_only; // "read-only" mode flag ENUM_ALIGN_MODE m_align_mode; // align mode public: CEdit(void); ~CEdit(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); //--- chart event handler virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam); //--- parameters of the chart object bool ReadOnly(void) const { return(m_read_only); } bool ReadOnly(const bool flag); ENUM_ALIGN_MODE TextAlign(void) const { return(m_align_mode); } bool TextAlign(const ENUM_ALIGN_MODE align); //--- data access string Text(void) const { return(m_edit.Description()); } bool Text(const string value) { return(CWndObj::Text(value)); } protected: //--- handlers of object events virtual bool OnObjectEndEdit(void); //--- handlers of object settings virtual bool OnSetText(void) { return(m_edit.Description(m_text)); } virtual bool OnSetColor(void) { return(m_edit.Color(m_color)); } virtual bool OnSetColorBackground(void) { return(m_edit.BackColor(m_color_background)); } virtual bool OnSetColorBorder(void) { return(m_edit.BorderColor(m_color_border)); } virtual bool OnSetFont(void) { return(m_edit.Font(m_font)); } virtual bool OnSetFontSize(void) { return(m_edit.FontSize(m_font_size)); } virtual bool OnSetZOrder(void) { return(m_edit.Z_Order(m_zorder)); } //--- internal event handlers virtual bool OnCreate(void); virtual bool OnShow(void); virtual bool OnHide(void); virtual bool OnMove(void); virtual bool OnResize(void); virtual bool OnChange(void); virtual bool OnClick(void); }; //+------------------------------------------------------------------+ //| Common handler of chart events | //+------------------------------------------------------------------+ bool CEdit::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam) { if(m_name==sparam && id==CHARTEVENT_OBJECT_ENDEDIT) return(OnObjectEndEdit()); //--- event was not handled return(CWndObj::OnEvent(id,lparam,dparam,sparam)); } //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CEdit::CEdit(void) : m_read_only(false), m_align_mode(ALIGN_LEFT) { m_color =CONTROLS_EDIT_COLOR; m_color_background=CONTROLS_EDIT_COLOR_BG; m_color_border =CONTROLS_EDIT_COLOR_BORDER; } //+------------------------------------------------------------------+ //| Destructor | //+------------------------------------------------------------------+ CEdit::~CEdit(void) { } //+------------------------------------------------------------------+ //| Create a control | //+------------------------------------------------------------------+ bool CEdit::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2) { //--- call method of the parent class if(!CWndObj::Create(chart,name,subwin,x1,y1,x2,y2)) return(false); //--- create the chart object if(!m_edit.Create(chart,name,subwin,x1,y1,Width(),Height())) return(false); //--- call the settings handler return(OnChange()); } //+------------------------------------------------------------------+ //| Set parameter | //+------------------------------------------------------------------+ bool CEdit::ReadOnly(const bool flag) { //--- save new value of parameter m_read_only=flag; //--- set up the chart object return(m_edit.ReadOnly(flag)); } //+------------------------------------------------------------------+ //| Set parameter | //+------------------------------------------------------------------+ bool CEdit::TextAlign(const ENUM_ALIGN_MODE align) { //--- save new value of parameter m_align_mode=align; //--- set up the chart object return(m_edit.TextAlign(align)); } //+------------------------------------------------------------------+ //| Create object on chart | //+------------------------------------------------------------------+ bool CEdit::OnCreate(void) { //--- create the chart object by previously set parameters return(m_edit.Create(m_chart_id,m_name,m_subwin,m_rect.left,m_rect.top,m_rect.Width(),m_rect.Height())); } //+------------------------------------------------------------------+ //| Display object on chart | //+------------------------------------------------------------------+ bool CEdit::OnShow(void) { return(m_edit.Timeframes(OBJ_ALL_PERIODS)); } //+------------------------------------------------------------------+ //| Hide object from chart | //+------------------------------------------------------------------+ bool CEdit::OnHide(void) { return(m_edit.Timeframes(OBJ_NO_PERIODS)); } //+------------------------------------------------------------------+ //| Absolute movement of the chart object | //+------------------------------------------------------------------+ bool CEdit::OnMove(void) { //--- position the chart object return(m_edit.X_Distance(m_rect.left) && m_edit.Y_Distance(m_rect.top)); } //+------------------------------------------------------------------+ //| Resize the chart object | //+------------------------------------------------------------------+ bool CEdit::OnResize(void) { //--- resize the chart object return(m_edit.X_Size(m_rect.Width()) && m_edit.Y_Size(m_rect.Height())); } //+------------------------------------------------------------------+ //| Set up the chart object | //+------------------------------------------------------------------+ bool CEdit::OnChange(void) { //--- set up the chart object return(CWndObj::OnChange() && ReadOnly(m_read_only) && TextAlign(m_align_mode)); } //+------------------------------------------------------------------+ //| Handler of the "End of editing" event | //+------------------------------------------------------------------+ bool CEdit::OnObjectEndEdit(void) { //--- send the ON_END_EDIT notification EventChartCustom(CONTROLS_SELF_MESSAGE,ON_END_EDIT,m_id,0.0,m_name); //--- handled return(true); } //+------------------------------------------------------------------+ //| Handler of the "click" event | //+------------------------------------------------------------------+ bool CEdit::OnClick(void) { //--- if editing is enabled, send the ON_START_EDIT notification if(!m_read_only) { EventChartCustom(CONTROLS_SELF_MESSAGE,ON_START_EDIT,m_id,0.0,m_name); //--- handled return(true); } //--- else send the ON_CLICK notification return(CWnd::OnClick()); } //+------------------------------------------------------------------+
CEdit com uso do método de gerenciamento de temas:
Observe as seções destacadas.
//+------------------------------------------------------------------+ //| Edit.mqh | //| Copyright 2000-2024, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #include "WndObj.mqh" #include <ChartObjects\ChartObjectsTxtControls.mqh> //+------------------------------------------------------------------+ //| Class CEdit | //| Usage: control that is displayed by | //| the CChartObjectEdit object | //+------------------------------------------------------------------+ class CEdit : public CWndObj { private: CChartObjectEdit m_edit; // chart object //--- parameters of the chart object bool m_read_only; // "read-only" mode flag ENUM_ALIGN_MODE m_align_mode; // align mode public: CEdit(void); ~CEdit(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); //--- chart event handler virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam); //--- parameters of the chart object bool ReadOnly(void) const { return(m_read_only); } bool ReadOnly(const bool flag); ENUM_ALIGN_MODE TextAlign(void) const { return(m_align_mode); } bool TextAlign(const ENUM_ALIGN_MODE align); //--- data access string Text(void) const { return(m_edit.Description()); } bool Text(const string value) { return(CWndObj::Text(value)); } //--- theme handling bool SetTextColor(const color clr); bool SetBackgroundColor(const color clr); bool SetBorderColor(const color clr); protected: //--- handlers of object events virtual bool OnObjectEndEdit(void); //--- handlers of object settings virtual bool OnSetText(void) { return(m_edit.Description(m_text)); } virtual bool OnSetColor(void) { return(m_edit.Color(m_color)); } virtual bool OnSetColorBackground(void) { return(m_edit.BackColor(m_color_background)); } virtual bool OnSetColorBorder(void) { return(m_edit.BorderColor(m_color_border)); } virtual bool OnSetFont(void) { return(m_edit.Font(m_font)); } virtual bool OnSetFontSize(void) { return(m_edit.FontSize(m_font_size)); } virtual bool OnSetZOrder(void) { return(m_edit.Z_Order(m_zorder)); } //--- internal event handlers virtual bool OnCreate(void); virtual bool OnShow(void); virtual bool OnHide(void); virtual bool OnMove(void); virtual bool OnResize(void); virtual bool OnChange(void); virtual bool OnClick(void); }; //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CEdit::CEdit(void) : m_read_only(false), m_align_mode(ALIGN_LEFT) { m_color =CONTROLS_EDIT_COLOR; m_color_background=CONTROLS_EDIT_COLOR_BG; m_color_border =CONTROLS_EDIT_COLOR_BORDER; } //+------------------------------------------------------------------+ //| Destructor | //+------------------------------------------------------------------+ CEdit::~CEdit(void) { } //+------------------------------------------------------------------+ //| Create a control | //+------------------------------------------------------------------+ bool CEdit::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2) { //--- call method of the parent class if(!CWndObj::Create(chart,name,subwin,x1,y1,x2,y2)) return(false); //--- create the chart object if(!m_edit.Create(chart,name,subwin,x1,y1,Width(),Height())) return(false); //--- call the settings handler return(OnChange()); } //+------------------------------------------------------------------+ //| Set parameter | //+------------------------------------------------------------------+ bool CEdit::ReadOnly(const bool flag) { //--- save new value of parameter m_read_only=flag; //--- set up the chart object return(m_edit.ReadOnly(flag)); } //+------------------------------------------------------------------+ //| Set parameter | //+------------------------------------------------------------------+ bool CEdit::TextAlign(const ENUM_ALIGN_MODE align) { //--- save new value of parameter m_align_mode=align; //--- set up the chart object return(m_edit.TextAlign(align)); } //+------------------------------------------------------------------+ //| Set text color | //+------------------------------------------------------------------+ bool CEdit::SetTextColor(const color clr) { m_color = clr; return(OnSetColor()); } //+------------------------------------------------------------------+ //| Set background color | //+------------------------------------------------------------------+ bool CEdit::SetBackgroundColor(const color clr) { m_color_background = clr; return(OnSetColorBackground()); } //+------------------------------------------------------------------+ //| Set border color | //+------------------------------------------------------------------+ bool CEdit::SetBorderColor(const color clr) { m_color_border = clr; return(OnSetColorBorder()); } //+------------------------------------------------------------------+ //| Create object on chart | //+------------------------------------------------------------------+ bool CEdit::OnCreate(void) { //--- create the chart object by previously set parameters return(m_edit.Create(m_chart_id,m_name,m_subwin,m_rect.left,m_rect.top,m_rect.Width(),m_rect.Height())); } //+------------------------------------------------------------------+ //| Display object on chart | //+------------------------------------------------------------------+ bool CEdit::OnShow(void) { return(m_edit.Timeframes(OBJ_ALL_PERIODS)); } //+------------------------------------------------------------------+ //| Hide object from chart | //+------------------------------------------------------------------+ bool CEdit::OnHide(void) { return(m_edit.Timeframes(OBJ_NO_PERIODS)); } //+------------------------------------------------------------------+ //| Absolute movement of the chart object | //+------------------------------------------------------------------+ bool CEdit::OnMove(void) { //--- position the chart object return(m_edit.X_Distance(m_rect.left) && m_edit.Y_Distance(m_rect.top)); } //+------------------------------------------------------------------+ //| Resize the chart object | //+------------------------------------------------------------------+ bool CEdit::OnResize(void) { //--- resize the chart object return(m_edit.X_Size(m_rect.Width()) && m_edit.Y_Size(m_rect.Height())); } //+------------------------------------------------------------------+ //| Set up the chart object | //+------------------------------------------------------------------+ bool CEdit::OnChange(void) { //--- set up the chart object return(CWndObj::OnChange() && ReadOnly(m_read_only) && TextAlign(m_align_mode)); } //+------------------------------------------------------------------+ //| Handler of the "End of editing" event | //+------------------------------------------------------------------+ bool CEdit::OnObjectEndEdit(void) { //--- send the ON_END_EDIT notification EventChartCustom(CONTROLS_SELF_MESSAGE,ON_END_EDIT,m_id,0.0,m_name); //--- handled return(true); } //+------------------------------------------------------------------+ //| Handler of the "click" event | //+------------------------------------------------------------------+ bool CEdit::OnClick(void) { //--- if editing is enabled, send the ON_START_EDIT notification if(!m_read_only) { EventChartCustom(CONTROLS_SELF_MESSAGE,ON_START_EDIT,m_id,0.0,m_name); //--- handled return(true); } //--- else send the ON_CLICK notification return(CWnd::OnClick()); } //+------------------------------------------------------------------+Preparamos com sucesso os arquivos de gerenciamento para o painel administrativo e agora estamos mais próximos da conclusão do nosso projeto do que nunca. No próximo segmento, ajustaremos o código do painel administrativo para suportar a troca de temas de acordo com os últimos avanços.
Configuração do painel administrativo para troca de temas.
Logicamente, podemos destacar quatro direções principais no nosso gerenciamento de temas.
- A funcionalidade de troca de temas no nosso painel administrativo deve girar em torno da variável darkTheme e da função UpdateThemeColors(). Veja como isso funciona:
bool darkTheme = false;
- O flag acima determina se o tema atual é escuro ou claro. Ele é alternado ao clicar no toggleThemeButton, como mostrado abaixo.
void OnToggleThemeButtonClick() { darkTheme = !darkTheme; UpdateThemeColors(); Print("Theme toggled: ", darkTheme ? "Dark" : "Light"); }
- Ao clicar no botão de troca de tema, essa função é chamada, alternando o flag darkTheme e, em seguida, atualizando o tema da interface do usuário através de UpdateThemeColors().
void UpdateThemeColors() { // Determine colors based on the current theme color textColor = darkTheme ? clrWhite : clrBlack; color buttonBgColor = darkTheme ? clrDarkSlateGray : clrGainsboro; color borderColor = darkTheme ? clrSlateGray : clrGray; color bgColor = darkTheme ? clrDarkBlue : clrWhite; // Set text box colors inputBox.SetTextColor(textColor); inputBox.SetBackgroundColor(bgColor); inputBox.SetBorderColor(borderColor); // Update button colors UpdateButtonTheme(clearButton, textColor, buttonBgColor, borderColor); UpdateButtonTheme(sendButton, textColor, buttonBgColor, borderColor); UpdateButtonTheme(toggleThemeButton, textColor, buttonBgColor, borderColor); UpdateButtonTheme(changeFontButton, textColor, buttonBgColor, borderColor); UpdateButtonTheme(minimizeButton, textColor, buttonBgColor, borderColor); UpdateButtonTheme(maximizeButton, textColor, buttonBgColor, borderColor); UpdateButtonTheme(closeButton, textColor, buttonBgColor, borderColor); // Update quick message buttons for (int i = 0; i < ArraySize(quickMessageButtons); i++) { UpdateButtonTheme(quickMessageButtons[i], textColor, buttonBgColor, borderColor); } // Update character counter color charCounter.Color(textColor); // Redraw chart to apply changes ChartRedraw(); }
Utilizando o flag darkTheme, escolhemos diferentes cores para texto, fundo dos botões, bordas e fundo geral. As cores são aplicadas a vários componentes da interface da seguinte forma:
- Campo de texto (inputBox): As funções SetTextColor, SetBackgroundColor, e SetBorderColor são usadas para aplicar o tema.
- Botões: A função UpdateButtonTheme() é chamada para cada botão, definindo a cor do texto, do fundo e da borda de acordo com os parâmetros especificados.
- Contador de caracteres: Define diretamente sua cor ao pressionar o botão de tema.
//Theme button application void UpdateButtonTheme(CButton &button, color textColor, color bgColor, color borderColor) { button.SetTextColor(textColor); button.SetBackgroundColor(bgColor); button.SetBorderColor(borderColor); }
Utilizamos a função auxiliar mencionada acima para aplicar todas as configurações de cor relacionadas ao tema a qualquer botão. Isso elimina código repetitivo e garante uniformidade entre os botões. Ao consolidar todos os trechos de código e integrá-los ao programa principal do painel administrativo, conseguimos fazer com que todas as funções operassem conforme o esperado.
Código final e resultados
Aqui está a versão final do nosso programa com as novas funcionalidades.
//+------------------------------------------------------------------+ //| Admin Panel.mq5 | //| Copyright 2024, Clemence Benjamin | //| https://www.mql5.com/en/users/billionaire2024/seller | //+------------------------------------------------------------------+ #property copyright "Copyright 2024, Clemence Benjamin" #property link "https://www.mql5.com/en/users/billionaire2024/seller" #property version "1.12" #include <Trade\Trade.mqh> #include <Controls\Dialog.mqh> #include <Controls\Button.mqh> #include <Controls\Edit.mqh> #include <Controls\Label.mqh> // Input parameters input string QuickMessage1 = "Updates"; input string QuickMessage2 = "Close all"; input string QuickMessage3 = "In deep profits"; input string QuickMessage4 = "Hold position"; input string QuickMessage5 = "Swing Entry"; input string QuickMessage6 = "Scalp Entry"; input string QuickMessage7 = "Book profit"; input string QuickMessage8 = "Invalid Signal"; input string InputChatId = "Enter Chat ID from Telegram bot API"; input string InputBotToken = "Enter BOT TOKEN from your Telegram bot"; // Global variables CDialog adminPanel; CButton sendButton, clearButton, changeFontButton, toggleThemeButton; CButton quickMessageButtons[8], minimizeButton, maximizeButton, closeButton; CEdit inputBox; CLabel charCounter; bool minimized = false; bool darkTheme = false; int MAX_MESSAGE_LENGTH = 4096; string availableFonts[] = { "Arial", "Courier New", "Verdana", "Times New Roman" }; int currentFontIndex = 0; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { // Initialize the Dialog if (!adminPanel.Create(ChartID(), "Admin Panel", 0, 30, 30, 500, 500)) { Print("Failed to create dialog"); return INIT_FAILED; } // Create controls if (!CreateControls()) { Print("Control creation failed"); return INIT_FAILED; } adminPanel.Show(); UpdateThemeColors(); Print("Initialization complete"); return INIT_SUCCEEDED; } //+------------------------------------------------------------------+ //| Create necessary UI controls | //+------------------------------------------------------------------+ bool CreateControls() { long chart_id = ChartID(); // Create the input box if (!inputBox.Create(chart_id, "InputBox", 0, 5, 25, 460, 95)) { Print("Failed to create input box"); return false; } adminPanel.Add(inputBox); // Character counter if (!charCounter.Create(chart_id, "CharCounter", 0, 380, 5, 460, 25)) { Print("Failed to create character counter"); return false; } charCounter.Text("0/" + IntegerToString(MAX_MESSAGE_LENGTH)); adminPanel.Add(charCounter); // Clear button if (!clearButton.Create(chart_id, "ClearButton", 0, 235, 95, 345, 125)) { Print("Failed to create clear button"); return false; } clearButton.Text("Clear"); adminPanel.Add(clearButton); // Send button if (!sendButton.Create(chart_id, "SendButton", 0, 350, 95, 460, 125)) { Print("Failed to create send button"); return false; } sendButton.Text("Send"); adminPanel.Add(sendButton); // Change font button if (!changeFontButton.Create(chart_id, "ChangeFontButton", 0, 95, 95, 230, 115)) { Print("Failed to create change font button"); return false; } changeFontButton.Text("Font<>"); adminPanel.Add(changeFontButton); // Toggle theme button if (!toggleThemeButton.Create(chart_id, "ToggleThemeButton", 0, 5, 95, 90, 115)) { Print("Failed to create toggle theme button"); return false; } toggleThemeButton.Text("Theme<>"); adminPanel.Add(toggleThemeButton); // Minimize button if (!minimizeButton.Create(chart_id, "MinimizeButton", 0, 375, -22, 405, 0)) { Print("Failed to create minimize button"); return false; } minimizeButton.Text("_"); adminPanel.Add(minimizeButton); // Maximize button if (!maximizeButton.Create(chart_id, "MaximizeButton", 0, 405, -22, 435, 0)) { Print("Failed to create maximize button"); return false; } maximizeButton.Text("[ ]"); adminPanel.Add(maximizeButton); // Close button if (!closeButton.Create(chart_id, "CloseButton", 0, 435, -22, 465, 0)) { Print("Failed to create close button"); return false; } closeButton.Text("X"); adminPanel.Add(closeButton); // Quick messages return CreateQuickMessageButtons(); } //+------------------------------------------------------------------+ //| Create quick message buttons | //+------------------------------------------------------------------+ bool CreateQuickMessageButtons() { string quickMessages[8] = { QuickMessage1, QuickMessage2, QuickMessage3, QuickMessage4, QuickMessage5, QuickMessage6, QuickMessage7, QuickMessage8 }; int startX = 5, startY = 160, width = 222, height = 65, spacing = 5; for (int i = 0; i < 8; i++) { if (!quickMessageButtons[i].Create(ChartID(), "QuickMessageButton" + IntegerToString(i + 1), 0, startX + (i % 2) * (width + spacing), startY + (i / 2) * (height + spacing), startX + (i % 2) * (width + spacing) + width, startY + (i / 2) * (height + spacing) + height)) { Print("Failed to create quick message button ", i + 1); return false; } quickMessageButtons[i].Text(quickMessages[i]); adminPanel.Add(quickMessageButtons[i]); } return true; } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { adminPanel.Destroy(); Print("Deinitialization complete"); } //+------------------------------------------------------------------+ //| Handle chart events | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { switch (id) { case CHARTEVENT_OBJECT_CLICK: if (sparam == "SendButton") OnSendButtonClick(); else if (sparam == "ClearButton") OnClearButtonClick(); else if (sparam == "ChangeFontButton") OnChangeFontButtonClick(); else if (sparam == "ToggleThemeButton") OnToggleThemeButtonClick(); else if (sparam == "MinimizeButton") OnMinimizeButtonClick(); else if (sparam == "MaximizeButton") OnMaximizeButtonClick(); else if (sparam == "CloseButton") OnCloseButtonClick(); else if (StringFind(sparam, "QuickMessageButton") != -1) { long index = StringToInteger(StringSubstr(sparam, 18)); OnQuickMessageButtonClick(index - 1); } break; case CHARTEVENT_OBJECT_ENDEDIT: if (sparam == "InputBox") OnInputChange(); break; } } //+------------------------------------------------------------------+ //| Handle custom message send button click | //+------------------------------------------------------------------+ void OnSendButtonClick() { string message = inputBox.Text(); if (message != "") { if (SendMessageToTelegram(message)) Print("Custom message sent: ", message); else Print("Failed to send custom message."); } else { Print("No message entered."); } } //+------------------------------------------------------------------+ //| Handle clear button click | //+------------------------------------------------------------------+ void OnClearButtonClick() { inputBox.Text(""); OnInputChange(); Print("Input box cleared."); } //+------------------------------------------------------------------+ //| Handle quick message button click | //+------------------------------------------------------------------+ void OnQuickMessageButtonClick(int index) { string quickMessages[8] = { QuickMessage1, QuickMessage2, QuickMessage3, QuickMessage4, QuickMessage5, QuickMessage6, QuickMessage7, QuickMessage8 }; string message = quickMessages[index]; if (SendMessageToTelegram(message)) Print("Quick message sent: ", message); else Print("Failed to send quick message."); } //+------------------------------------------------------------------+ //| Update character counter | //+------------------------------------------------------------------+ void OnInputChange() { int currentLength = StringLen(inputBox.Text()); charCounter.Text(IntegerToString(currentLength) + "/" + IntegerToString(MAX_MESSAGE_LENGTH)); ChartRedraw(); } //+------------------------------------------------------------------+ //| Handle toggle theme button click | //+------------------------------------------------------------------+ void OnToggleThemeButtonClick() { darkTheme = !darkTheme; UpdateThemeColors(); Print("Theme toggled: ", darkTheme ? "Dark" : "Light"); } //+------------------------------------------------------------------+ //| Update theme colors for the panel | //+------------------------------------------------------------------+ void UpdateThemeColors() { // Use the dialog's theme update method as a placeholder. adminPanel.UpdateThemeColors(darkTheme); color textColor = darkTheme ? clrWhite : clrBlack; color buttonBgColor = darkTheme ? clrDarkSlateGray : clrGainsboro; color borderColor = darkTheme ? clrSlateGray : clrGray; color bgColor = darkTheme? clrDarkBlue : clrWhite; inputBox.SetTextColor(textColor); inputBox.SetBackgroundColor(bgColor); inputBox.SetBorderColor(borderColor); UpdateButtonTheme(clearButton, textColor, buttonBgColor, borderColor); UpdateButtonTheme(sendButton, textColor, buttonBgColor, borderColor); UpdateButtonTheme(toggleThemeButton, textColor, buttonBgColor, borderColor); UpdateButtonTheme(changeFontButton, textColor, buttonBgColor, borderColor); UpdateButtonTheme(minimizeButton, textColor, buttonBgColor, borderColor); UpdateButtonTheme(maximizeButton, textColor, buttonBgColor,borderColor); UpdateButtonTheme(closeButton, textColor, buttonBgColor, borderColor); for (int i = 0; i < ArraySize(quickMessageButtons); i++) { UpdateButtonTheme(quickMessageButtons[i], textColor, buttonBgColor, borderColor); } charCounter.Color(textColor); ChartRedraw(); } //+------------------------------------------------------------------+ //| Apply theme settings to a button | //+------------------------------------------------------------------+ void UpdateButtonTheme(CButton &button, color textColor, color bgColor, color borderColor) { button.SetTextColor(textColor); button.SetBackgroundColor(bgColor); button.SetBorderColor(borderColor); } //+------------------------------------------------------------------+ //| Handle change font button click | //+------------------------------------------------------------------+ void OnChangeFontButtonClick() { currentFontIndex = (currentFontIndex + 1) % ArraySize(availableFonts); inputBox.Font(availableFonts[currentFontIndex]); clearButton.Font(availableFonts[currentFontIndex]); sendButton.Font(availableFonts[currentFontIndex]); toggleThemeButton.Font(availableFonts[currentFontIndex]); changeFontButton.Font(availableFonts[currentFontIndex]); for (int i = 0; i < ArraySize(quickMessageButtons); i++) { quickMessageButtons[i].Font(availableFonts[currentFontIndex]); } Print("Font changed to: ", availableFonts[currentFontIndex]); ChartRedraw(); } //+------------------------------------------------------------------+ //| Handle minimize button click | //+------------------------------------------------------------------+ void OnMinimizeButtonClick() { minimized = true; adminPanel.Hide(); minimizeButton.Hide(); maximizeButton.Show(); closeButton.Show(); Print("Panel minimized."); } //+------------------------------------------------------------------+ //| Handle maximize button click | //+------------------------------------------------------------------+ void OnMaximizeButtonClick() { if (minimized) { adminPanel.Show(); minimizeButton.Show(); maximizeButton.Hide(); closeButton.Hide(); Print("Panel maximized."); } } //+------------------------------------------------------------------+ //| Handle close button click | //+------------------------------------------------------------------+ void OnCloseButtonClick() { ExpertRemove(); Print("Admin Panel closed."); } //+------------------------------------------------------------------+ //| Send the message to Telegram | //+------------------------------------------------------------------+ bool SendMessageToTelegram(string message) { string url = "https://api.telegram.org/bot" + InputBotToken + "/sendMessage"; string jsonMessage = "{\"chat_id\":\"" + InputChatId + "\", \"text\":\"" + message + "\"}"; char post_data[]; ArrayResize(post_data, StringToCharArray(jsonMessage, post_data, 0, WHOLE_ARRAY) - 1); int timeout = 5000; char result[]; string responseHeaders; int res = WebRequest("POST", url, "Content-Type: application/json\r\n", timeout, post_data, result, responseHeaders); if (res == 200) { Print("Message sent successfully: ", message); return true; } else { Print("Failed to send message. HTTP code: ", res, " Error code: ", GetLastError()); Print("Response: ", CharArrayToString(result)); return false; } }
Novo tema do painel administrativo
A imagem abaixo mostra todas as operações executadas no painel, incluindo o tratamento de erros. A falha ao enviar uma mensagem personalizada pode estar relacionada a um token de bot do Telegram ou a um ID de chat ausente ou incorreto. Como pode ser visto na imagem, esses campos foram deixados em branco. É importante garantir que essas credenciais sejam inseridas corretamente, pois são fundamentais para o funcionamento. Guarde essas credenciais em um local seguro para evitar acessos não autorizados.
Logs na aba "Especialistas"
Considerações finais
Este artigo marca mais um marco no desenvolvimento do nosso painel administrativo de trading. Integramos com sucesso os algoritmos de gerenciamento de temas nas classes existentes, sem perceber nenhum impacto de desempenho que afetasse outras funções da plataforma que utilizam as mesmas bibliotecas. Essas conquistas têm como foco principal os objetivos educacionais e de pesquisa. No entanto, modificar classes e integrar novos métodos pode trazer benefícios, mas também envolve riscos de resultados indesejados, caso não sejam implementados corretamente. Nosso projeto tornou-se mais sofisticado, integrando funcionalidades com o Telegram e recursos avançados de visualização.
Estou satisfeito com o progresso e espero que você tenha adquirido informações valiosas ao trabalhar com os arquivos de biblioteca no MQL5. É possível alcançar resultados ainda mais expressivos utilizando algumas das abordagens empregadas neste projeto. Abaixo, anexei os arquivos-fonte modificados. Observe que a funcionalidade de troca de temas depende da presença dessas classes de biblioteca. Se você tiver qualquer problema, reinstale o MetaTrader 5 para restaurar os arquivos do sistema e redefinir as classes para o estado padrão.
Traduzido do Inglês pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/en/articles/16045
Aviso: Todos os direitos sobre esses materiais pertencem à MetaQuotes Ltd. É proibida a reimpressão total ou parcial.
Esse artigo foi escrito por um usuário do site e reflete seu ponto de vista pessoal. A MetaQuotes Ltd. não se responsabiliza pela precisão das informações apresentadas nem pelas possíveis consequências decorrentes do uso das soluções, estratégias ou recomendações descritas.





- 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