English Русский 中文 Español Deutsch 日本語
preview
Criando um Painel Administrativo de Negociação em MQL5 (Parte III): Aprimorando a Interface com Estilo Visual (I)

Criando um Painel Administrativo de Negociação em MQL5 (Parte III): Aprimorando a Interface com Estilo Visual (I)

MetaTrader 5Exemplos |
132 1
Clemence Benjamin
Clemence Benjamin

Conteúdo:

  1. Introdução
  2. Importância de uma GUI visualmente atraente
  3. Aplicando recursos de estilo de GUI no MQL5
  4. Personalizando Cores e Fontes
  5. Lógica de gerenciamento de tema
  6. Ajustando o Layout dos Novos Botões
  7. Aprimoramento avançado da interface
  8. Conclusão

Introdução

Analisando os objetivos delineados em nosso artigo anterior, podemos afirmar com confiança que fizemos o suficiente? Na minha opinião, o que vejo inspira um impulso para ir além do que já oferecemos. Imagine o quão benéfico seria implementar uma alternância entre temas claro e escuro para o nosso Painel Administrativo. Além disso, poderíamos melhorar a experiência do usuário adicionando botões estilosos, oferecendo uma seleção variada de fontes e permitindo a troca de idioma entre os principais idiomas. Isso tornaria nosso painel mais acessível para todos.

Nosso objetivo é fornecer aos administradores de negociação uma solução de comunicação abrangente integrada à plataforma de negociação. Os conceitos que pretendemos incorporar são inspirados em pesquisas e desenvolvimentos influentes em interfaces gráficas de usuário (GUIs) desde os anos 1970. Contribuidores notáveis incluem Alan Kay, Xerox PARC, Apple (macOS), Microsoft (Windows), CSS (Cascading Style Sheets) e Material Design do Google. Aproveitando essas ideias, podemos criar um Painel Administrativo que atenda às necessidades dos usuários e melhore sua experiência geral.



Admin Simples com botões de mensagem rápida

O Painel Administrativo Básico que desenvolvemos até agora.

Resumo do que realizamos até agora:

Ao final deste artigo, teremos um painel administrativo de negociação totalmente personalizado e com estilo visual em MQL5. Você aprenderá a implementar várias técnicas de estilo que melhoram tanto a aparência quanto a funcionalidade da interface, criando um ambiente profissional e amigável para os traders.

Aqui estão os principais objetivos deste artigo:
  • Aplicar técnicas básicas de estilo usando MQL5
  • Personalizar fontes, cores e layouts
  • Melhorar a interação do usuário com elementos visuais
  • Incorporar a customização entre modos claro e escuro
  • Adicionar recursos dinâmicos como animações e transições

O MQL5 oferece várias funções e recursos para estilizar a GUI da sua aplicação de negociação. Esses recursos incluem opções para personalizar cores, fontes e layouts para atender às necessidades dos seus usuários e ao design estético desejado.

