资源

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

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

 

PlaySound()

调用 PlaySound() 函数的示例:

//+------------------------------------------------------------------+
//| 调用标准OrderSend() 并播放一段音频                                  |
//+------------------------------------------------------------------+
void OrderSendWithAudio(MqlTradeRequest  &request, MqlTradeResult &result)
  {
  //--- 发送一个请求到服务器
   OrderSend(request,result);
   //--- 如果请求被采纳,播放音频Ok.wav 
   if(result.retcode==TRADE_RETCODE_PLACEDPlaySound("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。

Properties of the OBJ_BITMAP_LABEL object

图形界面的按钮大小会根据图像大小自动调整。通过在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) 无效,不能手动更改:

using_resource

 

使用其他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对象。第一个对象的图像在中间有红色条纹。

res_variables

应用资源的重要优势就是资源文件在编译成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()文件函数