你从VFP教程上看不到的编程小经验.docx
- 文档编号:9964382
- 上传时间:2023-02-07
- 格式:DOCX
- 页数:16
- 大小:30.15KB
你从VFP教程上看不到的编程小经验.docx
《你从VFP教程上看不到的编程小经验.docx》由会员分享,可在线阅读,更多相关《你从VFP教程上看不到的编程小经验.docx(16页珍藏版)》请在冰豆网上搜索。
你从VFP教程上看不到的编程小经验
你从VFP教程上看不到的编程小经验
这是我历年使用VFP编程过程中的小经验,许多问题在高手看来不值一提,但当时我可花了时间尝试后才解决的(那时互联网还不普及,许多问题在教材上又找不到)。
希望对初学VFP编程的网友有所帮助。
另外,虽然现在VFP被认为落伍了,但其实如果你真正学会了(不一定要精通),在日常数据处理工作中还是会有很大用处的。
我最喜欢的是它的命令窗口,灵活好用,可以说无能出其右者……
1、当程序运行之初,与字段绑定的控制显示的值不一定与被绑定的字段的值相同。
因此,要取得字段的值,不能用Object.Value属性值来取得。
2、编增加条码部分的“换条码”功能时,当选定表格中的条码号后,击”换条码“按钮,换条码窗口中出现欲替换的条码号总是为表格中的第一个条码号的情况,如欲删除条码号“D0100009”,却删除了“D0100001”(表格中出现的第一个条码),后将“换条码”的Click事件的方法中的Thisform.Refresh()这句去掉后,即解决了问题。
3、在编类别库Ts_libs中的frm_Cxflmx类别时,设定下拉列表框的RowSourceType属性为“字段”,RowSource属性为字段名。
每一下拉列表框影响GotFocus事件的方法为依据对应字段的索引,影响InternateChange事件的方法包含有“IF!
EMPTY(THIS.DisplayValue)...ENDIF”的条件判断语句,结果引用该类别的例程执行时死锁。
经查试,用“变量=ALLTRIM(THIS.DisplayValue)”和“IF!
EMPTY(变量)...ENDIF”语句后,死锁现象消除。
初步分析:
这是由于在重新建立不同关键词的索引时,“THIS.DisplayValue”的值与依据该作为判断条件的索引都在不断刷新的缘故。
4、激活其它表单时,当引用当前表单控件数据时,一定要指明全称。
如当前表单的控件Text1的LostFocus事件中引用自身控件的值时(例:
SETFILTERTO字段=Thisformset.Form1.Text1.Value),如果只用This.Value,当其它表单里的控件(例:
表格)引用到该值时,将会出错。
5、在编报刊订阅模块时,在读者栏输入过信息后,再在“个人”与“单位”选项中切换到个人时,数据表td_dzmx指向表尾。
反复查看代码,发现是由于在读者栏输入过信息后,数据表td_dzmx经过了SETFILTER过滤。
在“个人”与“单位”选项的INTERCHANGE事件代码中在选定“个人”项代码的选择SELECTtd_dzmx后加上SETFILTERTO,问题得到解决。
所以,在选择数据表后,一定要注意其原选的SETORDER和SETFILTER设置,尤其是SETFILTER。
6、在编报刊推荐模块时,遇到过在表格控件中无法浏览互相关联的子表td_bkmx(报刊明细库)的全部记录而在浏览窗口中却可以,解除两表(父表为td_bkflm)之间的关联并将记录指针移到表头也不行,后将子表的与关键字有关的索引取消即解决了问题(两表之间的关联没解除也没关系)。
7、一定要注意将工作区切换回要操作的工作区。
8、在设计报刊管理系统的随机更换壁纸的功能时,总是出现重复显示一两张画的情况,用VAL(RIGHT(SYS(3),2))获取任意序号的文件名后加在_SCREEN.Picture=(任意序号文件名)也好,还是获取任意序号的文件名后改为统一文件名后调用再改回原文件也好,都无法解决问题,但在Bmps目录下的位图文件大多是小文件的时候却能随机更换壁纸。
后来在DOWHILE...ENDDO语句循环获取VAL(RIGHT(SYS(3),2))时加上一句II=INKEY(0.00001),即解决了此问题。
9、编按班级号顺序+班内分组随机号获取考号时,以“索引”作为临时存放排序号的字段,并以此字段为分组依据。
由于设置的结构索引表达式是为“索引”字段为依据的,导致考号与“索引”字段值相对应。
经反复试验,找到原因,即:
执行LOCATEALLFORVAL(索引)>=lnStartIndexInGroup.AND.VAL(索引)<=lnLastIndexInGroup.AND.EMPTY(考号)命令的结果总是按“索引”字段的顺序寻找,找到的自然是与“索引”字段值相对应的记录。
后来改为按“姓名”字段排序,解决了此问题。
另外,由SYS(3)获取随机号在短时间内有可能重复,且总是按由小到大的顺序,改为RAND()函数后,不会出现这种情况。
(以上记录于2000.08.02以前)
10、找到了一个获取随机考号的既快又好的方法:
以“姓名”字段排序,用RAND()函数组成一个获取随机号的表达式,给“进退”字段(临时借用)赋一随机号,然后以“进退”字段(随机号)排序,根据是否分组(分组的依据如“号”、上次班名称)的设定依次赋给考试号(从小到大),最后再将存放临时数据的字段清空。
(2000.08.03)
另:
当表处于表缓冲状态下时,不能发出INDEXTO命令,因此须将需要在表缓冲状态排序字段设定在结构化索引文件中。
(2000.08.03)
11、在编打印登分表单表时,作为登分表报表的源数据表cj_dfb中总是出现重复学生。
经反复试验,发现是由于SETDELETEOFF语句所致。
可这条语句又不能不要,因为全部用INSERTINTO语句或APPENDBLANK语句建立登分表,会导致登分膨胀,所在我想用设置DELETE为OFF后,定位到已删除记录,找到了就用RECALL恢复它,找不到再用INSERTINTO或APPENDBLANK语句。
后来在过滤范围(全部/非编外/编外)时,在SETFILTERTO语句中加入.AND.!
DELETE()问题解决。
(2000.08.03)
12、今天在制作成绩汇总表的报表文件,解决了一个长期不得其解的问题:
报表数据源不能用宏替换函数“&”,以致报表作为数据源的字段不能随意更换,缺少了通用性。
原来用函数EVLAUATE就可以了。
用了这个函数据,就能在报表的文本框中用任意表达式来作为数据源,如先定义几个学科的相加表达式变量aaa="语文+数学+IIF(ISNULL(物理),0,物理)",然后在报表的文本框中以EVLAUATE(aaa)作为数据源就行了。
这样一来,在成绩库中没有专门的总分字段也行了。
可以考虑全科总分字段依然保留,因为这个数据要存档,特别是期中、期末考试的数据(包括班名次、年级名次),还可以保留语数外总分及名次字段,其它在报表中生成好了。
由于找到了这个办法,原报表中变量变得很有用了,如在报表中定义全部参考人的变量aa,再定义及格人数的变量bb,bb的值设定为如“语文>60”,再在报表的文本框数据源设为(bb/aa)*100,这样就得到了及格率。
由于找到了这个办法,甚至积各班分数段的统计都可用这个方法。
一句话,只要不想长期保留的统计信息,都可以打印报表时取得。
(2000.08.04)
13、昨天的经验让又我解决了表格控件的列控制源ControlSource的属性值不能用函数“&”的问题。
如设aaa="IIF(ISNULL(cj_ksnj1.语文),0,cj_ksnj1.语文)+IIF(ISNULL(cj_ksnj1.数学),0,cj_ksnj1.数学)+..."然后在Grid控件在设列控制源的ControlSource属性为EVLAUATE(aaa)就可以了。
如果表达式长度超过255个字符的话,还可以用两个或更多的变量如bbb="..."、ccc="...",ControlSource属性相应可设为EVLAUATE(aaa)+EVLAUATE(bbb)+EVLAUATE(ccc)就可以了。
如果表达式纯是字段表达式如"cj_ksnj1.语文+cj_ksnj1.数学+cj_ksnj1.外语+...",可直接不要EVLAUATE函数而直接赋给ControlSource就可以。
这一点我以前好象也试过,但不知为什么没成功,可能不是这样设的。
现在成绩库设几个总分字段还需要吗?
看来只需要一个就可以了,其它在浏览或用Grid控件时临时设置吧!
(2000.08.05)
14、又解决了一个在自定义类GrdClickHeaderOrder中不能对包含.NULL.值的字段进行排序的问题。
原用到grdOrderField=This.&lcCurrColumnName.ControlSource和INDEXONEVALUATE(grdOrderField)TAGtempOFc:
\tempcdxDESCENDING这两条命令,第一条用于取得当前列的控制源(包含别名的字段名,控制源包含别名还是经过多次试验后才在自动获取列控制源的方法中加上去的,开始没有加时,得不到预期的显示信息),第二条用于索引。
索引命令时,原来用的是“&”函数,但没有索引,后来改用EVALUATE函数才达到索引目的,可是却不能对包含.NULL.值的字段索引,为此增加了自定义方法,以获取可以接受.NULL.的字段,索引时需要判断该字段是否接受.NULL.值,接受则不索引并提示。
今天上午我在试验中发现在命令窗口中可以对包含.NULL.值的字段进行索引,索引时可以用变量加宏替换“&”代替字段名。
那为什么在自定义类中不能呢?
再试验后得知,原来问题的关键是别名,用变量代替字段名时,不能包含别名,如aa="cj_ksnj1.语文"和bb="语文"索引时就会出现不同情况,前者不能对包含.NULL.值的“语文”字段进行索引,后者却行。
原来担心这样一来,当工作区改变时可能出现找不到字段的错误,试验的结果没有,证明这个方法是行的。
于是我在grdOrderField=This.&lcCurrColumnName.ControlSource命令行后加了grdOrderField=SUBSTR(grdOrderField,AT(".",grdOrderField)+1)这一行,以去掉别名。
用这种方法索引时,只能用宏替换“&”,不能用EVALUATE函数。
(2000.08.05)
15、将自定义类GrdClickHeaderOrder的列控制源ControlSource用EVLAUATE()函数代替后,同样可以对这个列进行自动排序。
现在可以完全不要去考虑统计的问题了,除非要长期保留。
成绩库中可以去掉总分1、总分2字段,但总1、总2的班名次、年级名次可能还不能去掉。
(2000.08.05)
16、今天用SQL语句创建了一个自定义过程和自定义的类(功能一样),用于统计学科各班的分析数据。
用了它以后,一个学科的各班分析数据,只需要数秒钟就统计出来了,以一个班10班计,也只需要最多一分钟。
这比我以前的方法可简单多。
(2000.08.07)
17、对于ComboBox控件来说,当Enabled设为.F.后,即始将其DisplayValue属性设为空,其ListItemID值也不一定是0,因此表单启动后如果ComboBox的Enabled是.F.的话,不能用ListItemID是不是等于0来判断其有没有选定过选项,即使DisplayValue为空时也是这样。
这是我在修改任意条件查询的自定义类时得出的经验。
(2000.08.08)
18、当一个表处表尾时,将不管是否被其它用户锁定都不能锁定,也就是FLOCK()和RLOCK都返回.F.。
(2000.08.10)
19、在编查询当前成绩表单时,在执行到以自定义类GrdClickHeaderOrder创建的控件Form2.Grid1时速度大大降低,并出现了超过DO嵌套层数的错误信息。
原来在表单集的自定义的方法ResetGrid中调用了浏览工具栏的AfterLookStyleChange方法,而后者又调用执行了表单集的ResetGrid方法,导致不断循环。
(2000.08.25)
20、今天又彻底解决了一个在自定义类GrdClickHeaderOrder中存在的困惑问题。
我在用该类建立表格后,在单击列标题时有时会出现“找不到变量(如‘报刊名称’、‘半年价’之类)”的提示信息。
这种情况出现在第二次调用该类建立的表格的时候。
以前一直弄不清楚是什么原因,只是后来用“&”命令后有好长一段时间没有出现此问题,以为已经解决了。
今天当我对该类作了一些修改(对“INDEX”命令行增加了“ADDITIVE”子句,用不加别名的字段名作索引标识<通过变量转换>,以便对增索引过的列用索引标识排序,避免对同一列重复使用“INDEX”命令)后,又出现了此问题,我下决心要找到原因。
我“WAITWINDOW”命令步步搜索,发现问题就出现在“INDEX”命令行上。
我反复用“&”、“()”、“EVALUATE”方式对变量进行替换,都没有解决,甚至我直接用“INDEXON报刊名称TAG报刊名称...”命令还是不能解决问题。
为什么呢?
我真是百思不得其解。
后来我突然想到查看一个单击列标题后有关数据表(bk_bkys)的索引标识,于是我在单击列标题后立即进入命令窗口,键入“MODISTRU”出现数据结构窗口后,发现索引标识多了10多个,有“报刊名称”、“半年价”、“季价”、“一季份数”等,其中有些索引标识对应的同名字段在数据表(bk_bkys)中是没有的,是选前执行过的用该类建立的表格数据源表(bk_dymx),这下子我完全明白了,原来用问题正是出现在“ADDITIVE”子句上,由于用了该子句后,并没有替换了同名非结构复合索引文件,导致了原来的索引标识也保留着,这样自然就出现有些索引标识对应的同名字段在后来的数据表中不存在的情况。
原因找到后,解决起来就容易了,我在用该类的“INIT”事件中删除了同名非结构复合索引文件,一切解决了。
(2000.10.13)
21、在表单中对表进行过滤或排序时,尽可能直接不要使用“SETFILTERTO报刊名称=THISFORMSET.Text1.Value”之类的表达式,否则当表在单表启动就已之前致使表不能自动关闭时,再使用该表时,会出现找不到“THISFORMSET...”之类的提示信息,就是在打印时,也会出现错误信息,最好的方式还是使用全局变量。
(2000.10.26)
22、当编译项目时,能自动找到主程序调用的子程序、表单、报表、图片等,这此调用都是须在命令或自带的属性中明确声明的,如果在自定义的属性中调用的图片,编译时不能加进来,结果执行时出现找不图片的出错信息,因此这些图片需要自己加到项目中。
另编译时要排除的文件,也需要自己加进去,并设定为排除,否则将自动编译到执行程序中。
(2000.10.26)
23、用SELECT-SQL命令查询时可选择排序(ORDER)的方式即降序还是升序,用升降时可用DESCENDING,但不能用ASCENDING指定降序(默认值),因此当指定降序时,不加参数就可以了。
这就是我在编自定义的CboAddItemFromField(由数据表添加数据项Item标题)时指定用降序时出错的原因(我指定了ASCENDING参数)。
(2000.10.26)
24、项目编译时,只要加入主程序,就可以自动将调用的程序添加进来,因此,当不清楚项目中的文件是否有用时,可将项目中主程序以外的文件通通移走,这样项目编译后自动添加进来的文件即为有用文件。
但如果需要指定某文件排除即不编译到执行文件中,则必须将此文件事先手动添加到项目文件中,并设定为排除。
另对于控件的自定义属性中指定的文件(如图标文件),必须必须手动添加到项目文件中,才能编译到执行文件,否则不能自动添加到项目文件中,并不能编译到执行文件中,这样可能会出现执行时找不到文件的错误。
(2000.11.02)
25、在判断ComboBox选定项时,用DisplayValue属性值比用ListItemID属性值更可靠,尤其在经常执行ComboBox的Clear方法时。
我在编打印登分表的表单时,原设计的是在选定不同年级时,执行List1(ComboBox类)的InteractiveChange方法,根据List1值是否是全年级还是班级名来确定显示在Grid1在的注册学生信息,由于每次选定不同年级时,需要根据选定年级的班级数对List1的选择项进行更新(执行Clear方法),结果对List1用是否ListItemID=1(即是否显示为“全年级”)进行判断时,得不到应有的结果,改用DisplayValue="全年级"进行判断,问题解决了。
(2001.01.23)
26、将一些经常要用到的必须要设成全局性质的变量,可放_SCREEN对象的自定义属性中。
(2001.02.22)
27、本人习惯在FOR...ENDFOR语句中循环变量用i,当在被调用的程序或类中用这个循环变量时,会影响调用程序中在FOR...FOR语句中调用该程序或类可能使用的同名变量(i),因此应在程序特别是类库中使用时,最好加LOCALi语句。
(2001.04.10)
28、在对学生成绩进行全科总分、排名次等操作时,因使用BAGINTRAN...ENDTRAN(事务处理)语句,不能用INDEXON...TAG...OF...命令建立非结构索引文件,于是用不带OF的INDEX...TAG...命令在结构索引文件中追加索引标识,然后再用
lnTagCount=TAGCOUNT()
FORi=1TOlnTagCount
lcTagName=TAG(i)
IFlcTagName=...
DELETETAG&lcTagName
ENDIF
ENDFOR
命令删除追加的索引标识,可总是不能全部删除,经过仔细查找,发现了原因,原来当删除了一个索引标识后,索引标识号立即改变,在其后的索引标识号自动减小一个号,而这个号在FOR...ENDFOR循环中已跳过,所以导致删除索引标识时是一个间一个删除,这样待删除的索引如果是紧挨着的话,就不能全部删除。
后来改用下列命令后,问题解决。
lnTagCount=TAGCOUNT()
FORi=10TOlnTagCount&&假如原有的索引标识总共有9个,新增的临时用的索引号即从10号开始
lcTagName=TAG(10)
DELETETAG&lcTagName
ENDFOR
(2001.04.10)
29、在教师档案新教师建档表单集的主表单frmJbxx的Activate事件是加入下列代码后,在快速按移动指镇时,总是出现异常错误(错误码C000005),可能的错误是当按记录移动按钮时,表单都重新一资激活,系统来不及处理,所以出错。
另外,由于有了这些代码,按编辑按钮进行修改后,再按恢复按钮没有恢复。
这是由于GOTOP代码使记录指镇移动了。
THISFORMSET.FrmJbxx.参加工作期1.LostFocus()
THISFORMSET.FrmJbxx.从事教育期1.LostFocus()
SELECTjs_jbxx
GOTOP
结论,当按按钮组中的按钮时,表单都进行一资重新激活。
很大的可能还与按钮中的THISFORM.Refresh()代码有关。
(2001.04.28)
30、编辑教师档案录入表单期间,曾改变Js_jbxx的表结构(最高学历的“取得时间”改为“修毕时间”,但后来又变回去),后来在VFP环境下执行直接点表单文件执行时能顺利执行,但在执行编译好主程序(表单文件没编译进去),在菜单下执行时,却总是出现“找不到变量"修毕时间"”的错误信息,根本就没有出现录入界面。
从错误的信息看,是由于更新表单的代码行引起。
可是我在类库中将这一行注释掉后,还是有问题。
我也仍想可能是由于本地视图在原表修改后没有更新,但重建视图后依然如故。
后来我改变一下表单环境的BeforeOpenTable事件中的原提示信息时,发现在编译后环境下执行没有仍是原提示信息,于是我想这可能有两种情况:
一种可能是主程序中调用的表单文件不是修改后的表单文件(即在VFP环境下执行的表单文件),另一种可能是表单修改后没有重新编译。
这重新编译一下主程序后(表单还是没有编进去,但进行了重新编译),问题解决了。
这一折腾花了去不少时间(半天多)。
(2001.05.01)
31、在对表建立结构化索引时,如果要到复合索引,且字段中包含字段和数值型,此可用“VAL(字符字段)+数值字段”方式,也可“字符字段+STR(数值字段)”,两者看似差不多,但用前一个方法,没有按照预定的要求排序或排序不正确,而后一个方法却没有出现这种现象。
(2001.06.07)
32、表单集的激活事件(Activate)并不只是在首次启动时发生,每次切换表格集中的不同表单(使其可见)时,都会发生Activate事件。
所以如果在表单集的Activate事件中加类SETFILTERTO的命令,该表单集运行期间再设成SETFILTERTO姓名=XXXX之类的过滤在不同的表单时,将全部重置为SETFILTERTO。
也就是说,表单的Activate事件与表单集的Activate事件同时发生。
(2001.11.06)
33、在编程中设定Combobox或ListBox的RowSourceType属性的值为6时,应先清除RowSource属性值,否则可能会出现“找不到"字段"表达式”的错误信息。
(2001.11.09)
34、在编录入教师基本信息的表单,发现一个控件(“姓名1”)中的LostFocus事件中如果有代码,须在全部代码执行完后才会离开该控件,所以如果在LostFocus中有显示其它表单的代码,当其它表单关闭后,焦点依旧在该控件中,于是就会出现不能离开该控件的情况。
所以,如果要离开该控件,须在其它表单的相关代码中加上设置其它控件获取焦点的语句。
(2001.11.23)
35、切记:
在表单或表单集的Load事件中不能调用表单中控件的事件或方法,否则会出现不易发觉的错误。
在编“报刊订阅登记”模块时,我在表单集的load事件中调用了form1中的Dirandiniinfo控件中的getinistr()自定义方法(“lcLastChangeWay=thisformset.form1.Dirandiniinfo1.getinistr()”),结果返回值是莫名其妙的类型:
用type()函数返回类型是“L”型,可是在IFlcLastChangeWay="网上"语句没有提示类型不匹配的错误(如果人为的将lcLastChangeWay=.F.,却会出错);用Waitwindowslastchangeway语名,该语句不执行也不提示错误;而语句“lcLastChangeWay=thisformset.form1.Dirandiniinfo1.getinistr()”本身也没有提示错误。
真地莫名其妙啊!
(2002.10.31)
35、切记:
在用lcOrder=SET("ORDER")得到的原索引标识,再用SETORDERTO&lcOrder试图恢复原索引标识时,在下列情况下会出错:
原索引标识用的是结构索引文件,且
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- VFP 教程 看不到 编程 经验