MetaTrader 图形界面(GUI)库:安装与使用指南

MetaTrader 图形界面(GUI)库:安装与使用指南

10 十一月 2026, 16:34
Omar Alkassar
0
2

✔️ GUI 图形库MT4©:   https://www.mql5.com/en/market/product/206760

✔️ GUI 图形库MT5©:   https://www.mql5.com/en/market/product/206761

✔️ 完整的文档、元素库和图像转代码工具⁵:   https://www.betasoft.dev/gui-graphic-library



持仓表、订单单和实时图表。

GUI图形库为您的智能交易系统和指标提供完整的界面:窗口、标签页、菜单、表格、图表、选择器、对话框和交易小部件。所有元素都绘制在同一个画布上,同一段代码可在MetaTrader 4和MetaTrader 5中运行,整个API仅包含15个函数。

本指南将引导您从下载文件到创建第一个可运行的面板,并逐步介绍您最常用的功能。每个代码示例都仅使用公共头文件,因此您可以将其粘贴到自己的程序中。

78 个元素中的一小部分:按钮、输入框、滑块和标签页。

1. 开始之前

  • 适用于 Windows 系统的 MetaTrader 4 或 MetaTrader 5。字体和图标遵循 Windows 显示比例(100%、125%、150% 和 200%)。
  • MetaEditor,用于编译演示程序和您自己的程序。
  • 终端选项中无需允许任何内容:该库不使用 DLL,不发出任何 Web 请求,也不使用任何终端全局变量。
  • MT4 和 MT5 是不同的产品。请安装与您的终端匹配的版本。

2. 安装

  1. 在终端中选择“文件”,然后选择“打开数据文件夹”。
  2. 打开 MQL5 文件夹(MetaTrader 5)或 MQL4 文件夹(MetaTrader 4)。
  3. 将每个文件复制到上表所示的文件夹中:Libraries、Include、Experts 和 Indicators。
  4. 在 MetaEditor 中打开每个演示,然后按 F7。结果应显示 0 个错误,0 个警告。
  5. 回到终端,刷新导航器(右键单击,刷新),以便显示新程序。

文件夹结构应如下所示:

MQL5/

  Include/GUI_Graphic_Library.mqh

  Libraries/GUI_Graphic_Library.ex5

  Experts/GUI_Graphic_Library_FullDemo.mq5

          GUI_Graphic_Library_ElementTests.mq5

  Indicators/GUI_Graphic_Library_IndicatorWindow.mq5

             GUI_Graphic_Library_IndicatorChart.mq5

MQL4/   the same files with .mq4 and .ex4

请勿重命名库文件。包含文件会按原名加载它。

安装后检查

查看

在哪里

.ex5(或 .ex4)文件位于库中

数据文件夹

.mqh 文件位于 Include 目录中。

数据文件夹

演示程序编译无误

元编辑器

演示中会在图表上显示一个窗口。

图表

“专家”选项卡中没有“不支持”的行。

终端,工具箱

GUI_Graphic_Library.mqh 文件里有什么?

包含文件特意做得很小。在导入块上方,它声明了枚举类型(对象类型、属性、事件、主题和图标)。下面的导入块加载已编译的库并列出其 15 个函数。MetaTrader 5 加载 .ex5 文件,而 MetaTrader 4 加载 .ex4 文件,由编译器选择。您只需包含该文件,无需对其进行任何编辑。

 #ifdef __MQL5__
#import "\\Market\\GUI_Graphic_Library.ex5"
#else
#import "\\Market\\GUI_Graphic_Library.ex4"
#endif
   string Gui_Version();
   bool    Gui_Create( const long chart= 0 , const string name= "GUI_Graphic_Library" , const int subwin= 0 );
   void    Gui_Destroy();
   void    Gui_ChartEvent( const int id, const long lparam, const double dparam, const string sparam);
   void    Gui_Timer();
   void    Gui_Update( const bool force= false );
   bool    Gui_NextEvent(ENUM_GUI_EVENT &event, int &sender, long &lparam, double &dparam, string &sparam);
   int     Gui_Add( const ENUM_GUI_OBJECT type, const int parent, const string name, const string text, const int x, const int y, const int w, const int h);
   int     Gui_Set( const int id, const ENUM_GUI_PROP prop, const string s= "" , const double a= EMPTY_VALUE , const double b= EMPTY_VALUE , const double c= EMPTY_VALUE , const double d= EMPTY_VALUE );
   string Gui_Get( const int id, const ENUM_GUI_PROP prop, const string s= "" , const double a= EMPTY_VALUE , const double b= EMPTY_VALUE );
   double Gui_GetNum( const int id, const ENUM_GUI_PROP prop, const string s= "" , const double a= EMPTY_VALUE , const double b= EMPTY_VALUE );
   int     Gui_SetArray( const int id, const ENUM_GUI_PROP prop, const double &values[], const double a= EMPTY_VALUE );
   int     Gui_AddImage( const string name, const uint &argb[], const int w, const int h);
   int     Gui_Find( const string name);
   void    Gui_BringToFront();
#import

这15个功能按出现顺序排列:

功能

它的作用

你称之为

Gui_Version

返回库版本信息(文本格式)。

任何地方

Gui_创建

在图表上启动图形用户界面。传入参数 0 表示当前图表,传入程序名称,传入指标所在的子窗口编号。如果程序运行成功,则返回 true。

OnInit

Gui_Destroy

移除图形用户界面及其绘制的所有内容。

OnDeinit

Gui_ChartEvent

将图表事件(鼠标、键盘、点击)传递给库。

图表事件

Gui_Timer

运行库中的计时器:动画、提示信息、计数器。

定时器

Gui_更新

重绘已更改的部分。传递 true 参数则重绘所有内容。

每个处理程序结束

Gui_NextEvent

从队列中获取下一个事件(点击、更改、对话框结果、交易请求)。当队列为空时返回 false。

事件循环

Gui_Add

创建一个元素并返回其 id。你需要提供类型、父元素、名称、文本以及 x、y、宽度和高度。

OnInit

Gui_Set

更改元素的属性或执行操作。如果元素不支持此操作,则返回 -1 并记录一行日志。

任何地方

Gui_Get

将属性读取为文本。

任何地方

Gui_GetNum

将属性值读取为数字。

任何地方

Gui_SetArray

将数字列表发送给元素,例如整个图表系列。

任何地方

Gui_AddImage

从 ARGB 像素数组中注册图像,以便元素可以显示它。网站上的“图像转代码”工具会将 PNG 文件转换为此数组。

OnInit

Gui_Find

根据名称查找元素 ID。

任何地方

Gui_BringToFront

将图形用户界面移动到您之后绘制的图表对象上方。

创建图表对象之后

这就是全部界面。本指南中的其他所有内容都是这15个调用组合而成的。

3. 运行完整演示

  1. 打开图表。例如,使用 1280 x 720 像素或更大的窗口可以显示更多信息。
  2. 将导航器中的 GUI_Graphic_Library_FullDemo 拖到图表上。
  3. 使用顶部的选项卡:首页、用例、按钮、输入、选择器、数据、图表、布局、反馈、交易和设置。

除非您将输入参数 InpLiveTrading 设置为 true,否则演示程序不会发送订单。在真实账户中,请将其关闭。如果您关闭主窗口,智能交易系统将自动关闭。

当您想要一次查看一个元素时,请使用 GUI_Graphic_Library_ElementTests:单击其选择器窗口中的组。

一个完全由库中的元素构建的仪表盘。

4. 你的第一个面板

这是一个完整的智能交易系统:一个包含交易手数输入框、“买入”按钮和状态栏的窗口。它不会进行交易,只会显示一条信息。

 #include <GUI_Graphic_Library.mqh>
