English Русский Español Deutsch 日本語 Português
preview
在MQL5中创建交互式图形用户界面(第1部分):制作面板

在MQL5中创建交互式图形用户界面(第1部分):制作面板

MetaTrader 5交易 | 8 一月 2025, 11:02
104 1
Allan Munene Mutiiria
Allan Munene Mutiiria

概述

欢迎来到我们关于使用MetaQuotes Language 5(MQL5)构建自定义图形用户界面(GUI)面板综合指南的第一部分!作为交易者和开发者,我们深知高效且用户友好的界面对我们的交易工具至关重要。在本系列中,我们将深入MQL5的世界,探索如何创建强大的GUI面板,以提升您的交易体验。

在本初始部分中,我们将介绍基础知识:设置项目、设计面板布局以及添加基本控件。在下一部分中,我们将使面板变得生动、交互性强且响应迅速。无论您是经验丰富的MQL5程序员还是初学者,本文都将提供逐步指导,帮助您创建一个功能强大且视觉效果出色的GUI面板。我们将通过以下主题来实现上述目标:

  1. 图例
  2. MQL5中的GUI面板组装
  3. 结论

在本文中,我们将广泛使用MetaQuotes Language 5(MQL5)作为我们的基础集成开发环境(IDE)编程环境,并在MetaTrader 5(MT5)交易平台上执行文件。因此,拥有上述版本至关重要。那么,让我们开始吧。


图例

我们将创建一个GUI面板,其中包含任何交易者可能需要的最常用的实用工具,因此我们希望在这一系列中概述并涵盖所有内容。因此,需要涵盖的元素数量众多,但我们会将它们整合在一起,以便更容易理解。我们的GUI开发将使用4个元素,并通过这些元素来创建它。该面板将包括交易按钮的创建、锐利的矩形框、实时更新功能、表情符号的使用、不同的字体样式、标签、可移动的面板部分以及悬停效果。为了阐述整体内容,我们在下面给出了一个示例。

GUI示例


MQL5中的GUI面板组装

为了创建面板,我们将以其EA作为基础。要在您的MetaTrader 5终端中创建EA,请点击“工具”选项卡并查看“MetaQuotes语言编辑器”,或者简单地按键盘上的F4键。另外,您也可以点击工具栏上的IDE(集成开发环境)图标。这样就会打开MetaQuotes语言编辑器环境,该环境允许用户编写自动交易、技术指标、脚本和函数库。

IDE

打开MetaEditor后,在工具栏上,点击“文件”选项卡,然后勾选“新建文件”,或者直接按CTRL + N键,以创建一个新文档。或者,您也可以点击工具栏选项卡上的“新建”图标。这将弹出一个MQL向导窗口。

新EA

在弹出的向导中,选中EA(模板),然后单击下一步。

WIZARD

在EA的一般属性中,在名称部分,提供您的文件名称。请注意,如果要指定或创建一个不存在的文件夹,您需要在EA名称前使用反斜杠。例如,这里我们默认有“Experts\”。这意味着我们的EA将被创建在Experts文件夹中,我们可以去那里找。其他部分相对直观,但您可以按照向导底部的链接了解如何精准地执行该过程。

EA名称

在输入您希望的EA文件名后,依次点击“下一步”、再“下一步”,然后点击“完成”。完成上述步骤后,我们现在就可以开始为我们的GUI面板编写代码和程序了。

首先,我们需要为所需的4个元素创建函数,即矩形标签、按钮、编辑字段和文本标签。这将非常有用,因为它将允许我们在创建类似功能时重复使用相同的函数,而无需在创建类似对象时重复整个过程。为了创建矩形标签,我们将创建一个函数,该函数需要10个参数或自变量。

为了创建矩形标签,我们将新建一个函数,该函数接受10个参数。

//+------------------------------------------------------------------+
//|     Function to create rectangle label                           |
//+------------------------------------------------------------------+

bool createRecLabel(string objName, int xD, int yD, int xS, int yS,
                    color clrBg, int widthBorder, color clrBorder = clrNONE,
                    ENUM_BORDER_TYPE borderType = BORDER_FLAT, ENUM_LINE_STYLE borderStyle = STYLE_SOLID) {

...
}

函数签名说明了一切。这是一个名为“createRecLabel”的布尔函数,意味着它将返回两个布尔标识(true或false),分别表示成功或失败。为了更容易理解其参数,我们下面逐一概述并解释它们。

  • objName: 此参数代表矩形标签对象的唯一名称。它作为将要创建的图形元素的标识符。
  • xD和yD:这些参数确定矩形标签相对于图表角落的X向和Y向距离。可以将它们视为定义矩形左上角图表相关的坐标。
  • xS和yS: 这些参数指定矩形的宽度和高度。xS值确定矩形在水平方向上的宽度,而yS控制其在垂直方向上的高度。

DISTANCE & SIZE

  • clrBg:clrBg参数代表矩形标签的背景颜色。请选择一种与图表背景形成良好对比或与其他元素相协调的颜色。
  • widthBorder:此参数定义了矩形周围边框的宽度。如果需要边框,请设置一个正值;否则,使用0表示无边框。
  • clrBorder:边框颜色的可选参数。如果需要边框,请指定一种颜色(例如,clrNONE表示无边框颜色)。
  • borderType:指定矩形的边框类型。选项包括平面、凸起或其他样式。对于简单的平面边框,请使用BORDER_FLAT。
  • borderStyle:如果选择平面边框,此参数决定了线条样式(例如,实线、虚线)。使用STYLE_SOLID表示连续线条。

在函数签名上,您可能注意到一些参数已经被初始化为某个值。这个初始化值代表了如果在函数调用时忽略该参数,则会赋给该参数的默认值。例如,我们的默认边框颜色是“none”,这意味着如果在函数调用时没有指定颜色值,则矩形标签的边框将不会应用任何颜色。 

在函数体内,由大括号({})包围的部分,我们定义了对象的创建过程。 

    // Create a rectangle label object
    if (!ObjectCreate(0, objName, OBJ_RECTANGLE_LABEL, 0, 0, 0)) {
        Print(__FUNCTION__, ": failed to create rec label! Error code = ", _LastError);
        return (false); // Return false if object creation fails
    }

我们从使用if语句开始,检查对象是否未被创建。ObjectCreate是一个布尔函数,接受6个参数。该函数用于在指定的图表子窗口中创建一个具有指定名称、类型和初始坐标的对象。首先,我们指定图表窗口,其中0表示将在主窗口中创建对象。然后,我们提供对象的名称。这是将唯一分配给特定对象的名称。我们要创建的对象类型是“OBJ_RECTANGLE_LABEL”,代表用于创建和设计自定义图形界面的对象。接下来,我们提供子窗口,其中0表示当前子窗口。最后,我们将时间和价格值都设置为0,因为我们不会将它们附加到图表上,而是附加到图表窗口的坐标上。使用像素来设置映射。

如果对象创建失败,最终“ObjectCreate”函数会返回false,显然继续执行下去没有意义,我们会报错并返回。在这种情况下,我们通过将错误信息及其代码打印到日志中来通知错误,并返回false。可能之前已经存在错误,因此为了获取最新的错误,我们需要在对象创建逻辑之前清除之前的错误。这可以通过调用内置的MQL5的“ResetLastError”函数来实现。 

    ResetLastError(); // Reset any previous error codes

该函数的目的是将预定义变量“_LastError”的值设置为0,该变量存储了上一次遇到错误的操作所产生的错误代码。通过调用这个函数,我们可以确保在进行下一步操作之前清除任何之前的错误代码。这一步至关重要,因为它使我们能够独立地处理新的错误,而不会受到之前错误状态的干扰。

如果我们没有返回到这里,这意味着我们已经创建了对象,因此我们可以继续更新对象的属性。一个内置函数“ObjectSet...”用于设置相应对象属性的值。对象属性必须是日期时间、整数、颜色、布尔值或字符类型。

    // Set properties for the rectangle label
    ObjectSetInteger(0, objName, OBJPROP_XDISTANCE, xD); // X distance from the corner
    ObjectSetInteger(0, objName, OBJPROP_YDISTANCE, yD); // Y distance from the corner
    ObjectSetInteger(0, objName, OBJPROP_XSIZE, xS); // Width of the rectangle
    ObjectSetInteger(0, objName, OBJPROP_YSIZE, yS); // Height of the rectangle
    ObjectSetInteger(0, objName, OBJPROP_CORNER, CORNER_LEFT_UPPER); // Positioning corner
    ObjectSetInteger(0, objName, OBJPROP_BGCOLOR, clrBg); // Rectangle background color
    ObjectSetInteger(0, objName, OBJPROP_BORDER_TYPE, borderType); // Border type
    ObjectSetInteger(0, objName, OBJPROP_STYLE, borderStyle); // Border style (only if borderType is flat)
    ObjectSetInteger(0, objName, OBJPROP_WIDTH, widthBorder); // Border width (only if borderType is flat)
    ObjectSetInteger(0, objName, OBJPROP_COLOR, clrBorder); // Border color (only if borderType is flat)
    ObjectSetInteger(0, objName, OBJPROP_BACK, false); // Not a background object
    ObjectSetInteger(0, objName, OBJPROP_STATE, false); // Not selectable
    ObjectSetInteger(0, objName, OBJPROP_SELECTABLE, false); // Not selectable
    ObjectSetInteger(0, objName, OBJPROP_SELECTED, false); // Not selected

让我们专注于第一属性逻辑。

    ObjectSetInteger(0, objName, OBJPROP_XDISTANCE, xD); // X distance from the corner

在此,我们使用内置的“ObjectSetInteger”函数,并分别传递参数。参数描述如下:

  • Chart id: 这是图表的标识符。“0”指的是当前图表(chart ID)。我们要调整此图表内对象的属性。
  • Name: 这是对象的名称。“objName”表示分配给矩形标签对象的唯一名称。
  • Property id: 这是对象属性ID,其值可以是“ENUM_OBJECT_PROPERTY_INTEGER”枚举中的一个值。“OBJPROP_XDISTANCE”指定我们正在修改的X距离属性。
  • Property value: 这是属性的值。分配给“xD”的值决定了矩形标签的左上角将从图表的左边缘水平向右(或向左,如果为负值)移动多远。

同样,我们使用相同的格式来设置其他属性。“OBJPROP_YDISTANCE”配置矩形标签的Y距离属性。“yD”值决定了矩形标签的左上角将从图表的顶部边缘垂直向下移动多远。换句话说,它控制着标签在图表区域内的垂直位置。这样就设置了从角落开始的Y距离。“OBJPROP_XSIZE”和“OBJPROP_YSIZE”分别设置矩形的宽度和高度。 

为了定位我们的对象,我们使用“OBJPROP_CORNER”属性来确定我们希望对象位于图表窗口的哪个角落。

    ObjectSetInteger(0, objName, OBJPROP_CORNER, CORNER_LEFT_UPPER); // Positioning corner

该属性只能包含4种类型:

  • CORNER_LEFT_UPPER: 坐标中心位于图表的左上角。
  • CORNER_LEFT_LOWER: 坐标中心位于图表的左下角。
  • CORNER_RIGHT_LOWER: 坐标中心位于图表的右下角。
  • CORNER_RIGHT_UPPER: 坐标中心位于图表的右上角。

图像显示的情况就是这样。

CORNERS

其余的属性都很直接明了。我们为它们添加了注释,以便更容易理解。然后,我们只需重新绘制图表,就能使更改自动生效,而无需等待价格报价或图表事件的变化。 

    ChartRedraw(0); // Redraw the chart

最后,我们返回true,表示对象属性的创建和更新都是成功的。

    return (true); // Return true if object creation and property settings are successful

负责在图表窗口上创建矩形对象的完整代码如下:

bool createRecLabel(string objName, int xD, int yD, int xS, int yS,
                    color clrBg, int widthBorder, color clrBorder = clrNONE,
                    ENUM_BORDER_TYPE borderType = BORDER_FLAT, ENUM_LINE_STYLE borderStyle = STYLE_SOLID) {
    ResetLastError(); // Reset any previous error codes
    
    // Create a rectangle label object
    if (!ObjectCreate(0, objName, OBJ_RECTANGLE_LABEL, 0, 0, 0)) {
        Print(__FUNCTION__, ": failed to create rec label! Error code = ", _LastError);
        return (false); // Return false if object creation fails
    }
    
    // Set properties for the rectangle label
    ObjectSetInteger(0, objName, OBJPROP_XDISTANCE, xD); // X distance from the corner
    ObjectSetInteger(0, objName, OBJPROP_YDISTANCE, yD); // Y distance from the corner
    ObjectSetInteger(0, objName, OBJPROP_XSIZE, xS); // Width of the rectangle
    ObjectSetInteger(0, objName, OBJPROP_YSIZE, yS); // Height of the rectangle
    ObjectSetInteger(0, objName, OBJPROP_CORNER, CORNER_LEFT_UPPER); // Positioning corner
    ObjectSetInteger(0, objName, OBJPROP_BGCOLOR, clrBg); // Rectangle background color
    ObjectSetInteger(0, objName, OBJPROP_BORDER_TYPE, borderType); // Border type
    ObjectSetInteger(0, objName, OBJPROP_STYLE, borderStyle); // Border style (only if borderType is flat)
    ObjectSetInteger(0, objName, OBJPROP_WIDTH, widthBorder); // Border width (only if borderType is flat)
    ObjectSetInteger(0, objName, OBJPROP_COLOR, clrBorder); // Border color (only if borderType is flat)
    ObjectSetInteger(0, objName, OBJPROP_BACK, false); // Not a background object
    ObjectSetInteger(0, objName, OBJPROP_STATE, false); // Not selectable
    ObjectSetInteger(0, objName, OBJPROP_SELECTABLE, false); // Not selectable
    ObjectSetInteger(0, objName, OBJPROP_SELECTED, false); // Not selected
    
    ChartRedraw(0); // Redraw the chart
    
    return (true); // Return true if object creation and property settings are successful
}

要创建一个按钮对象,也可使用相同的函数方法。创建自定义按钮功能的代码如下所示。

//+------------------------------------------------------------------+
//|     Function to create button                                    |
//+------------------------------------------------------------------+

bool createButton(string objName, int xD, int yD, int xS, int yS,
                  string txt = "", color clrTxt = clrBlack, int fontSize = 12,
                  color clrBg = clrNONE, color clrBorder = clrNONE,
                  string font = "Arial Rounded MT Bold") {
    // Reset any previous errors
    ResetLastError();

    // Attempt to create the button object
    if (!ObjectCreate(0, objName, OBJ_BUTTON, 0, 0, 0)) {
        // Print an error message if creation fails
        Print(__FUNCTION__, ": failed to create the button! Error code = ", _LastError);
        return (false);
    }

    // Set properties for the button
    ObjectSetInteger(0, objName, OBJPROP_XDISTANCE, xD); // X distance from the corner
    ObjectSetInteger(0, objName, OBJPROP_YDISTANCE, yD); // Y distance from the corner
    ObjectSetInteger(0, objName, OBJPROP_XSIZE, xS); // Width of the button
    ObjectSetInteger(0, objName, OBJPROP_YSIZE, yS); // Height of the button
    ObjectSetInteger(0, objName, OBJPROP_CORNER, CORNER_LEFT_UPPER); // Positioning corner
    ObjectSetString(0, objName, OBJPROP_TEXT, txt); // Text displayed on the button
    ObjectSetInteger(0, objName, OBJPROP_COLOR, clrTxt); // Text color
    ObjectSetInteger(0, objName, OBJPROP_FONTSIZE, fontSize); // Font size
    ObjectSetString(0, objName, OBJPROP_FONT, font); // Font name
    ObjectSetInteger(0, objName, OBJPROP_BGCOLOR, clrBg); // Background color
    ObjectSetInteger(0, objName, OBJPROP_BORDER_COLOR, clrBorder); // Border color
    ObjectSetInteger(0, objName, OBJPROP_BACK, false); // Transparent background
    ObjectSetInteger(0, objName, OBJPROP_STATE, false); // Button state (not pressed)
    ObjectSetInteger(0, objName, OBJPROP_SELECTABLE, false); // Not selectable
    ObjectSetInteger(0, objName, OBJPROP_SELECTED, false); // Not selected

    // Redraw the chart to display the button
    ChartRedraw(0);

    return (true); // Button creation successful
}

代码的区别在于,矩形对象不能包含文本,但按钮在需要时可以包含描述按钮功能的说明性文本。因此,对于输入参数,我们考虑了文本属性,在我们的实例里是文本值、颜色、字体大小和字体名称。我们按钮的边框类型是静态的,因此我们删除了其属性,只保留了边框颜色。 

我们创建的对象类型是“OBJ_BUTTON”,表示新建了一个按钮图形对象。它的锚点是以像素为单位设置的。我们保留的边框属性是边框颜色,并用文本输入属性替换其余属性。

在创建编辑框按钮时,使用相同的逻辑。 

//+------------------------------------------------------------------+
//|     Function to create edit field                                |
//+------------------------------------------------------------------+

bool createEdit(string objName, int xD, int yD, int xS, int yS,
                string txt = "", color clrTxt = clrBlack, int fontSize = 12,
                color clrBg = clrNONE, color clrBorder = clrNONE,
                string font = "Arial Rounded MT Bold") {
    // Reset any previous errors
    ResetLastError();

    // Attempt to create the edit object
    if (!ObjectCreate(0, objName, OBJ_EDIT, 0, 0, 0)) {
        // Print an error message if creation fails
        Print(__FUNCTION__, ": failed to create the edit! Error code = ", _LastError);
        return (false);
    }

    // Set properties for the edit field
    ObjectSetInteger(0, objName, OBJPROP_XDISTANCE, xD); // X distance from the corner
    ObjectSetInteger(0, objName, OBJPROP_YDISTANCE, yD); // Y distance from the corner
    ObjectSetInteger(0, objName, OBJPROP_XSIZE, xS); // Width of the edit field
    ObjectSetInteger(0, objName, OBJPROP_YSIZE, yS); // Height of the edit field
    ObjectSetInteger(0, objName, OBJPROP_CORNER, CORNER_LEFT_UPPER); // Positioning corner
    ObjectSetString(0, objName, OBJPROP_TEXT, txt); // Default text in the edit field
    ObjectSetInteger(0, objName, OBJPROP_COLOR, clrTxt); // Text color
    ObjectSetInteger(0, objName, OBJPROP_FONTSIZE, fontSize); // Font size
    ObjectSetString(0, objName, OBJPROP_FONT, font); // Font name
    ObjectSetInteger(0, objName, OBJPROP_BGCOLOR, clrBg); // Background color
    ObjectSetInteger(0, objName, OBJPROP_BORDER_COLOR, clrBorder); // Border color
    ObjectSetInteger(0, objName, OBJPROP_ALIGN, ALIGN_LEFT); // Text alignment (left-aligned)
    ObjectSetInteger(0, objName, OBJPROP_READONLY, false); // Edit field is not read-only
    ObjectSetInteger(0, objName, OBJPROP_BACK, false); // Transparent background
    ObjectSetInteger(0, objName, OBJPROP_STATE, false); // Edit field state (not active)
    ObjectSetInteger(0, objName, OBJPROP_SELECTABLE, false); // Not selectable
    ObjectSetInteger(0, objName, OBJPROP_SELECTED, false); // Not selected

    // Redraw the chart to display the edit field
    ChartRedraw(0);

    return (true); // Edit field creation successful
}

与创建一个按钮函数的代码相比,其主要区别在于对象类型。我们使用“OBJ_EDIT”来表示我们希望创建一个可编辑的按钮。之后,在字段属性中,我们添加了水平文本对齐属性,可以右对齐、左对齐或居中对齐。在我们的实例中,我们选择将文本水平左对齐。 

    ObjectSetInteger(0, objName, OBJPROP_ALIGN, ALIGN_LEFT); // Text alignment (left-aligned)

最终的差异在于一个属性,该属性能够启用对象中文本的编辑功能。为了启用编辑功能,我们将属性“OBJPROP_READONLY”的值设置为false。

    ObjectSetInteger(0, objName, OBJPROP_READONLY, false); // Edit field is not read-only

其余的参数保持不变。 

最后,我们需要最后一个元素的功能,即文本标签。文本标签省去了背景对象的需要,因此其实现比其他功能要简单得多。我们只需要文本,因此我们专注于文本属性。其代码如下:

//+------------------------------------------------------------------+
//|     Function to create text label                                |
//+------------------------------------------------------------------+

bool createLabel(string objName, int xD, int yD,
                 string txt, color clrTxt = clrBlack, int fontSize = 12,
                 string font = "Arial Rounded MT Bold") {
    // Reset any previous errors
    ResetLastError();

    // Attempt to create the label object
    if (!ObjectCreate(0, objName, OBJ_LABEL, 0, 0, 0)) {
        // Print an error message if creation fails
        Print(__FUNCTION__, ": failed to create the label! Error code = ", _LastError);
        return (false);
    }

    // Set properties for the label
    ObjectSetInteger(0, objName, OBJPROP_XDISTANCE, xD); // X distance from the corner
    ObjectSetInteger(0, objName, OBJPROP_YDISTANCE, yD); // Y distance from the corner
    ObjectSetInteger(0, objName, OBJPROP_CORNER, CORNER_LEFT_UPPER); // Positioning corner
    ObjectSetString(0, objName, OBJPROP_TEXT, txt); // Text displayed on the label
    ObjectSetInteger(0, objName, OBJPROP_COLOR, clrTxt); // Text color
    ObjectSetInteger(0, objName, OBJPROP_FONTSIZE, fontSize); // Font size
    ObjectSetString(0, objName, OBJPROP_FONT, font); // Font name
    ObjectSetInteger(0, objName, OBJPROP_BACK, false); // Transparent background
    ObjectSetInteger(0, objName, OBJPROP_STATE, false); // Label state (not active)
    ObjectSetInteger(0, objName, OBJPROP_SELECTABLE, false); // Not selectable
    ObjectSetInteger(0, objName, OBJPROP_SELECTED, false); // Not selected

    // Redraw the chart to display the label
    ChartRedraw(0);

    return (true); // Label creation successful
}

此代码结构与按钮功能的主要区别在于对象大小和边框属性。在函数签名上,我们移除了对象大小以及边框属性。我们将对象类型定义为“OBJ_LABEL”,这表明我们会根据定义的标签坐标在图表窗口中绘制标签。最后,我们移除了大小和边框参数。就是如此简单。 

既然我们有了创建图形用户界面(GUI)所需的函数,现在让我们使用它们来创建面板。我们需要为对象命名,并且为了更轻松地管理对象名称的交互,定义宏会更加方便。 

#define MAIN_REC "MAIN_REC"

我们使用 #define 关键字来定义一个名为 "MAIN_REC" 的宏,其值也为 "MAIN_REC",以便轻松存储我们的主矩形基础名称,而无需在创建每一级实例时反复键入该名称,从而大大节省了时间并减少了提供错误名称的可能性。因此,基本上宏在编译过程中被用于替换文本。

我们的代码将主要基于初始化部分,因为我们希望在初始化实例时创建面板。因此, OnInit事件处理程序将包含大部分代码结构。 

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+

int OnInit(){

   ...
   
   return(INIT_SUCCEEDED);
}

OnInit函数是一个事件处理程序,它在初始化实例时被调用,以执行必要的初始化操作(如果有需要时)。 

接下来,我们通过键入函数名并提供其参数来调用该函数,以创建一个矩形标签。

   createRecLabel(MAIN_REC,10,30,250,400,clrWhite,1,clrBlack);

此处,我们的矩形名称为“MAIN_REC”,这是从宏定义中获取的。从图表窗口左上角开始,我们在x轴(时间和日期刻度)上的距离是10像素,在y轴(价格刻度)上的距离是30像素。矩形的宽度为250像素,高度为400像素。我们选择背景颜色为白色,边框宽度为1,边框颜色为黑色。要大致获取像素范围,您可以将图表缩小到0,此时两个十字光标坐标之间的柱形图数量等于水平刻度上的像素数。下面举例说明。

CROSS-HAIR

在省略其他参数的情况下,将自动应用默认值,即边框类型为平面,线条样式为连续的实线。编译后,我们目前得到如下结果。

PANEL1

即使我们有如下默认值的所有参数,结果也总是相同。

   createRecLabel(MAIN_REC,10,30,250,400,clrWhite,1,clrBlack,BORDER_FLAT,STYLE_SOLID);

为了创建一个子框架,我们再次为它声明一个宏。

#define MAIN_SUB_REC "MAIN_SUB_REC"

然后我们调用相同的函数来创建子框架。我们希望我们的框架位于基础面板的框架内部,因此需要使用稍微不同的颜色。为了实现这一点,我们使用了浅蓝色,并设置了5像素的边距。

   createRecLabel(MAIN_SUB_REC,15,35,240,390,clrLightBlue,1,clrNONE);

由于我们希望有5像素的边距,因此我们在左侧和顶部各留出5像素的空间。因此,x轴上的距离将是初始的10像素加上5像素的边距,总共等于15像素。y轴上也采用同样的处理方式。这意味着尺寸也需要减少5像素,但等等,我们还需要在面板的右侧留出5像素的边距。因此,两侧各需要减少5像素,总共需要减少10像素。所以,所需的总像素数为5乘以2,即10像素。因此,在子矩形的尺寸上减少10像素后,子框架矩形的宽度为250 - 10 = 240像素,高度为400 - 10 = 390像素。以下是我们得到的结果:

PANEL2

淡蓝色对人眼来说不够明显,所以我们选择了更深一些的颜色。为了更精确地控制所使用的颜色,我们用字体来表示背景颜色。我们将采用“C'000,000,000'”的格式,其中的三组零可以是0到255之间的任何数字。所采用的格式是RGB(红、绿、蓝)格式。这三个值分别代表红色、绿色和蓝色成分,它们的取值范围都是从0到255。因此,245,245,245代表的是接近白色的色调。 

   createRecLabel(MAIN_SUB_REC,15,35,240,390,C'245,245,245',1,clrNONE);

我们将边框颜色设置为无,以创造出更具吸引力的颜色融合效果。建议每次添加新的GUI元素后,都重新编译程序并检查结果。以下是我们得到的结果:

PANEL3

为了创建垂直和水平边界线,我们定义了两个以上的宏。

#define MAIN_LINE_UP "MAIN_LINE_UP"
#define MAIN_LINE_DN "MAIN_LINE_DN"

虽然使用了相同的结构,但是这次我们采用的是凸起的边框类型。因此,这样会忽略边框颜色,从而产生边界错觉。

   createRecLabel(MAIN_LINE_UP,15,35,240,1,C'245,245,245',1,clrNONE,BORDER_RAISED);
   createRecLabel(MAIN_LINE_DN,15,35-1,1,390+1,C'245,245,245',1,clrNONE,BORDER_RAISED);

以下是我们得到的结果:

PANEL4

到目前为止,我们GUI面板的框架、边距和边界的已经设置完成。接下来,我们将添加面板的其他实用功能,如响应式按钮、标题、编辑字段和标签,以及它们的属性和效果。 

首先,我们给面板添加一个标题: 

#define LABEL_NAME "LABEL_NAME"
...
   createLabel(LABEL_NAME,25,35,"DashBoard v1.0",clrBlue,14,"Cooper Black");

第一步,我们为标题名称定义一个宏,并通过键入其名称来调用负责创建标签的函数。之后,我们分别设定x轴和y轴的距离为25像素和35像素。我们选择的输入文本是“DashBoard v1.0”,表示面板的类型和版本号为第一版。同时,我们将文本颜色设置为蓝色,字体大小为14,字体类型为“Cooper Black”。至于字体类型,其名称不区分大小写。也就是说无论是大写、小写还是大小写混合,都没有影响。它可以是“cooper black”或“COOPER BLACK”等。重要的是你需要提供正确的字体名称。编译后,我们得到如下结果:

PANEL5 TITLE

您可能已经注意到字体类型是可以更改的。让我们锦上添花,看看效果如何。有些字体确实包含图标和表情符号。现在,MQL5确实接受并融入了一些这样的字体。例如“Webdings”、“Wingdings”、“Wingdings 2”和“Wingdings 3”。还有很多其他字体,但我们选择使用前面提到的那些。这意味着我们可以使用这些图标和表情符号字体来让面板看起来更加美观。具体如下:

FONTS

我们在面板名称前添加了三个图标:一个心形图标、一个工具修理图标和一个救护车图标。当然,您可以根据自己的喜好来选择这些图标。这需要我们再次定义三个宏来保存我们的图标名称,在创建图标后使用。逻辑说明如下:

#define ICON_HEART "ICON_HEART"
#define ICON_TOOL "ICON_TOOL"
#define ICON_CAR "ICON_CAR"

...
   createLabel(ICON_HEART,190,35,"Y",clrRed,15,"Webdings");

使用相同的功能,包括坐标轴距离、颜色和字体大小。但是,您能注意到我们的字体名称现在已更改为“Webdings”,并且文本值为大写字母“Y”。这并不意味着我们将显示“Y”作为我们的输出。我们显示的是与该特定字符相对应的图标。至于字体,该字符的图标如下,即心形图标。

HEART ICON

文本的值是区分大小写的,您可以看出,小写字母“y”对应的图标与大写字母“Y”对应的图标是不同的。编译后,我们得到的就是这样的结果: 

PANEL6

现在可以使用与前一个图标相同的方式添加另外两个图标。

   createLabel(ICON_TOOL,210,35,"@",clrBlue,15,"Webdings");
   createLabel(ICON_CAR,230,35,"h",clrBlack,15,"Webdings");

然后使用相同的实现将其他实用程序对象添加到图表中。逻辑说明如下:

#define LINE1 "LINE1"
#define BTN_CLOSE "BTN_CLOSE"
#define BTN_MARKET "BTN_MARKET"
#define BTN_PROFIT "BTN_PROFIT"
#define BTN_LOSS "BTN_LOSS"
#define BTN_PENDING "BTN_PENDING"
#define LINE2 "LINE2"

...

   createRecLabel(LINE1,15+10,60,240-10,1,C'245,245,245',1,clrNONE,BORDER_RAISED);
   createLabel(BTN_CLOSE,25,65,"Close",clrBlack,13,"Impact");
   createLabel(BTN_MARKET,70,65,"Market",clrDarkRed,13,"Impact");
   createLabel(BTN_PROFIT,125,65,"Profit",clrGreen,13,"Impact");
   createLabel(BTN_LOSS,170,65,"Loss",clrRed,13,"Impact");
   createLabel(BTN_PENDING,205,65,"Pend'n",clrDarkGray,13,"Impact");
   createRecLabel(LINE2,15+10,87,240-10,1,C'245,245,245',1,clrNONE,BORDER_RAISED);
  

我们定义了对象宏名称,并调用相应的自定义函数来创建这些对象。创建两个垂直边界线的实例,它们将标签实用按钮夹在中间。这些标签分别是“关闭”、“市场”、“盈利”、“亏损”和“待处理”,其中“待处理”被简写为“Pend'n”,以适应框架边界内的文字显示。这些标签的用途分别是关闭所有市场和待处理订单、仅关闭市场订单、仅关闭盈利仓位、仅关闭亏损仓位以及删除待处理订单。编译完成后,我们得到如下结果:

PANEL7

到目前为止,我们已经成功创建了面板的上部区域。接下来,我们将开始创建按钮实用工具。首先,让我们专注于交易量按钮。我们的按钮将包含一个标签和一个下拉箭头。

#define BTN_LOTS "BTN_LOTS"
#define LABEL_LOTS "LABEL_LOTS"
#define ICON_DROP_DN1 "ICON_DROP_DN1"

宏定义已经完成。之后,我们通过调用按钮函数来创建一个按钮。

   createButton(BTN_LOTS,25,95,130,25,"",clrBlack,12,C'210,210,210',C'150,150,150');

我们再次为按钮提供了x和y坐标,按钮的大小为130像素宽和25像素高。至于文本,我们原本可以提供一个值,但选择不这样做,因为我们想要控制文本的位置,因此将其留空或设为null。最后,我们使用文字颜色表示法来设置按钮的背景色和边框色。由于我们选择省略了默认的按钮标签,因此我们创建了一个新的文本标签,该标签将位于按钮附近,通过以下函数实现:

   createLabel(LABEL_LOTS,25+10,95+5,"LotSize",clrBlack,9);

现在您已经熟悉了这个函数,并且知道了传递的参数。对于下拉图标,我们使用了一种提供图标的字体类型。

   createLabel(ICON_DROP_DN1,130,95+5,CharToString(240),C'070,070,070',20,"Wingdings 3");

你可以注意到,在文本参数上,我们将字符转换为字符串,这是提供相应字符代码而非字符串的另一种方式,如果您已经知道符号代码,将很有帮助。在创建编辑字段按钮时,也采用了相同的步骤。 

#define EDIT_LOTS "EDIT_LOTS"
#define BTN_P1 "BTN_P1"
#define BTN_M1 "BTN_M1"

...

   createEdit(EDIT_LOTS,165,95,60,25,"0.01",clrBlack,14,clrWhite,C'100,100,100',"Callibri");
   createButton(BTN_P1,225,95,20,12,"5",clrBlack,12,clrLightGray,C'100,100,100',"Webdings");
   createButton(BTN_M1,225,95+12,20,12,"6",clrBlack,12,clrLightGray,C'100,100,100',"Webdings");


我们像之前一样定义宏名称并调用函数。在创建编辑按钮时,我们使用了60像素的宽度和25像素的高度作为尺寸。默认文本设置为0.01,文本颜色为黑色,字体大小为14,字体类型为“Calibri”。按钮背景设置为白色,边框颜色为接近黑色的深色。对于交易量增减的按钮,我们使用了“Webdings”字体类型,并分别将文本值设置为“5”和“6”。编译完成后,我们到达了如下里程碑:

PANEL8

目前已经取得了不错的进展。要创建其他的止损和止盈按钮工具,可以通过以下代码使用相同的逻辑来实现。 

#define BTN_SL "BTN_SL"
#define LABEL_SL "LABEL_SL"
#define ICON_DROP_DN2 "ICON_DROP_DN2"
#define EDIT_SL "EDIT_SL"
#define BTN_P2 "BTN_P2"
#define BTN_M2 "BTN_M2"

#define BTN_TP "BTN_TP"
#define LABEL_TP "LABEL_TP"
#define ICON_DROP_DN3 "ICON_DROP_DN3"
#define EDIT_TP "EDIT_TP"
#define BTN_P3 "BTN_P3"
#define BTN_M3 "BTN_M3"

...

   createButton(BTN_SL,25,95+30,130,25,"",clrBlack,12,C'210,210,210',C'150,150,150');
   createLabel(LABEL_SL,35,95+30,"SL Pips",clrBlack,14);
   createLabel(ICON_DROP_DN2,130,100+30,CharToString(240),C'070,070,070',20,"Wingdings 3");
   createEdit(EDIT_SL,165,95+30,60,25,"100.0",clrBlack,13,clrWhite,C'100,100,100',"Callibri");
   createButton(BTN_P2,225,95+30,20,12,"5",clrBlack,12,clrLightGray,C'100,100,100',"Webdings");
   createButton(BTN_M2,225,107+30,20,12,"6",clrBlack,12,clrLightGray,C'100,100,100',"Webdings");

   createButton(BTN_TP,25,95+30+30,130,25,"",clrBlack,12,C'210,210,210',C'150,150,150');
   createLabel(LABEL_TP,35,95+30+30,"TP Pips",clrBlack,14);
   createLabel(ICON_DROP_DN3,130,100+30+30,CharToString(240),C'070,070,070',20,"Wingdings 3");
   createEdit(EDIT_TP,165,95+30+30,60,25,"100.0",clrBlack,13,clrWhite,C'100,100,100',"Callibri");
   createButton(BTN_P3,225,95+30+30,20,12,"5",clrBlack,12,clrLightGray,C'100,100,100',"Webdings");
   createButton(BTN_M3,225,107+30+30,20,12,"6",clrBlack,12,clrLightGray,C'100,100,100',"Webdings");
   

定义实用宏,并调用相应的函数来创建。此段代码的逻辑与我们之前用来创建交易量按钮的代码没有区别。编译完成后,您应该会得到如下结果:

PANEL 9

#define BTN_BUY "BTN_BUY"
#define LABEL_BUY "LABEL_BUY"
#define LABEL_BUY_PRICE "LABEL_BUY_PRICE"
#define BTN_OVERLAY "BTN_OVERLAY"
#define BTN_SPREAD "BTN_SPREAD"

#define BTN_SELL "BTN_SELL"
#define LABEL_SELL "LABEL_SELL"
#define LABEL_SELL_PRICE "LABEL_SELL_PRICE"

#define BTN_CONTACT "BTN_CONTACT"

...

   
   createRecLabel(BTN_SELL,25,335,105,60,clrRed,1,clrNONE);
   createLabel(LABEL_SELL,35,335,"Sell",clrWhite,15,"ARIAL black");
   createLabel(LABEL_SELL_PRICE,35,335+30,DoubleToString(Bid(),_Digits),clrWhite,13,"ARIAL black");
   createRecLabel(BTN_BUY,140,335,105,60,clrGreen,1,clrNONE);
   createLabel(LABEL_BUY,150+35,335,"Buy",clrWhite,15,"ARIAL black");
   createLabel(LABEL_BUY_PRICE,150,335+30,DoubleToString(Ask(),_Digits),clrWhite,13,"ARIAL black");
   createRecLabel(BTN_OVERLAY,90,335,90,25,C'245,245,245',0,clrNONE);
   createButton(BTN_SPREAD,95,335,80,20,(string)Spread(),clrBlack,13,clrWhite,clrBlack);
   createButton(BTN_CONTACT,25,335+62,230-10,25,"https://t.me/Forex_Algo_Trader",clrBlack,10,clrNONE,clrBlack);
   

为了实现购买、出售、叠加、额外信息以及价差按钮的创建,请使用上述代码。唯一修改的是出售和购买价格以及价差值的文本显示。调用额外的自定义函数Bid(卖出价)、Ask(买入价)和Spread(价差)来填充这些值。bid和ask函数返回的是double类型的数据值,因此,为了将double类型转换为字符串,我们调用了内置的“DoubleToString”函数。对于spread,我们直接将整数值类型转换为字符串。这些自定义函数如下所示:

double Ask(){return(NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK),_Digits));}
double Bid(){return(NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID),_Digits));}
int Spread(){return((int)SymbolInfoInteger(_Symbol,SYMBOL_SPREAD));}

这些函数返回不同交易品种信息对应的数据类型。编译完成后,我们得到如下结果:

PANEL10

现在,我们将新建一些附加的按钮,用于演示如何创建一个具有锐利边缘的按钮,并复制该按钮以用于自动悬停效果。

#define BTN_SHARP "BTN_SHARP"
#define LABEL_SHARP "LABEL_SHARP"
#define BTN_HOVER "BTN_HOVER"
#define LABEL_HOVER "LABEL_HOVER"

...

   createRecLabel(BTN_SHARP,25,190,220,35,C'220,220,220',2,C'100,100,100');
   createLabel(LABEL_SHARP,25+20,190+5,"Sharp Edged Button",clrBlack,12,"ARIAL black");
   //createRecLabel(BTN_HOVER,25,230,220,35,C'220,220,220',3,C'050,050,255');
   createRecLabel(BTN_HOVER,25,230,220,35,C'220,220,220',3,C'100,100,100');
   createLabel(LABEL_HOVER,25+50,230+5,"Hover Effect",clrBlack,12,"ARIAL black");

里程碑如下:

PANEL11

还有一些多余的空间可以用于其他实用程序,但让我们用一些表情符号和图标字符来填充。

#define LABEL_EXTRA1 "LABEL_EXTRA1"
#define LABEL_EXTRA2 "LABEL_EXTRA2"
#define LABEL_EXTRA3 "LABEL_EXTRA3"
#define LABEL_EXTRA4 "LABEL_EXTRA4"

...

   createLabel(LABEL_EXTRA1,25,290,"_",clrBlack,25,"WEBDINGS");
   createLabel(LABEL_EXTRA2,25+40,290,"J",clrBlack,25,"WINGDINGS");
   createLabel(LABEL_EXTRA3,25+40+40,290,"{",clrBlack,25,"WINGDINGS 2");
   createLabel(LABEL_EXTRA4,25+40+40+40,290,"G",clrBlack,25,"WINGDINGS 3");

一旦点击了交易量按钮,我们希望有一些实例来创建一个下拉菜单,从中可以选择不同的选项。我们需要有3个选项,以及一个图标,以便可以将列表从初始创建点拖到其他位置。这里使用相同的逻辑。

#define BTN_DROP_DN "BTN_DROP_DN"
#define LABEL_OPT1 "LABEL_OPT1"
#define LABEL_OPT2 "LABEL_OPT2"
#define LABEL_OPT3 "LABEL_OPT3"
#define ICON_DRAG "ICON_DRAG"

...

void createDropDown(){
   createRecLabel(BTN_DROP_DN,25,95+25,130,70,clrWhite,2,clrBlack);
   createLabel(LABEL_OPT1,25+10,95+25,"LotSize",clrBlack,12,"stencil");
   createLabel(LABEL_OPT2,25+10,95+25+20,"Risk Percent %",clrBlack,12,"calibri Italic");
   createLabel(LABEL_OPT3,25+10,95+25+20+20,"Money Balance",clrBlack,12,"Arial bold");
   createLabel(ICON_DRAG,25+10+95,95+25,"d",clrRoyalBlue,15,"webdings");
}

此处,我们在一个自定义函数中创建按钮和标签,以便在点击交易量时调用该函数。然而,为了显示出位置,我们先调用该函数,但稍后会在代码中注释掉。

   createDropDown();

最终的里程碑如下:

PANEL12. FINAL PART1

最后,我们需要从图表中移除EA时销毁并删除已创建的对象。为了实现这一点,我们创建了另一个函数来删除已创建的对象。

void destroyPanel(){
   ObjectDelete(0,MAIN_REC);
   ObjectDelete(0,MAIN_SUB_REC);
   ObjectDelete(0,MAIN_LINE_UP);
   
   //... other objects
   
   ChartRedraw(0);
}

