文件或文件夹选择对话框
在处理文件和文件夹的函数组中,有一个函数允许从用户交互式请求文件或文件夹的名称,以及一组文件的名称,以便将该信息传递给一个 MQL 程序。调用 FileSelectDialog 函数可以使一个用于选择文件和文件夹的标准 Windows 窗口出现在终端中。
由于该对话框中断 MQL 程序的执行直至其关闭,该函数仅在以单独线程执行的两种类型的 MQL 程序中允许调用:EA 和脚本(参见 MQL 程序类型)。在指标和服务中禁止使用该函数:前者在终端的接口线程中执行(阻止它们将会冻结对应金融工具图表的更新),而后者在后台执行,不能访问用户接口。
该函数处理的文件系统的所有元素均位于沙盒中,即位于当前终端副本或测试程序(如果程序在测试程序中运行)的目录中的 MQL5/Files 子文件夹中。
如果 FSD_COMMON_FOLDER 标志出现在 flags 参数中(参见下文),则使用所有终端的公用沙盒 Users/<user>...MetaQuotes/Terminal/Common/Files。
对话框的外观取决于 Windows 操作系统。以下显示了其中一种可能的界面选项。
Windows 文件和文件夹选择对话框
int FileSelectDialog(const string caption, const string initDir, const string filter,
uint flags, string &filenames[], const string defaultName)
该函数显・示一个用于打开或创建文件或选择文件夹的标准 Windows 对话框。标题在 caption 参数中指定。如果值为 NULL,则使用标准标题:“打开”(用于读取)、“另存为”(用于写入文件)或者“选择文件夹”,取决于 flags 参数中的标志。
initDir 参数允许你设置将为之打开对话框的初始文件夹。如果设为 NULL,则将显示 MQL5/Files 文件夹的内容。如果在 initDir 中指定了不存在的路径,则同样会使用上述文件夹。
使用 filter 参数可以限制将在对话框中显示的文件扩展名集合。其它格式的文件将被隐藏。NULL 表示无限制。
filter 字符串的格式如下:
"<description 1>|<extension 1>|<description 2>|<extension 2>..." |
可以使用任何字符串作为 description。可以编写带替换字符 '*' 和 '?' 的任何筛选器(这两个替换字符在 查找文件和文件夹 中介绍过)作为 extensions。定界符为 '|' 符号。
由于相邻说明和扩展名形成一个逻辑相关对,因此行中的元素总数必须为偶数,而定界符的数量必须为奇数。
每个说明和扩展名组合在对话框的下拉列表中生成一个单独的选择。向用户显示的是说明,而扩展名用于筛选。
例如,“文本文档 (*.txt)|*.txt|所有文件 (*.*)|*.*”,其中第一个扩展名“文本文档 (*.txt)|*.txt”将被选择为默认文件类型。
在 flags 参数中,你可以指示位掩码,使用 '|' 运算符指定操作模式。为其定义以下常量:
- FSD_WRITE_FILE 文件写入模式(“另存为”)。在没有该标志的情况下,默认使用读模式(“打开”)。如果存在该标志,则允许输入任意新名称,无论 FSD_FILE_MUST_EXIST 标志如何。
- FSD_SELECT_FOLDER 文件夹选择模式(仅一个并且仅当存在时)。有了该标志,除了 FSD_COMMON_FOLDER 以外的所有其它标志均被忽略,或者会导致错误。不能显式请求创建文件夹,但可以在对话框中交互式创建一个文件夹并立即选择该文件夹。
- FSD_ALLOW_MULTISELECT 允许在读模式下选择多个文件。如果指定了 FSD_WRITE_FILE 或 FSD_SELECT_FOLDER,则该标志被忽略。
- FSD_FILE_MUST_EXIST 选择的文件必须存在。如果用户试图指定一个任意名称,则该对话框将显示一个警告并保持打开。如果指定了 FSD_WRITE_FILE 模式,则该标志被忽略。
- FSD_COMMON_FOLDER 对话框为所有客户终端的公用沙盒打开。
该函数将以选定的文件或文件夹的名称填充 filenames 字符串数组。如果该数组为动态数组,则其大小更改以适配实际数据量,尤其是如果没有选择任何内容,则扩展或截断至 0。如果数组为 fixed 数组,则其必须足够大以容纳预期数据。否则将发生错误 4007 (ARRAY_RESIZE_ERROR)。
defaultName 参数指定默认文件/文件夹名称,在打开对话框后,该名称会立即代入对应的输入字段中。如果参数为 NULL,则该字段将初始为空。
如果设置了 defaultName 参数,则在 MQL 程序的非可视化测试期间,FileSelectDialog 调用将返回 1,而 defaultName 值本身将被拷贝到 filenames 数组。
该函数将返回选择的项目数(如果用户未选择任何项目,则返回 0),如果出错,则返回 -1。
参见 FileSelect.mq5 脚本以了解该函数用法示例。在 OnStart 函数中,我们将以不同设置依次调用 FileSelectDialog。只要用户选择了某项内容(未单击对话框中的“取消”按钮),则测试将继续直至最后一步(即使函数执行时出现错误代码)。
void OnStart()
|
首先,我们将要求用户从 "MQL5Book" 文件夹中选择一个文件。你可以选择一个现有文件或输入一个新文件名(因为没有 FSD_FILE_MUST_EXIST 标志)。
Print("Open a file");
|
假设该文件夹包含至少 5 个随本书交付提供的文件,在这里选择其中一个。
然后我们将在“写入”模式下作出一个类似的请求(使用 FSD_WRITE_FILE 标志)。
Print("Save as a file");
|
其中,用户也将能够选择一个现有文件或输入一个新名称。编程人员必须检查用户是否将要覆写一个现有文件(对话框不会生成警告)。
现在我们在一个动态数组中检查多个文件的选择 (FSD_ALLOW_MULTISELECT)。
if(PRTF(FileSelectDialog(NULL, "MQL5book", NULL,
|
存在 FSD_FILE_MUST_EXIST 标志则表示如果你试图输入一个新名称,则对话框将会显示警告并保持打开。
如果我们试图以类似方式在一个固定大小数组中选择超过一个文件,则将会出错。
Print("Open multiple files (fixed, choose more than 1 file for error)");
|
最后,我们检查文件夹操作 (FSD_SELECT_FOLDER)。
Print("Select a folder");
|
在此情况下,不存在的子文件夹“nonexistent”被指定为开始路径,因此对话框将在沙盒 MQL5/Files 的根目录中打开。在那里,我们选择 "MQL5book"。
如果我们组合无效的标志组合,则我们会遇到另一个错误。
if(PRTF(FileSelectDialog(NULL, "MQL5book", NULL,
|
由于错误,函数不会修改传递的数组,并且旧的 "MQL5Book" 元素仍然保留在其中。
在此测试中,我们故意仅检查结果是否为 0 的情况,以演示所有选项,无视错误的存在。在真实程序中,在考虑错误的情况下检查函数的结果,即考虑三个结果的条件:用户作出选择 (>0)、用户未作出选择 (==0) 以及错误 (<0)。