int wMain, spLots, btnBuy, lblInfo;
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int OnInit ()
  {
   if (!Gui_Create( 0 , "MyPanel" ))
       return INIT_FAILED ;       // 0 = this chart
   Gui_Set( 0 , GUI_PROP_THEME, "" , GUI_THEME_DARK);
   wMain = Gui_Add(GUI_OBJ_WINDOW, 0 , "wMain" , "My panel" , 20 , 40 , 300 , 170 );
   Gui_Set(wMain, GUI_PROP_THEME_BUTTON, "" , true );       // sun / moon button
   Gui_Set(wMain, GUI_PROP_MAIN_WINDOW, "" , true );         // close asks to remove the program
   spLots = Gui_Add(GUI_OBJ_SPIN, wMain, "spLots" , "" , 10 , 10 , 280 , 30 );
   Gui_Set(spLots, GUI_PROP_RANGE, "" , 0.01 , 50 , 0.01 , 2 ); // min, max, step, digits
   Gui_Set(spLots, GUI_PROP_VALUE, "" , 0.10 );
   Gui_Set(spLots, GUI_PROP_SUFFIX, "lots" );
   btnBuy = Gui_Add(GUI_OBJ_BUTTON, wMain, "btnBuy" , "BUY" , 10 , 50 , 280 , 40 );
   Gui_Set(btnBuy, GUI_PROP_STYLE, "" , GUI_BUTTON_SUCCESS);
   Gui_Set(btnBuy, GUI_PROP_ICON, "" , GUI_ICON_ARROW_UP);
   lblInfo = Gui_Add(GUI_OBJ_LABEL, wMain, "lblInfo" , "Ready" , 10 , 100 , 280 , 20 );
   Gui_Set(lblInfo, GUI_PROP_DIM, "" , true );
   Gui_Set( 0 , GUI_PROP_REDRAW);
   return INIT_SUCCEEDED ;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void ProcessEvents()
  {
   ENUM_GUI_EVENT ev;
   int sender;
   long l;
   double d;
   string s;
   while (Gui_NextEvent(ev, sender, l, d, s))
       if (ev == GUI_EVENT_CLICK && sender == btnBuy)
        {
         double lots = Gui_GetNum(spLots, GUI_PROP_VALUE);
         Gui_Set(lblInfo, GUI_PROP_TEXT, "Buy " + DoubleToString (lots, 2 ) + " lots" );
         Gui_Set( 0 , GUI_PROP_TOAST, "Buy|" + DoubleToString (lots, 2 ) + " lots" , GUI_NOTICE_SUCCESS, 3000 );
        }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnDeinit ( const int r)
  {
   Gui_Destroy();
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnTimer ()
  {
   Gui_Timer();
   ProcessEvents();
   Gui_Update();
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnChartEvent ( const int id, const long &l, const double &d, const string &s)
  {
   Gui_ChartEvent(id, l, d, s);
   ProcessEvents();
   Gui_Update();
  }

模式始终不变:

  1. OnInit 会创建 GUI 及其元素。
  2. OnChartEvent 和 OnTimer 将事件传递给库,读取队列并调用 Gui_Update。
  3. OnDeinit 会销毁 GUI。

5. 图书馆的思维方式

  • ID。Gui_Add 函数返回一个整数 ID。您可以保存所需的 ID,或者稍后使用 Gui_Find("name") 函数按名称查找。ID 0 代表 GUI 本身:主题、提示信息、对话框、计数器等。
  • 父元素。每个元素都会被添加到某个父元素(窗口或容器)中。窗口、菜单和价格标签使用父元素 0。对于选项卡,其父元素是选项卡本身,返回的 ID 是您添加子元素的页面。
  • 属性。Gui_Set(id, property, text, a, b, c, d) 用于更改属性或执行操作。文本放在 text 参数中;数字、颜色和枚举值分别放在 a 到 d 参数中。Gui_Get 用于读取文本,Gui_GetNum 用于读取数字。
  • 事件。该库会将用户操作添加到队列中。使用 Gui_NextEvent 读取队列。
  • 坐标以像素为单位,缩放比例为 100%。该库会自动将其乘以 Windows 显示缩放比例。

如果传递的属性是元素不支持的,也不会出错:调用返回 -1,并在 Experts 日志中写入一行。

6. 你最常做的任务

读取用户输入或选择的内容

string name=Gui_Get(edName,GUI_PROP_TEXT);
double lots=Gui_GetNum(spLots,GUI_PROP_VALUE);
int     tab =( int )Gui_GetNum(tabs,GUI_PROP_SELECTED);

标签页

int t=Gui_Add(GUI_OBJ_TABS,win, "tabs" , "" , 10 , 10 , 600 , 300 );
int pOrders =Gui_Add(GUI_OBJ_TAB,t, "" , "Orders" , 0 , 0 , 0 , 0 );     // returns the page
int pHistory=Gui_Add(GUI_OBJ_TAB,t, "" , "History" , 0 , 0 , 0 , 0 );
Gui_Add(GUI_OBJ_BUTTON,pOrders, "b1" , "Close all" , 10 , 10 , 120 , 30 );

表格

int tb=Gui_Add(GUI_OBJ_TABLE,page, "tbl" , "" , 10 , 10 , 600 , 300 );
Gui_Set(tb,GUI_PROP_ADD_COLUMN, "Symbol" , 120 ,GUI_ALIGN_LEFT);
Gui_Set(tb,GUI_PROP_ADD_COLUMN, "Strength" , 130 ,GUI_ALIGN_LEFT,GUI_COL_PROGRESS);
Gui_Set(tb,GUI_PROP_ADD_BUTTON_COLUMN, "Action" , 100 ,GUI_BUTTON_PRIMARY);
Gui_Set(tb,GUI_PROP_ADD_ROW, "EURUSD|64|Trade" );
Gui_Set(tb,GUI_PROP_SORT, "" , 0 , true );

单击按钮单元格会发送 GUI_EVENT_CELL_BUTTON 事件,其中 lparam 为行号,dparam 为列号。

图表

int ch=Gui_Add(GUI_OBJ_LINECHART,page, "chart" , "Price" , 10 , 10 , 500 , 260 );
int ln=Gui_Set(ch,GUI_PROP_ADD_SERIES, "Close" , clrDodgerBlue );     // returns the series index
double closes[]; CopyClose ( _Symbol , PERIOD_H1 , 0 , 100 ,closes);
Gui_SetArray(ch,GUI_PROP_SERIES,closes,ln);                       // a whole series at once

int cd=Gui_Add(GUI_OBJ_CANDLECHART,page, "cd" , _Symbol , 10 , 280 , 500 , 260 );
Gui_Set(cd,GUI_PROP_LOAD_BARS, _Symbol , 80 );
Gui_Set(cd,GUI_PROP_ADD_MA, "" , 20 , clrDodgerBlue );
Gui_Set(cd,GUI_PROP_ADD_BANDS, "" , 20 , 2.0 );

对话和祝酒

enum { CMD_CLOSE_ALL= 500 };
Gui_Set( 0 ,GUI_PROP_CONFIRM, "Close all|Close every position?|Close|Cancel" ,CMD_CLOSE_ALL);
// later, in the event loop:
if (ev==GUI_EVENT_DIALOG && Gui_GetNum(sender,GUI_PROP_CMD)==CMD_CLOSE_ALL && l== 0 )
   CloseAll();                       // l = button index, -1 = cancelled

Gui_Set( 0 ,GUI_PROP_TOAST, "Order|Filled" ,GUI_NOTICE_SUCCESS, 3000 );

主题和颜色

Gui_Set( 0 ,GUI_PROP_THEME, "" ,GUI_THEME_MIDNIGHT);   // DARK, LIGHT, MIDNIGHT, HIGHCONTRAST, SOFT
Gui_Set( 0 ,GUI_PROP_ACCENT, "" , clrOrange );
Gui_Set( 0 ,GUI_PROP_RADIUS, "" , 10 );

记住窗口和价值观

Gui_Set( 0 ,GUI_PROP_AUTO_LAYOUT, "" , true );   // load now, save when the GUI is destroyed
Gui_Set( 0 ,GUI_PROP_LOAD_VALUES);             // in OnInit
Gui_Set( 0 ,GUI_PROP_SAVE_VALUES);             // in OnDeinit

两者都使用小型文本文件,未使用终端全局变量。

每秒都做点什么

Gui_Set( 0 ,GUI_PROP_COUNTER, "refresh" , 1000 , true );   // name, ms, repeat
// in OnTimer:
if (Gui_GetNum( 0 ,GUI_PROP_COUNTER_DONE, "refresh" )!= 0 ) RefreshNumbers();

7. 一个带有自定义订单功能的交易面板

订单单、持仓面板和风险计算器会读取账户和交易品种,然后向您提供事件信息。它们本身不会发送订单。用户点击“买入”或“卖出”按钮后,具体执行什么操作,由您决定。

 #include <GUI_Graphic_Library.mqh>
#ifdef __MQL5__
#include <Trade\Trade.mqh>
CTrade g_trade;
#endif
input bool InpLiveTrading = false ;   // send real orders
int g_ticket = 0 ;

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int OnInit ()
  {
   if (!Gui_Create( 0 , "GUI_TradePanel" ))
       return INIT_FAILED ;
   int w = Gui_Add(GUI_OBJ_WINDOW, 0 , "w" , "Trade" , 20 , 40 , 360 , 260 );
   Gui_Set(w, GUI_PROP_MAIN_WINDOW, "" , true );
   g_ticket = Gui_Add(GUI_OBJ_ORDERTICKET, w, "ticket" , _Symbol , 10 , 10 , 340 , 212 );
   Gui_Set(g_ticket, GUI_PROP_LOTS, "" , 0.10 );
   Gui_Set(g_ticket, GUI_PROP_STOP_POINTS, "" , 300 );
   Gui_Set(g_ticket, GUI_PROP_TP_POINTS, "" , 600 );
   Gui_Set(g_ticket, GUI_PROP_SHOW_LINES, "" , true );   // SL and TP lines on the chart
   Gui_Set( 0 , GUI_PROP_CLEAR_EVENTS);
   return INIT_SUCCEEDED ;
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void MyTrade( const bool buy, const double lots, const double sl, const double tp)
  {
   if (!InpLiveTrading)
     {
       Print ( "Trading is off. Would " , buy ? "buy " : "sell " , lots, " lots" );
       return ;
     }
#ifdef __MQL5__
   if (buy)
      g_trade.Buy(lots, _Symbol , 0.0 , sl, tp);
   else
      g_trade.Sell(lots, _Symbol , 0.0 , sl, tp);
#else
   if (buy)
       OrderSend ( _Symbol , OP_BUY, lots, Ask, 3 , sl, tp, "GUI" , 0 , 0 , clrGreen );
   else
       OrderSend ( _Symbol , OP_SELL, lots, Bid, 3 , sl, tp, "GUI" , 0 , 0 , clrRed );
#endif
   }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void ProcessEvents()
  {
   ENUM_GUI_EVENT ev;
   int sender;
   long l;
   double d;
   string s;
   while (Gui_NextEvent(ev, sender, l, d, s))
       if (ev == GUI_EVENT_TRADE)           // l: 0 buy, 1 sell   d: lots   s: "sl|tp" prices
        {
         string p[];
         StringSplit (s, '|' , p);
         double sl = ( ArraySize (p) > 0 ) ? StringToDouble (p[ 0 ]) : 0.0 ;
         double tp = ( ArraySize (p) > 1 ) ? StringToDouble (p[ 1 ]) : 0.0 ;
         MyTrade(l == 0 , d, sl, tp);
        }
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnDeinit ( const int r)
  {
   Gui_Destroy();
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnTimer ()
  {
   Gui_Timer();
   ProcessEvents();
   Gui_Update();
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnChartEvent ( const int id, const long &l, const double &d, const string &s)
  {
   Gui_ChartEvent(id, l, d, s);
   ProcessEvents();
   Gui_Update();
  }

先在模拟账户上测试。下单前,还要检查手数是否符合交易品种的最小、最大和步长要求,以及止损距离是否符合经纪商的止损水平。

位置的工作方式相同:添加 GUI_OBJ_POSITIONS,然后响应 GUI_EVENT_POSITION(lparam 是票据,dparam 为 1 表示关闭,为 2 表示修改)。

8. 在指标中使用它

指示器可以在其自身的子窗口中绘制 GUI。将该窗口的编号传递给 Gui_Create:

 #property indicator_separate_window
int OnInit ()
  {
   int sub= ChartWindowFind ();
   Gui_Create( 0 , "GUI_MyIndicator" ,sub);
   // add windows and controls as usual
   return INIT_SUCCEEDED ;
  }

要在价格图表上绘制指标,请使用子窗口 0。两个指标演示都是完整的示例。每个程序和图表都有一个独立的图形用户界面 (GUI),因此请为每个程序指定一个 GUI 名称。

9. MetaTrader 4 和 MetaTrader 5

话题

MetaTrader 4

MetaTrader 5

库文件

.ex4

.ex5

上下文菜单

长按鼠标左键,或按住 Ctrl 键并单击

右键单击

鼠标滚轮

未通过终端发送。请使用滚动条。

作品

市场深度

自行添加关卡

阅读市场报告

经济日历

自行添加行

来自终端的负载

打字

内置美国地图

每种键盘布局都有效

10. 如果某件事行不通

问题

该怎么办

图表上没有任何显示。

检查 Gui_Create 是否返回 true,并阅读“专家”选项卡的最后几行。

编译器无法打开 GUI_Graphic_Library.mqh

包含文件不在与程序相同的数据文件夹的 Include 文件夹中。

程序无法在运行时加载库。

库中缺少 .ex5 或 .ex4 文件,或者其名称已更改。

代码中更改的值不会显示出来。

在处理程序的末尾调用 Gui_Update()。

“专家”选项卡显示该属性不受支持。

该元素不存在此属性。请查阅 API 文档。

两个程序在同一张图表上展开较量

在 Gui_Create 中给每个组件命名。

图表线覆盖了图形用户界面

创建图表对象后调用 Gui_BringToFront()。

文字太小或太大

设置 Gui_Set(0,GUI_PROP_SCALE,"",1.5),或者在更改 Windows 缩放比例后重新启动终端。

你想看看图书馆在做什么

启用 Gui_Set(0,GUI_PROP_DEBUG,"",true) 以启用调试叠加层。

11. 提示

  • 在每个处理程序结束时调用 Gui_Update()。它只会重绘已更改的部分。
  • 隐藏的标签页和折叠的窗口不会导致页面重绘,因此通过定时器更新它们成本很低。
  • 如果运行多个图表,请使用 GUI_PROP_MAX_FPS 来限制帧速率。
  • 在 OnInit 的末尾使用 GUI_PROP_CLEAR_EVENTS 来删除在构建面板时排队的事件。
  • 使用网站上的“图像转代码”工具,将 PNG 徽标或图标转换为 Gui_AddImage 的数组。
  • 新的枚举值只会在末尾添加,因此使用旧版包含文件构建的程序在更新后仍能继续运行。请同时替换库文件和包含文件。

12. 下一步去哪里

欢迎您的意见。如有任何疑问或改进建议,请在产品评论区留言或通过 MQL5.com给我发送消息。




附加的文件: