如果你在程序中从没想过需要用到Timer, 那是多么地遗憾! 本版的朋友们一定要看!
这篇文章希望能给本论坛的朋友们一些帮助, 让我们的程序变得更加的完美. 因为有一些代码引用和注释,请调整窗口到较宽看起来会更清晰且易理解一些。
不要奇怪我为什么这么自信, 因为即便是VFP的高手老手, 相信这篇文章也能起到参考作用.
这些内容从未被收录到任何技术文献或者教材中, 所以你不太可能从别的地方见到,对,这是本人在本论坛2012年6月1日的原创小文。
也不要奇怪我为什么这么热情,那全是因为 Timer ,也因为事隔十年突然翻开尘封的编程记忆...
我最近爱上Timer了,她们是如此简单温顺,我到处都带上她们,在每个Form里都要带上她们,
是的,是她们,不止一个,虽然她们每一个在表面上都长得一模一样,
但我把她们在骨子里调教得每个都各有特点.....呃.....
我说的是用 Timer 优化程序设计, 顺便想跟大家讨论一下Timer的某些特性,
Timer 是有共性的,但当然我们也可以把她们打扮得极具个性,以下就是把 Timer 个性化的案例。
在这个案例中,我的 Timer 表现出色,令人惊艳。
案例1.(仿佛还有案例n.....)
假设有一个三层的多表关联,我们分别用三个Grid来显示它们, 如下所示:
Grid1 父表 省 市 其它n个字段
Grid2 子表 省 市 县 其它n个字段
Grid3 孙表 省 市 县 镇 其它n个字段
子表需要用省和市与父表关联
孙表需要用省和市和县与子表关联
一般情况下, 我们会使用Grid控件的AfterRowColChange事件来刷新表单, 以达到用户交互的目的.
这个方法当然很好,
用户在父表中换行时, 子表的记录先联动,然后孙表的记录再跟着子表联动
用户在子表中换行时, 孙表的记录联动
实际应用中, 经常有这样的景象:
用户处在第三行, 想看第七行的内容, 他连续向下滚行四次到第七行, 停下来看内容,
那么第四、五、六这三行都只是过路而已,但我们的软件仍然把所有该做的不该做的事都做了一次。
有时候,用户会按住方向键不放长达10秒,滚n(n>10)行后再停下来
甚至有时候,用户会上下方向键不停乱按(无意识或者下意识行为?)
我们惊奇地发现,用户的这些无效操作远多于他们的有效操作,比例甚至超过10倍!!!
有两个问题产生了
1.因为拖着关联表, 父表的记录移动肯定跑得不快, 用户操作起来感觉不爽了
2.网络环境下, 恐怖的流量产生了, 有时会搞得父表根本跑不动
(----我本人对操作的爽度有点小苛求,对数据流量控制也有点小苛求)
于是本文的精华来了, Timer 悄悄地轻轻地慢慢地施施然出场了
Timer 可以达到如下的神奇效果:
1. 用户操作快捷爽利, 翻页滚行运行如飞, 就如同没有任何关联的单一表格般轻松
2. 系统开销更小, 网络数据流量成倍数减少, 无效流量几乎减少到极限
3. 开发者(也就是兄弟您哪)维护关键的刷新代码更容易, 变更检索条件更轻松
先设置一下我们可爱的Timer吧, 初始设置如下:
Timer1.enaled = .f. (( Timer1 说了:我不是普通的 Timer,我是本贴的主角Timer,我的口号是 敌不动,我不动,敌动了,我也忍忍再动 ))
Timer1.Interval = 300 (( Timer1又说了:我就忍 0.3 秒再行动吧,如果期间有敌情,我就再忍 0.3 秒才行动,总之要把敌情摸清楚再搞比较好 ))
再把咱们以前的换行后的事件代码中所有用于刷新表单的东西删除掉,写上一句代码就够了。
Grid1.AfterRowColChange事件代码:
thisform.timer1.enable = .t. && 这一句的意思是说:俺知道是时候更新关联表的数据了,但现在这事儿归 Timer1 管,俺只负责通知它就行了。
再为咱们的timer事件写一点点代码Timer1.timer事件代码:
this.enable = .f. && Timer1说了: 这事儿归我管没错,但我只做一次,我可不会象个普通 Timer 一样翻来覆去无休无止搞同一件事。下次?下次另外通知我哈
thisform.refresh && Timer1又说了:表单里的各位兄弟姐妹们,打雷了,下雨了,收衣服喽.....总之该干嘛干嘛吧
看到这里,高手应该已经明白了,快点去改程序吧,你一定有很多地方用得上这个思路。thisform.refresh && Timer1又说了:表单里的各位兄弟姐妹们,打雷了,下雨了,收衣服喽.....总之该干嘛干嘛吧
以下是给新人们的进一步讲解
第一、表间关联在什么地方体现啊?
答: 前面的描述中没有体现表间关联的部分,我们假设已经用set filter建立了表间关联,例如,可以这样:
1.在数据环境中添加所有相关的表: 父表/子表/孙表
2.在表单的init事件中写如下代码
sele 子表 && 这一句的意思是说:先教育儿子吧
set filter to 省 = 父表.省 and 市 = 父表.市 && 这一句的意思是说:教育主题:做儿子的别搞错了爹哦,以后点到你老子时,你得站出来
sele 孙表 && 这一句的意思是说:再接着教育孙子
set filter to 省 = 子表.省 and 市 = 子表.市 and 县 = 子表.县 && 这一句的意思是说:教育主题:做孙子的要学习他爷爷的儿子那样的不忘本的优良品德
这样一个最简单的手动的表间关联就建立起来了.set filter to 省 = 父表.省 and 市 = 父表.市 && 这一句的意思是说:教育主题:做儿子的别搞错了爹哦,以后点到你老子时,你得站出来
sele 孙表 && 这一句的意思是说:再接着教育孙子
set filter to 省 = 子表.省 and 市 = 子表.市 and 县 = 子表.县 && 这一句的意思是说:教育主题:做孙子的要学习他爷爷的儿子那样的不忘本的优良品德
第二、但我推荐用参数化的视图来做Grid的数据源
(------------arefeng:代码略了吧,打字好辛苦------------看官:切......arefeng:好吧,我坚持一下-------------------),
在表单的load事件中写如下代码(一定要看清楚啊,每个符号都很关键的,尤其是那些出现在不合适地方的符号)
create sql view 子表 as sele * from 子表 where;
省 = ?父表.省 and ;
市 = ?父表.市 &&:这一句的意思是说,让我看看这个当老子的都有哪些儿子
create sql view 孙表 as sele * from 孙表 where;
省 = ?子表.省 and ;
市 = ?子表.市 and ;
县 = ?子表.县 &&:这一句的意思是说,让我看看那个儿子都生了哪些孙子
省 = ?父表.省 and ;
市 = ?父表.市 &&:这一句的意思是说,让我看看这个当老子的都有哪些儿子
create sql view 孙表 as sele * from 孙表 where;
省 = ?子表.省 and ;
市 = ?子表.市 and ;
县 = ?子表.县 &&:这一句的意思是说,让我看看那个儿子都生了哪些孙子
则上面的Timer1.Timer事件需要补充成如下:
this.enable = .f. &&:Timer1说:这一句的意思......前面不是已经说过了吗?
=requery("子表") &&:Timer1说:那个谁,叫你的儿子们都出来吧
=requery("孙表") &&: 然后那个站最前面那儿子,去把你家的儿子们都叫出来吧,你兄弟们的儿子就不要来了。
thisform.refresh &&:Timer最后说:这一句的意思...还用得着我再说吗?
=requery("子表") &&:Timer1说:那个谁,叫你的儿子们都出来吧
=requery("孙表") &&: 然后那个站最前面那儿子,去把你家的儿子们都叫出来吧,你兄弟们的儿子就不要来了。
thisform.refresh &&:Timer最后说:这一句的意思...还用得着我再说吗?
OK, 神奇的可以智能感知用户操作意图的表间联动表单出世了, 而且它的代码简单到招天打雷劈的妖孽程度, 两种方案都只要7行就搞定一切 !!!
什么?不可以忽悠?好吧,我承认这不是软件的AI在智能感知,这其实是我在炒作概念,但是我这不是为了让我心爱的 Timer 能早点红起来吗?
这7行代码手动建立了表间的关联关系, 实现了表格间的数据联动, 还实现了对用户操作意图的智能感知......呃.....用户使用了后也这么说啊...
我们来看一下这7行代码的分布 代码的位置 filter方案 参数化视图方案
表单load中 2行
表单init中 4行
timer中 2行 4行
表格的AfterRowColChange中 1行 1行
兄弟们, 有木有见过比这更 牛 的多表间联动刷新的方案 ?
再解释几个要点:
一、 timer1.interval = 300 这个是我测试的操作习惯临界点, 它意味着如果用户连续按方向键的时间间隔不超过0.3秒的话,就不进行任何读取和刷新的动作,这样就实现了"操作意图智能感知", 这个时间调整到1000(也就是1秒)都不会给用户带来反感.
二、AfterRowColChange中一般还应加上行列移动判断,但这不是Timer相关的代码,大多数应用中本身就会有,所以没有算进来。实际应用中AfterRowColChange的代码写成大体如下这样比较合理:
if this.rowColChange <> 0 and rowColChange <> 2 &&:这一句的意思是说:如果用户横着跑,俺就不去招惹 Timer1 了吧,她烦着呢
thisform.time1.enable = .t. &&:这一句的意思是说:如果用户顺着来,俺还是让 Timer1 搞一下吧,总是要搞一下的,少搞不等于不搞啊。
endi &&:这一句的意思是说:没有其它如果了。
thisform.time1.enable = .t. &&:这一句的意思是说:如果用户顺着来,俺还是让 Timer1 搞一下吧,总是要搞一下的,少搞不等于不搞啊。
endi &&:这一句的意思是说:没有其它如果了。
三、要点太多了,看朋友们的理解程度再讨论吧。非常欢迎朋友们试验并提出问题来讨论,我在实际项目中有太多应用小花招,相信可以就这方面帮上大家的忙。
以上给出的描述并不适合大家作为终极方案直接用,因为有许多细节需要处理得更细致才能达到真正美妙的效果,
但是为了易于理解,我刻意剔除了那些可能会影响重点的细枝末节。
很期待有朋友应用了之后拿出自己的应用体会来讨论,看能不能发现并自行修正补充这些细节,甚至优化整个思路和方案,给我一些惊喜。
最后,别找我要完整实现的代码或者表单什么的,我是卖方案的,啊不,我是推广方案普及科技的...呃...我只负责...想法子...出点子...找路子...泡m子...
如果你看到这里只是满脑子想要我家那些 Timer,哼哼...嘿嘿...
----------------------------------------------------------------------------
台上一分钟,台下十年功,看看Tony的代码神功,我直想自废武功
[ 本帖最后由 arefeng 于 2012-6-2 19:44 编辑 ]