数字选择(NumericUpDown, 数字列表窗口)
日期时间选择器(DataTimePicker, 日期选择窗口)
ElementHide 和 ElementEnable - 隐藏及禁用指定元素
AddItem - 添加子元素
Exception - 接收异常的事件
可用图形元素和事件的汇总表格
从 2018 年10月开始, MetaTrader 5 支持了
与
.Net 框架库的整合
。这组库实际上远不止是执行特定任务范围的框架或专用系统,例如绘制图形窗口或实现网络交互,.NET框架实际上拥有一切。它允许开发网站(Net
Core,MVC),创建具有统一专业界面(Windows窗体)的系统应用程序,构建复杂的分布式系统,在节点之间进行数据交换,以及使用数据库(实体框架)。此外,.NET框架是一个由程序员和公司组成的庞大社区,拥有数千个不同的开源项目。如果交互是正确组织的,那么所有这些都可以在今天的MQL中使用。
在本文中,我们将继续开发在
第一部分
中创建的 GuiController
的功能。此功能旨在与基于Windows窗体技术的
.NET框架的图形功能交互。目前,在MQL图形功能上提供了大量信息,有许多不同的库通过MQL或多或少地做相同的事情。因此,我不希望读者将此材料视为“使用表单的另一个库”。事实上,本材料只是描述与.NET框架交互的一系列文章的一部分,并逐渐揭示了该软件平台的无限特性。Windows窗体只是这个平台中的一个构建块,尽管它非常方便和全面,就像.NET技术的任何一部分一样。Windows窗体图形子系统是探索此框架的一个很好的起点,经过适当的研究,它可以应用于与
.NET 框架的其他交互。此外,它还允许创建相当高效且最重要的是易于实现的交易面板、EA配置窗口、高级图形指标、机器人控制系统以及用户与交易平台之间交互的其他相关内容。
然而,为了实现所有这些令人兴奋的特性,有必要显著改进MQL程序和C#库之间的交互模块。您可能还记得,在第一节中,GuiController 模块只能与几个 WinForms
元素交互,例如按钮(Button)、文本标签(Label)、用于输入文本的文本字段(TextBox)和垂直滚动条。尽管支持很少,我们还是成功地创建了一个完整且功能相当强大的图形面板:
图 1. 文章第一部分创建的交易面板
尽管取得了令人印象深刻的成绩,但我们不会就此止步,继续改进我们的控制器。在本文中,我们将为它提供额外的图形元素,允许用户创建大多数类型的表单。
安排新元素测试
为了引入对新元素的支持,需要组织一种“测试台”。这使我们能够微调新元素的使用,并消除引入新功能时出现的潜在错误。我们的“测试台”由控制器、带有必要图形元素集的表单和用于处理这些元素的EA组成。所有窗体都将位于单个 DemoForm.exe 中。在EA中,我们将开发一个自定义参数,指定从DemoForm.exe下载的图形表单:
图 2. 选择下载的带有必要元素的自定义表单
测试EA本身非常简单,实际上,它由两部分组成:下载函数(标准的OnInit初始化函数)和图形事件处理程序函数(OnTimer函数中的事件循环)。您可能还记得,GuiController中的工作是通过调用静态方法来执行的。只有四种主要方法:
void OnTimer()
for(static int i = 0; i < GuiController::EventsTotal(); i++)
int id;
string el_name;
long lparam;
double dparam;
string sparam;
GuiController::GetEvent(i, el_name, id, lparam, dparam, sparam);
if(id == TabIndexChange)
printf("Selecet new tab. Index: " + (string)lparam + " Name: " + sparam);
else if(id == ComboBoxChange)
printf("组合框 '" + el_name + "' 已改变 " + sparam);
这样,对于每个图形元素,我们将创建一个简短的工作示例,说明与它的交互。我们还将详细描述它支持的事件。
消息框(MessageBox)
从第二个版本开始,控制器支持消息框,这是一个标准的用户信息元素。它还向用户提供多个选项,并以所选选项的形式接收响应。
要启动消息窗口的演示,请在启动EA时选择 Windows 窗体元素类型参数中的“按钮和消息框(Buttons and MessageBox)”选项。启动EA后,会出现一个表单,提示您选择以下选项之一:
图 3. 调用消息框的示例窗体
这个窗体以及随后的所有窗体都是示范形式,因此不具备交易逻辑。但是,按下任何按钮后,EA会发送一条警告消息,请求确认所选操作。例如,单击“卖出(SELL)”时将显示以下消息窗口:
图 4. 交易EA要求确认开立新的空头头寸
用户单击其中一个按钮后,单击事件将被记住并记录在GuiController事件缓冲区中。EA以指定的频率调查事件缓冲区,并在发现新事件进入缓冲区后立即开始处理它。这样,EA需要接收“点击按钮(Button clicking)”事件,并通过发送 “MessageBox”对到来的事件做出反应。
for(static int i = 0; i < GuiController::EventsTotal(); i++)
int id;
string el_name;
long lparam;
double dparam;
string sparam;
GuiController::GetEvent(i, el_name, id, lparam, dparam, sparam);
if(id == ClickOnElement)
printf("您按下了 '" + sparam + "' 按钮");
string msg;
if(el_name != "btnCancelAll")
msg = "您是否想要开立一个新的 " + sparam + " 仓位?";
msg = "您是否确定关闭所有仓位?";
GuiController::SendEvent("ButtonForm", MessageBox, LockControl, OKCancel, msg);
让我们分析发送事件的签名:
GuiController::SendEvent("ButtonForm", MessageBox, LockControl, OKCancel, msg);
这意味着EA要求显示消息框,其中“msg”变量中的主文本显示“确定”和“取消”按钮(OKCancel)。在本文的第一部分中,我们提到SendEvent方法的第一个参数包含发送事件接收器的图形元素的名称。但是,此字段与MessageBox的工作方式不同。消息框没有绑定到特定的图形窗口或元素(尽管Windows
Froms允许这样的绑定)。因此,GuiController创建新的消息窗口,它不需要目标地址。通常,在显示消息后,应该阻止与之相关的窗口。事实上,如果在显示消息时,可以重复单击“买入”或“卖出”按钮而忽略出现的消息框,则会很奇怪。因此,
在GuiController中,此事件的第一个参数的名称代表应被阻止的元素,直到用户单击其中一个MessageBox按钮。任意图形元素的阻塞函数是可选的。它是使用整数lparam变量指定的:0-不阻挡窗口,1-如果存在就阻挡。但是,使用常量而不是零和一更方便。为此,使用
BlockingControl枚举在 GuiController中定义两个常量:
第一个选项在用户按下按钮之前阻止窗口,第二个选项不允许用户访问图形窗口。
除了文本,消息窗口可以包含各种按钮的组合,通过单击这些按钮,用户同意某种选择。按钮集是使用System.Windows.Forms.MessageBoxButtons系统枚举定义的。枚举元素对MQL用户不可用,因为它们是在外部生成中定义的。为了简化处理 GuiController的MQL程序员的工作,我们实现了新的枚举——具有相同参数的System.Windows.Forms.MessageBoxButtons的克隆。枚举是在
IController.cs 中定义的:
public enum MessageBoxButtons
OK = 0,
OKCancel = 1,
AbortRetryIgnore = 2,
YesNoCancel = 3,
YesNo = 4,
RetryCancel = 5
这些枚举的常量可以直接在MQL编辑器中使用,例如通过 IntelliSens,使得配置MessageBox非常方便。例如,如果我们在 SendEvent中将OKCancel替换为YesNoCancel,对话框窗口将接收另一组按钮:
GuiController::SendEvent("ButtonForm", MessageBox, LockControl, YesNoCancel, msg);
图 5. 标准的三按钮组合 - Yes/No/Cancel
除了按钮集,GuiController还支持配置消息图标以及窗口标题文本。由于 SendEvent 方法具有固定数量的参数,因此通过它传递所有设置是很有问题的,因此找到了另一种解决方案。消息文本行可以使用“|”符号分为多个部分。在这种情况下,每个部分负责一个特定的附加参数。节数可能从一个(无分隔符)到三个(两个分隔符)不等。让我们探讨几个例子,假设您希望显示一条不带图标或附加标题的简单消息,在这种情况下,消息发送格式如下:
GuiController::SendEvent("ButtonForm", MessageBox, LockControl, OK, "This is a simple message");
图 9. 含有两个选项卡的面板
选项卡控件元素支持单个TabIndexChange事件,它通知用户已移动到另一个选项卡。测试EA以表单上的代码跟踪表更改为特征。让我们看看代码片段:
for(static int i = 0; i < GuiController::EventsTotal(); i++)
int id;
string el_name;
long lparam;
double dparam;
string sparam;
GuiController::GetEvent(i, el_name, id, lparam, dparam, sparam);
if(id == TabIndexChange)
printf("选择了新页面. Index: " + (string)lparam + " Name: " + sparam);
TabIndexChange 事件传递两个参数: lparam 和 sparam. 第一个包含用户选择选项卡的索引。第二个包含所选选项卡的名称。例如,如果用户选择第一个选项卡,则EA会键入以下消息:
选择新选项卡. 索引: 0 名称: tabPage1
选项卡是非常有用的图形元素,并不总是需要跟踪选项卡。WindowsForm要求单个窗体的所有元素具有唯一的名称。因此,位于不同选项卡中的同一类型的两个元素是唯一的,并且根据
WindForms,应以不同的方式命名。另一方面,通常需要跟踪直接控件的按下情况,这样一个元素所在的标签并不总是重要的。然而,有时有必要跟踪这些事件,因此,GuiController提供了足够用于此元素的必要交互接口。
复选框(CheckBox)
复选框是任何图形界面的关键元素之一。尽管它很简单,但是它被用于各种各样的界面,从旧版本的Windows开始,到Web和移动应用程序结束。它允许任何选项的直观指示。此外,还可以显示由于某种原因不可用的选项,允许用户直观地选择彼此不矛盾的选项:
图 10. 使用复选框组合选择选项
复选框有三种状态:选中(Checked)、未选中(Unchecked)和部分选中(Indeterminate)。Windows Forms 使用 System.Windows.Forms.CheckState 结构来描述这些状态:
namespace System.Windows.Forms
public enum CheckState
Unchecked = 0,
Checked = 1,
Indeterminate = 2
每次用户单击此复选框时,GuiController都会通过lparam变量使用 CheckBoxChange 事件将其状态传递给MQL EA。它的数值对应了枚举中的选项之一: 0 — Unchecked, 1 — Checked, 2 — Indeterminate.
在演示示例中,EA跟踪“启用EURUSD交易”和“启用GBPUSD交易”复选框的选择。一旦其中一个选项可用,它就会解锁其“允许获利”和“允许止损”子选项。相反,如果用户从其中一个主选项中删除标志,则其子选项将立即锁定。这要归功于两个事件:ElementEnable和CheckBoxChange。下面的代码介绍了EA处理复选框的算法:
void OnTimer()
for(static int i = 0; i < GuiController::EventsTotal(); i++)
int id;
string el_name;
long lparam;
double dparam;
string sparam;
GuiController::GetEvent(i, el_name, id, lparam, dparam, sparam);
if(id == CheckBoxChange)
ChangeEnableStopAndProfit(el_name, id, lparam, dparam, sparam);
void ChangeEnableStopAndProfit(string el_name, int id, long lparam, double dparam, string sparam)
int id_enable = ElementEnable;
if(el_name == "EURUSDEnable")
GuiController::SendEvent("EURUSDProfit", id_enable, lparam, dparam, sparam);
GuiController::SendEvent("EURUSDStop", id_enable, lparam, dparam, sparam);
else if(el_name == "GBPUSDEnable")
GuiController::SendEvent("GBPUSDProfit", id_enable, lparam, dparam, sparam);
GuiController::SendEvent("GBPUSDStop", id_enable, lparam, dparam, sparam);
一旦通知EA用户选中了其中一个复选框,它就会将当前的
ElementEnable事件“true”发送给GuiController。相反,如果用户取消选中该框,则发送ElementEnable等于'false'。由于EA和表单在不同事件的帮助下进行了交互,因此创建了一种交互效果:表单开始根据用户选择更改子元素的可访问性,尽管控制逻辑本身直接位于EA中。
单选按钮(Radio Button)
单选按钮是一个简单的图形元素,允许用户从预定义的点中选择必要的点:
图 11. 单选按钮
当用户更改他们的选择时,EA会收到两次更改事件:来自未选中按钮和来自选中按钮。使用相同的RadioButtonChange标识符跟踪这两个事件。Here is an example of its use:
for(static int i = 0; i < GuiController::EventsTotal(); i++)
int id;
string el_name;
long lparam;
double dparam;
string sparam;
GuiController::GetEvent(i, el_name, id, lparam, dparam, sparam);
else if(id == RadioButtonChange)
if(lparam == true)
printf("您选择了 " + sparam);
printf("您取消选择了 " + sparam);
lparam参数包含一个标志,通知按钮发生了什么:它是被选中(plaram=true)还是未选中(lparam=false)。单击按钮时,EA在终端中显示类似的消息:
你已经取消选择了EA
您已经选择了指标
您已经取消选择了指标
您已经选择了脚本
图 13. 选择能够输入新符号的符号
第二种模式只为用户提供预先定义的菜单项,而不能选择自定义菜单项(见图11)。还有第三种模式隐藏菜单项,但很少使用,所以我们不会停留在它上面。
所有组合框显示模式都是使用DropDownStyle属性设置的。此属性通常在开发图形界面时设置一次,因此guiController没有允许您更改组合框类型的事件。但是,控制器允许跟踪组合框中元素的选择,以及输入新值。因此,ComboBox支持两个事件:它自己的ComboBoxChange和TextChange。我们的演示表单由两个组合框元素组成。第一个选项提供选择平台(MetaTrader 4/MetaTrader
5),第二个选项选择交易品种。第二个元素在默认情况下被阻止。然而,一旦用户选择了一个平台,他们就可以选择一个交易符号。下面是实现该功能的代码:
for(static int i = 0; i < GuiController::EventsTotal(); i++)
int id;
string el_name;
long lparam;
double dparam;
string sparam;
GuiController::GetEvent(i, el_name, id, lparam, dparam, sparam);
if(id == ComboBoxChange)
if(el_name == "comboBox1")
//-- 用户选择平台后立即取消阻止交易品种列表:
GuiController::SendEvent("comboBox2", ElementEnable, 1, 0.0, "");
printf("组合框 '" + el_name + "' 已改变 " + sparam);
如果我们开始选择组合框元素,演示 EA 将开始在终端中显示用户选择的参数:
在 MetaTrader 5 中组合框 “comboBox1" 已经改变
在 GBPUSD 上组合框 'comboBox2' 已经改变
在 USDJPY 上组合框 'comboBox2' 已经改变
数字选择(NumericUpDown, 数字列表窗口)
数字列表窗口通常用于分析系统,包括交易面板。这就是为什么这个元素是第一个包含在 GuiController中的元素。数字列表窗口允许设置控制输入类型的特定值,只能输入数字。可以使用特殊的小滚动按钮更改步长,也可以显示数字的小数位:
图 14. 数字列表窗口
GuiController 对这种元素类型支持四种事件:
NumericChange 接收或发送包含窗口新数值的事件;
NumericFormatChange 发送一个事件,指定数字的位数容量(在lparam变量中)及其更改步长(在dparam变量中);
NumericMaxChange 发送指定最大可能值的事件;
NumericMinChange 发送指定最小可能值的事件。
NumericUpDown 通过单一的 NumericChange
事件与用户交互。当用户更改此窗口中的数值时,EA将通过事件接收适当的通知。这是唯一可能的用户交互。但是,EA可以配置窗口设置最重要的参数:小数位数、更改步长以及最大和最小可接受值。所有这些参数都取决于EA逻辑及其使用的数据类型,因此,不可能在表单设置中直接定义它们。它们应该在程序启动期间定义。
测试EA包括一个小示例,说明如何使用NumericUpDown。下面提供了从图13上传表单的代码。
int OnInit()
if(ElementType != WINFORM_HIDE)
EventSetMillisecondTimer(100);
EventSetMillisecondTimer(1000);
switch(ElementType)
case WINFORM_NUMERIC:
GuiController::ShowForm(assembly, "NumericForm");
double ask = SymbolInfoDouble(Symbol(), SYMBOL_ASK);
double bid = SymbolInfoDouble(Symbol(), SYMBOL_BID);
double price_step = NormalizeDouble(SymbolInfoDouble(Symbol(), SYMBOL_TRADE_TICK_SIZE), Digits());
long digits = (long)Digits();
GuiController::SendEvent("NumericForm", TextChange, 0, 0.0, "NumericForm (" + Symbol() + ")");
NumericSet("StopLoss", Digits(), ask, (double)LONG_MAX, 0.0, price_step);
NumericSet("TakeProfit", Digits(), bid, (double)LONG_MAX, 0.0, price_step);
break;
return(INIT_SUCCEEDED);
从代码中可以看出,在上传过程中,EA接收到当前交易品种上的数据:其询问和投标价格、小数位数和价格步长。然后,使用特殊的辅助 NumericSet 函数为 NumericUpDown表单元素设置这些参数。让我们看一下它的代码:
void NumericSet(string name, long digits, double init, double max, double min, double step)
int id_foramt_change = NumericFormatChange;
int id_change = NumericChange;
int id_max = NumericMaxChange;
int id_min = NumericMinChange;
long lparam = 0;
double dparam = 0.0;
string sparam = "";
GuiController::SendEvent(name, id_max, lparam, max, sparam);
GuiController::SendEvent(name, id_min, lparam, min, sparam);
GuiController::SendEvent(name, id_change, lparam, init, sparam);
GuiController::SendEvent(name, id_foramt_change, digits, step, sparam);
代码可以自适应地工作,根据它所运行的交易品种,我们将看到不同的价格格式:
图 15. 每个交易品种的单独价格格式
日期时间选择器(DataTimePicker, 日期选择窗口)
此元素在概念上与 NumericUpDown类似,唯一的区别是它允许用户安全地选择日期,而不是数字:
图 16. 在 DateTimePicker元素中选择精确时间
与 NumericUpDown 元素相比,与 DateTimePicker
的交互更加简单,这是因为,与数字格式不同,数字格式取决于EA当前的交易环境,日期格式或多或少具有通用性。它可以在开发表单时设置,然后保持完整。因而 DataTimePicker 支持唯一的
DateTimePickerChange 事件,通过 lparam 参数传递和接收准确的日期。这里是使用元素的一个例子:
for(static int i = 0; i < GuiController::EventsTotal(); i++)
int id;
string el_name;
long lparam;
double dparam;
string sparam;
GuiController::GetEvent(i, el_name, id, lparam, dparam, sparam);
if(id == DateTimePickerChange)
printf("用户设置了新 datetime 值: " + TimeToString((datetime)lparam));
如果我们运行演示 EA 并把 DateTimePicker 作为演示元素,窗口类似于图15中出现的窗口,如果我们开始以各种方式更改日期和时间,则EA将响应这些事件,并在日志中显示新的日期和时间值:
User set a new datetime value: 2019.05.16 14:21
User set a new datetime value: 2019.05.16 10:21
User set a new datetime value: 2021.05.16 10:21
然而,与元素的交互比看起来要复杂一些,MQL 和 C#
有不同的时间格式,MQL采用简化的POSIX时间格式,分辨率为1秒,最早的可能日期为1970.01.01,而C#采用更高级的时间格式,分辨率为100纳秒。因此,为了与不同的系统交互,我们需要开发将一种时间格式转换为另一种时间格式的时间转换器。在
GuiController 中就使用了这样的转换器,它设计为 MtConverter 公共静态类:
public static long ToMqlDateTime(DateTime date_time)
DateTime tiks_1970 = new DateTime(1970, 01, 01);
if (date_time < tiks_1970)
return 0;
TimeSpan time_delta = date_time - tiks_1970;
return (long)Math.Floor(time_delta.TotalSeconds);
public static DateTime ToSharpDateTime(long mql_time)
DateTime tiks_1970 = new DateTime(1970, 01, 01);
if (mql_time <= 0 || mql_time > int.MaxValue)
return tiks_1970;
TimeSpan time_delta = new TimeSpan(0, 0, (int)mql_time);
DateTime sharp_time = tiks_1970 + time_delta;
return sharp_time;
目前,它只包含两个方法:ToMqlDateTime 将 DateTime转换为 MQL。第二个方法将MQL时间值转换为C# DateTime结构,结果正好相反。由于datetime(mql)和
datetime(C#)类型彼此不兼容,因此转换是通过常规的“long”类型执行的,这对于所有系统都是相同的。因此,在接收到 DateTimePikerChange
事件时,我们需要显式地将lparam转换为datetime以接收正确的时间值:
printf("User set new datetime value: " + TimeToString((datetime)lparam));
我们不仅可以获得新的值,而且可以用类似的方式自己设定它们。例如,我们可以使用以下命令设置当前终端时间:
GuiController::SendEvent("DateTimePicker", DateTimePickerChange, ((long)TimeCurrent()), 0.0, "");
ElementHide 和 ElementEnable - 隐藏及禁用指定元素
有一些通用事件允许您控制任何 WinForms 元素,其中就有 ElementHide 和 ElementEnable 事件。如需隐藏元素,按如下方法使用 ElementHide :
GuiController::SendEvent("HideGroup", ElementHide, true, 0.0, "");
其中 HideGroup 是需要隐藏的元素名称,如需显示元素,就做对应的调用:
GuiController::SendEvent("HideGroup", ElementHide, false, 0.0, "");
请注意所使用元素的名称,WindowsForm中的单个元素可能包含内部元素,这被称为元素嵌套(elements nesting)。这样的安排允许在组级别管理所有元素。在示例中,文本框与嵌套在其中的“label”标题一起使用。在给定的频率下,框中的所有元素都将消失,然后再次出现:
图 17. 从EA中隐藏任意图形元素
此外,可以使每个元素不可用,虽然它不会消失,但使用它变得不可使用。这是一个有用的选项,允许设计更复杂和直观的界面。我们已经在标志描述中提到使用此事件。可以通过发送以下事件使元素不可用:
GuiController::SendEvent("element", ElementEnable, false, 0.0, "");
只需将“false”标志替换为“true”,即可再次激活元素:
GuiController::SendEvent("element", ElementEnable, true, 0.0, "");
AddItem — 添加子元素
某些元素可能包含其他元素,在程序启动之前,这些子元素的内容通常是未知的。假设我们需要显示一个交易品种列表,这样用户就可以选择他们需要的交易品种。出于这些目的,最合理的做法是使用组合框:
图 18. 预先设置的交易品种列表
但是,在编译图形表单的阶段不能提前输入交易品种,因为可用交易品种的列表可能因代理而异。因此,此类型的内容应动态形成。使用的命令是 AddItem
。最简单的方法是列出 MarketWatch 中所有可用的交易品种,并将其作为菜单项添加:
int OnInit()
EventSetMillisecondTimer(100);
GuiController::ShowForm(assembly, "SendOrderForm");
for(int i = 0; i < SymbolsTotal(true); i++)
GuiController::SendEvent("SymbolComboBox", AddItem, 0, 0, SymbolName(i, true));
return(INIT_SUCCEEDED);
如您所见,这个命令非常容易使用。尽管该命令是通用的,但并非所有元素都允许向其添加子元素,目前,GuiController仅支持组合框的此事件,然而,这足以构建高效的图形界面。此列表将来可能会扩展。
Exception — 接收异常的事件
我们不可能总是写没有错误的程序,此外,在一些情况下,可能在无法预知的场景下程序执行时会出现错误。在这些情况下,能够获得所发生的数据的反馈是必要的。Exception 事件就是为了这种交互而提供的,它是由 GuiController 本身生成,再发送给到 MQL EA 中的。GuiController 在两种情况下会创建错误消息:
让我们逐个分析这些选项。为了演示第一个选项,让我们返回演示代码,即显示 NumericUpDown元素的选项。在这个启动选项中,调用一个特殊的 NumericSet函数。它会设置 NumericUpDown 元素的工作范围:
void NumericSet(string name, long digits, double init, double max, double min, double step)
int id_foramt_change = NumericFormatChange;
int id_change = NumericChange;
int id_max = NumericMaxChange;
int id_min = NumericMinChange;
long lparam = 0;
double dparam = 0.0;
string sparam = "";
GuiController::SendEvent(name, id_min, lparam, min, sparam);
GuiController::SendEvent(name, id_change, lparam, init, sparam);
GuiController::SendEvent(name, id_foramt_change, digits, step, sparam);
此函数已被轻微更改,因此未设置元素的最大值(其中的相应字符串被注释掉),如果在黄金图表上编译后运行此表单,它会突然停止显示当前价格:
图 19. 价格设置表单中的零值
发生了什么?异常系统是用来回答这个问题的。每个异常都可以通过 GuiController::GetEvent获得,就像其他消息一样:
for(static int i = 0; i < GuiController::EventsTotal(); i++)
int id;
string el_name;
long lparam;
double dparam;
string sparam;
GuiController::GetEvent(i, el_name, id, lparam, dparam, sparam);
if(id == Exception)
printf("Unexpected exception: " + sparam);
消息输出已经说了很多:
意外异常:“1291,32”值对于“Value”是不可接受的,"Value”应在“Minimum”到“Maximum”的范围内。
参数名称: Value
意外异常: '1291,06' 对于 'Value' 是不可接受的,"Value”应在“Minimum”到“Maximum”的范围内。
参数名称: Value
实际情况是 NumericUpDown 默认的工作范围是从 0 到
100,因此,设置黄金的当前价格(每金衡盎司1292美元)会导致错误。要避免这种情况,请使用NumericMaxChange事件通过程序扩展可接受值的范围。这就是 NumericSet 函数中注释掉的代码所做的。
当发送错误事件时,调用异常的第二个选项是可能出现的,例如,可以将事件发送到不存在的目标:
GuiController::SendEvent("empty", ElementEnable, 0, 0.0, "");
回应将如下:
意外异常: SendEvent:未找到名为“empty”的元素
我们还可以尝试发送不支持该项目的事件。例如,让我们尝试将以下文本添加到“止损水平”输入字段(NumericUpDown元素类型):
GuiController::SendEvent("StopLoss", AddItem, 0, 0.0, "New Text");
答案将非常简洁:
意外异常:元素“StopLos”不支持“Add Item”事件
异常系统为创建复杂的图形应用程序提供了宝贵的帮助,这种应用程序中的错误是不可避免的,开发速度和方便程度取决于程序员识别它们的速度。
可用图形元素和事件的汇总表格
将支持的图形元素系统化,与 GuiController协同工作是合理的。为此,我们创建一个表,其中包含有关这些元素的摘要信息以及在GuiController中使用它们的方法。“Sample
usage(示例用法)”列包含一个简短的示例代码,说明如何从MQL程序中使用此元素。所讨论的代码应被视为使用元素的总体模式的一部分。例如,第一个示例的代码(MessageBox):
string msg = "!!!|操作被取消|严重错误";
GuiController::SendEvent("ButtonForm", MessageBox, LockControl, OK, msg);
应当在下面的环境中考虑:
void OnTimer
for(static int i = 0; i < GuiController::EventsTotal(); i++)
int id;
string el_name;
long lparam;
double dparam;
string sparam;
GuiController::GetEvent(i, el_name, id, lparam, dparam, sparam);
if(id == MessageBox)
string msg = "!!!|操作被取消|严重错误";
GuiController::SendEvent("ButtonForm", MessageBox, LockControl, OK, msg);
该模式在其他示例中也以类似的方式使用。
GuiController::GetEvent(i, el_name, id, lparam, dparam, sparam);
if(lparam == true)
printf("您选择了 " + sparam);
printf("您取消选择了 " + sparam);
GuiController::ShowForm(assembly, "SendOrderForm");
for(int i = 0; i < SymbolsTotal(true); i++)
GuiController::SendEvent("SymbolComboBox", AddItem, 0, 0, SymbolName(i, true));
我们分析了Windows窗体的主要图形元素以及与之交互的示例。这些元素很少,但它们代表了任何图形应用程序的主干。尽管它们不包括表格(交易中另一个非常重要的元素),但是您仍然可以使用它们来创建功能性的图形应用程序。
最新的 GuiController 版本附在下面,此外,还可以从GitHub存储库系统复制此版本。可以在此处找到库版本: https://github.com/PublicMqlProjects/MtGuiController.git.
您还可以复制示范窗体项目。它位于
https://github.com/PublicMqlProjects/GuiControllerElementsDemo.git.
文章的第一部分,了解如何通过版本控制系统获得最新的库版本。所附文件包含所有项目的完整源代码。其中有三个:EA调用带有元素的窗体,DemoForm.exe 构建中的一组表单,编译的
Guicontroller(source\mql5\libraries\guicontroller.dll)以及一个源代码(source\sharp\guicontroller)。另外,请注意,演示 EA
需要到已启动表单的绝对路径。在您的PC上,它将与 “assembly” EA参数中指定的不同,因此将其替换为实际路径。
本文由MetaQuotes Ltd译自俄文
原文地址: https://www.mql5.com/ru/articles/6549
附加的文件 |
下载ZIP
Source.zip
(50.14 KB)