Estilizar a GUI em MQL5 envolve o uso de várias funções e técnicas-chave. Vamos abordar as funções que permitem alterar as propriedades de objetos gráficos, como botões, rótulos e painéis. Com isso, podemos personalizar a cor de fundo, o estilo da borda, o tamanho da fonte e outros aspectos visuais para criar uma aparência coesa.

  1. Personalizando Cores e Fontes
  2. Lógica de Gerenciamento de tema
  3. Ajustando o Layout dos Novos Botões

    Personalizando Cores e Fontes:

    Array de Fontes e Índice:

    Começamos definindo um array availableFonts e um currentFontIndex para gerenciar as seleções de fonte no Painel Administrativo. O array availableFonts inclui nomes de fontes como "Arial", "Courier New", "Verdana" e "Times New Roman", oferecendo aos usuários uma gama de opções para personalizar a aparência do painel. O currentFontIndex mantém o controle da fonte selecionada ao indexar esse array. Essa configuração nos permite alternar facilmente entre as fontes e aplicá-las aos componentes da interface sempre que o usuário mudar a fonte, garantindo que a experiência do usuário permaneça dinâmica e coesa.


    // Array of available fonts
    string availableFonts[] = {"Arial", "Courier New", "Verdana", "Times New Roman"};
    // Index of the current font in use
    int currentFontIndex = 0;
    


    Criando o Botão de Troca de Fonte:

    Vamos criar um botão rotulado como "Fonte<>", que será posicionado estrategicamente dentro do Painel Administrativo. Esse botão não é apenas mais um botão; ele é um recurso essencial para a troca de fontes. Garantimos que ele se encaixe bem no layout do painel e lidamos com quaisquer problemas durante sua criação. Ao adicionar esse botão, oferecemos aos usuários uma forma intuitiva de alternar entre diferentes fontes, melhorando a usabilidade e a flexibilidade estética do painel. Se houver qualquer falha na criação do botão, imprimimos uma mensagem de erro para rastrear o problema.
    // Create a button for changing the font
    CButton changeFontButton;
    changeFontButton.Create(panel, "ChangeFontButton", 0, 10, 10, 100, 30);
    changeFontButton.Text("Font<>");
    
    // Verify button creation and handle errors
    if(!changeFontButton.IsCreated())
    {
        Print("Error creating Font<> button.");
    }
    

    Lidando com o Clique no Botão de Troca de Fonte:

    Ao implementarmos a função OnChangeFontButtonClick, nosso objetivo é gerenciar o processo de troca de fonte de forma fluida. Essa função atualiza o currentFontIndex para selecionar a próxima fonte no array availableFonts, voltando ao início, se necessário. Depois de atualizar o índice, aplicamos a nova fonte a todos os componentes relevantes da interface, como a caixa de entrada, botão limpar e botão enviar, garantindo uma aparência consistente em todo o painel. Para finalizar as alterações, usamos o ChartRedraw para atualizar a exibição e imprimimos uma mensagem de confirmação, informando ao usuário que a fonte foi alterada com sucesso.
    // Function to handle the font change button click
    void OnChangeFontButtonClick()
    {
        // Update the font index, wrapping around if necessary
        currentFontIndex = (currentFontIndex + 1) % ArraySize(availableFonts);
        string newFont = availableFonts[currentFontIndex];
        
        // Apply the new font to UI components
        inputBox.Font(newFont);
        clearButton.Font(newFont);
        sendButton.Font(newFont);
    
        // Refresh the display to apply the changes
        ChartRedraw();
    
        // Print confirmation of the font change
        Print("Font changed to ", newFont);
    }
    

    OnChartEvent para Lidar com Cliques nos Botões:

    Na função OnChartEvent, lidamos com interações do usuário com diversos objetos do gráfico, incluindo nosso botão de troca de fonte. Essa função escuta eventos de clique em botões e verifica qual botão foi clicado inspecionando a string sparam. Quando o botão "ChangeFontButton" é clicado, chamamos a função OnChangeFontButtonClick para realizar a troca da fonte. Essa abordagem orientada a eventos mantém nossa interface responsiva e interativa, garantindo que as ações do usuário acionem as respostas corretas e mantenham a interface envolvente.
    // Function to handle chart events
    void OnChartEvent(const int id, const int sub_id, const int type, const int x, const int y, const int state)
    {
        // Handle button clicks
        if(type == CHARTEVENT_OBJECT_CLICK)
        {
            string buttonName = ObjectGetString(0, "ChangeFontButton", OBJPROP_TEXT);
            if(buttonName == "Font<>")
            {
                OnChangeFontButtonClick();
            }
        }
    }
    

    Troca de Fonte funcionando perfeitamente

    Troca de Fonte funcionando

    Lógica de Gerenciamento de Tema:


    Lógica de Alternância de Tema:
    Começamos configurando o sistema de gerenciamento de tema com dois temas distintos: claro e escuro. Para controlar a troca, usamos uma variável booleana, isDarkMode, que mantém o controle de qual tema está ativo no momento. A alternância é simples: quando o usuário clica no botão de tema, o valor de isDarkMode é invertido, alterando toda a aparência do Painel Administrativo. Definindo separadamente as cores para cada tema, simplificamos o processo, tornando mais fácil a manutenção e aplicação de novos estilos sempre que necessário.
    bool isDarkMode = false; // Tracks the current theme mode (light or dark)
    color lightBackgroundColor = clrWhite;  // Background color for light mode
    color darkBackgroundColor = clrBlack;   // Background color for dark mode
    color lightTextColor = clrBlack;        // Text color for light mode
    color darkTextColor = clrWhite;         // Text color for dark mode
    

    Criar o Botão de Alternância de Tema:
    Vamos agora criar um botão rotulado como "Tema<>." Esse botão é inserido dentro do Painel Administrativo e oferece aos usuários uma maneira simples de alternar entre os modos claro e escuro. Se algo der errado durante sua criação, garantimos o tratamento do erro com uma mensagem impressa. Isso facilita a resolução de problemas e garante que a interface continue intuitiva e responsiva.
    //Creating the theme switch button
    if(!CreateButton("ToggleThemeButton", "Theme<>", 50, 220, 100, 30)) 
    {
       Print("Error: Failed to create theme toggle button"); // Error handling if button creation fails
    }
    

    Tratar o Clique no Botão de Alternância de Tema:
    Em seguida, lidamos com a mudança de tema propriamente dita implementando a função OnToggleModeButtonClick. Essa função inverte o valor da variável isDarkMode, alternando entre os temas claro e escuro. Assim que identificamos qual tema está ativo, aplicamos as cores de fundo e texto correspondentes a todos os elementos da interface, como painel, botões e textos. A mudança de tema acontece em tempo real graças a uma atualização rápida, tornando a interface fluida e responsiva. Também imprimimos uma mensagem de confirmação para que o usuário saiba que o modo foi alterado.
    //Theme switching handler
    void OnToggleModeButtonClick()
    {
        isDarkMode = !isDarkMode; // Toggle the theme mode
        if(isDarkMode)
        {
            ApplyTheme(darkBackgroundColor, darkTextColor); // Apply dark mode colors
        }
        else
        {
            ApplyTheme(lightBackgroundColor, lightTextColor); // Apply light mode colors
        }
        Print("Theme has been switched"); // Inform the user that the theme has changed
    }
    


    OnChartEvent para Lidar com Cliques no Botão de Alternância de Tema:
    Na função OnChartEvent, detectamos quando um usuário clica no botão "Alternar Tema" e acionamos a função OnToggleModeButtonClick. Essa abordagem orientada a eventos garante que o painel responda instantaneamente às ações do usuário. Ao escutar eventos de clique em botões, garantimos que o Painel Administrativo continue interativo e envolvente, permitindo que os usuários alternem facilmente entre os temas claro e escuro conforme necessário.
    //The OneChartEvent for  the theme
    void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
    {
        if(id == CHARTEVENT_OBJECT_CLICK) // Check if the event is a button click
        {
            if(sparam == "ToggleThemeButton") // Check if the clicked button is the theme toggle button
            {
                OnToggleModeButtonClick(); // Call the function to handle the theme change
            }
        }
    }
    

    Aplicando Tema sem Recriar Objetos:
    Uma de nossas decisões de design mais importantes é atualizar o tema sem recriar nenhum dos objetos do painel. Em vez de desmontar e reconstruir novos componentes da interface, simplesmente aplicamos o novo esquema de cores aos elementos existentes. Isso mantém o sistema eficiente, reduzindo atrasos e mantendo uma experiência de usuário fluida. Também garante que o painel permaneça responsivo ao aplicarmos as novas cores dinamicamente.
    
    //Applying theme
    void ApplyTheme(color backgroundColor, color textColor)
    {
        // Update background and text colors of existing objects
        ObjectSetInteger(0, "AdminPanelBackground", OBJPROP_COLOR, backgroundColor); // Change background color
        ObjectSetInteger(0, "ClearButton", OBJPROP_COLOR, textColor);                // Change text color of clear button
        ObjectSetInteger(0, "SendButton", OBJPROP_COLOR, textColor);                 // Change text color of send button
        ObjectSetInteger(0, "InputBox", OBJPROP_COLOR, textColor);                   // Change text color of input box
        ChartRedraw(); // Redraw the chart to reflect the changes
    }
    

    Ajustando o Layout dos Novos Botões.

    Botão de Troca de Fonte:

     O botão de troca de fonte foi posicionado no painel administrativo com seu canto superior esquerdo em (95, 95) e o canto inferior direito em (230, 115). Isso o coloca à esquerda dos botões Enviar e Limpar. Suas dimensões o tornam largo o suficiente para o rótulo "Fonte<>" e para uma interação amigável ao usuário. O botão permite que os usuários alternem entre diferentes opções de fonte para todos os elementos de texto no painel.
    if (!changeFontButton.Create(chart_id, "ChangeFontButton", 0, 95, 95, 230, 115))

    Botão de Alternância de Tema:

    Quanto ao botão de alternância de tema, o posicionamos nas coordenadas (5, 95) para o canto superior esquerdo e (90, 115) para o inferior direito. Isso coloca o botão na extremidade esquerda do painel, ligeiramente acima do botão de troca de fonte, proporcionando uma separação clara. O tamanho compacto e a proximidade de outros botões facilitam para os usuários alternarem entre os modos claro e escuro sem sobrecarregar a interface.
    if (!toggleThemeButton.Create(chart_id, "ToggleThemeButton", 0, 5, 95, 90, 115))


    Aqui está nosso programa completo com todos os novos recursos perfeitamente integrados.
    //+------------------------------------------------------------------+
    //|                                             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 description "A responsive Admin Panel. Send messages to your telegram clients without leaving MT5"
    #property version   "1.11"
    
    #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;
    #define BG_RECT_NAME "BackgroundRect"
    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();
        // Initialize with the default theme
        CreateOrUpdateBackground(ChartID(), darkTheme ? clrBlack : clrWhite);
    
        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();
        ObjectDelete(ChartID(), BG_RECT_NAME);
        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)
                {
                    int 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(""); // Clear the text in the input box
        OnInputChange();   // Update the character counter
        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;
        color bgColor = darkTheme ? clrBlack : clrWhite;
        color textColor = darkTheme ? clrWhite : clrBlack;
    
        // Set text color appropriate to the theme
        inputBox.Color(textColor);
        clearButton.Color(textColor);
        sendButton.Color(textColor);
        toggleThemeButton.Color(textColor);
        changeFontButton.Color(textColor);
    
        for(int i = 0; i < ArraySize(quickMessageButtons); i++)
        {
            quickMessageButtons[i].Color(textColor);
        }
    
        charCounter.Color(textColor);
    
        CreateOrUpdateBackground(ChartID(), bgColor);
    
        ChartRedraw();
    }
    
    //+------------------------------------------------------------------+
    //| Create and update background rectangle                           |
    //+------------------------------------------------------------------+
    void CreateOrUpdateBackground(long chart_id, color bgColor)
    {
        if (!ObjectFind(chart_id, BG_RECT_NAME))
        {
            if (!ObjectCreate(chart_id, BG_RECT_NAME, OBJ_RECTANGLE, 0, 0, 0))
                Print("Failed to create background rectangle");
        }
    
        ObjectSetInteger(chart_id, BG_RECT_NAME, OBJPROP_COLOR, bgColor);
        ObjectSetInteger(chart_id, BG_RECT_NAME, OBJPROP_BACK, true);
        ObjectSetInteger(chart_id, BG_RECT_NAME, OBJPROP_SELECTABLE, false);
        ObjectSetInteger(chart_id, BG_RECT_NAME, OBJPROP_SELECTED, false);
        ObjectSetInteger(chart_id, BG_RECT_NAME, OBJPROP_HIDDEN, false);
        ObjectSetInteger(chart_id, BG_RECT_NAME, OBJPROP_CORNER, CORNER_LEFT_UPPER);
        ObjectSetInteger(chart_id, BG_RECT_NAME, OBJPROP_XOFFSET, 25); 
        ObjectSetInteger(chart_id, BG_RECT_NAME, OBJPROP_YOFFSET, 25);
    }
    
    //+------------------------------------------------------------------+
    //| 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(); // Completely remove the EA
        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) // HTTP 200 OK
        {
            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;
        }
    }


    Testando Novos Recursos

    Novos Recursos Testados no XAUUSD

    Com essas técnicas básicas de estilo implementadas, agora podemos explorar opções de personalização mais avançadas que podem proporcionar ainda mais interatividade e apelo visual à GUI. Na imagem acima, podemos ver que nosso tema está funcionando apenas no texto do primeiro plano, mas queremos que ele também afete o fundo do painel. No próximo segmento, abordaremos formas de resolver esse problema.

    Aprimoramento avançado da interface

    Estendendo a Classe Dialog para Gerenciamento de Tema:

    Para estender a Dialog para gerenciamento de tema, podemos personalizar a classe de diálogo existente para suportar mudanças dinâmicas de tema, da mesma forma como fazemos no Painel Administrativo. Isso envolve modificar ou criar uma subclasse da CDialog para incluir propriedades de cores de fundo e texto, além de métodos para aplicar diferentes temas (claro ou escuro). Substituindo o construtor ou adicionando métodos como ApplyTheme, garantimos que caixas de diálogo criadas com essa classe respondam às mudanças de tema sem recriar os objetos de diálogo.

    Customizando a classe Dialog

    Personalizando as cores na classe Dialog

    Por que isso é importante? 

    Estender a classe Dialog para gerenciamento de tema permite uma experiência de usuário mais fluida e coesa em todos os elementos da interface, não apenas no Painel Administrativo. Garante que todas as partes do aplicativo — incluindo caixas de diálogo — sigam o tema escolhido, melhorando tanto a usabilidade quanto a consistência visual. Esse recurso se torna especialmente importante em aplicações de negociação onde os usuários podem passar longos períodos interagindo com a interface, e temas personalizáveis podem reduzir o cansaço visual e melhorar a satisfação geral.

    Tema de fundo após modificar a classe Dialog

    Painel Administrativo: Tema de fundo após modificar a classe Dialog

    Outras opções:

    Embora estender a classe Dialog seja uma abordagem direta e flexível, outra opção é aplicar o gerenciamento de tema em um nível mais elevado. Por exemplo, poderíamos criar um sistema global de gerenciamento de tema que atualize automaticamente as propriedades de todos os elementos da interface, incluindo diálogos, sem exigir alterações em componentes individuais. Além disso, usar bibliotecas externas ou projetar uma estrutura personalizada de diálogos pode oferecer um controle mais granular dos elementos de interface, caso surjam necessidades específicas de estilo.

    Classe CEdit

    Segundo pesquisa no Google, o comprimento máximo de uma mensagem no Telegram é de 4096 caracteres e ela deve estar codificada em UTF-8. Ao tentar implementar esse valor neste projeto, fomos limitados a um máximo de 63 caracteres, e o problema provavelmente está na limitação da classe CEdit, que abordaremos no próximo artigo.

    Ao editar arquivos da biblioteca MQL5, tenha cautela, pois modificações incorretas podem causar erros de compilação ou problemas em tempo de execução devido à sintaxe e estrutura rígidas da linguagem, que é orientada a objetos. Sempre faça backup dos arquivos originais antes de alterá-los e certifique-se de entender os relacionamentos entre as classes envolvidas para evitar quebrar funcionalidades. Após editar, compile seu código para verificar erros e teste cuidadosamente as mudanças em um ambiente de demonstração para verificar a estabilidade. Se encontrar problemas significativos que não conseguir resolver, considere reinstalar a plataforma MetaTrader 5 para restaurar as configurações e arquivos padrão.



    Conclusão

    Em conclusão, nossa implementação do gerenciamento de fontes e tema no programa do Painel Administrativo demonstrou resultados promissores. Embora tenhamos enfrentado limitações com o fundo estático da classe de diálogo, o texto do primeiro plano se adaptou com sucesso às mudanças de tema, proporcionando uma experiência de usuário aprimorada O gerenciamento dinâmico de fontes também funcionou bem, permitindo que os usuários alternassem entre diferentes fontes com facilidade.

    Seguindo em frente, nosso próximo objetivo será estender a classe de diálogo para oferecer suporte total a mudanças de tema, incluindo atualizações dinâmicas de fundo. Essa melhoria visa superar as limitações atuais e proporcionar uma interface mais coesa e visualmente atraente. Fique ligado enquanto enfrentamos esses desafios nos próximos artigos!
    Experimente essas técnicas de estilo nos seus próprios painéis de negociação e explore outras opções de personalização no MQL5. Adoraria saber sobre suas experiências e ideias — fique à vontade para compartilhá-las nos comentários enquanto exploramos desafios mais avançados de design de GUI. O arquivo-fonte deste projeto está anexado — sinta-se à vontade para analisá-lo.

    Conteúdo:

    Traduzido do Inglês pela MetaQuotes Ltd.
    Artigo original: https://www.mql5.com/en/articles/15419

    Arquivos anexados |
    Admin_Panel.mq5 (14.67 KB)
    Últimos Comentários | Ir para discussão (1)
    SERGEI NAIDENOV
    SERGEI NAIDENOV | 23 mai. 2025 em 19:09
    Ao tentar compilar, ele gera um aviso:

    possível perda de dados devido à conversão de tipo de 'long' para 'int' Admin_Panel.mq5 208 27

    Linha de código:
    int index = StringToInteger(StringSubstr(sparam, 18));
    Se você fizer dessa forma, tudo ocorrerá sem erros:
    int index = int(StringToInteger(StringSubstr(sparam, 18)));

    se você anexar a um gráfico e tentar minimizá-lo e depois expandi-lo... o botão de fechar "X" (excluir o Expert Advisor) não funciona no estado expandido do painel. Se você minimizá-lo, ele funciona.

    pergunta: a movimentação da janela no gráfico não está implementada?
    Usando PSAR, Heiken Ashi e Aprendizado Profundo Juntos para Operações de Trading Usando PSAR, Heiken Ashi e Aprendizado Profundo Juntos para Operações de Trading
    Este projeto explora a fusão entre aprendizado profundo e análise técnica para testar estratégias de trading no mercado de câmbio (forex). Um script em Python é usado para experimentação rápida, utilizando um modelo ONNX juntamente com indicadores tradicionais como PSAR, SMA e RSI para prever movimentos do par EUR/USD. Um script em MetaTrader 5 então leva essa estratégia para um ambiente ao vivo, usando dados históricos e análise técnica para tomar decisões de trading mais informadas. Os resultados do backtesting indicam uma abordagem cautelosa, porém consistente, com foco em gestão de risco e crescimento estável em vez da busca agressiva por lucros.
    Como Implementar Otimização Automática em Expert Advisors MQL5 Como Implementar Otimização Automática em Expert Advisors MQL5
    Guia passo a passo para otimização automática em MQL5 para Expert Advisors. Vamos abordar uma lógica de otimização robusta, boas práticas para seleção de parâmetros e como reconstruir estratégias com backtesting. Além disso, métodos mais avançados como a otimização walk-forward serão discutidos para aprimorar sua abordagem de trading.
    Redes neurais em trading: Aprendizado dependente de contexto com memória (Conclusão) Redes neurais em trading: Aprendizado dependente de contexto com memória (Conclusão)
    Estamos finalizando a implementação do framework MacroHFT para trading de alta frequência com criptomoedas, que utiliza aprendizado por reforço dependente de contexto e memória para se adaptar às condições dinâmicas do mercado. E para concluir este artigo, será realizado um teste com os métodos implementados utilizando dados históricos reais, a fim de avaliar sua eficácia.
    Métodos de discretização dos movimentos de preço em Python Métodos de discretização dos movimentos de preço em Python
    Vamos explorar métodos de discretização de preços com Python + MQL5. Neste artigo, compartilho minha experiência prática no desenvolvimento de uma biblioteca em Python que implementa uma variedade de abordagens para formar barras, desde as clássicas Volume e Range bars até métodos mais exóticos como Renko e Kagi. Barras, candles de três linhas rompidas, range bars — qual é a sua estatística? De que outras formas podemos representar os preços de maneira discreta?