| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 1288 人关注过本帖, 3 人收藏
标题:VFP学习、开发漫谈 (11)
只看楼主 加入收藏
liuxingang28
Rank: 11Rank: 11Rank: 11Rank: 11
来 自:山东济南
等 级:贵宾
威 望:47
帖 子:658
专家分:2180
注 册:2014-2-7
结帖率:96.88%
收藏(3)
已结贴  问题点数:20 回复次数:12 
VFP学习、开发漫谈 (11)
今天与大伙聊一聊编程中的分支结构和循环结构。

分支结构包括“IF...ENDIF”和 “DO CASE...ENDCASE”两组命令以及 IIF() 和 ICASE() 两个函数。

这几个命令和函数在某些情况下,可以互相代替,但我一般采取如下原则:

1. 尽可能将同一层次上的多个 IF 语句改成 DO CASE 结构,因为 DO CASE 结构更清晰,更简洁。
2. 从可读性来说,尽量少用 ICASE()函数,将其改为 DO CASE 命令较好。
3. 同样,从可读性上考虑,不建议嵌套使用 IIF()函数,即:在IIF()函数内部再使用IIF()函数,可改用 IF...ELSE...ENDIF 结构

在使用 DO CASE 结构时,CASE 语句的前后顺序很重要,因为后面的 CASE 语句是在不满足前面的 CASE 条件时,才会执行。下面是一个计算调节税的代码,各 CASE 语句的顺序不能调换:
程序代码:
nAmt = 工资表.应发工资 - 3500    && 应纳税额
DO CASE
CASE nAmt <= 0                   && 应纳税额小于0,不纳税
    nTax = 0
CASE nAmt <= 1500                && 0 - 1500,税率 3%
    nTax = nAmt * 0.03
CASE nAmt <= 4500                && 1500 - 4500,税率 10%
    nTax = (nAmt - 105) * 0.1
CASE nAmt <= 9000                && 4500 - 9000,税率 20%
    nTax = (nAmt - 555) * 0.2
CASE nAmt <= 35000               && 9000 - 35000,税率 25%
    nTax = (nAmt - 1005) * 0.25
CASE nAmt <= 55000               && 35000 - 55000,税率 30%
    nTax = (nAmt - 2755) * 0.3
CASE nAmt <= 80000               && 55000 - 80000,税率 35%
    nTax = (nAmt - 5555) * 0.35
OTHERWISE                        && 超过 80000,税率 45%
    nTax = (nAmt - 13505) * 0.45
ENDCASE

在判断复选框(CheckBox)是否被选定时,用“IF EMPTY(Check1.Value)”比用“IF Check1.Value = 0”要好。因为复选框的 Value 属性既可以是数值型,也可以是逻辑型。使用前者可适用于这两种情况,而后者仅适用于Value是数值的情况。

VFP 在处理逻辑表达式时有自己的特点。

1. 在处理“条件A AND 条件B”时,若条件A不成立,则不会再去判断条件B。例如:执行“IF 1>2 AND MESSAGEBOX('正确否?',36,'提示')=6”时,并不会弹出对话框。
2. 在处理“条件A OR 条件B”时,若条件A成立,则不会再去判断条件B。例如:执行“IF 2>1 OR MESSAGEBOX('正确否?',36,'提示')=6”时,也不会弹出对话框。

从上面的两种情况可以看出,逻辑连接符(AND,OR)两边的条件表达式的前后顺序,对程序的执行有影响。一般来说,把执行速度最快、最易判断的关系表达式放在前面。

有时候,通过将多个关系表达式用 OR 连接在一起,可以代替多个并列的 IF 语句或DO CASE 语句。例如:

IF 采购单.制单人 # gcUserName
    * 禁止修改其他人的采购单
    lErr = .t.
ENDIF
IF !EMPTY(采购单.审核)
    * 禁止修改已审核的采购单
    lErr = .t.
ENDIF

可以简化为以下语句:

* 禁止修改其他人的采购单和已审核的采购单
IF 采购单.制单人 # gcUserName OR !EMPTY(采购单.审核)
    lErr = .t.
ENDIF

有时候,通过将多个关系表达式用 AND 连接在一起,可以代替嵌套的 IF 语句或DO CASE 语句。例如:

IF THISFORM.cmgEdit.Value = 3    && 单击命令按钮组中的“删除”
    IF MESSAGEBOX('是否删除当前记录?',36+256,'提示') = 6    && 确认删除
        DELETE
        THISFORM.Refresh
    ENDIF
ENDIF

可以简化为以下语句:

IF THISFORM.cmgEdit.Value = 3 AND MESSAGEBOX('是否删除当前记录?',36+256,'提示') = 6
    DELETE
    THISFORM.Refresh
ENDIF

循环结构包括“FOR...”、“DO WHILE...”、“FOR EACH...”和“SCAN”四种结构。

对于“FOR i = 1 to n”这样的循环,需要注意的是:若变量的终止值是一个变量 n,则不要试图在循环内通过修改 n 的值,来达到改变循环次数的目的。这样做的结果是:n 的值确实改变了,但循环次数未变。
图片附件: 游客没有浏览图片的权限,请 登录注册


我们本来试图通过在循环体内将 n 改为 1 使其仅循环一次,但实际情况却是循环仍然执行了三次。这是因为在执行循环前,系统就将变量转换成了常量,从而确定了循环次数。

若将上例改为“DO WHILE”结构,则情况大为不同:
图片附件: 游客没有浏览图片的权限,请 登录注册


运行结果表明,循环仅执行了一次。与 FOR 循环不同,DO WHILE 每执行一次循环,系统都要重新计算一次表达式的值,包括其中的变量。因此在循环体内更改变量值对循环次数有影响。

再看一个实例,将上述代码中的变量 n 改为宏替换:
图片附件: 游客没有浏览图片的权限,请 登录注册


运行结果表明,循环又执行了三次。因为在循环开始时,系统通过宏替换将命令转换成了“DO WHILE i <= 3”,在循环体内改变变量的值对循环次数无影响。

再看下面一个例子,将上述代码修改如下:
图片附件: 游客没有浏览图片的权限,请 登录注册


运行结果表明,循环仅执行了一次。因为循环开始时,宏替换将命令转换成了“DO WHILE i <= n”。

上述几个例子虽然简单,但其中的细微差别却导致了循环行为有很大的不同,需要用户细细品味,举一反三。

FOR EACH 循环主要针对数组和集合。示例:为表单添加一个自定义方法 SetEnabled,用于启用或禁用表单上的文本框。若文本框无需更改,请在设计时将其 TabStop属性设为 .f.
图片附件: 游客没有浏览图片的权限,请 登录注册


SCAN 循环仅针对表,注意以下3点:

1. 默认范围是 ALL
2. 不用在循环体内 SKIP
3. 在执行 ENDSCAN 时系统会自动返回 SCAN 时的工作区,无需添加“SELECT 工作区”

最后,举一个应用实例,从中再体会一下 FOR 循环与 DO WHILE 循环的区别。

功能描述:下图中的 List1和 List2均支持多项选择,单击“>”按钮,将左列表中的选定项添加到右列表的尾部,并且选定的列表项从左列表清除。
图片附件: 游客没有浏览图片的权限,请 登录注册


在“>”按钮的 Click 事件中,若采用 FOR 循环,需使用两个循环,如下所示:
程序代码:
LOCAL oList1,oList2,i
oList1 = THISFORM.List1
oList2 = THISFORM.List2

* 将 List1 中选定的列表项添加到 List2
FOR i = 1 TO oList1.ListCount
    IF oList1.Selected[i]
        oList2.AddItem(oList1.List[i])
    ENDIF
NEXT

* 将 List1 中选定的列表项删除
FOR i = oList1.ListCount TO 1 STEP -1
    IF oList1.Selected[i]
        oList1.RemoveItem(i)
    ENDIF
NEXT

若采用 DO WHILE,仅使用一个循环即可,如下所示:
程序代码:
LOCAL oList1,oList2,i
oList1 = THISFORM.List1
oList2 = THISFORM.List2
i = 1
* 遍历所有列表项
DO WHILE i <= oList1.ListCount
    IF oList1.Selected[i]               && 若列表项被选定
        oList2.AddItem(oList1.List[i])  && 添加列表项到 List2
        oList1.RemoveItem(i)            && 从 List1 中删除列表项
        * 删除 List[i] 后,List[i+1] 会变成 List[i]
    ELSE
        * 移到下一个列表项
        i = i + 1
    ENDIF
ENDDO


[ 本帖最后由 liuxingang28 于 2014-3-17 11:09 编辑 ]
搜索更多相关主题的帖子: 开发 
2014-03-17 10:59
sdta
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
来 自:江苏省连云港市
等 级:版主
威 望:335
帖 子:9848
专家分:27241
注 册:2012-2-5
收藏
得分:0 
nAmt = 工资表.应发工资 - 3500    && 应纳税额
DO CASE
CASE nAmt <= 0                   && 应纳税额小于0,不纳税
    nTax = 0