用一个无返回值的自定义函数表示它不返回任何内容。该函数使用内置函数“ObjectDelete”来删除传递的相应对象。“ObjectDelete”函数需要两个参数:图表ID(当前图表为0)和要删除的对象名称。其在EA的反初始化函数中被调用。

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason){
//---
   destroyPanel();
}

以下是负责在MetaTrader 5(MT5)的MQL5中创建如图所示的GUI面板的完整源代码。

//+------------------------------------------------------------------+
//|                                             DASHBOARD PART 1.mq5 |
//|                                  Copyright 2024, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"

//--- DEFINE MACRO PROPERTIES

#define MAIN_REC "MAIN_REC"
#define MAIN_SUB_REC "MAIN_SUB_REC"
#define MAIN_LINE_UP "MAIN_LINE_UP"
#define MAIN_LINE_DN "MAIN_LINE_DN"
#define LABEL_NAME "LABEL_NAME"
#define ICON_HEART "ICON_HEART"
#define ICON_TOOL "ICON_TOOL"
#define ICON_CAR "ICON_CAR"
#define LINE1 "LINE1"
#define BTN_CLOSE "BTN_CLOSE"
#define BTN_MARKET "BTN_MARKET"
#define BTN_PROFIT "BTN_PROFIT"
#define BTN_LOSS "BTN_LOSS"
#define BTN_PENDING "BTN_PENDING"
#define LINE2 "LINE2"

#define BTN_LOTS "BTN_LOTS"
#define LABEL_LOTS "LABEL_LOTS"
#define ICON_DROP_DN1 "ICON_DROP_DN1"
#define EDIT_LOTS "EDIT_LOTS"
#define BTN_P1 "BTN_P1"
#define BTN_M1 "BTN_M1"

#define BTN_SL "BTN_SL"
#define LABEL_SL "LABEL_SL"
#define ICON_DROP_DN2 "ICON_DROP_DN2"
#define EDIT_SL "EDIT_SL"
#define BTN_P2 "BTN_P2"
#define BTN_M2 "BTN_M2"

#define BTN_TP "BTN_TP"
#define LABEL_TP "LABEL_TP"
#define ICON_DROP_DN3 "ICON_DROP_DN3"
#define EDIT_TP "EDIT_TP"
#define BTN_P3 "BTN_P3"
#define BTN_M3 "BTN_M3"

#define BTN_BUY "BTN_BUY"
#define LABEL_BUY "LABEL_BUY"
#define LABEL_BUY_PRICE "LABEL_BUY_PRICE"
#define BTN_OVERLAY "BTN_OVERLAY"
#define BTN_SPREAD "BTN_SPREAD"

#define BTN_SELL "BTN_SELL"
#define LABEL_SELL "LABEL_SELL"
#define LABEL_SELL_PRICE "LABEL_SELL_PRICE"

#define BTN_CONTACT "BTN_CONTACT"

#define BTN_SHARP "BTN_SHARP"
#define LABEL_SHARP "LABEL_SHARP"
#define BTN_HOVER "BTN_HOVER"
#define LABEL_HOVER "LABEL_HOVER"

#define LABEL_EXTRA1 "LABEL_EXTRA1"
#define LABEL_EXTRA2 "LABEL_EXTRA2"
#define LABEL_EXTRA3 "LABEL_EXTRA3"
#define LABEL_EXTRA4 "LABEL_EXTRA4"

#define BTN_DROP_DN "BTN_DROP_DN"
#define LABEL_OPT1 "LABEL_OPT1"
#define LABEL_OPT2 "LABEL_OPT2"
#define LABEL_OPT3 "LABEL_OPT3"
#define ICON_DRAG "ICON_DRAG"

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+

int OnInit(){

   createRecLabel(MAIN_REC,10,30,250,400,clrWhite,1,clrBlack);
   createRecLabel(MAIN_SUB_REC,15,35,240,390,C'245,245,245',1,clrNONE);
   createRecLabel(MAIN_LINE_UP,15,35,240,1,C'245,245,245',1,clrNONE,BORDER_RAISED);
   createRecLabel(MAIN_LINE_DN,15,35-1,1,390+1,C'245,245,245',1,clrNONE,BORDER_RAISED);

   createLabel(LABEL_NAME,25,35,"DashBoard v1.0",clrBlue,14,"Cooper Black");
   
   createLabel(ICON_HEART,190,35,"Y",clrRed,15,"Webdings");
   createLabel(ICON_TOOL,210,35,"@",clrBlue,15,"Webdings");
   createLabel(ICON_CAR,230,35,"h",clrBlack,15,"Webdings");
   createRecLabel(LINE1,15+10,60,240-10,1,C'245,245,245',1,clrNONE,BORDER_RAISED);
   createLabel(BTN_CLOSE,25,65,"Close",clrBlack,13,"Impact");
   createLabel(BTN_MARKET,70,65,"Market",clrDarkRed,13,"Impact");
   createLabel(BTN_PROFIT,125,65,"Profit",clrGreen,13,"Impact");
   createLabel(BTN_LOSS,170,65,"Loss",clrRed,13,"Impact");
   createLabel(BTN_PENDING,205,65,"Pend'n",clrDarkGray,13,"Impact");
   createRecLabel(LINE2,15+10,87,240-10,1,C'245,245,245',1,clrNONE,BORDER_RAISED);
   
   createButton(BTN_LOTS,25,95,130,25,"",clrBlack,12,C'210,210,210',C'150,150,150');
   createLabel(LABEL_LOTS,25+10,95+5,"LotSize",clrBlack,9);
   //createLabel(ICON_DROP_DN1,150,75,CharToString(100),clrBlack,12,"Wingdings");
   createLabel(ICON_DROP_DN1,130,95+5,CharToString(240),C'070,070,070',20,"Wingdings 3");
   createEdit(EDIT_LOTS,165,95,60,25,"0.01",clrBlack,14,clrWhite,C'100,100,100',"Callibri");
   createButton(BTN_P1,225,95,20,12,"5",clrBlack,12,clrLightGray,C'100,100,100',"Webdings");
   createButton(BTN_M1,225,95+12,20,12,"6",clrBlack,12,clrLightGray,C'100,100,100',"Webdings");

   createButton(BTN_SL,25,95+30,130,25,"",clrBlack,12,C'210,210,210',C'150,150,150');
   createLabel(LABEL_SL,35,95+30,"SL Pips",clrBlack,14);
   createLabel(ICON_DROP_DN2,130,100+30,CharToString(240),C'070,070,070',20,"Wingdings 3");
   createEdit(EDIT_SL,165,95+30,60,25,"100.0",clrBlack,13,clrWhite,C'100,100,100',"Callibri");
   createButton(BTN_P2,225,95+30,20,12,"5",clrBlack,12,clrLightGray,C'100,100,100',"Webdings");
   createButton(BTN_M2,225,107+30,20,12,"6",clrBlack,12,clrLightGray,C'100,100,100',"Webdings");

   createButton(BTN_TP,25,95+30+30,130,25,"",clrBlack,12,C'210,210,210',C'150,150,150');
   createLabel(LABEL_TP,35,95+30+30,"TP Pips",clrBlack,14);
   createLabel(ICON_DROP_DN3,130,100+30+30,CharToString(240),C'070,070,070',20,"Wingdings 3");
   createEdit(EDIT_TP,165,95+30+30,60,25,"100.0",clrBlack,13,clrWhite,C'100,100,100',"Callibri");
   createButton(BTN_P3,225,95+30+30,20,12,"5",clrBlack,12,clrLightGray,C'100,100,100',"Webdings");
   createButton(BTN_M3,225,107+30+30,20,12,"6",clrBlack,12,clrLightGray,C'100,100,100',"Webdings");
   
   createRecLabel(BTN_SELL,25,335,105,60,clrRed,1,clrNONE);
   createLabel(LABEL_SELL,35,335,"Sell",clrWhite,15,"ARIAL black");
   createLabel(LABEL_SELL_PRICE,35,335+30,DoubleToString(Bid(),_Digits),clrWhite,13,"ARIAL black");
   createRecLabel(BTN_BUY,140,335,105,60,clrGreen,1,clrNONE);
   createLabel(LABEL_BUY,150+35,335,"Buy",clrWhite,15,"ARIAL black");
   createLabel(LABEL_BUY_PRICE,150,335+30,DoubleToString(Ask(),_Digits),clrWhite,13,"ARIAL black");
   createRecLabel(BTN_OVERLAY,90,335,90,25,C'245,245,245',0,clrNONE);
   createButton(BTN_SPREAD,95,335,80,20,(string)Spread(),clrBlack,13,clrWhite,clrBlack);
   createButton(BTN_CONTACT,25,335+62,230-10,25,"https://t.me/Forex_Algo_Trader",clrBlack,10,clrNONE,clrBlack);
   
   createRecLabel(BTN_SHARP,25,190,220,35,C'220,220,220',2,C'100,100,100');
   createLabel(LABEL_SHARP,25+20,190+5,"Sharp Edged Button",clrBlack,12,"ARIAL black");
   //createRecLabel(BTN_HOVER,25,230,220,35,C'220,220,220',3,C'050,050,255');
   createRecLabel(BTN_HOVER,25,230,220,35,C'220,220,220',3,C'100,100,100');
   createLabel(LABEL_HOVER,25+50,230+5,"Hover Effect",clrBlack,12,"ARIAL black");

   createLabel(LABEL_EXTRA1,25,290,"_",clrBlack,25,"WEBDINGS");
   createLabel(LABEL_EXTRA2,25+40,290,"J",clrBlack,25,"WINGDINGS");
   createLabel(LABEL_EXTRA3,25+40+40,290,"{",clrBlack,25,"WINGDINGS 2");
   createLabel(LABEL_EXTRA4,25+40+40+40,290,"G",clrBlack,25,"WINGDINGS 3");
   
   // createDropDown();
   
   return(INIT_SUCCEEDED);
}

double Ask(){return(NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK),_Digits));}
double Bid(){return(NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID),_Digits));}
int Spread(){return((int)SymbolInfoInteger(_Symbol,SYMBOL_SPREAD));}

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason){
//---
   destroyPanel();
}
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick(){

}
//+------------------------------------------------------------------+


//+------------------------------------------------------------------+
//|     Function to create rectangle label                           |
//+------------------------------------------------------------------+

bool createRecLabel(string objName, int xD, int yD, int xS, int yS,
                    color clrBg, int widthBorder, color clrBorder = clrNONE,
                    ENUM_BORDER_TYPE borderType = BORDER_FLAT, ENUM_LINE_STYLE borderStyle = STYLE_SOLID) {
    ResetLastError(); // Reset any previous error codes
    
    // Create a rectangle label object
    if (!ObjectCreate(0, objName, OBJ_RECTANGLE_LABEL, 0, 0, 0)) {
        Print(__FUNCTION__, ": failed to create rec label! Error code = ", _LastError);
        return (false); // Return false if object creation fails
    }
    
    // Set properties for the rectangle label
    ObjectSetInteger(0, objName, OBJPROP_XDISTANCE, xD); // X distance from the corner
    ObjectSetInteger(0, objName, OBJPROP_YDISTANCE, yD); // Y distance from the corner
    ObjectSetInteger(0, objName, OBJPROP_XSIZE, xS); // Width of the rectangle
    ObjectSetInteger(0, objName, OBJPROP_YSIZE, yS); // Height of the rectangle
    ObjectSetInteger(0, objName, OBJPROP_CORNER, CORNER_LEFT_UPPER); // Positioning corner
    ObjectSetInteger(0, objName, OBJPROP_BGCOLOR, clrBg); // Rectangle background color
    ObjectSetInteger(0, objName, OBJPROP_BORDER_TYPE, borderType); // Border type
    ObjectSetInteger(0, objName, OBJPROP_STYLE, borderStyle); // Border style (only if borderType is flat)
    ObjectSetInteger(0, objName, OBJPROP_WIDTH, widthBorder); // Border width (only if borderType is flat)
    ObjectSetInteger(0, objName, OBJPROP_COLOR, clrBorder); // Border color (only if borderType is flat)
    ObjectSetInteger(0, objName, OBJPROP_BACK, false); // Not a background object
    ObjectSetInteger(0, objName, OBJPROP_STATE, false); // Not selectable
    ObjectSetInteger(0, objName, OBJPROP_SELECTABLE, false); // Not selectable
    ObjectSetInteger(0, objName, OBJPROP_SELECTED, false); // Not selected
    
    ChartRedraw(0); // Redraw the chart
    
    return (true); // Return true if object creation and property settings are successful
}

//+------------------------------------------------------------------+
//|     Function to create button                                    |
//+------------------------------------------------------------------+

bool createButton(string objName, int xD, int yD, int xS, int yS,
                  string txt = "", color clrTxt = clrBlack, int fontSize = 12,
                  color clrBg = clrNONE, color clrBorder = clrNONE,
                  string font = "Arial Rounded MT Bold") {
    // Reset any previous errors
    ResetLastError();

    // Attempt to create the button object
    if (!ObjectCreate(0, objName, OBJ_BUTTON, 0, 0, 0)) {
        // Print an error message if creation fails
        Print(__FUNCTION__, ": failed to create the button! Error code = ", _LastError);
        return (false);
    }

    // Set properties for the button
    ObjectSetInteger(0, objName, OBJPROP_XDISTANCE, xD); // X distance from the corner
    ObjectSetInteger(0, objName, OBJPROP_YDISTANCE, yD); // Y distance from the corner
    ObjectSetInteger(0, objName, OBJPROP_XSIZE, xS); // Width of the button
    ObjectSetInteger(0, objName, OBJPROP_YSIZE, yS); // Height of the button
    ObjectSetInteger(0, objName, OBJPROP_CORNER, CORNER_LEFT_UPPER); // Positioning corner
    ObjectSetString(0, objName, OBJPROP_TEXT, txt); // Text displayed on the button
    ObjectSetInteger(0, objName, OBJPROP_COLOR, clrTxt); // Text color
    ObjectSetInteger(0, objName, OBJPROP_FONTSIZE, fontSize); // Font size
    ObjectSetString(0, objName, OBJPROP_FONT, font); // Font name
    ObjectSetInteger(0, objName, OBJPROP_BGCOLOR, clrBg); // Background color
    ObjectSetInteger(0, objName, OBJPROP_BORDER_COLOR, clrBorder); // Border color
    ObjectSetInteger(0, objName, OBJPROP_BACK, false); // Transparent background
    ObjectSetInteger(0, objName, OBJPROP_STATE, false); // Button state (not pressed)
    ObjectSetInteger(0, objName, OBJPROP_SELECTABLE, false); // Not selectable
    ObjectSetInteger(0, objName, OBJPROP_SELECTED, false); // Not selected

    // Redraw the chart to display the button
    ChartRedraw(0);

    return (true); // Button creation successful
}

//+------------------------------------------------------------------+
//|     Function to create edit field                                |
//+------------------------------------------------------------------+

bool createEdit(string objName, int xD, int yD, int xS, int yS,
                string txt = "", color clrTxt = clrBlack, int fontSize = 12,
                color clrBg = clrNONE, color clrBorder = clrNONE,
                string font = "Arial Rounded MT Bold") {
    // Reset any previous errors
    ResetLastError();

    // Attempt to create the edit object
    if (!ObjectCreate(0, objName, OBJ_EDIT, 0, 0, 0)) {
        // Print an error message if creation fails
        Print(__FUNCTION__, ": failed to create the edit! Error code = ", _LastError);
        return (false);
    }

    // Set properties for the edit field
    ObjectSetInteger(0, objName, OBJPROP_XDISTANCE, xD); // X distance from the corner
    ObjectSetInteger(0, objName, OBJPROP_YDISTANCE, yD); // Y distance from the corner
    ObjectSetInteger(0, objName, OBJPROP_XSIZE, xS); // Width of the edit field
    ObjectSetInteger(0, objName, OBJPROP_YSIZE, yS); // Height of the edit field
    ObjectSetInteger(0, objName, OBJPROP_CORNER, CORNER_LEFT_UPPER); // Positioning corner
    ObjectSetString(0, objName, OBJPROP_TEXT, txt); // Default text in the edit field
    ObjectSetInteger(0, objName, OBJPROP_COLOR, clrTxt); // Text color
    ObjectSetInteger(0, objName, OBJPROP_FONTSIZE, fontSize); // Font size
    ObjectSetString(0, objName, OBJPROP_FONT, font); // Font name
    ObjectSetInteger(0, objName, OBJPROP_BGCOLOR, clrBg); // Background color
    ObjectSetInteger(0, objName, OBJPROP_BORDER_COLOR, clrBorder); // Border color
    ObjectSetInteger(0, objName, OBJPROP_ALIGN, ALIGN_LEFT); // Text alignment (left-aligned)
    ObjectSetInteger(0, objName, OBJPROP_READONLY, false); // Edit field is not read-only
    ObjectSetInteger(0, objName, OBJPROP_BACK, false); // Transparent background
    ObjectSetInteger(0, objName, OBJPROP_STATE, false); // Edit field state (not active)
    ObjectSetInteger(0, objName, OBJPROP_SELECTABLE, false); // Not selectable
    ObjectSetInteger(0, objName, OBJPROP_SELECTED, false); // Not selected

    // Redraw the chart to display the edit field
    ChartRedraw(0);

    return (true); // Edit field creation successful
}

//+------------------------------------------------------------------+
//|     Function to create text label                                |
//+------------------------------------------------------------------+

bool createLabel(string objName, int xD, int yD,
                 string txt, color clrTxt = clrBlack, int fontSize = 12,
                 string font = "Arial Rounded MT Bold") {
    // Reset any previous errors
    ResetLastError();

    // Attempt to create the label object
    if (!ObjectCreate(0, objName, OBJ_LABEL, 0, 0, 0)) {
        // Print an error message if creation fails
        Print(__FUNCTION__, ": failed to create the label! Error code = ", _LastError);
        return (false);
    }

    // Set properties for the label
    ObjectSetInteger(0, objName, OBJPROP_XDISTANCE, xD); // X distance from the corner
    ObjectSetInteger(0, objName, OBJPROP_YDISTANCE, yD); // Y distance from the corner
    ObjectSetInteger(0, objName, OBJPROP_CORNER, CORNER_LEFT_UPPER); // Positioning corner
    ObjectSetString(0, objName, OBJPROP_TEXT, txt); // Text displayed on the label
    ObjectSetInteger(0, objName, OBJPROP_COLOR, clrTxt); // Text color
    ObjectSetInteger(0, objName, OBJPROP_FONTSIZE, fontSize); // Font size
    ObjectSetString(0, objName, OBJPROP_FONT, font); // Font name
    ObjectSetInteger(0, objName, OBJPROP_BACK, false); // Transparent background
    ObjectSetInteger(0, objName, OBJPROP_STATE, false); // Label state (not active)
    ObjectSetInteger(0, objName, OBJPROP_SELECTABLE, false); // Not selectable
    ObjectSetInteger(0, objName, OBJPROP_SELECTED, false); // Not selected

    // Redraw the chart to display the label
    ChartRedraw(0);

    return (true); // Label creation successful
}

//+------------------------------------------------------------------+
//|     Function to create the drop down utilities                   |
//+------------------------------------------------------------------+

void createDropDown(){
   createRecLabel(BTN_DROP_DN,25,95+25,130,70,clrWhite,2,clrBlack);
   createLabel(LABEL_OPT1,25+10,95+25,"LotSize",clrBlack,12,"stencil");
   createLabel(LABEL_OPT2,25+10,95+25+20,"Risk Percent %",clrBlack,12,"calibri Italic");
   createLabel(LABEL_OPT3,25+10,95+25+20+20,"Money Balance",clrBlack,12,"Arial bold");
   createLabel(ICON_DRAG,25+10+95,95+25,"d",clrRoyalBlue,15,"webdings");
}

//+------------------------------------------------------------------+
//|    Function to destroy the entire GUI Panel                      |
//+------------------------------------------------------------------+

void destroyPanel(){
   ObjectDelete(0,MAIN_REC);
   ObjectDelete(0,MAIN_SUB_REC);
   ObjectDelete(0,MAIN_LINE_UP);
   ObjectDelete(0,MAIN_LINE_DN);
   ObjectDelete(0,BTN_LOTS);
   ObjectDelete(0,LABEL_NAME);
   ObjectDelete(0,LABEL_LOTS);
   ObjectDelete(0,ICON_HEART);
   ObjectDelete(0,ICON_TOOL);
   ObjectDelete(0,ICON_CAR);
   ObjectDelete(0,ICON_DROP_DN1);
   ObjectDelete(0,LINE1);
   ObjectDelete(0,BTN_CLOSE);
   ObjectDelete(0,BTN_MARKET);
   ObjectDelete(0,BTN_PROFIT);
   ObjectDelete(0,BTN_LOSS);
   ObjectDelete(0,BTN_PENDING);
   ObjectDelete(0,LINE2);
   ObjectDelete(0,EDIT_LOTS);
   ObjectDelete(0,BTN_P1);
   ObjectDelete(0,BTN_M1);
   
   ObjectDelete(0,BTN_SL);
   ObjectDelete(0,LABEL_SL);
   ObjectDelete(0,ICON_DROP_DN2);
   ObjectDelete(0,EDIT_SL);
   ObjectDelete(0,BTN_P2);
   ObjectDelete(0,BTN_M2);
   
   ObjectDelete(0,BTN_TP);
   ObjectDelete(0,LABEL_TP);
   ObjectDelete(0,ICON_DROP_DN3);
   ObjectDelete(0,EDIT_TP);
   ObjectDelete(0,BTN_P3);
   ObjectDelete(0,BTN_M3);
   
   ObjectDelete(0,BTN_BUY);
   ObjectDelete(0,LABEL_BUY);
   ObjectDelete(0,LABEL_BUY_PRICE);
   ObjectDelete(0,BTN_OVERLAY);
   ObjectDelete(0,BTN_SPREAD);
   
   ObjectDelete(0,BTN_SELL);
   ObjectDelete(0,LABEL_SELL);
   ObjectDelete(0,LABEL_SELL_PRICE);
   
   ObjectDelete(0,BTN_CONTACT);
   
   ObjectDelete(0,BTN_SHARP);
   ObjectDelete(0,LABEL_SHARP);
   ObjectDelete(0,BTN_HOVER);
   ObjectDelete(0,LABEL_HOVER);
   
   ObjectDelete(0,LABEL_EXTRA1);
   ObjectDelete(0,LABEL_EXTRA2);
   ObjectDelete(0,LABEL_EXTRA3);
   ObjectDelete(0,LABEL_EXTRA4);
   
   ObjectDelete(0,BTN_DROP_DN);
   ObjectDelete(0,LABEL_OPT1);
   ObjectDelete(0,LABEL_OPT2);
   ObjectDelete(0,LABEL_OPT3);
   ObjectDelete(0,ICON_DRAG);
   
   ChartRedraw(0);
}


结论

总体来说,您可以看出,创建GUI面板并不像想象中那么复杂。这个过程包括一系列步骤:从定义面板尺寸(即决定面板的位置、大小和外观,可以使用绝对坐标或相对于图表的坐标)开始,到创建各种图形对象(如按钮、标签、编辑字段和矩形标签)并指定它们的属性(颜色、文本、字体等),再到在事件处理器中实现面板的创建和用户交互。

第一部分已经成功展示了面板的创建。第二部分将使面板更加生动,具有响应性。例如,我们将使按钮在点击时具有响应性,每次价格变动时更新报价,使下拉菜单可拖动,为按钮添加悬停效果等等。我们希望这篇文章在创建GUI面板方面对您有所帮助,并且应用这里的知识创建更复杂和精美的GUI面板。


本文由MetaQuotes Ltd译自英文
原文地址: https://www.mql5.com/en/articles/15205

附加的文件 |
最近评论 | 前往讨论 (1)
Frist001
Frist001 | 8 1月 2025 在 16:18

可以使这个面板随意移动位置吗? move free???

《数据科学与机器学习(第25部分):使用循环神经网络(RNN)进行外汇时间序列预测》 《数据科学与机器学习(第25部分):使用循环神经网络(RNN)进行外汇时间序列预测》
循环神经网络(RNN)非常擅长利用过去的信息来预测未来的事件。它们卓越的预测能力已经在各个领域得到了广泛应用,并取得了巨大成功。在本文中,我们将部署RNN模型来预测外汇市场的趋势,展示它们在提高外汇交易预测准确性方面的潜力。
用Python重塑经典策略:移动平均线交叉 用Python重塑经典策略:移动平均线交叉
在本文中,我们重新审视了经典的移动平均线交叉策略,以评估其当前的有效性。鉴于该策略自诞生以来已经过去了很长时间,我们探索了人工智能可能为其带来的潜在增强效果。通过融入人工智能技术,我们旨在利用高级的预测能力来潜在地优化交易的入场和出场点,适应不断变化的市场条件,并与传统方法相比提高整体表现。
使用Python和MQL5进行交易策略的自动参数优化 使用Python和MQL5进行交易策略的自动参数优化
有多种用于交易策略和参数自我优化的算法。这些算法基于历史和当前市场数据自动改进交易策略。在本文中,我们将通过Python和MQL5的示例来探讨其中一种算法。
开发多币种 EA 交易 (第 11 部分):自动化优化(第一步) 开发多币种 EA 交易 (第 11 部分):自动化优化(第一步)
为了获得一个好的 EA,我们需要为它选择多组好的交易策略实例参数。这可以通过对不同的交易品种运行优化然后选择最佳结果来手动完成。但最好将这项工作委托给程序,并从事更有成效的活动。