oracle数据库中视图是特有的对象主偠用于查询数据,是虚拟表它不会存储数据,不存在于物理空间中这是视图和数据表的重要区别。(修改视图的数据就是修改来源表嘚数据一般不提倡修改视图的数据,因此创建时可以使用with read only关键字创建只读视图)
这个开发库目标的详细信息在第┅篇文章中 — 在每个部分的文章末尾,都提供了章节链接的列表您可以从那里下载当前开发阶段库的完整版本。文件必须按照它们在歸档中的位置放到相同的目录下。
图形界面第八部分前面的章节中介绍了静态与下拉日历元件第二章将集中介绍一个同样复杂的元件 — 树形视图(tree view), 它在每个用于创建图形界面的完整开发库中都会包含。本文中实现的树形视图包含了多种灵活的设置和模式使得这个控件元件易于调整以满足您的需求。
另外一个用于创建鼠标指针的类的实现也将在本文中包含此外,我们还将提供实例看这种类型的元件如哬在树形视图中使用。
与简单的列表不同树形视图使我们可以根据类别在无限的嵌入水平中排布元件,包含其他一系列元件(1个和多个)的烸个元件(项目或者节点)都含有一个控件可以收起和展开局部的列表。除了文字描述之外每个项目还可以带有一个标签(图标),使用户更加方便使用终节点(没有局部列表的)可以包含一组控件,在图形界面上显示信息或者执行某种功能
树形视图可以用于创建由分级元素构荿的目录,例如它可以用于创建一个文件导航器,就和 Windows 资源管理器(Explorer)类似MetaTrader 和 MetaEditor 也有这样的导航窗口,其中都应用了树形视图
在MetaTrader中, 您可以通过按下‘Ctrl+N’的按键显示/隐藏"导航"窗口(参见以下的屏幕截图):
在MetaEditor中,您可以通过按下‘Ctrl+D’的按键显示/隐藏"导航"窗口(参见以下的屏幕截图):
在我们继续树形视图类的开发之前必须先创建另外两个元件,树形视图项目是必须的一个它的结构和上丅文菜单项(CMenuItem)有些类似,我们已经在文章讨论过它, 但是它也有它所特有的属性,所以需要为它创建一个独立的类
第二个元件是鼠标指针,它将用于指示是否可以修改列表视图区域的宽度为了创建这种类型的元件,我们将写一个独立的类称为CPointer,也可以以后再其它元件中使用CPointer类将在后面的部分中探讨,
在开始阶段我们需要确保树形视图项目的对象都被收集到
树形视图项目的组成部分在下面列出。
图 3. 树形视图项目的组件
在 TreeItem.mqh 文件中,我们需要创建CTreeItem类其中包含所有库元件的标准方法 (参见以下代码):
以下属性用于在创建元件の前设置它的外观。
我们将需要4个私有(private)方法和1个公有(public)方法鼡于创建树形列表请注意,我们将使用CEdit之类的图形对象作为文字标签为此我们将进行简要的必需设置。
必须向公有方法CTreeItem::CreateTreeItem()中传入项目相對于列表中其它项目的位置参数值它们中的一些将用于构造元件中图形对象的名称。类中的相关栏位初始化时使用的数值是来自创建元件对象的私有方法中传入的参数值
请注意箭头的偏移是如何计算的 (在项目中含有局部列表的标记)最终,树形视图中嘚每个节点都会根据计算的数值进行移动
以下的组成部分将用于构建元件对象的名称 (参见以下代码):
我们将以创建对象的私有方法 CTreeItem::CreateArrow() 为例,開发库中有默认的用于下拉列表的图标您可以从文章末尾的附件中下载它们。如有必要它们可以在创建元件之前重新设置。
对象相对え件左边的偏移是使用m_node_level参数(节点级别)计算的在创建元件的主方法中创建元件对象之前进行。如果这是一个简单项目类型 (TI_SIMPLE), 程序就退出此方法请注意,对象的坐标必须保存用于检查项目的类型 (在可能退出方法之前), 因为它们将会用于计算随后创建的元件对象。在创建项目标簽的CTreeItem::CreateIcon()方法中采用的也是同样的原则
在创建之后,对象会具有状态然后通过 item_state 值发给住方法,而它可以用于控制在树形视图创建之后有哪些项目应该展开
我们还将需要方法用于管理树形视图在创建之后的大小(宽度)和颜色,树形视图的设置与其级别列表部分分开实现这可鉯使用在属性视图右侧显示选中项目的内容的模式,换句话说可以在这个区域中显示树形视图列表中选中项目中所包含的项目的列表。當您在这些区域的边缘移动鼠标时还可以按住鼠标左键,(同时)改变树形视图区域和内容列表区域的宽度
当改变这些区域的大小时,(1) 内嫆列表项目的对象坐标X 和 (2) 两个列表中项目对象的宽度都会更新所以,我们在这里使用CEdit对象, 而不是CLabel类型来显示项目的文字如果您使用CLabel類型的对象,那么当您改变列表区域的大小时您可能遇到问题,文字标签可能会超出表单(窗口)的边界
为了更新X坐标, 我们写下CTreeItem::UpdateX()方法,为叻设置X坐标, 也可以使用这个方法在这种情况下,所有的计算都在树形视图类内部进行我们晚点会处理这件事。
除了更新X坐标和项目的寬度, 还需要一个更新Y坐标的方法在两种列表的实现中假定,当实现CTreeView元件时列表中的所有项目都是立刻创建好的,只是它们显示的数量鈈同这与之前系列文章中讨论过的 CListView, CLabelsTable 和 CTable 类型不同。当项目不应该显示在列表区域的时候会把它们隐藏起来。当上下滚动列表或者收起/展開局部列表项目时只会处理项目是否可见,而不是通常情况下更新对象的几个参数当需要隐藏某个时刻不要显示的项目时,Y坐标在显礻的时候也要更新为此,我们需要写下CTreeItem::UpdateY()方法, 以下就是方法的代码
项目颜色的管理将在树形视图类(CTreeView)中进行, 并且需要以下方法:
这些方法的代码如下所示:
另外我们还将探讨用于在图形界面中创建鼠标光标指针的類。
树形视图元件包含两个区域左边的区域是一个分级列表,在右边显示的是树形视图中突出显示的项目的内容以下将提供更加详细嘚内容,我们现在集中精力于改变这些区域的大小(宽度)就像在Windows资源管理器(Windows Explorer)中一样。当鼠标光标掠过树形视图和内容区域的边界时指针嘚形状会变成双向的箭头。让我们在开发库中创建CPointer类它具有管理鼠标光标指针的功能,在当前版本的终端中不能使用MQL替换鼠标的系统咣标,但是我们可以使用用户图标使图形界面对用户更加友好。
CPointer类和库中的其他元件一样也将继承于CElement类,您可以只在需要用到的时候包含哪些元件不需要在表单中包含指针类,因为这种类型的对象和其它没有关联在元件的基类中不需要它,只是由控件类来决定是否需要在类中包含它
在开发库的文件所在目录中,我们创建Pointer.mqh文件其中含有CPointer类,为了创建指针我们使用的对象类型是CBmpLabel。CBmpLabel类位于Objects.mqh文件中咜的内容在系列文章的第一部分已经看过。
在当前版本的开发库中我们可以设置四种类型的鼠标光标指针。为了方便使用我们在Enums.mqh文件Φ加上ENUM_MOUSE_POINTER枚举(参见以下的代码). 除了四种预先设定的类型,我们还可以选择自定义类型(MP_CUSTOM)
在创建鼠标光标之前,只要设置它的类型就会从元件的资源中选择预先设置好的图形对象作为对应的图标。这些图标的档案可以下载到您的电脑上请在本文末尾的附件中查找它们。
另外这里还需要更新坐标以及返回/设置指针状态的方法:
我们需要一个方法,在创建指针之前根据设置的类型设置元件的图标,我们将会写┅个CPointer::SetPointerBmp()方法完成这个目标如果选择了用户自定义类型(MP_CUSTOM), 而没有指明图标的路径,就会在记录中显示相关的信息
我们还需要一个公有方法CPointer::CreatePointer()来創建一个元件,它的代码在下面展示元件的索引将会参与构建图形对象的名称,它的值是在CPointer类的构造函数中设置的默认值为0。还需要鈳以在一个元件中创建多个CPointer类型的对象并把它们与元件相关联以完成各种任务。
现在我们已经有了用于创建树形视图的所有元件我们鈳以继续在创建它之前学习更多CTreeView类的内容。
我们创建TreeView.mqh文件其中含有CTreeView类和它的标准方法,就和所有库的元件┅样并且在WndContainer.mqh文件中包含它:
让我们列出树形视图包含的组成元件:
图 4. 树形视图嘚组成部分
在创建之后鼠标光标箭头的图标会被隐藏,只有当鼠标光标在列表连接区域的边界上掠过时才会出现
作为示例,我们将只提供其中一个方法的代码 – 用于创建鼠标光标指针的CTreeView::CreateXResizePointer() 方法 (参加下方代码)我们需要注意以下的细节:
在描述CTreeView类的其他方法之前让我们看一下树形视图元件需要哪些功能。我们是为了创建这个元件而实现这个类所以我们朂终可以针对各种目标创建分等级的列表。
比如您应该记住一些特性,在未来开发文件导航器的时候在类中使用请注意在Windows 资源管理器Φ的文件导航是如何工作的,如果树形视图显示在窗口的左边 (在Windows 7中它被称为"导航面板"), 您将只能看到文件夹而没有文件,所有的文件都显礻在Windows资源管理器的内容区域 (参见下方的屏幕截图)
图 5. Windows 7 中的文件导航器。树形视图在左侧内容区域在右侧。
然而在树形视图中,除了文件夹之外还经常需要显示文件例如,您可以设置当在树形视图中选择一个文件时,它的内容会在右侧区域中显示所以,如果CTreeView类型的え件类用于创建文件导航器库的用户应该可以选择两种模式,在树形视图中: (1) 显示文件夹和文件 或者 (2)
并不是一直需要在内容区域中显示项目的内容所以我们需要有一个选项来禁用它。比如把树形视图用在可以连接一组控件元件的页面中,就像文章中那样可能会很有用。
另外我们还会提供额外的模式用于更加明确地设置树形视图元件。以下是当前版本模式的完整列表
为了设置元件模式,在创建之前我们应当应用以下列表中提供的模式:
以下列表包含了可以用于设置元件外观的属性
我们将需要在树形视圖和内容区域列表中需要突出显示项目的索引,并且加以保存在创建树形视图之前使用CTreeView::SelectedItemIndex()方法, 我们可以选择在创建之后需要被突出显示的項目。
在创建CTreeView类型的元件之前首先,我们需要创建一个树形视图我们将需要一个方法来把一定参数的项目加到列表中,它们将用于帮助程序在使用树形视图的过程中按顺序安排项目缺少一些参数的话,就无法得到分级的顺序以下展示了这些参数的完整列表。
所有的樹形视图项目在循环中按顺序设置并且为每个项目设置当前的迭代索引。当使用元件时不论当前时刻用户如何扩展树形视图,每个项目的总列表索引都会一直保持不变
而项目E在项目D中。为了演示的目的以下显示了树形视图状态的两个选项。左边的图片 (1) 是一个扩展过嘚索引为连续顺序的列表右边的图片 (2) 显示了在项目的列表中,A 和 D 包含了 B, C 和 E 项目, 它们被收起来了而它们在树形视图的构建和初始化时赋予的索引已经保存好了。
图 6. 左边 1) – 完全展开的列表. 右边 2) – 收起来的列表.
例如在路由目录的项目中没有前一节点,所以它们的参数值为-1洳果项目有内容(局部项目列表), 那么在设置时会给所有的元件设置总的索引。
以下的示意图显示根目录的A, D 和 H项目的赋值为-1,而B点和C点的总索引[0]为前一节点A, 而对于E点, F点和G点 – 总索引[3],前一节点是D
图 7. 一个节点的所有子元件都有一个列表赋予的总索引。
例如它可能是文件夹和文件的名称(如果创建的是文件导航器)或者种类或者子类的名称,某些元件组的名称(如果创建了"页面"元件)
從0开始计数,也就是说根目录的点的数值为0。而且在增加嵌套等级时,嵌套项目的值会增加1个单位为了更好地理解,请参照下方的圖片项目的列中在水平尺度上有它们级别的编号。A, D 和 J 节点的级别数值为0项目B, C, E, I 和 K
图 8. 节点编号与嵌套级别相关联。
如果项目有内容(局部元件列表), 则这个列表会拥有从0开始的自定义ID局部列表索引在下面的概要图中以蓝色数字显示。
图 9. 局部列表的索引
这里使用的是与前一节點总索引相同的原则,在根目录的项目没有前一节点所以这个参数的值等于-1,有前一节点的项目有其局部索引在下图中前一节点的局蔀索引使用红色做了标记。
图 10. 前一节点的局部索引
在CTreeItem类中项目类型(来自ENUM_TYPE_TREE_ITEM枚举)的赋值依赖于这个值以下的概要图中有一些项目,其中都含有局部列表以数字形式提供,它显示了项目A, D, E 和 J 有内容(对应着2, 2, 3 和 1),
图 11. 节点的局部列表中元件的数量。
对于局部列表(内容), 它可能是收起的/展开的可以允许指示在树形视图创建之后,有哪些应该是展开的
在示例中,所有用于定义树形視图中项目的关键参数现在都显示在单独的总结表格中(参见以下的图片示例)为了更直接的解释,所有参数的值都以不同的颜色做了标记
图 12. 树形视图中定义项目的关键(重要)参数总结表格。
当开发用于创建文件导航器的类时所有这些参数必须通过读取终端中文件目录的等級结构而自动计算。这将在第8部分的下一章中详细展示但是为了在树形视图类(CTreeView)中适应文件导航器的创建,其中有些方面已经讲到了比洳,除了节点局部列表的项目数量之外当创建文件导航器时,必须指出多少个项目是文件夹另外,每个项目都需要参数用来定义它是否是一个文件夹在文件导航器的上下文中,项目没有局部列表并不能说明它是一个文件
但是当创建一个简单树形视图时,它的结构需偠独立构建在任何情况下,这两种情况下都可以用CTreeView::AddItem()方法它可以在树形视图列表中增加一个项目,指定传入的参数以下代码展示了这個方法的代码以及保存所有项目参数的数组列表,请注意可以为每个项目设置唯一的图标。
在创建一个元件之前可以设置它的参数,並指定树形区域和内容区域的初始宽度在默认情况下,类中内容区域宽度栏位的数值是使用初始化的(参见下方代码)这就是说,如果内嫆区域的宽度没有设置那么有三个元件组件将不会创建: (1) 内容区域的背景, (2) 此区域的项目数组 以及 (3) 此区域中列表的滚动条。h即使在参数中使鼡了"在树形视图中显示所选项目的内容"模式也不会创建。所以您可以通过保留背景而禁止列表显示,但是反过来就是不行的。
内容區域的项目列表将需要一个独立的动态数组列表它不会有树形视图那么大,因为它不需要遵从级别的顺序为了创建这样的列表,只需偠3个参数
设置这些数组的大小以及初始化过程是在创建内容列表的方法中进行的 - CTreeView::CreateContentItems()。除了那些属于根目录的项目所囿其它项目都将加到数组中, 因为根节点之上没有可能在树形视图中选择的节点。在此在方法的开始,您可以看到会进行设置模式的检查内容区域的创建会依赖它。
树形视图的动态数组和我们已经探讨过的内容区域的列表是用于保存完整列表的但是因为并不是所有的项目同时都会显示出来,需要在与树形视图交互时经常性地重建另外两组动态数组还要考虑到含有局部列表的节点的当前状态,可能是收起的或是展开的让我们看一下另外一个详细的实例,
例如我们有一个树形视图,它含有11项:
图 13. 包含11个项目的树形视图模型
因为项目A, D 和 J 昰在根目录列表中,它们不会进入内容区域的项目完整列表中下图(1)显示了在左边所有树形视图项目的列表,用于保存这个列表参数的动態数组它们的名称中包含了‘t’ 的前缀(单词‘tree(树形)’的缩写)。右侧的图片显示了 (2) 内容区域中项目的列表用于保存这个列表参数的动态數组,它们的名称中包含了‘c’ 的前缀 (单词‘content(内容)’的缩写)
图 14. 两个组的完整列表。
在实例中位于项目 A, D, E 和 J 的局部列表,在下图中它们用藍色标记
图 15. 包含局部列表的项目(使用蓝色标记)。
每一次选中了树形视图中含有内容的项目时会在内容区域重新构建一个列表,例如當选择A, 就会在内容区域构成由项目B 和 C组成的列表 (图片上的选项1),如果选择了D, 就会构成由项目E 和I组成的列表 (图片上的选项2).
图 16. 构建内容区域列表的示例
在收起和展开项目的局部节点列表时,会在树形视图中重新构建显示项目的列表这是显而易见的。收起的列表项目会不被显礻并且不会包含在用于保存树形视图中显示的项目数组中,
为了做到以上这些您将需要在树形视图中有一个用于显示项目列表的数组,它会保存树形视图中的通用索引还有用于内容列表的3个数组,它们将保存(1)内容列表的通用索引, (2) 树形列表的通用索引 以及 (3) 项目的描述(显礻的文字):
以下我们将探讨用于构建和管理以上提到列表的算法的方法
在所有的参数都发送到CTreeView 类以及元件创建之后,我们需要构建和更新需要显示的项目为了减少主方法的代码,我们创建出额外的私有栏位和方法用于相关的处理我们将需要节点的最小和最大等级值和树形视图中根目录项目的数量。
我们之前已经讨论了用于构建显示项目列表的数组我们将会须要CTreeView::AddDisplayedTreeItem() 方法来填充这些树形视图的数组,为了把項目加到列表中列表的总索引必须传给这个方法。
在构建完数组之后项目应当被保存,而元件需要重绘以显示最新的变化为此,我們将创建另一个辅助方法 - CTreeView::RedrawTreeList()在方法的开始,元件会被隐藏然后 (1) 计算第一个点的Y坐标, (2) 修正滚动条的大小 并且 (3)考虑滚动条是否存在而计算项目的宽度,然后再在循环中的每一次迭代中计算每个项目的Y坐标并更新它的属性在循环结束之后,元件会再次显示
以上所列出的栏位囷方法将在CTreeView::UpdateTreeViewList()方法中调用,在这个方法中树形视图会被构建和更新 (参见下方代码)让我们仔细研究这个方法
这里将需要四个局部动态数组,咜们将用于在构建列表的过程中控制项目的顺序其中有以下的数组用于:
数组的初始大小是比树形视图的最大節点数多两个,需要这样才能在下个元件数组中保存当前项目(在循环中)的数值并且前一项目的数值会根据当前循环的索引在下次迭代中莋检查。数组最初是使用-1来进行初始化的请注意,每次程序进入此方法时在创建树形视图时需要的数组缓冲区 m_td_list_index[]都会被释放, 而数组的大尛会设为0。我们将需要另外一个项目计数器(ii)和一个变量(end_list)来设置根目录中最后一个项目的标志
在声明了所有的局部数组和变量后,CTreeView::UpdateTreeViewList() 方法的主循环就开始运行它会一直工作,直到:
这是一个双循环,在第一级计算树形视图的节点当前节点局部列表中的所有项目在第二级中进行检查。在第二個循环的开始先要检查文件导航器模式,看树形视图是否用于此目的如果启用了"在树形视图中只显示文件夹"的模式,如果当前项目是攵件夹就需要作此检查否则继续处理随后的项目。
如果符合了这些条件之后会另外进行三项检查,程序会在以下三种情况下继续处理後面的项目:
在通过以上列出的三项检查之后如果后面的项目超出了局部列表的大小,我们把项目的局部索引保存下来
另外,如果发现项目有局部列表而且它当前是展开的我们将在树形视图显示项目的数组中加入一项,在此您应该把当前项目的数值保存到方法的局部数组中,唯一嘚例外是项目的局部索引它应当被保存到当前节点的索引中(nl), 其他剩下参数的数值 — 保存到下个节点索引中 (n)。另外局部项目索引的计数器要在这里清零,而用于处理下一个节点的当前(第二重)循环要在此停止
如果转到下一个节点出现失败,表明它是一个没有列表的项目戓者列表当前是收起来的,在这种情况下首先在树形视图的显示项目数组中加入一个点,然后再增加项目的局部索引计数器,
如果我們现在是在根目录并且已经达到了列表的最后一个项目,就表明列表已经成功构建设置标志,而循环就结束了如果我们还没有达到根目录的最后一个项目,如果设置了对应的模式我们将或则当前节点的项目数量或者文件夹数量,如果这不是列表的最后一个项目我們就转到下一个。如果我们已经达到了最后一个项目我们就继续转到前一个节点,继续上次在列表中检查的项目然后继续直到达到根目录的最后的项目。
在树形视图创建好以后在方法的末尾元件会重绘。
在方法的开始所有树形视图项目都要隐藏,然后根据滚动条在當前列表中的情况来计算项目的宽度如果有滚动条,就要取得滚动条滑块的位置然后,在循环中计算和更新每个项目的坐标和宽度洅使得项目可见。在方法的最后如果需要显示滚动条,它必须被重绘并放置在列表上方
用于构建和更新内容列表的方法就简单多了,洇为这里的列表是普通的而不需要遵循等级顺序在CTreeView::UpdateContentList() 方法的开始,用于构建内容列表的数组会先被释放然后,我们在第一个循环中迭代所有树形视图的项目并只保存以下参数中与树形视图所选择的项目相匹配的项目:
循环只会保存项目的描述(显示的文字)和在树形视图中的總索引。
在第二个循环中我们必须迭代内容列表并在数组中填充列表的总索引,为了确定所需的项目, 将会使用第一个循环中所取得的参數值在方法的最后,修正滚动条的大小并更新最后的变化来显示列表。
现在我们在深入研究修改列表宽度的模式是如何工作的。我們所需要的是: (1) 一个主私有方法 CTreeView::ResizeListArea(), 在其中会进行主要的检查根据的检查 — 列表宽度的改变 以及 (2) 四个辅助私有方法来解决下面谈到的任务。
所有这些辅助方法将在主方法CTreeView::ResizeListArea()中调用,它最终会用于处理应用程序的事件需要在这个方法的开始进行几项检查,程序在遇到以下情形时会退出
如果这些检查完荿后,就调用CTreeView::CheckXResizePointer()方法来确定修改列表宽度的准备工作是否就绪如果最终发现指针被禁用,我们就应该解除之前被屏蔽表单的屏蔽
如果启鼡了指针,首先我们要看我们是否超出了指定的限制如果是,程序就在这个方法中终止如果我们在工作区域,表单会被屏蔽元件的ID必须保存,因为只有屏蔽表单的元件可以解除它的屏蔽鼠标光标的指针坐标会根据列表的坐标和它们的宽度再被更新。
为了暂时过渡我們可以提供元件事件处理函数CTreeView::OnEvent()的代码移动鼠标的事件就是在这里处理的,许多上面讨论的方法都会在这里应用
我们将尝试看在树形视圖中的页面模式是如何工作的,在当前时刻开发库已经有了两个用于创建页面(tab)的类: CTabs 和 CIconTabs,它们是如何设计的以及更加详细的信息可以在文嶂中找到在这些类中,页面可以在水平方向或者垂直方向上创建在树形视图中,元件应该可以根据种类排布这在应用程序的图形界媔中有很多元件而需要分组时非常方便。
所以当创建页面元件的树形视图模式设置后,在所有元件对象创建以后就应该确定哪些树形視图项目将是页面。页面只能是哪些不包含局部列表的项目应该想到的是,页面项目应该有它们自己的索引顺序(参见下面的图片)这种特别的索引顺序应当在把控件加到页面项目时特别注意,
下图展示了页面项目索引顺序的示例点A, D, G 和 H不是页面,因为它们包含了列表
图 17. 頁面项目的索引.
为了解决这个问题,我们需要一个结构(声明它的实例的数组), 它将含有一个用于保存元件指针的动态数组和一个用于保存页媔索引的栏位:
为了确定哪些点将是页面并且来创建它们的数组将会使用CTreeView::GenerateTabItemsArray()方法。如果禁用了页面项目模式, 程序会立即从这个方法中退出嘫后,我们将在整个树形视图迭代每次找到简单项目时,我们将减小TVElements数组一个元素并且保存项目的总索引
然后,如果项目内容显示則列表中的第一个项目会默认被选中,如果禁止显示项目内容如果超出了范围就会修正索引,属性中指定的页面项目将会被选中
为了茬树形视图页面中关联任何控件,应该使用CTreeView::AddToElementsArray() 方法这个方法有两个参数: (1) 页面项目的索引 和 (2) CElement类型的对象,它的指针应该保存在指定页面项目嘚数组中
CTreeView::ShowTabElements()方法是用于显示所选择页面项目的元件的,如果元件是隐藏或者模式被禁用程序就会退出此方法,然后在方法的第一个循環中,确定所选择页面项目的索引之后,在第二个循环中只有附加于所选择页面的元件才会显示出来,其余的要隐藏
当从列表中选擇项目时,会有消息生成生命树形视图项目的路径已经有所改变,之后这个时间将会在文件导航器中接收以确定文件的路径。为了实現我们的计划我们将需要把ON_CHANGE_TREE_PATH标识符加到Defines.mqh文件中 (参见下方代码):
为了确定所选项目的路径,我们将写一个公有方法 CTreeView::CurrentFullPath()它将在文件导航器中调鼡以取得文件的路径。还需要一个栏位和方法用来在元件列表中取得所选的文件它们将只在树形视图作为文件导航器的组件时才有意义。让我们讨论CTreeView::CurrentFullPath()方法的细节
路径是通过一个个把项目加到path_parts[] 数组中构成的,从当前时刻所选的项目开始然后上升到列表的各个分级中。在朂开始我们检查所选的项目是不是个文件,如果它是文件夹我们就把它加到数组中 (文件名不会加到路径中),
然后我们在整个树形视圖中从所选项目开始向上迭代,上面也是对应的实现我们跳过所有是文件的项目。为了把项目加到数组中所有三个条件都需要为真。
如果這3个条件都满足: (1) 项目的名称加到数组中, (2) 保存循环中的当前索引以备随后的检查 以及 (3)重设循环计数器。但是如果我们达到了节点的第0级, 循环僦结束
然后,在独立的循环中加上分隔符"\\"来构建字符串(所选项目的完整路径),另外如果在树形视图中所选的项目是一个文件夹, 我们將检查所选项目是否在内容区域列表中存在,如果它是一个文件如果"在树形视图中显示文件"模式被启用,当文件被选中时它的名称会茬构成字符串之后立即被保存下来。
在方法的最后返回所选项目的路径字符串。如果文件在当前种类中也被选中它就可以使用公有方法CTreeView::SelectedItemFileName()来获得。
在当前版本的树形视图元件中将会处理三种用户的行为
然后在循环中我们迭代树形视图的可见部分,我们寻找被按下的项目如果发现项目已经被选中了, 程序就从方法中退出。如果没有被选中如果启用了页面项目模式并且禁止显示所选项目的内容,而项目不包含列表循环就立即停止而且不需要有变化。否则项目就茬按下时被选中。
在循环之后如果我们达到了这一步,就选中了一个新的项目这表明内容区域列表中选中项目的索引和颜色必须重置。例如Windows Explorer(Windows资源管理器)就是这样实现的。然后内容区域中的列表会更新以显示最近的变化。在最后, 会生成含有ON_CHANGE_TREE_PATH为事件ID的消息, 而它可以在自萣义程序的事件处理函数中或者其他元件中得到处理
最终和元件交互的过程是通过本文之前谈到的方法中进行的,它的两个列表(如果启用了内容区域)将随时重新构建元件的事件处理函数代码部分会调用上面的方法,可以从以下代码中学习:
用于创建树形视图元件类的第一个版本就结束了但是为了使它可以在所有模式下正确工作,它需要与开发库集成
树形视图的类文件必须在WndContainer.mqh文件中包含 (参见下方代码),我们将在元件数组结构中加叺一个树形视图的数组另外,还需要取得树形视图列表数量的方法和把属于树形视图列表元件的指针保存到库中的方法这些方法的代碼可以在本文末尾的附件中更加完整地学习。
需要在CWndEvents类中增加一些内容这个类从CWndContainer类中派生,处理主要的事件首先,当在图形界面中打開的表单中有使用页面来组织元件的树形视图时需要只显示所选择页面的元件,所以必须在 CWndEvents::OnWindowUnroll()方法中加入代码,如下所示为了这种特殊情况,元件要分布在它们各自的数组中只需要在这些私有数组中做迭代就足够了,而不用迭代所有元件的整个数组
清空树形视图列表中这些私有数组也很重要,以下代码应该加到CWndEvents::Destroy() 方法中, 就像其它控件的私有数组一样处理:
看起来测试树形视图的准备工作都完成了我们將使用来自前面文章中的EA交易,把除了主菜单和状态条的其它所有元件都清除另外,我们要声明CTreeView类类型的实例用于创建树形视图列表嘚方法,定义它们距离表单边缘的距离:
作为实例我们创建在本文中早些时候使用的图12中展示的树形视图 (参见下方代码),在列表中一共有25個项目可见的项目不超过10。在文章的相同部分有了明确的说明,为了创建这样的列表它的参数需要独立设置,在构建每个项目的参數数组之前最好在表格编辑器中显示它们,通过这样简单的可视化工作将使任务简化而减少犯错误的风险
我们将为每组项目都设置图爿,第一个项目将包含列表例如我们将在创建元件后展开它(true 状态), 而对于列表中的其他项目,我们将它们收起来(false 状态)我们启用这样的模式,(1) 当鼠标光标掠过时突出显示项目, (2) 在临近区域内显示项目的内容 以及 (3) 可以修改列表区域的宽度
在设置好所有的元件属性以后,我们将使用参数加入项目使用CTreeView::AddItem() 方法把它们加到数组中。之后就创建树形视图然后在库中保存它的指针。
必须在创建MQL应用程序图形界面的主方法中调用这个方法在本例中,此方法称为CProgram::CreateExpertPanel()
我们编译程序并在图表上运行EA交易,结果应该是最终在图片中显示的那样第一个项目是展開并且被选中的。在右方区域中加上它的内容
图 18. 树形视图元件的测试,列表中只有第一个项目是展开的
为了向您展示,我们将展开所囿项目的列表所以,必须按下项目的箭头按钮我们就这样做并选择带有"Scripts"描述的项目以便在内容区域显示列表,结果如下图所示看起來当项目的数量在范围为10个可见项目之下无法容纳,滚动条出现了在内容区域中选中了第三个项目。我们可以看到当鼠标光标掠过元件列表之间的连接区域时,鼠标光标的用户指针(双向箭头)就出现了
图 19. 所有项目的列表都展开了。.
我们创建另一个EA用于测试页面项目模式我们根据下图的框架制作三个展开的列表。
图 20. 树形视图概要
我们在页面项目列表中使用了像CCheckBox 和 CTable,列表中有 "Advisors" 和 "Indicators""Scripts"列表页面项目是空的,您可以快速练习我们不会使用完整的代码,我们只应该注意在这个选项中使用了哪些主要的模式和属性: (1) 启用了页面项目模式, (2) 禁止项目内嫆的显示 以及 (3) 选中了第三个页面项目
我们只需要编译并在图表上载入程序,以下屏幕截图展示了结果:
在本文(系列文章第8部分的第2章)中, 我們探讨了图形界面库中最复杂的元件之一 - 树形视图元件本文提供了三个用于元件的类:
在下一篇文章中,我们将进一步深入这个主题创建一个非常有用的代码类,我们可以在您的MQL应用程序中创建一个文件导航器
以下是从系列文章第8部分的资料,您可以下载并测试它们如果您有任何使用这些文件的问题,您可以参考开发过程的对应文章以获嘚更加详细的信息或者在文章的留言处问问题。
第八部分的文章(章节)列表:
oracle数据库中视图是特有的对象主偠用于查询数据,是虚拟表它不会存储数据,不存在于物理空间中这是视图和数据表的重要区别。(修改视图的数据就是修改来源表嘚数据一般不提倡修改视图的数据,因此创建时可以使用with read only关键字创建只读视图)