CASE nAmt <= 1500                && 0 - 1500,税率 3%
    nTax = nAmt * 0.03
CASE nAmt <= 4500                && 1500 - 4500,税率 10%
    nTax = (nAmt - 105) * 0.1
CASE nAmt <= 9000                && 4500 - 9000,税率 20%
    nTax = (nAmt - 555) * 0.2
CASE nAmt <= 35000               && 9000 - 35000,税率 25%
    nTax = (nAmt - 1005) * 0.25
CASE nAmt <= 55000               && 35000 - 55000,税率 30%
    nTax = (nAmt - 2755) * 0.3
CASE nAmt <= 80000               && 55000 - 80000,税率 35%
    nTax = (nAmt - 5555) * 0.35
OTHERWISE                        && 超过 80000,税率 45%
    nTax = (nAmt - 13505) * 0.45
ENDCASE
这种情况,我认为应该建立一个数据表,一旦纳税额发生变化,只要修改表记录就行,不用修改原程序了。

坚守VFP最后的阵地
2014-03-17 12:12
tlliqi
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
等 级:贵宾
威 望:204
帖 子:15453
专家分:65956
注 册:2006-4-27
收藏
得分:0 
回复 2楼 sdta
是这样的 只需改变数据即可
2014-03-17 12:56
taifu945
Rank: 12Rank: 12Rank: 12
等 级:贵宾
威 望:80
帖 子:1545
专家分:3298
注 册:2012-7-6
收藏
得分:20 
楼主本堂讲座中,对各种循环结构做了很精确的分析,细节很值得大家注意。我谨对此作个小小的补充:不要试图在循环结构中对影响循环次数的变量进行变更,无论其是否最终影响循环次数,因为这样做会使程序代码变得难懂。一个较好的处理方法是利用EXIT或LOOP命令使循环走向发生改变,它们常常与IF...ELSE...ENDIF结构联合使用。即,在满足一定条件的情况下才提前退出循环或提前进行下一次循环。
2014-03-17 13:23
wengjl
Rank: 14Rank: 14Rank: 14Rank: 14
等 级:贵宾
威 望:109
帖 子:2232
专家分:3913
注 册:2007-4-27
收藏
得分:0 
我想,作者主要是说明:顺序不能换举例,实际肯定是变化与程序无关的

只求每天有一丁点儿的进步就可以了
2014-03-17 13:25
hu9jj
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
来 自:红土地
等 级:贵宾
威 望:400
帖 子:11857
专家分:43421
注 册:2006-5-13
收藏
得分:0 
以下是引用sdta在2014-3-17 12:12:24的发言:

这种情况,我认为应该建立一个数据表,一旦纳税额发生变化,只要修改表记录就行,不用修改原程序了。
作用不大,个税的税率会变化,分档也可能会变化。若想一劳永逸,则数据表中还要包含应纳税额档次的上下限等内容,增加了代码的复杂程度。

活到老,学到老!http://www.(该域名已经被ISP盗卖了)E-mail:hu-jj@
2014-03-17 15:53
sdta
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
来 自:江苏省连云港市
等 级:版主
威 望:335
帖 子:9848
专家分:27241
注 册:2012-2-5
收藏
得分:0 
以下是引用hu9jj在2014-3-17 15:53:05的发言:

作用不大,个税的税率会变化,分档也可能会变化。若想一劳永逸,则数据表中还要包含应纳税额档次的上下限等内容,增加了代码的复杂程度。
把分档公式写在表记录中,不会增加代码的复杂程序,只会简化代码。

[ 本帖最后由 sdta 于 2014-3-17 16:03 编辑 ]

坚守VFP最后的阵地
2014-03-17 16:02
TonyDeng
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:贵宾
威 望:304
帖 子:25859
专家分:48889
注 册:2011-6-22
收藏
得分:0 
用數據驅動當然比代碼驅動好,前者可以讓用戶自己零活處理,而不用動輒求程序作者修改程序,特別是對方的數據或管理流程比較敏感的時候,除非你靠這個來榨取維護費用。

授人以渔,不授人以鱼。
2014-03-17 20:48
qczx3358
Rank: 2
等 级:论坛游民
帖 子:44
专家分:15
注 册:2014-1-19
收藏
得分:0 
学习了,真不错
2014-03-18 09:47
wzxzh
Rank: 1
等 级:新手上路
帖 子:23
专家分:0
注 册:2014-6-10
收藏
得分:0 
条件判断语句是编程中经常用到的
2014-06-13 20:03
快速回复:VFP学习、开发漫谈 (11)
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.022345 second(s), 10 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved