资源

在MQL5程序中使用图形和声音

MQL5程序允许使用声音和图形文件:

PlaySound()

调用 PlaySound() 函数的示例:

//+------------------------------------------------------------------+

//| 调用标准OrderSend() 并播放一段音频                                  |

//+------------------------------------------------------------------+

void OrderSendWithAudio(MqlTradeRequest  &request, MqlTradeResult &result)

  {

  //--- 发送一个请求到服务器

   OrderSend(request,result);

   //--- 如果请求被采纳,播放音频Ok.wav 

   if(result.retcode==TRADE_RETCODE_PLACED) PlaySound("Ok.wav");

   //--- 如果失败,播放文件timeout.wav的警告音 

   else PlaySound("timeout.wav");

  }

该示例表达了如何播放来自文件 'Ok.wav' 和 'timeout.wav'的音频,这些文件包含在标准程序包中。这些文件位于 terminal_directory\Sounds文件夹。 在这里 terminal_directory 是文件夹,MetaTrader 5 客户端在这里启动。程序端目录的位置可以通过以下方式,从mql5程序找到:

//--- 文件夹,存储程序端数据的地方

   string terminal_path=TerminalInfoString(TERMINAL_PATH);

您不仅可以使用来自terminal_directory\Sounds文件夹的音频文件,还可以使用位于子文件夹terminal_data_directory\MQL5的任何音频文件。 您可以通过程序端菜单“文件”->"打开”程序端数据或使用编程方式找到程序端数据目录的位置:

//--- 文件夹,存储程序端数据的地方

   string terminal_data_path=TerminalInfoString(TERMINAL_DATA_PATH);

例如,如果Demo.wav音频文件位于terminal_data_directory\MQL5\Files,那么调用PlaySound() 应该按以下方式编写:

//--- 播放来自terminal_directory_data\MQL5\Files\Demo.wav文件夹的Demo.wav 

   PlaySound("\\Files\\Demo.wav");

请注意在评论中,文件路径使用“\”反斜杠编写,而在函数中使用“\\"。

当指定路径时,通常使用双反斜杠作为分隔符,因为单反斜杠是处理程序源代码中的字符串常数和字符常数时,编译器的控制符号。

用NULL参数调用 PlaySound() 函数以停止回放:

//--- 用NULL参数调用PlaySound()来停止回放

   PlaySound(NULL);

ObjectCreate()

EA交易的示例,使用ObjectCreate()函数创建一个图形标签 (OBJ_BITMAP_LABEL) 。

string label_name="currency_label";        // OBJ_BITMAP_LABEL 对象的名称

string euro      ="\\Images\\euro.bmp";    // 文件terminal_data_directory\MQL5\Images\euro.bmp的路径

string dollar    ="\\Images\\dollar.bmp";  // 文件terminal_data_directory\MQL5\Images\dollar.bmp的路径

//+------------------------------------------------------------------+

//| EA初始化函数                                                     |

//+------------------------------------------------------------------+

int OnInit()

  {

//--- 如果还未创建按钮OBJ_BITMAP_LABEL,请创建

   if(ObjectFind(0,label_name)<0)

     {

      //--- 尝试创建对象OBJ_BITMAP_LABEL

      bool created=ObjectCreate(0,label_name,OBJ_BITMAP_LABEL,0,0,0);

      if(created)

        {

         //--- 连接图表左上角的按钮

         ObjectSetInteger(0,label_name,OBJPROP_CORNER,CORNER_RIGHT_UPPER);

         //--- 现在设置对象属性

         ObjectSetInteger(0,label_name,OBJPROP_XDISTANCE,100);

         ObjectSetInteger(0,label_name,OBJPROP_YDISTANCE,50);

         //--- 重置过去错误的代码为0

         ResetLastError();

         //--- 下载图片显示按钮的”按键“状态

         bool set=ObjectSetString(0,label_name,OBJPROP_BMPFILE,0,euro);

         //--- 测试结果

         if(!set)

           {

            PrintFormat("Failed to download image from file %s. Error code %d",euro,GetLastError());

           }

         ResetLastError();

         //--- 下载图片显示按钮的”无按键“状态

         set=ObjectSetString(0,label_name,OBJPROP_BMPFILE,1,dollar);



         if(!set)

           {

            PrintFormat("Failed to download image from file %s. Error code %d",dollar,GetLastError());

           }

         //--- 发送图表评论刷新,以便于无需标记即可立即显示按钮

         ChartRedraw(0);

        }

      else

        {

         //--- 创建对象失败,公告

         PrintFormat("Failed to create object OBJ_BITMAP_LABEL. Error code %d",GetLastError());

        }

     }

//---

   return(INIT_SUCCEEDED);

  }

//+------------------------------------------------------------------+

//| 专家去初始化函数                                                   |

//+------------------------------------------------------------------+

void OnDeinit(const int reason)

  {

//--- 删除图表对象 

   ObjectDelete(0,label_name);

  }

创建和设置名为currency_label的图形对象通过currency_label函数实行。图形文件的路径设置在全局变量 eurodollar, 用双反斜杠作为分隔符:

string euro      ="\\Images\\euro.bmp";    // terminal_dara_directory\MQL5\Images\euro.bmp文件的路径

string dollar    ="\\Images\\dollar.bmp";  // terminal_dara_directory\MQL5\Images\dollar.bmp文件的路径

文件位于文件夹 terminal_data_directory\MQL5\Images。

对象 OBJ_BITMAP_LABEL 实际上是一个按钮,根据按钮的状态(已按或未按)展示两个图像中的一个:euro.bmp 或 dollar.bmp。

图形界面的按钮大小会根据图像大小自动调整。通过在OBJ_BITMAP_LABEL对象上点击鼠标左键来改变图像( 属性中必须设置"禁用选择")。OBJ_BITMAP对象以相同方式创建 - 它用于创建必要的背景图像。

OBJPROP_BMPFILE 属性的值,负责对象OBJ_BITMAP 和 OBJ_BITMAP_LABEL的外表,可以动态地变化。这允许为mql5程序创建各种交互式用户界面。

包括mql5程序编译期间的可执行文件资源

mql5程序可能需要许多图像和音频文件格式的不同下载资源。为了消除移动MQL5可执行文件时转移所有这些文件的需要,应该会使用到编译器#resource指令:

 #resource path_to_resource_file

#resource 指令告诉编译器指定路径path_to_resource_file的资源应该被包括到可执行EX5 文件。因此,所有这些必要的图像和音频文件可以直接放在EX5文件,以便在您想要在不同程序端运行程序时,无需分别转移其中使用的文件。任何EX5文件都可以包含资源,而任何EX5程序都可以使用来自其他EX5程序的资源。

BMP 和 WAV 格式的文件在包含到EX5文件之前自动压缩。这表示除了创建完整的MQL5程序外,与通常的MQL5编程方式相比较,使用资源还允许在使用图形和音频时,减少所需文件的总大小。

资源文件大小一定不要超过16Mb。

通过编译器搜索指定的资源

插入资源使用命令 #resource "<path to the resource file>"

 #resource "<path_to_resource_file>"

常量字符串<path_to_resource_file> 的长度不得超过63个字符。

编译器根据以下顺序在指定路径搜索资源:

  • 如果单反斜杠"\"分隔符(写成"\\")放在路径前面,它搜索目录terminal_data_directory\MQL5\涉及的资源。
  • 如果没有反斜杠,则搜索资源编写所在的源文件的位置涉及的资源。

资源路径不能包括子字符串"..\\" 和 ":\\"。

资源包含的示例:

//--- 正确的资源规范

#resource "\\Images\\euro.bmp" // euro.bmp 位于 terminal_data_directory\MQL5\Images\

#resource "picture.bmp"        // picture.bmp 位于与源文件相同的目录

#resource "Resource\\map.bmp"  // 资源位于source_file_directory\Resource\map.bmp

 

//--- 错误的资源规范

#resource ":picture_2.bmp"     // 不能包括 ":"

#resource "..\\picture_3.bmp"  // 不能包括 ".."

#resource "\\Files\\Images\\Folder_First\\My_panel\\Labels\\too_long_path.bmp" //超过 63 个交易品种

使用资源

资源名称

当资源使用#resource指令声明后,它可以用于程序的任何部分。资源的名称是在行开始没有反斜杠的路径,来设置资源的路径。若要在代码中使用您自己的资源,特殊符号 "::" 应该添加在资源名称的前面。

示例:

//--- 评论中资源规范和其名称的示例

#resource "\\Images\\euro.bmp"          // 资源名称 - Images\euro.bmp

#resource "picture.bmp"                 // 资源名称 - picture.bmp

#resource "Resource\\map.bmp"           // 资源名称 - Resource\map.bmp

#resource "\\Files\\Pictures\\good.bmp" // 资源名称 - Files\Pictures\good.bmp

#resource "\\Files\\Demo.wav";          // 资源名称 - Files\Demo.wav"

#resource "\\Sounds\\thrill.wav";       // 资源名称 - Sounds\thrill.wav"

...



//--- 资源利用

ObjectSetString(0,bitmap_name,OBJPROP_BMPFILE,0,"::Images\\euro.bmp");

...

ObjectSetString(0,my_bitmap,OBJPROP_BMPFILE,0,"::picture.bmp");

...

set=ObjectSetString(0,bitmap_label,OBJPROP_BMPFILE,1,"::Files\\Pictures\\good.bmp");

...

PlaySound("::Files\\Demo.wav");

...

PlaySound("::Sounds\\thrill.wav");

请注意,当设置资源到OBJ_BITMAP 和 OBJ_BITMAP_LABEL对象的图像时,OBJPROP_BMPFILE 属性的值不能手动更改。例如,为了创建OBJ_BITMAP_LABEL,我们只有资源 euro.bmp 和 dollar.bmp。

#resource "\\Images\\euro.bmp";    // euro.bmp位于terminal_data_directory\MQL5\Images\

#resource "\\Images\\dollar.bmp";  // dollar.bmp位于terminal_data_directory\MQL5\Images\

当查看该对象属性时,我们将看到属性BitMap 文件 (On) 和 BitMap 文件 (Off) 无效,不能手动更改:

使用其他mql5程序的资源

资源使用方面还有另一个优势 - 在任何mql5程序中,也可以使用另一个EX5文件的资源。因此,来自一个EX5文件的资源可以用在许多其他mql5程序。

若要使用来自另一个文件的资源名称,它应该被指定为 <path_EX5_file_name>::<resource_name>。例如,假设Draw_Triangles_Script.mq5 脚本在文件triangle.bmp中包含一个图像资源:

 #resource "\\Files\\triangle.bmp"

然后脚本本身使用的其名称将类似"Files\triangle.bmp",并且若要使用它, "::" 应该添加到资源名称。

//--- 使用脚本资源

ObjectSetString(0,my_bitmap_name,OBJPROP_BMPFILE,0,"::Files\\triangle.bmp");

若要使用另一个程序的相同资源,例如EA交易,我们需要添加资源名称路径到terminal_data_directory\MQL5\相对的EX5文件和脚本EX5文件的名称 - Draw_Triangles_Script.ex5。假设脚本位于标准文件夹 terminal_data_directory\MQL5\Scripts\, 那么应该按照以下方式调用:

//--- 使用EA中的脚本资源

ObjectSetString(0,my_bitmap_name,OBJPROP_BMPFILE,0,"\\Scripts\\Draw_Triangles_Script.ex5::Files\\triangle.bmp");

如果从另一个EX5调用资源时没有指定可执行文件的路径,那么可执行文件在包括调用资源程序的相同文件夹中搜索。这意味着如果EA交易调用来自Draw_Triangles_Script.ex5的资源而没有指定路径,就像这样:

//--- 调用未指定路径的EA脚本资源

ObjectSetString(0,my_bitmap_name,OBJPROP_BMPFILE,0,"Draw_Triangles_Script.ex5::Files\\triangle.bmp");

那么如果EA位于terminal_data_directory\MQL5\Experts\,则文件将在文件夹terminal_data_directory\MQL5\Experts\中搜索。

 

使用包括资源的自定义指标

一个或多个自定义指标对于MQL5应用程序操作可能是必需的。所有这些都包含在可执行MQL5程序的代码中。包含作为资源的指标简化了应用程序的分布。

下面就是包含和使用位于terminal_data_folder\MQL5\Indicators\目录的SampleIndicator.ex5自定义指标的示例:

//+------------------------------------------------------------------+

//|                                                     SampleEA.mq5 |

//|                        Copyright 2013, MetaQuotes Software Corp. |

//|                                              https://www.mql5.com |

//+------------------------------------------------------------------+

#resource "\\Indicators\SampleIndicator.ex5"

int handle_ind;

//+------------------------------------------------------------------+

//| EA初始化函数                                                     |

//+------------------------------------------------------------------+

int OnInit()

  {

//---

   handle_ind=iCustom(_Symbol,_Period,"::Indicators\\SampleIndicator.ex5");

   if(handle_ind==INVALID_HANDLE)

     {

      Print("Expert: iCustom call: Error code=",GetLastError());

      return(INIT_FAILED);

     }

//--- ...

   return(INIT_SUCCEEDED);

  }

OnInit() 函数自定义指标创建一个或多个副本时,这种情况需要特别考虑。请谨记资源应该按照以下方式指明:<path_EX5_file_name>::<resource_name>。

例如,如果SampleIndicator.ex5指标作为资源包含在SampleEA.ex5 EA交易,在自定义指标初始化函数调用iCustom()指定的路径如下: "\\Experts\\SampleEA.ex5::Indicators\\SampleIndicator.ex5"。当该路径明确设置时,SampleIndicator.ex5自定义指标严格连接到SampleEA.ex5 EA交易,失去独立工作的能力。

路径本身可以使用GetRelativeProgramPath() 函数接收。用法示例如下:

//+------------------------------------------------------------------+

//|                                              SampleIndicator.mq5 |

//|                        Copyright 2013, MetaQuotes Software Corp. |

//|                                              https://www.mql5.com |

//+------------------------------------------------------------------+

#property indicator_separate_window

#property indicator_plots 0

int handle;

//+------------------------------------------------------------------+

//| 自定义指标初始化函数                                                |

//+------------------------------------------------------------------+

int OnInit()

  {

//--- 提供自身链接的错误方式

//--- 字符串路径="\\Experts\\SampleEA.ex5::Indicators\\SampleIndicator.ex5";  

//--- 接收自身链接的正确方式

  string path=GetRelativeProgramPath();

//--- 指标缓冲映射

   handle=iCustom(_Symbol,_Period,path,0,0);

   if(handle==INVALID_HANDLE)

     {

      Print("Indicator: iCustom call: Error code=",GetLastError());

      return(INIT_FAILED);

     }

   else Print("Indicator handle=",handle);

//---

   return(INIT_SUCCEEDED);

  }

///....

//+------------------------------------------------------------------+

//| GetRelativeProgramPath                                           |

//+------------------------------------------------------------------+

string GetRelativeProgramPath()

  {

   int pos2;

//--- 接收应用程序的绝对路径

   string path=MQLInfoString(MQL_PROGRAM_PATH);

//--- 找出 "\MQL5\" 字符串的位置

   int    pos =StringFind(path,"\\MQL5\\");

//--- 子字符串未找到 - 错误

   if(pos<0)

      return(NULL);

//--- 跳过 "\MQL5" 目录

   pos+=5;

//--- 跳过多余的 '\' 交易品种

   while(StringGetCharacter(path,pos+1)=='\\')

      pos++;

//--- 如果这是一个资源,返回MQL5目录的相对路径

   if(StringFind(path,"::",pos)>=0)

      return(StringSubstr(path,pos));

//--- 为第一个MQL5子目录找到一个分隔符 (例如,MQL5\Indicators)

//--- 如果没找到,返回MQL5目录相对的路径

   if((pos2=StringFind(path,"\\",pos+1))<0)

      return(StringSubstr(path,pos));

//--- 返回子目录相对的路径(例如, MQL5\Indicators)

   return(StringSubstr(path,pos2+1));

  }

//+------------------------------------------------------------------+

//| 自定义指标重复函数                                                  |

//+------------------------------------------------------------------+

int OnCalculate(const int rates_total,

                const int prev_calculated,

                const int begin,

                const double& price[])

  {

//--- 返回prev_calculated值用于下次调用

   return(rates_total);

  }

 

资源变量

资源可以使用资源变量来声明并被当做适当类型的变量。声明格式:

#resource path_to_the_resource_file as resource_variable_type resource_variable_name

示例声明:

#resource "data.bin" as int ExtData[]             // 声明包含data.bin 文件数据的数字数组

#resource "data.bin" as MqlRates ExtData[]        // 声明包含data.bin文件数据的 示例结构数组

//--- 字符串

#resource "data.txt" as string ExtCode            // 声明包含data.txt文件数据的字符串(支持ANSI,UTF-8 和 UTF-16 编码)

#resource "data.txt" as string ExtCode[]          // 声明包含data.txt文件字符串的数组(支持ANSI,UTF-8 和 UTF-16 编码)

//--- 图形资源

#resource "image.bmp" as bitmap ExtBitmap[]       // 声明包含BMP位图文件的一维数组,数组大小 = 高 * 宽

#resource "image.bmp" as bitmap ExtBitmap2[][]    // 声明包含BMP位图文件的二维数组,数组大小 [高][宽]

这种声明情况下,资源数据只能通过变量来解决,通过"::<rsource name>"的自动解决 无法工作。

#resource "\\Images\\euro.bmp" as bitmap euro[][]

#resource "\\Images\\dollar.bmp"

//+------------------------------------------------------------------+

//|  OBJ_BITMAP_LABEL 对象使用资源创建函数   |

//+------------------------------------------------------------------+

void Image(string name,string rc,int x,int y)

  {

   ObjectCreate(0,name,OBJ_BITMAP_LABEL,0,0,0);

   ObjectSetInteger(0,name,OBJPROP_XDISTANCE,x);

   ObjectSetInteger(0,name,OBJPROP_YDISTANCE,y);

   ObjectSetString(0,name,OBJPROP_BMPFILE,rc);

  }

//+------------------------------------------------------------------+

//| 脚本程序起始函数                                    |

//+------------------------------------------------------------------+

void OnStart()

  {

//--- 输出存储在欧元资源变量的图像大小[宽,高] 

   Print(ArrayRange(euro,1),", ",ArrayRange(euro,0));

//--- 改变欧元图像 - 在中间绘制红色横纹

   for(int x=0;x<ArrayRange(euro,1);x++)

      euro[ArrayRange(euro,1)/2][x]=0xFFFF0000;

//--- 使用资源变量创建图形资源

   ResourceCreate("euro_icon",euro,ArrayRange(euro,1),ArrayRange(euro,0),0,0,ArrayRange(euro,1),COLOR_FORMAT_ARGB_NORMALIZE);

//--- 创建欧元图形标签对象,并在此设置euro_icon资源图像

   Image("Euro","::euro_icon",10,40);

//--- 应用资源的另一个方法,我们不能绘制

   Image("USD","::Images\\dollar.bmp",15+ArrayRange(euro,1),40);

//--- 不提供解决euro.bmp资源的直接方法,因为它已经通过欧元资源变量进行声明

   Image("E2","::Images\\euro.bmp",20+ArrayRange(euro,1)*2,40); // 将会发生执行时间错误

  }

脚本执行结果 – 三个对象中只能创建两个OBJ_BITMAP_LABEL对象。第一个对象的图像在中间有红色条纹。

应用资源的重要优势就是资源文件在编译成EX5可执行文件之前自动解压。因此,使用资源变量可以使您将全部必要数据直接放入可执行文件EX5以及减少相较于MQL5程序传统编写方式的文件的数量和总大小。

使用资源变量可以非常方便在市场发布产品。

特点

  • 特殊的位图资源变量类型告诉编译者资源使一个图像。 这种变量接收uint类型。
  • 位图类型数组资源变量可以有两种维度。在这种情况下,数组大小定义为[image_height ][ image_width ]。如果指定了一维数组,那么元素数量则等于image_height*image_width。
  • 下载24-位图像时,阿尔法通道组件的全部图像像素设置为255.
  • 下载没有阿尔法通道的32-位图时,阿尔法通道组件的全部图像像素设置为255。
  • 下载有阿尔法通道的32-位图时,不以任何方式处理像素。
  • 资源文件大小不能超过128 Mb。
  • 通过存在的BOM(标题)自动编码检测执行字符串文件。如果没有BOM,则通过文件内容定义编码。支持ANSI,UTF-8和UTF-16编码文件。当阅读文件数据时,全部字符串转换为Unicode。

OpenCL程序

使用资源字符串变量可以极大的促进一些程序的开发。例如,您可以在独立的CL文件内编写一个OpenCL 程序的编码,然后将其包含为一个字符串放入您的MQL5程序资源。

#resource "seascape.cl" as string cl_program

...

int context;

if((cl_program=CLProgramCreate(context,cl_program)!=INVALID_HANDLE)

  {

   //--- 通过OpenCL程序执行进一步操作

  }

在这个示例中,如果没有使用cl_program资源变量,那么您需要编写整个代码作为一个大的字符串。

另见

ResourceCreate()ResourceSave()PlaySound()ObjectSetInteger()ChartApplyTemplate()文件函数