English Deutsch
preview
MQL5で取引管理者パネルを作成する(第3回):ビジュアルスタイリングによるGUIの強化(I)

MQL5で取引管理者パネルを作成する(第3回):ビジュアルスタイリングによるGUIの強化(I)

MetaTrader 5 | 15 11月 2024, 10:36
92 0
Clemence Benjamin
Clemence Benjamin

内容

  1. はじめに
  2. 視覚的に魅力的なGUIの重要性
  3. MQL5 GUI スタイル機能の適用
  4. 色とフォントのカスタマイズ
  5. テーマ管理ロジック
  6. 新しいボタンのレイアウトを調整する
  7. GUIの高度な強化
  8. 結論

はじめに

前回の記事で示した目標を振り返ると、どれだけの成果を上げたか自信を持って言えるでしょうか。個人的には、現在の進展を超えて更なる成長を促進するためのアイデアが浮かびます。たとえば、管理パネルにダークテーマとライトテーマの切り替え機能を実装した場合、どれほど便利になるか想像してみてください。また、スタイリッシュなボタンの追加や、さまざまなフォントの提供、さらには主要言語間での言語切り替え機能を加えることで、ユーザーエクスペリエンスをさらに向上させることができます。これにより、パネルはより多くのユーザーにとって使いやすくなります。

私たちの目標は、取引管理者に対し、取引プラットフォーム内で統合された包括的なコミュニケーションソリューションを提供することです。私たちが目指すコンセプトは、1970年代以降のグラフィカルユーザーインターフェイス(GUI)における影響力のある研究と開発から多くのインスピレーションを受けています。著名な貢献者には、Alan KayXerox PARCApple (macOS)、Microsoft (Windows)CSS (Cascading Style Sheets)、GoogleのMaterial Designなどが挙げられます。これらの先人たちの洞察を活用することで、ユーザーのニーズを満たし、全体的なエクスペリエンスを向上させる管理パネルを作成できると信じています。


クイックメッセージボタン付きのシンプルな管理画面

これまでに開発した基本的な管理パネル

これまでに達成した成果を要約すると、次のようになります。

この記事の最後には、MQL5で完全にカスタマイズされ、視覚的にスタイリングされた取引管理パネルが完成します。インターフェイスの外観と機能性を向上させるさまざまなスタイル設定テクニックを実装し、トレーダーにとってプロフェッショナルで使いやすい環境を作り上げる方法を学びます。

この記事の主な目的は次のとおりです。
  • MQL5を使用した基本的なスタイリング手法を適用する
  • フォント、色、レイアウトをカスタマイズする
  • 視覚的な要素によってユーザーインタラクションを強化する
  • ライトテーマモードとダークテーマモード間のカスタマイズ機能を組み込む
  • アニメーションやトランジションなどの動的な機能を追加する

MQL5は、取引アプリケーションのGUIをスタイリングするためのさまざまな機能とオプションを提供します。これにより、ユーザーのニーズや目指すデザインに合わせて、色、フォント、レイアウトをカスタマイズできます。

MQL5でGUIをスタイリングするためには、いくつかの重要な機能とテクニックを活用します。  ここでは、ボタン、ラベル、パネルなどのグラフィックオブジェクトのプロパティを変更する方法について説明します。これらの機能を使用することで、背景色や境界線のスタイル、フォントサイズ、その他の視覚的要素をカスタマイズし、統一感のある外観と雰囲気を作り上げることができます。

  1. 色とフォントのカスタマイズ
  2. テーマ管理ロジック
  3. 新しいボタンレイアウトの調整

    色とフォントのカスタマイズ

    フォント配列とインデックス

    まず、管理パネルのフォント選択を管理するために、availableFonts配列とcurrentFontIndexを定義します。availableFonts配列には、「Arial」、「Courier New」、「Verdana」、「Times New Roman」などのフォント名が含まれており、ユーザーはパネルの外観をカスタマイズするためのさまざまな選択肢を利用できます。currentFontIndexは、この配列のインデックスを使用して、選択されたフォントを追跡します。この設定により、ユーザーがフォントを変更するたびに簡単にフォントを切り替え、UIコンポーネントに即座に適用できるため、ユーザーエクスペリエンスが動的で一貫したものになります。


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


    フォント変更ボタンの作成

    Font<>」というラベルの付いたボタンを作成し、管理パネル内に戦略的に配置します。これは単なるボタンではなく、フォントを変更するための重要な機能を持ちます。パネルのレイアウトにうまく適合することを確認し、作成に関する問題を処理します。このボタンを追加することで、ユーザーはさまざまなフォントを直感的に切り替えることができ、パネルの使いやすさと美的柔軟性が向上します。ボタンの作成中に問題が発生した場合は、エラーメッセージを出力して問題の追跡を容易にします。
    // 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.");
    }
    

    フォント変更ボタンのクリックの処理

    OnChangeFontButtonClick関数の実装目標は、フォント変更プロセスをスムーズに管理することです。この関数では、currentFontIndexを更新して、availableFonts配列の次のフォントを選択し、必要に応じて先頭に戻ります。インデックスの更新後、入力ボックス、クリアボタン、送信ボタンなどの関連するUIコンポーネントに新しいフォントを適用し、パネル全体で一貫した外観を維持します。変更を確定するために、ChartRedrawを使用して画面表示を更新し、フォント変更が成功したことをユーザーに知らせる確認メッセージを表示します。
    // 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

    OnChartEvent関数では、フォント変更ボタンを含むさまざまなチャートオブジェクトに対するユーザー操作を処理します。この関数は、ボタンのクリックイベントをリッスンし、sparam文字列を調べてどのボタンがクリックされたかを確認します。「ChangeFontButton」がクリックされると、フォントの変更を管理するためにOnChangeFontButtonClick関数が呼び出されます。このイベント駆動型のアプローチにより、UIの応答性とインタラクティブ性が維持され、ユーザーのアクションによって適切な応答がトリガーされ、魅力的なインターフェイスが維持されます。
    // 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();
            }
        }
    }
    

    フォントの切り替えが正常に動作しています

    フォント切り替えが機能している

    テーマ管理ロジック


    テーマ切り替えロジック
    まず、ライトテーマとダークテーマという 2 つの異なるテーマを使用してテーマ管理システムを設定します。切り替えを管理するには、現在アクティブなテーマを追跡するブール変数isDarkModeを使用します。切り替えは簡単です。ユーザーがテーマボタンをクリックすると、isDarkModeの値が反転し、管理パネル全体の外観と操作性が変わります。各テーマの色を個別に定義することで、プロセスが合理化され、必要に応じて新しいスタイルを簡単に維持および適用できるようになります。
    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
    

    テーマ切り替えボタンの作成
    次に、「Theme<>」というラベルの付いたボタンを作成します。このボタンは管理パネル内に配置され、ユーザーがライトモードとダークモードを簡単に切り替えられるようにします。作成中に何か問題が発生した場合、メッセージを出力してエラーが処理されるようにしています。これにより、トラブルシューティングが容易になり、インターフェイスが直感的で応答性に優れたものになります。 
    //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
    }
    

    テーマ切り替えボタンをクリックの処理
    次に、OnToggleModeButtonClick関数を実装して、実際のテーマの変更を処理します。この関数は、isDarkMode変数を反転し、ライトテーマとダークテーマを切り替えます。どのテーマがアクティブであるかがわかったら、パネル、ボタン、テキストなどのすべてUI要素に、対応する背景色とテキスト色を適用します。テーマの変更は、素早い更新によりリアルタイムで行われるため、インターフェイスがスムーズで応答性が高くなります。モードが変更されたことをユーザーに知らせるために、確認メッセージも出力します。
    //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
    OnChartEvent関数では、ユーザーが「テーマの切り替え」ボタンをクリックしたことを検出し、OnToggleModeButtonClick関数をトリガーします。このイベント駆動型のアプローチにより、パネルがユーザーのアクションに即座に応答することが保証されます。ボタンのクリック イベントをリッスンすることで、管理パネルがインタラクティブで魅力的な状態を維持し、ユーザーが必要に応じてライトテーマとダークテーマを簡単に切り替えられるようにします。
    //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
            }
        }
    }
    

    オブジェクトを再作成せずにテーマを適用する
    私たちの重要な設計上の決定1つは、パネルのオブジェクトを再作成せずにテーマを更新することです。UI コンポーネントを解体して新しいコンポーネントを構築する代わりに、既存の要素に新しい配色を適用するだけです。これにより、システムの効率が維持され、遅延が削減され、スムーズなユーザー エクスペリエンスが維持されます。また、新しい色を動的に適用する際に、パネルが応答性を維持することも保証されます。
    
    //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
    }
    

    新しいボタンレイアウトの調整

    フォント変更ボタン

     フォント変更ボタンは、管理パネルの左上隅を (95, 95)、右下隅を (230, 115)に配置しました。これにより、送信ボタンとクリアボタンの左側に配置されます。その寸法は、「フォント<>」ラベルとユーザーフレンドリーな操作に十分な幅があります。このボタンを使用すると、パネル内のすべてのテキスト要素に対してさまざまなフォント オプションを切り替えることができます。
    if (!changeFontButton.Create(chart_id, "ChangeFontButton", 0, 95, 95, 230, 115))

    テーマ切り替えボタン

    テーマ切り替えボタンについては、左上の座標 (5, 95)、右下の座標 (90, 115)に配置しました。これにより、ボタンがパネルの左端、フォント変更ボタンの少し上に配置され、明確な区別が実現します。コンパクトなサイズと他のボタンに近いため、ユーザーはインターフェイスを煩雑にすることなく、ダークテーマとライトテーマを簡単に切り替えることができます。
    if (!toggleThemeButton.Create(chart_id, "ToggleThemeButton", 0, 5, 95, 90, 115))


    すべての新機能が完璧に統合された完全なプログラムをご紹介します。
    //+------------------------------------------------------------------+
    //|                                             Admin Panel.mq5      |
    //|                     Copyright 2024, Clemence Benjamin            |
    //|     https://www.mql5.com/ja/users/billionaire2024/seller         |
    //+------------------------------------------------------------------+
    #property copyright "Copyright 2024, Clemence Benjamin"
    #property link      "https://www.mql5.com/ja/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;
        }
    }


    新機能のテスト

    XAUUSDでテストされた新機能

    これらの基本的なスタイリング手法を導入することで、GUIにさらに優れたインタラクティブ性と視覚的な魅力をもたらす、より高度なカスタマイズ オプションを検討できるようになりました。上の画像から、テーマが前景テキストにのみ機能していることがわかりますが、パネルの背景にも影響を与える必要があります。次のセグメントでは、この問題を解決する方法について説明します。

    GUIの高度な強化

    テーマ管理用のダイアログクラスの拡張

    テーマ管理用ダイアログを拡張するには、管理パネルでテーマを管理する方法と同様に、既存のダイアログクラスをカスタマイズして動的なテーマの変更をサポートします。これには、背景色とテキスト色のプロパティ、およびさまざまなテーマ(ライトテーマまたはダークテーマ)を適用するためのメソッドを含めるようにCDialogクラスを変更またはサブクラス化することが含まれます。コンストラクタをオーバーライドするか、ApplyThemeなどのメソッドを追加することで、このクラスを使用して作成されたダイアログボックスが、ダイアログオブジェクトを再作成せずにテーマの変更に応答することを保証できます。

    Dialogクラスのカスタマイズ

    Dialogクラスの色のカスタマイズ

    重要な理由 

    テーマ管理のためにDialogクラスを拡張することで、管理パネルだけでなく、すべてのUI要素にわたって、よりシームレスで統一されたユーザーエクスペリエンスが実現します。このアプローチにより、ダイアログボックスを含むアプリケーションのすべての部分が選択したテーマに適応し、視覚的な一貫性と使いやすさが向上します。特に取引アプリケーションなど、ユーザーが長時間インターフェースを操作するケースでは、この機能が重要となり、カスタマイズ可能なテーマによって目の疲れを軽減し、全体的なユーザー満足度の向上にもつながります。

    Dialogクラスを変更した後の背景テーマ

    管理パネル:Dialogクラスを変更した後の背景テーマ

    その他のオプション

    Dialogクラスを拡張するのは直接的で柔軟なアプローチですが、もう 1 つのオプションは、より高いレベルでテーマ管理を適用することです。たとえば、個々のコンポーネントを変更することなく、ダイアログを含むすべてUI要素のプロパティを自動的に更新するグローバル テーマ管理システムを作成できます。さらに、外部ライブラリを活用したり、カスタム ダイアログフレームワークを設計したりすることで、特定のスタイル設定のニーズが生じた場合にUI要素をより細かく制御できるようになります。

    CEditクラス

    Google検索によると、Telegramメッセージは、最大長が4096文字でUTF-8でエンコードされている必要があります。このプロジェクトで値を実装しようとした際、文字数が最大63文字に制限されていましたが、これは次の記事で説明するCEdit クラスの制約範囲内に収まるはずです。

    MQL5ライブラリファイルを編集する際には注意が必要です。オブジェクト指向言語の厳密な構文と構造により、不適切な変更を行うとコンパイルエラーや実行時の問題が発生する可能性があります。変更を加える前に、元のファイルを必ずバックアップし、機能を損なわないように関連クラスの関係性を理解してください。編集後にはコードをコンパイルしてエラーの有無を確認し、デモ環境で変更を徹底的にテストして安定性を確認します。深刻な問題が解決できない場合、MetaTrader5プラットフォームを再インストールし、デフォルト設定とファイルを復元することも検討してください。



    結論

    結管理パネルプログラムにおけるフォントとテーマの管理の実装は、有望な結果を示しました。ダイアログクラスの静的背景にはまだ制約があるものの、テキストの前景はテーマ変更にうまく適応し、ユーザーエクスペリエンスが向上しました。また、動的フォント管理も効果的に機能し、ユーザーはさまざまなフォントを簡単に切り替えることが可能になりました。

    今後は、ダイアログクラスを拡張し、動的な背景の更新を含むテーマ変更に完全対応させることが次の目標です。この改善により、現在の制約を克服し、より統一感のある視覚的に魅力的なインターフェイスを提供できるようになります。これらの課題については、今後の記事で詳しく取り上げる予定ですので、どうぞご期待ください!
    これらのスタイリング手法をご自身の取引パネルで試し、MQL5のさらなるカスタマイズオプションも探ってみてください。皆さんの体験やご意見をお聞かせいただければ幸いです。また、高度なGUIデザインの課題に取り組む際には、以下のコメント欄で共有してください。このプロジェクトのソースファイルも添付してありますので、ぜひご確認ください。

    内容

    MetaQuotes Ltdにより英語から翻訳されました。
    元の記事: https://www.mql5.com/en/articles/15419

    添付されたファイル |
    Admin_Panel.mq5 (14.67 KB)
    PSAR、平均足、ディープラーニングを組み合わせて取引に活用する PSAR、平均足、ディープラーニングを組み合わせて取引に活用する
    このプロジェクトでは、ディープラーニングとテクニカル分析の融合を探求し、FXの取引戦略を検証します。EUR/USDの動きを予測するために、PSAR、SMA、RSIのような伝統的な指標とともにONNXモデルを採用し、迅速な実験のためにPythonスクリプトを使用します。MetaTrader 5のスクリプトは、この戦略をライブ環境に導入し、ヒストリカルデータとテクニカル分析を使用して、情報に基づいた取引決定をおこないます。バックテストの結果は、積極的な利益追求よりもリスク管理と着実な成長に重点を置いた、慎重かつ一貫したアプローチを示しています。
    MQL5エキスパートアドバイザーに自動最適化を実装する方法 MQL5エキスパートアドバイザーに自動最適化を実装する方法
    エキスパートアドバイザー(EA)のためのMQL5の自動最適化のためのステップバイステップガイド。堅牢な最適化ロジック、パラメーター選択のベストプラクティス、バックテストを通じた戦略の再構築方法について解説します。さらに、ウォークフォワード最適化などの高レベルな手法を紹介し、取引アプローチの強化を目指します。
    ニューラルネットワークが簡単に(第91回):周波数領域予測(FreDF) ニューラルネットワークが簡単に(第91回):周波数領域予測(FreDF)
    周波数領域における時系列の分析と予測を継続的に探求していきます。この記事では、これまでに学習した多くのアルゴリズムに追加できる、周波数領域でデータを予測する新しい方法について説明します。
    ディープラーニングを用いたCNA(因果ネットワーク分析)、SMOC(確率モデル最適制御)、ナッシュゲーム理論の例 ディープラーニングを用いたCNA(因果ネットワーク分析)、SMOC(確率モデル最適制御)、ナッシュゲーム理論の例
    以前の記事で発表されたこれら3つの例にディープラーニング(DL)を加え、以前の結果と比較します。目的は、他のEAにディープラーニングを追加する方法を学ぶことです。