资源描述
单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,*,*,第,7,章 菜单、工具栏及数据共享,菜单是用户和应用程序的接口。菜单设计的好坏不但反映了应用程序中的功能模块组织的水平,同时也反映了应用程序的用户友善性。,数据共享技术允许多用户共享数据。数据加锁与解锁以及更新数据的方法是实现数据共享的重要方法。,2024/11/28,1,7.1,菜单和工具栏,7.1.1,设计菜单,菜单具有较好的组织形式和内容,是应用程序的一种直观的反映。用户通过菜单很好地理解应用程序,方便地使用应用程序。,2024/11/28,2,7.1.1,设计菜单,1,创建一个完整菜单系统的步骤,(,1,)规划菜单系统,确定需要哪些菜单、出现在界面的何处及哪几个菜单要有子菜单等。,(,2,)创建菜单及子菜单,用菜单设计器定义菜单标题、菜单项和子菜单。图,7-1,菜单系统组成,(,3,)指定菜单所要执行的任务,例如显示表单或对话框等。如果需要,还可以包括初始化代码或清理代码。,(,4,)选择“预览”按钮预览菜单系统。,(,5,)从“菜单”菜单上选择“生成”命令,生成菜单程序以及运行菜单程序,对菜单系统进行测试。,(,6,)从“程序”菜单中选择“执行”命令,然后选择已生成的菜单程序运行。,2024/11/28,3,2,菜单系统结构及组成,一个完整的菜单系统如图,7-1,所示。,主要包括菜单栏、菜单标题、下拉菜单、菜单项和子菜单。,菜单项中可包括,VFP,命令或者子菜单。,图,7-1,菜单系统组成,2024/11/28,4,7.1.2,使用菜单设计器创建菜单,使用菜单设计器可快速开发出菜单。可用以下几种方法打开菜单设计器:,单击“常用”工具栏上的“新建”按钮,从文件类型列表中选择“菜单”,然后单击“新建文件”按钮。,选择“文件”菜单的“新建”命令。,应用项目管理器,即从项目管理器中选择“菜单”,然后单击“新建”按钮。,2024/11/28,5,7.1.2,使用菜单设计器创建菜单(续),在打开“菜单设计器”之前,系统将打开“新建”对话框,如图,7-2,所示,可以创建两种形式的菜单:普通菜单和快捷菜单,单击其中任何一个按钮可打开菜单设计器。,普通菜单和快捷菜单的菜单设计器在外观上并无区别,只是两者的设计方法略有不同。,图,7-2,“新建菜单”对话框,2024/11/28,6,1.,创建普通菜单和快捷菜单,如图,7-3,所示是一个快捷菜单示例。,在快捷菜单中,可将若干选定的系统菜单项加入到自己的菜单系统中。,方法是单击“插入栏”按钮打开“插入系统菜单栏”对话框,如图,7-4,所示,然后从中选择所需要的菜单项,并单击“插入”按钮即可。,快捷菜单的调用方法和普通菜单相同,用户只需要在程序中加入命令“,DO,菜单名称,.,mpr,”,即可。,2024/11/28,7,1.,创建普通菜单和快捷菜单(续),图,7-3,快捷菜单示例,图,7-4,“插入系统菜单栏”对话框,2024/11/28,8,1.,创建普通菜单和快捷菜单(续),在普通菜单设计器中,也可利用,VFP,菜单为模板来创建自己的菜单系统。,方法是从“菜单”菜单中选择“快速菜单”选项。,“菜单设计器”中即出现,VFP,系统菜单,如图,7-5,所示。,图,7-5,已添加菜单系统的菜单设计器,2024/11/28,9,2.,菜单设计器的使用,(,1,)菜单设计窗口组成,“菜单名称”栏用于输入菜单的提示字符串。,若要设定菜单项的热键,可在要设定为热键的字母前面加上,号。,如果没有给出这个符号,则菜单提示字符串的第一个字母即自动被定义为热键。,执行菜单时,按“,Alt+,热键”即可打开该菜单项。在图,7-3,中,“输入”菜单的热键是,Alt+I,,“,查询”菜单的热键是,Alt+S,,“,退出”菜单的热键是,Alt+Q,。,在菜单名的左边有一个小方框按钮,称为“移动指示器”,当鼠标移动到它的上面时形状会变成上下双箭头的样子。用鼠标拖动“移动指示器”即可改变当前菜单项在菜单列表中的位置。,2024/11/28,10,1,)“结果”栏,该项中共有,4,个选项,用于选定菜单项的功能类别。,子菜单(,Submenu):,如果用户定义的当前菜单项还有子菜单,应选这一项。,命令(,Command):,若当前菜单项的功能是执行某种动作的话应选这一项。,主菜单名/菜单项#(,Pad Name/Bar#):“,主菜单名”出现在定义主菜单时,“菜单项#”出现在定义子菜单项时。,过程(,Procedure):,用于定义一个与菜单项相关联的过程,当用户选择了该菜单项将执行这一过程。,2024/11/28,11,2,)“选项”按钮,单击该按钮将弹出“提示选项”对话框,如图,7-6,所示。,使用该对话框可设置用户定义的菜单系统中各菜单项的属性。,例如,定义菜单项的快捷键,控制如何禁止或允许使用菜单项,选取菜单项时是否在系统状态条上显示对菜单项的说明信息,指定菜单项的名字以及在编辑,OLE,对象期间控制菜单项的位置等。,图,7-6,“提示选项”对话框,2024/11/28,12,2,)“选项”按钮(续),该对话框主要有以下几个选项:,“,快捷方式”区:用于指定菜单或菜单项的快捷键(即,Ctrl,键和其他键的组合)。,“,位置”选项区:当用户在应用程序中编辑一个,OLE,对象时,可在该区指定菜单项的位置。,跳过:单击这个编辑框右侧的“,”,按钮将调出表达式生成器,用户可在表达式生成器中输入允许,/,禁止菜单项的条件。如表达式为真,则菜单项不可用。,信息:单击这个编辑框右侧的“”按钮也将调出表达式生成器。在表达式生成器的“信息”编辑框中输入对菜单项的说明信息,这些信息将出现在系统状态条上。,菜单项:允许指定可选的菜单标题,用户可以在程序中通过该标题引用菜单项。,备注:在这里输入对菜单项的注释。,2024/11/28,13,3,)菜单级,菜单级弹出列表显示出当前所处的菜单级别。当菜单的层次较多时,利用这一项可快速返回任意一级菜单。,4,)“预览”按钮,使用这个按钮可查看正在设计的菜单的形象,并可在所显示的菜单中进行选择,检查菜单的层次关系及提示等是否正确,但这种选择不执行各菜单的相应动作。,5,)“插入”按钮,在当前菜单项的前面插入一新的菜单项。,6,)“删除”按钮,删除当前的菜单项。,2024/11/28,14,(,2,)“常规选项”对话框,当用户选择“显示”菜单中的“常规选项”时将显示“常规选项”对话框,如图,7-7,所示。该对话框用于为整个菜单系统输入代码,它主要由以下几个部分组成:,1,)“过程”编辑框:在这里输入菜单过程的代码。,2,)“编辑”按钮:单击“编辑”按钮将打开一个编辑窗口,用户可在编辑窗口中输入菜单过程的代码。,图7-7 “常规选项”对话框,2024/11/28,15,(,2,)“常规选项”对话框(续),3)“位置”区:共有4个按钮,它们的含义分别是:,替换:将现有的菜单系统替换成新的(用户定义的)菜单系统。,追加:将用户定义的菜单附加在现有菜单的后面。,在之前:将用户定义的菜单插入到指定菜单的前面。选中这一选项将出现一个弹出列表,在其中列出了当前菜单系统的菜单名。从这里选择一个菜单名,用户定义的菜单将出现在该菜单的前面。,在之后:将用户定义的菜单插入到指定菜单的后面。,4)菜单代码:它包括如下两个复选框:,设置:为菜单系统加入一段初始化代码。单击“设置”复选框可打开初始化代码编辑窗口,即可编辑初始化代码;单击“确定”按钮关闭“常规选项”对话框。,清理:为菜单系统加入一段结束代码。单击“清理”按钮进入结束代码编辑窗口,即可编辑结束代码;单击“确定”按钮关闭“常规选项”对话框。,5)顶层菜单:如果选定该复选框,将允许该菜单在顶层表单(,SDI),中使用。如果未选定,则只允许该菜单在,VFP,页框中使用。,2024/11/28,16,(3)“菜单选项”对话框,单击“显示”菜单中的“菜单选项”命令,出现“菜单选项”对话框,如图,7-8,所示。该对话框用于为菜单栏(即顶层菜单)或各子菜单项输入代码,它包括以下几个选项:,1)名称:显示菜单的名称,如果用户当前正在编辑主菜单,则此处的文件名是不可改变的(其名称为“菜单栏”)。如果用户当前正在编辑子菜单,则此处的文件名可以改变。默认时这里的文件名与用户在菜单设计窗口提示列的内容一样。,2)过程:“过程”编辑框用于输入或显示菜单的过程代码。,3)“编辑”按钮:单击“编辑”按钮将打开一个文本编辑窗口,它实际上是放大了的过程框。,2024/11/28,17,(3)“菜单选项”对话框(续),图,7-8,“菜单选项”对话框,2024/11/28,18,7.1.3,在应用程序中使用菜单,菜单创建好后,可用于实际应用程序中,也就是用菜单将编制好的应用程序有机地组织起来。形成一个界面友好的应用程序。,1. 为菜单或菜单项指定任务,(1)为菜单项指定一个命令,该命令可以是任何有效的,VFP,命令,包括对程序和过程的调用。,过程应该在“常规选项”对话框的“清理”选项中定义。,为菜单指定命令应符合下列的语法格式:,DO procname& procname,是过程名称。,例如,在图7-3的菜单的查询子菜单中,在“结果”项选择“命令”项。在“选项”中输入下述语句:,DO e:txtvfp60,统计学生成绩.,qpr,该命令将已经建立“统计学生成绩”的查询功能加入菜单。,2024/11/28,19,(,2,)为菜单项指定一个过程,当为不含有子菜单的菜单或菜单项指定过程时,可在“结果”菜单框中,选择“过程”,单击“创建”按钮或“编辑”按钮,在打开的编辑窗口中输入过程代码。,当为含有子菜单的菜单或菜单项指定过程时,应首先在“菜单级”框中选择要指定过程的菜单项。然后从“显示”菜单中选择“菜单选项”菜单项,显示“菜单选项”对话框,如图7-9所示。,图,7-9,为含有子菜单的菜单指定过程,2024/11/28,20,(,2,)为菜单项指定一个过程(续),用下述方法之一可指定下一个过程:,在“过程”框中编写或调用过程;,单击“编辑”按钮,再单击“确定”按钮,打开独立的编辑窗口并编辑或调用过程。,在图7-3中,为增加输入功能,可以在输入菜单添加下述过程语句:,USE e:txtvfp60xk.dbf EXCLUSIVE,Append,use,2024/11/28,21,2.,添加初始化代码,菜单的初始化代码可包含:,创建环境的代码,定义内存变量的代码,打开所需要文件的代码,用,PUSH MENU,和,POP MENU,保存或恢复菜单系统的代码。,向菜单系统添加初始化代码的方法是:,(1)从“显示”菜单中选择“常规选项”(“常规选项”对话框如图7-7所示)。,(2)在“常规选项”对话框的“菜单代码”区域,选择“设置”复选框。,(3)单击“确定”按钮,打开一个初始化代码编辑窗口。,(4)在初始化代码编辑窗口输入适当的初始化代码。,对所建的菜单,当多次执行时,会发出“表已打开”的错误,为此可以添加下述初始化代码:,CLOSE ALL,2024/11/28,22,3.,添加清理代码,菜单清理代码的作用是在菜单初次启用时启用菜单或菜单项,或在菜单使用过程中,根据用户的选择废止或启用菜单系统中的菜单或菜单项。,菜单清理代码一般放在初始化代码及菜单定义代码后,菜单的指定任务过程代码之前。,添加菜单清理代码的步骤是:,在“常规选项”对话框的“菜单代码”区域选择“清理”复选框。,在打开的编辑窗口中输入清理代码。,2024/11/28,23,4.,释放菜单,当应用程序结束时,菜单的使命也宣告完成。,这时,需要释放菜单,以节约内存。,释放菜单的命令为:,RELEASE MENUS,例如,在“退出”菜单中,输入如下过程语句:,RELEASE MENUS,SET SYSMENU TO DEFAULT,最后完成的菜单设计器如图7-10所示。,图,7-10,最后完成的菜,单设计器画面,2024/11/28,24,4.,释放菜单(续),完成菜单设计后,单击“菜单”菜单的“生成”命令,在“另存为”对话框中为新设计的菜单程序命名,单击“保存”按钮,在“生成菜单”对话框中单击“生成”按钮。,菜单生成后,自动生成两个文件:,.,mnx,文件,用来保存菜单系统,该文件的作用是可以将其加入项目中并同其余模块连编成一个应用程序。,.,mpr,文件,这个文件是生成的,VFP,菜单程序,用户可自行修改,并可将其加入.,prg,程序文件中。,运行菜单程序,其执行结果如图7-11所示。,图,7-11,已完成的菜单,2024/11/28,25,7.1.4,创建自定义工具栏,用户应用程序中有一些任务使用非常频繁,如果通过菜单系统选择执行,用户会感到不方便。,VFP,允许将这些高频率的重复任务定制在工具栏上,即一个任务增添一个按钮,以简化和加速任务的执行。,本节主要介绍定制工具栏、定义工具栏类、在表单集中添加自定义工具栏等内容。,值得注意的是,虽然可以新建工具栏,但用户不能重置创建的工具栏按钮。,2024/11/28,26,1.,定制,Visual FoxPro,工具栏,(,1,)制定,VFP,工具栏的步骤,1,)从“显示”菜单选择“工具栏”选项,出现“工具栏”对话框,如图,7-12,所示。,2,)选择要定制的工具栏使其显示在当前屏幕上,然后单击“定制”按钮,打开“定制工具栏”对话框,如图,7-13,所示。,图,7-12,“工具栏”对话框,图,7-13,“定制工具栏”对话框,2024/11/28,27,(,1,)制定,VFP,工具栏的步骤,3,)选择“定制工具栏”对话框中的分类,然后将选定按钮拖动到制定工具栏上。,例如,如果将“编辑”工具栏中的“剪切”和“复制”工具拖到“报表设计器”工具栏上,则这两个工具就成为了“报表设计器”工具栏中的两个工具。,4,)单击“关闭”选项,关闭工具栏窗口,完成工具栏的定制。,2024/11/28,28,(,2,)创建自己的工具栏的步骤,1,)从“显示”菜单中选择“工具栏”选项打开“工具栏”对话框。,2,)在“工具栏”对话框中单击“新建”按钮,出现如图,7-14,所示的“新工具栏”对话框。,3,)在“新工具栏”对话框中为工具栏命名,如“我的工具栏”。然后单击“确定”按钮,此时系统将打开“定制工具栏”对话框。,4,)选择“定制工具栏”对话框中的一个分类,然后拖动适当的按钮到新建的工具栏上。,5,)选择“定制工具栏”对话框的“关闭”选项,关闭工具栏窗口,完成新建工具栏。,图,7-14,“新工具栏”对话框,2024/11/28,29,(,3,)删除创建的工具栏步骤,1,)从“显示”菜单中选择“工具栏”打开“工具栏”对话框。,2,)在“工具栏”对话框选择要删除的工具栏。,3,)单击“删除”按钮。,4,)单击“确定”按钮以确定删除。,2024/11/28,30,2.,定义工具栏类,定义一个自定义工具栏类的步骤如下:,(1)从“文件”菜单中选择“新建”命令,在“新建”对话框中选定“类”,然后单击“新建文件”按钮。,(2)在“类名”框中键入新类的名称。,(3)从“派生于”框中选择,Toolbar,,以使用工具栏基类。,(4)在“存储于”框中输入类库名,保存创建新类。此时“新建类”对话框画面如图7-15所示。,图,7-15,“新建类”对话框,2024/11/28,31,2.,定义工具栏类(续),(,5,)单击“确定”按钮,出现如图,7-16,所示的类设计器。,(6)在该工具栏中放置三个控件,通过“布局”工具栏将它们调整至等宽和等高。最后通过属性窗口为控件对象设置属性和代码,其最终的设计结果如图7-17所示。,(7)保存所设计的类,新建类命名为“新类.,vcx”。,图,7-16,类设计器,图,7-17,设计好的工具栏,2024/11/28,32,3.,在表单集中添加自定义工具栏,可在表单设计器中协调工具栏和表单。,可以在表单中添加工具栏,让工具栏与表单中的各表单一起打开。步骤如下:,(,1,)打开要使用上述工具栏类的表单集,如“学生花名册”表单集。再从“表单控件”工具栏选择“查看类”,然后从其快捷菜单中选择“添加”命令。系统此时将打开“打开”对话框,从中选择刚创建的自定义工具栏的可视类库文件“新类,.,vcx,”,,并单击“打开”按钮,则“表单控件”工具栏将选定可视类库文件中的类图表所代替。,(,2,)从“表单控件”工具栏中选择工具栏类。,(,3,)在表单设计器单击,,VFP,将在表单上添加工具栏,如果尚未创建表单集,,VFP,将提示用户创建一个。,2024/11/28,33,3.,在表单集中添加自定义工具栏(续),(,4,)为工具栏及其按钮定义操作,此时表单设计器画面中新添加一个,TOOLBAR1,工具栏。,(,5,)运行表单,其结果如图,7-18,所示。可看到添加的工具栏随表单的打开或关闭而打开或关闭。,图,7-18,包含,TOOLBAR1,工具栏的表单运行画面,2024/11/28,34,7.2,定制和调测菜单系统,菜单系统的测试与调试,定制菜单系统,2024/11/28,35,7.2.1,菜单系统的测试与调试,调试菜单一般有两个过程:,在设计菜单时,可通过预览功能进一步完善菜单系统;,在生成菜单程序后,可使用诊断工具进行调试。只要单击“预览”按钮即可在屏幕上预览整个菜单系统。,该菜单可模拟执行,此方法前面已经讲述,本节重点介绍用诊断工具进行调试菜单系统的方法。,在测试中发现菜单程序有错误后,可使用,VFP,的调试环境逐步找到错误,具体有如下几个步骤:,跟踪代码,挂起程序的执行,查看存储的值。,2024/11/28,36,1.,启动调试器,调试器是用来调试,VFP,程序的工具,打开调试器的方法是从“工具”菜单中选择“调试器”。,调试器如图,7-19,所示。,图,7-19,调试器应用程序外观,2024/11/28,37,2.,跟踪代码,跟踪代码可观察每一行代码的运行,同时检查所有的变量、属性和环境设置的值:,(1)在调试器中打开菜单应用程序。从调试器的“文件”菜单中选择“打开”命令,可打开一个需要调试的菜单应用程序。图7-19的调试器中打开了“菜单3.,mpr”,的菜单程序。,(2)在调试器中连续执行程序。从调试器的“调试”菜单中选择“执行”命令。菜单可连续执行。当遇到断点时程序会自动停止执行,并停在断点处。,(3)在调试器中单步执行程序。单击工具栏“单步”按钮。,(4)定位修改错误代码。,当发现错误时,进行修改的方法:,从“调试”菜单中选择“定位修改”命令,将挂起执行程序,然后打开代码编辑器,编辑器中的代码定位在“跟踪”窗口中光标所在位置的代码。,2024/11/28,38,3.,挂起程序的执行,挂起程序实际上就是在程序的适当地方设置断点。,根据要分析的代码错误的原因,有几种设置断点的方法:,(1)在某行代码处设置断点。,1)在“跟踪”窗口中,找到要设置断点的行。,2)将光标放置在该代码行上。,3)按,F9,键或者单击“调试器”工具栏上的“切换断点”按钮;或者双击该代码行左边的灰色区域。此时,该代码行左边的灰色区域中会显示一个实心点,表明该行已经设置了一个断点。,2024/11/28,39,(,1,)在某行代码处设置断点(续),还可使用断点对话框设置断点,从“工具”菜单中选择“断点”命令,打开“断点”对话框,如图,7-20,所示。,在“断点”对话框中断点的设置方法请参见表,7-1,。,图,7-20,“断点”对话框,2024/11/28,40,(,2,)对表达式设置断点,了解运行条件何时发生改变,可对表达式设置断点:,1)在图7-20所示的“断点”对话框中,从“类型”列表中选择“当表达式值改变时中断”。,2)在“表达式”对话框中输入相应的表达式。表7-2给出了各种表达式断点的设置方法。,表达式,程序挂起条件,RECNO( ),当表中的记录指针移动时,程序挂起,PROGRAM( ),在任意一个新的程序、过程、方法程序或事件的第一行上,将程序挂起,Myform.text1.value,当该属性的值由于用户交互或程序运行而发生了改变时,将程序挂起,表,7-2,断点表达式示例,1,2024/11/28,41,(,2,)对表达式设置断点(续),(,3,)有条件地将程序挂起。调试程序时,当满足某种条件时将程序挂起的方法:,1)在图7-20所示的“断点”对话框中,从“类型”列表中,选择“当表达式值为真时中断”。,2)在“表达式”对话框中输入相应的表达式。断点表达式示例如表7-3所示。,3,)单击“添加”按钮,将断点添加到“断点”列表中。,表达式,程序挂起条件,Eof( ),当表中的记录指针移过最后一条记录时,将程序挂起,Click$program( ),在与,Click,或者,DblCclick,事件相关的第一行代码上,将程序挂起,nReturnValue=6,如果一个信息框的返回值存储在,nReturnValue,中,当用户在该信息框上选择“确定”的时候,将程序挂起,表,7-3,断点表达式示例,2,2024/11/28,42,(,4,)有条件地在某代码行上将程序挂起,当某条件为真时,才挂起某代码行。,1)从“类型”列表中选择“如果表达式为真则在定位处中断”。,2)在“定位”框中,输入适当的位置。,3)在“表达式”框中,输入相应的表达式。,4)单击“添加”按钮。,5)单击“确定”按钮。,(5)移去断点,1)在“断点”对话框中,选择要删除的断点,单击“删除”按钮即可删除断点。,2)在“跟踪”窗口中,找到要删除的断点,双击该代码行左边的灰色区域。或者单击“调试器”工具栏上的“切换断点”按钮。,2024/11/28,43,4.,查看存储的值,(,1,)在“跟踪”窗口中,将光标定位到任何一个变量、数组或属性上,即可在提示条中显示它的当前值。,(,2,)在“监视”窗口的“监视”框中,输入任意有效的,VFP,表达式。该表达式的值和类型就会出现在“监视”窗口的列表中。,2024/11/28,44,7.2.2,定制菜单系统,本节主要介绍状态栏、标题位置、保存与还原和创建默认过程、设置系统菜单。,创建一个基本的菜单系统后,可对它进行定制。例如创建状态栏信息、定义菜单的位置、添加与菜单相匹配的工具栏按钮等。,2024/11/28,45,1.,显示状态栏信息,在选到一个菜单或菜单项时,可在状态栏显示一些说明该菜单或菜单项的信息。,这种信息可帮助用户了解所选菜单的有关情况。,添加提示信息的方法是:,在“提示”栏中单击相应的菜单标题或菜单项。,单击“选项”栏中的按钮,显示“提示选项”对话框,如图,7-21,所示。,在该对话框中已输入了提示信息,并已定义了键标签和键说明。,图,7-21,“提示选项”对话框,2024/11/28,46,2.,定义菜单标题的位置,在应用程序中可预先设置用户自定义菜单标题位置。,首先打开“常规选项”对话框,根据提示可设置菜单相对于活动菜单系统的相对位置。,在“常规选项”对话框中,有几个位置选项:“替换”、“追加”、“在,.,之前”和“在,.,之后”。,如图7-21所示,在每一个菜单对应的“提示选项”对话框中,“对象”下拉列表中也有几个选项可控制菜单标题位置,其含义已在7.1.2节介绍。,2024/11/28,47,3.,保存与还原菜单,有时需要暂时将正在使用的菜单移去,而用另一个菜单替换,使用完成后再将原来的菜单恢复过来。,VFP,提供了压栈与出栈技术可实现这种替换。,压栈与出栈技术主要由下述两条命令完成:,PUSH MENU,和,POP MENU,。,下面的程序段从系统菜单栏上删除“窗口”菜单标题:,PUSH MENU _MSYSMENU,RELEASE PAD MSMWINDO OF _MSYSMENU,WAIT WINDO “,按任一键还原默认菜单,”,POP MENU _MSYSMENU,2024/11/28,48,4.,创建菜单系统默认过程,默认过程就是一段程序代码,是一种全局过程。,可以被程序中的各程序或过程调用。,例如,一个正在开发的应用程序,其中有一些未开发设计好的子菜单或过程,可以为这些菜单或过程创建一个临时占位过程,当选定这些菜单时,执行这个默认过程,这样有利于调试。下面的代码就是用于这一目的的:,=,MESSAGEBOX(,此功能不可用),将上述代码输入“常规选项”的过程窗口即完成了创建默认过程。图7-22是上述默认过程的运行结果。,图,7-22,默认过程执行结果,2024/11/28,49,7.3,数据共享访问程序设计,在共享环境中,一般有两种方式访问数据:,从独占文件中访问,从共享文件中访问,独占方式是指只有打开表的用户有权使用数据,其他用户不能对该文件进行读写。显然,这种方式不适合大量用户共享数据的环境。,从共享文件中访问数据是指当一个用户访问某文件数据时,允许其他用户对该文件数据进行访问。,2024/11/28,50,7.3.1,控制对数据的访问,1.,访问数据,对于共享方式,允许多个用户在同一时刻打开同一个数据文件。,如果某一用户想要更新数据,例如对某一条记录进行修改或添加一条新的记录,则必须首先将该记录占用,不允许其他用户读或写该记录。,在数据库中,这种行为称为给记录加锁。,其他用户仍有权读或写其他未加锁的记录。,该用户将数据写入该加锁的记录,写完后,再释放该记录,即开锁。,实际上,所谓的共享,是通过对记录或表的不断加锁和开锁完成的。,2024/11/28,51,(,1,)以独占方式使用表,打开一个文件最严格的限制方式是独占方式。,在默认情况下,通过界面打开的表都是独占方式的。,也可以使用,VFP,命令明确声明以独占打开一个表,其方法是在“命令”窗口或在程序中使用下述命令:,SET EXCLUSIVE ON,USE ,或者,USE ,EXCLUSIVE,2024/11/28,52,(,1,)以独占方式使用表(续),另外,下述命令要求以独占方式打开一个表:,ALTER TABLE,INDEX,,当创建、添加或删除一个复合索引标识时,INSERT BLANK,MODIFY STRUCTURE,PACK,REINDEX,ZAP,可以使用,FLOCK(),函数来限制对表的访问。,使用该函数锁定一个表,则其他用户不能对该表进行写操作,只能读。,2024/11/28,53,(,2,)以共享访问的方式使用表,以共享方式打开一个表时,多个工作站可同时访问该表。,通过界面打开表时,可以不考虑,SET EXCLUSIVE,默认的,ON,设置,而明确使用,VFP,命令打开一个表供共享使用。,若要打开一个共享方式的表,可在“命令”窗口中键入下列命令:,SET EXCLUSIVE OFF,USE ,或者,USE ,SHARED,2024/11/28,54,2.,数据的加锁与解锁,如果要共享访问文件,必须通过锁定表和记录来对这种访问进行管理。,锁定不同于访问权限,它既可以对数据进行长期控制,也可以短期控制。,VFP,提供自动和人工两种锁定方式。,(1)选择记录或表锁定,无论是自动记录锁定还是人工记录锁定,目的都是为了防止两个用户同时写一个记录。,表锁定用来防止其他用户在表中进行写入操作,但允许读取整个表。,由于表锁定阻止其他用户更新表中的记录,因而很少使用。,2024/11/28,55,(,2,)选择自动或人工锁定,除了选择记录锁定或者表锁定,还可以选择自动锁定或者人工锁定。,许多,VFP,命令在执行之前都会自动锁定一个记录或一个表,如果成功锁定了记录或表,则执行该命令,然后再解锁。,表,7-4,列出一些具有能自动锁定记录和表功能的命令。,2024/11/28,56,2,)表头和表锁定的特点,一些,VFP,命令锁定整个表,而有些命令则只锁定表头。,表锁定命令比表头锁定命令更严格。,锁定表头时,其他用户不能添加或删除记录,但可以修改字段内的数据。,在任一时刻,只允许一个用户对表执行,APPEND BLANK,命令,否则,用户将得到错误信息:“其他用户正在使用文件”。,这个信息表明有两个或多个用户正在执行,APPEND BLANK,命令。,2024/11/28,57,(,3,)人工锁定记录和表,可以用锁定函数人工锁定一个记录或一个表。,包括:,RLOCK(),、,LOCK(),和,FLOCK(),。,RLOCK(),函数等同于,LOCK(),函数,都可以锁定一个或多个记录。,FLOCK(),锁定一个文件。,LOCK(),和,RLOCK(),函数可以用于锁定表头。,如果把,0,作为记录编号提供给,LOCK(),或,RLOCK(),,,而且测试表明表头未锁定,则该函数将锁定表头并返回“真”(,.,T.,)。,2024/11/28,58,(,4,)数据解锁,在共享环境下锁定记录或文件并完成了相应的数据操作之后,应及时解锁。,几种解锁的办法:,只需简单地移动到下一个记录就能解锁,其他情况则需要明确的命令,要解锁被自动锁定的记录,只需移动记录指针,甚至在设置,MULTILOCKS ON,的情况下也是如此。,对于人工锁定的记录,必须明确地对记录解锁,仅仅移动记录指针是不够的。,2024/11/28,59,(,4,)数据解锁(续),对人工和自动的记录锁定和表锁定进行解锁的命令:,UNLOCK:,解锁当前工作区内的记录和文件。,UNLOCK ALL:,对当前工作期内所有的工作区解锁。,SET MULTILOCKS OFF:,建立新锁定的同时自动解锁当前锁定。,FLOCK():,在锁定文件之前解锁文件中的所有记录。,CLEAR ALL、CLOSE ALL、USE、QUIT:,对所有记录和文件解锁。,END TRANSACTION:,对所有的自动锁定项解锁。,TABLEUPDATE():,在更新表之前解锁所有锁定项。,注意:,如果记录在,UDF,中被自动锁定,那么当移开记录指针然后又移回该记录时,锁定将被解除。可以使用表缓冲避免这个问题。,2024/11/28,60,7.3.2,使用数据工作期,为确保共享环境中的每个用户都具有安全、正确的环境副本,确保表单的多个实例能独立操作,,VFP,提供了数据工作期。,数据工作期是对当前动态工作环境的描述。,可以将数据工作期看成是一个小型的数据环境,这个环境运行在同一机器上一个开放的,VFP,工作期内。,每个数据工作期包括:,表单的数据环境中各项的备份。,临时表代表打开的表、索引及其关系。,2024/11/28,61,1.,使用私有数据工作期,如果想更多地控制表单的多个实例,可以使用私有数据工作期。,当表单使用私有数据工作期时,,VFP,为应用程序创建的表单、表单集或工具栏控件的每个实例新建一个数据工作期。,每个私有数据工作期包括:,表单的数据环境中每个表、索引和关系的独立备份。,数目不限的工作区。,独立于表单基表的每个备份表的记录指针。,2024/11/28,62,1.,使用私有数据工作期(续),可用数据工作期数目只受可用的系统内存和磁盘空间的限制。,通过设置表单的,DataSession,属性可使用数据工作期。,DataSession,的含义是:,DataSession = 1,默认的数据工作期(缺省设置),DataSession = 2,私有数据工作期。,若要使用私有数据工作期,可以:,在“表单设计器”中,将表单的,DataSession,属性设置为“,2,私有数据工作期”;,或者在程序代码中将,DataSession,属性设置为,2,:,frmFormName.DataSession = 2,注意:,只能在设计时设置,DataSession,属性。在运行时刻,DataSession,为只读属性。,2024/11/28,63,1.,使用私有数据工作期(续),当表单使用的是私有数据工作期时,在单个的机器上,一个,VFP,工作期中打开表单的每个实例都使用自己的数据环境。,使用私有数据工作期类似于在不同的工作站上同时运行同一个表单,如图,7-23,所示。,图,7-23,等价的多个数据工作期,2024/11/28,64,2.,识别数据工作期,每个私有数据工作期是单独识别的。,可在“数据工作期”窗口中查看每个数据工作期内容;也可通过在,Load,事件代码中的命令改变数据工作期说明。,使用,DataSessionID,运行时刻属性,可以查看每个数据工作期的识别号。,示例显示名为,frmMyForm,的表单的,DataSessionID,属性。,DO FORM frmMyForm,? frmMyForm.DataSessionID,如果使用,NAME,子句激活表单,可使用该表单的名称访问,DataSessionID,属性,如下面的代码所示:,DO FORM MyForm NAME one,? one.DataSessionID,2024/11/28,65,3.,使用多个表单实例更新数据,私有数据工作期生成各自独立的工作区,工作区包含了表单的开启表、索引和关系的独立备份,表单的每个备份引用了相同的基表和索引文件。,当用户从表单的一个实例中更新记录时,将同时更新该表单引用的基表。,当定位到更改的记录时,就可以看到表单另一个实例所作的更改。,如果在一个私有数据工作期对记录或表进行了锁定,其他私有数据工作期就不能再进行锁定。,通过遵守其他数据工作期所作的锁定,,VFP,可以保护基表更新的完整性。,2024/11/28,66,4.,定制数据工作期的环境,由于数据工作期控制着某些,SET,命令的范围,可以在单一的,VFP,工作期中使用私有数据工作期以建立自定义的,SET,命令设置。,例如,,SET EXACT,命令控制比较不同长度字符串时使用的规则,作用于当前数据工作期。,SET EXACT,命令的默认设置为,OFF,,规定表达式右边直到末尾的每个字符都完全匹配时,两个表达式才算相等。,通过在默认的数据工作期中将,SET EXACT,命令设置为,OFF,,可以使用“模糊”搜索或相似查找。,但是,应用程序可能包含特殊的表单,它需要精确匹配。,可以将需要精确匹配的表单的,DataSession,属性设置为2,使用私有数据工作期,然后将,SET EXACT,命令设置为,ON。,由于仅在使用私有数据工作期的表单时,使用,SET,命令,则当为一个特定的表单启用自定义工作期设置时,可以保留整个,VFP,工作期设置。,2024/11/28,67,5.,使自动私有数据工作期的设置无效,在使用表单的私有数据工作期时,在一个表单中对数据所作的更改不会自动地体现到相同表单的其他实例中。,如果想让表单的所有实例都访问相同的数据,并且立即反映对公共数据所作的更改,则可以取消自动数据工作期的设置。,要使自动数据工作期的设置无效,可使用命令:,SET DATASESSION TO 1,或者,SET DATASESSION TO,这两个命令都将启用命令窗口以及项目管理器所控制的默认数据工作期。,2024/11/28,68,7.3.3,缓冲访问数据,在多用户环境下,,VFP,的记录缓冲和表缓冲技术可以保护对单个记录或多个记录所做的数据更新以及数据维护操作。,缓冲区可以自动测试、锁定及解锁记录或表。,缓冲技术用来解决数据更新操作过程中所遇到的冲突。,2024/11/28,69,1.,缓冲方法和锁定方式,VFP,提供两种缓冲:,记录缓冲:用于一次只对一个记录进行的访问、修改或写操作。,表缓冲:用于对多个记录的更新操作。,在使用缓冲时,有两种锁定方式:,保守式,开放式,锁定方式用来决定一个或多个记录被锁定的时机和方法,2024/11/28,70,1.,缓冲方法和锁定方式(续),保守式缓冲:在多用户环境中,保守式缓冲能防止其他用户在对某一特定记录或表正进行修改时访问它。保守式缓冲为单个记录的修改提供最安全的工作环境,但是会降低用户的操作速度。这种缓冲方式非常类似于,FoxPro,以前版本的标准锁定机制,此外它还带有内在数据缓冲等更多的好处。,开放式缓冲:开放式缓冲是更新记录的有效方法,因为锁定只在写记录时生效,这样在多用户环境中使单个用户独占系统的时间最少。在视图上使用记录或表缓冲时,,VFP,将强制使用开放式锁定。,2024/11/28,71,2.,启用缓冲,使用函数,CURSORSETPROP(Buffering, Num),可设置缓冲和锁定方法,表,7-5,列出了,Num,函数的有效值。,缓冲方法,缓冲方法和锁定方式,Num,取值,无缓冲,默认值,1,记,录,缓,冲,保守式记录锁定。,Visual FoxPro,在指针位置锁定记录。如果锁定成功,,Visual FoxPro,将该记录放入缓冲区并允许编辑。在移动记录指针或发出,TABLEUPDATE( ),命令时,,Visual FoxPro,将把缓冲记录写入原来的表中,2,开放式记录锁定。,Visual FoxPro,将指针位置所在的记录写入缓冲区并允许编辑。当移动记录指针或发出,TABLEUPDATE( ),命令时,,Visual FoxPro,对该记录进行锁定。如果锁定成功,,Visual FoxPro,将对磁盘上的记录的当前值与原来的缓冲区值进行比较。如果两值相同,则编辑结果写入原来的表;否则发出错误信息,3,表,缓,冲,保守式表锁定。,Visual FoxPro,在记录指针位置锁定记录。如果锁定成功,,Visual FoxPro,将把该记录放入缓冲区并允许编辑。使用,TABLEUPDATE( ),命令将把缓冲记录写入原来的表,4,开放式表锁定。在发出,TABLEUPDATE( ),命令前,,Visual FoxPro,把记录写入缓冲区并允许编辑,然后对缓冲区内的每一个记录进行下列操作:,对每一个已编辑的记录锁定,一旦锁定成功,即对磁盘上的每一记录的当前值与原来的缓冲区值进行比较,如果两值相同,将编辑结果写入原来的表,如果两值不同,给出错误信息,5,表,7-5,缓冲方式及设定方法,2024/11/28,72,7.3.4,更新数据,1.,使用缓冲更新数据,(,1,)在表缓冲区中追加和删除记录,1,)追加记录。使用,APPEND,或,APPEND BLANK,命令。当追加了一条记录之后,在表缓冲区中刚增加的记录的记录序号为负值。可使用,RECNO(),函数返回记录序号,使用,GO n,命令定位记录。,例如,在当前表缓冲区中原有,7,、,7,、,9,三条记录,使用,APPEND,或,APPEND BLANK,命令追加三条记录后,此时缓冲区将包含,6,条记录,对应的,RECNO(),的值是,7,、,7,、,9,、-,1,、-,2,和-,3,。,2024/11/28,73,(,1,)在表缓冲区中追加和删除记录(续),2,)删除记录。从表缓冲区中删除追加的记录的操作步骤如下:,使用带负值的,GO,命令将记录指针定位到要删除的记录,例如,,GO,-,1,。,使用,DELETE,命令将该记录加上删除标记。,使用,TABLEREVERT(),函数将该记录从缓冲区中移去。,使用,.,T.,值的,TABLEREVRT(),函数,可从表缓冲区中移去所有追加的记录。,2024/11/28,74,(,2,)将表缓冲区中记录写入表中,TABLEUPDATE(),命令将所有当前的记录写入一个表,包括已打上删除标记的记录。,下面是一个在启用保守式记录缓冲方式的情况下,更新记录的代码程序段:,OPEN DATABASE,成绩管理,USE xk.dbf,= cursorsetprop(Buffering, 2),lModified = .F.,FOR nFieldNum = 1 TO FUNCTION( ),IF GETFLDSTATE(nFieldNum) = 2,lModified = .T.,EXIT,ENDIF,ENDFOR,IF lModified,nResult = MESSAGEBOX (Record has been modified. Save?, 4+32+256, data change),IF nResult = 7,=,TABLEREVERT(.F.),ENDIF,ENDIF,SKIP,IF EOF( ),= MESSAGEBOX(already at bottom),SKIP 1,ENDIF,THISFORM.REFRESH,2024/11/28,75,2.,使用事务处理更新数据,事务处理更新操作是一种“要么全都做,要么全不做”的更新操作。,它实际上不直接对数据库进行更新操作,而是处于缓冲操作的外层,用来缓冲对内存或硬盘的数据更新操作。实际的数据库更新在事务结束之后进行。,若由于某种原因系统不能执行对数据库的更新操作,就可回滚整个事务处理,而不执行任何更新操作。,事务保护机制将整段代码作为一个受保护的、可恢复的单元,其保护功能更强。,可以使用事务处理缓冲对表、结构化的,.,cdx,文件及与数据库表相关的备注文件进行修改,但不能使用事务对涉及内存变量和其他对象的操作进行更新。,一般情况下,事务最好和记录缓冲一起使用。,2024/11/28,76,(,1,)控制事务处理的命令,VFP,提供了三个命令和一个函数控制对事务处理:,BEGIN TRANSACTION:,初始化一个事务。,TXNLEVEL():,确定当前事务的等级。,ROLLBACK:,取消最近一条,BEGINTRANSACTION,语句以来所做的全部修改。,END TRANSACTION:,锁定记录,将最近一条,BEGIN TRANSACTION,语句以来对数据库中的表所做的全部修改写入磁盘,然后解锁记录。,另外,当使用远程表中存储的数据时,事务处理命令控件只更新视图临时表的本地备份中的数据,而不能更新远程基表的数据。,对远程基表的数据的更新操作可使用,SQLSETPROP(),,然后用,SQLCOMMIT(),和,SQLROLLBACK(),函数控制事务处理。,2024/11/28,77,(,1,)控制事务处理的命令(续),下面是事务处理的程序代码:,BEGIN TRANSACTION,*,更新数据,IF lSuccess=.F.&,出错,ROLLBACK&,回滚,ELSE&,执行修改,*,确认数据,IF&,出错,ROLLBACK,ELSE,END TRANSACTION,ENDIF,ENDIF,2024/11/28,78,(,2,)事务处理规则,1,)一个事务处理起始于,BEGIN TRANSACTION,命令,以,END TRANSACTION,或,ROLLBACK,命令终止。只有,END TRANSACTION,语句,而前面没有,BEGIN TRANSACTION,与之匹配则会出错。,2,),ROLLBACK,语句前没有,BEGIN TRANSACTION,将出错。,3,)除非应用程序中止(这将导致回滚操作),事务处理一旦开始,直到遇到相应的,END TRANSACTION,语句(或回滚语句)这一期间,始终保持有效,在多个程序、函数之间切换的情况下也是如此。,2024/11/28,79,(,2,)事务处理规则(续),4,)对于涉及事务处理数据的查询,,VFP,在使用磁盘数据前,首先使用在事务处理缓冲区内的高速缓冲数据,确保使用的是最近的数据。,5,)如果在事务处理过程中应用程序中止,则所有操作回滚。,6,)事务处理只在数据库容器内进行。,7,)如果,INDEX,命令改写了一个已有的索引文件,或者有任一索引文件已打开,则不能使用,INDEX,命令。,8,)事务处理只在数据工作期中起作用。,2024/11/28,80,(,2,)事务处理规则(续),事务处理完成了下列锁定动作:,当一个命令直接或间接调用事务处理时,,VFP,将强制执行锁定动作。任何系统或用户的直接或间接命令将被放入高速缓存,直至,ROLLBACK,或,END TRANSACTION,命令结束事务处理操作。,如果在事务处理中使用了锁定命令,如,FLOCK(),或,RLOCK(),,则,END TRANSACTION,语句将不会解锁。因此必须明确地解除任何在事务处理中进行的明确锁定。应该使包含,FLOCK(),或,RLOCK(),命令的事务处理尽量简短;否则,用户会长时间不能访问被锁定的记录。,2024/11/28,81,3.,使用视图更新数据,VFP,视图具有的更新冲突管理技术可以用来管理多用户对数据的访问。,通过使用,WhereType,属性,视图控制发送到基于视图的基表的内容。,可以为本地和远程视图设置该属性。,WhereType,属性提供了,4,种设置:,DB_KEY:,只比较关键字。,DB_KEYANDUPDATABLE:,比较视图中的关键字段和所有可更新字段。,DB_KEYANDMODIFIED(,默认):比较视图中的关键字段和已更改字段。,DB_KEYANDTIMESTAMP:,比较基表记录中所有字段的时间戳。,2024/11/28,82,3.,使用视图更新数据(续),通过选择,4,种设置之一,可控制,VFP,如何生成发送到视图基表的,SQL Update,语句的,WHERE,子句。,可以使用“视图设计器”的“更新条件”选项卡来选择需要的设置,或者使用,DBSETPROP(),函数设置一个视图定义的,WhereType,属性。,要想更改一个活动视图临时表的,WhereType,设置,则使用,CURSORSETPROP(),。,在,VFP,中,建立视图需要选择表和视图中包含的字段,指定与表的连接条件,以及如何将视图中已修改的数据送回到原表或者基表中,参见第,5,章有关内容的介绍。,2024/11/28,83,3.,使用视图更新数据(续),视图设计器的“更新条件”选项卡如图,7-24,所示。,通过设置至少一个关键字段并选中“发送,SQL,更新”选项,可使对本地表的修改能回送到源表中。,打开视图时,“更新条件”选项卡会显示表中哪些字段是关键字段。在“更新条件”选项卡中单击“字段名”左边的钥匙图标,可重新设置关键字段。单击“重置关键字”按钮,可将关键字段恢复到原来设置的情况。,在视图中可指定可更新的字段。方法是在“更新条件”选项卡中单击“字段名”左边的铅笔图标。,在已定义了关键字段的前提下,单击“全部更新”按钮,则表中所有字段可更新。,图,7-24,视图设计器的,“更新条件”选项卡,2024/11/28,84,7.3.5,管理冲突,本节主要介绍冲突的检测与消除的方法。,在一个多用户环境中,精心选择打开、缓冲并锁定数据的时间和方式能保证高效地进行数据更新。,应尽量减少访问记录或表时发生冲突的时间,同时必须预测到不可避免的冲突将导致的后果,并对这种冲突进行管理。,冲突一般在一个用户试图锁定一个当前正被其他用户锁定的记录或表时发生。,当第一个用户已经锁定一个记录或表,现在却又试图去锁定另一个已经被
展开阅读全文