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

先说一说“Properties Window(属性窗口)”。

1. 要快速定位到某个属性、事件或方法,可先切换到 ALL 标签,再按下 Cltrl+Alt+属性/事件/方法的首字母,如:要定位到 Name 属性,可按下 Ctrl+Alt+N
2. 要修改枚举型属性,可以不从列表中选择,而直接双击属性名或列表框,系统自动在各个选项间切换。如:要将表单的 ShowTips 属性由 .f.设为 .t.,可直接双击 ShowTips属性名或.f.属性列表值
3. 若修改了某个属性,则其属性值的字体由黑色变成粗体紫色,而添加了代码的事件或方法变为粗体红色
4. 若要将某个属性改回系统默认值,最好不要直接修改属性值,而应该单击右键,选择“Set to Default”。好处有二:一是可减少编译后EXE文件的大小,二是若控件来源于自定义类,可恢复对父类属性的继承。
5. 若要仅显示被修改的属性以及添加了代码的事件、方法,可以右键单击属性窗口上方区域,选择“Non_Default Properties Only(仅显示默认属性)”

为表单窗口命名时,应该遵守一定的规范,以保持窗口名称的唯一性,便于在命令或函数中引用。一般情况下,我习惯在表单文件名前加“frm”作为窗口的名称。如:供应商字典的表单文件名为 Vendor.scx,则表单的 Name 属性可设为 frmVendor。要判断供应商字典窗口是否打开,可检测 WEXIST('frmVendor') 函数的返回值。

顺便说一下,若要修改表单文件名,如:Vendor.scx,最好不要在资源管理器中修改,而应该在项目管理器中右键单击表单名,选择“Rename”,再输入新文件名。这样做的好处是,表单的附属文件(如:Vendor.sct)也自动改名。

表单有一个“DataSession(数据工作期)”属性,默认值是“1-Default Data Session(默认工作期)”,实际应用中,应该将其设置为“2-Private Data Session(私有数据工作期)”。当设置为私有工作期时,每个表单的数据环境和系统状态(如:Set Talk、Set Delete、Set Safety等)都是相互独立的,互不影响。

一般情况下,我们只允许运行表单的一个实例。当窗口不存在时,运行DO FORM命令,窗口存在时,运行ACTIVATE WINDOW命令激活该窗口即可。为此,我编写了一个 Doform()函数来运行表单,内容如下:

程序代码:
* 运行表单--------------------------------------------------------------------------------------------------
FUNCTION DoForm(tcForm,tcVar,tcPara) && tcForm(表单文件名),tcVar(表单变量),tcPara(参数)
    LOCAL W_Name,lErr,i
    = WaitWindow('正在启动程序,请稍候……')
    W_Name = 'frm' + tcForm          && 表单窗口名
    IF !WEXIST(W_Name)               && 窗口不存在时,运行表单
        FOR i = 1 TO 5               && 尝试运行表单 5 次,约 3 秒
            lErr = .f.
            TRY
                IF TYPE('tcVar') = 'C'
                    IF TYPE('tcPara') = 'C'
                        DO FORM (tcForm) NAME (tcVar) LINKED WITH tcPara
                    ELSE
                        DO FORM (tcForm) NAME (tcVar) LINKED
                    ENDIF
                ELSE
                    IF TYPE('tcPara') = 'C'
                        DO FORM (tcForm) WITH tcPara
                    ELSE
                        DO FORM (tcForm)
                    ENDIF
                ENDIF
            CATCH TO oErr WHEN oErr.ErrorNo = 2005
                lErr = .t.          && 因表被其他用户占用,导致无法打开表单时,再重试 4 次
            ENDTRY
            IF !lErr
                EXIT                && 正常打开时,退出
            ENDIF               

            = INKEY(0.5,'H')        && 等待 0.5 秒后,再重试
        NEXT i
        IF lErr
            MESSAGEBOX('数据库中的表正在被其他用户使用,请稍后重试!',16,'提示')
        ENDIF
    ELSE
        ACTIVATE WINDOW (W_Name) TOP    && 窗口存在时,激活窗口
        IF WMINIMUM(W_Name)             && 窗口最小化时,恢复窗口大小
            ZOOM WINDOW (W_Name) NORM
        ENDIF
    ENDIF
    WAIT CLEAR
ENDFUNC

上述代码中,将DO FORM 放在了一个循环中,并对 2005 号错误进行了捕获。

为什么要捕获错误信息呢?难道DO FORM也会出错?我们先做一个小实验:建立一个自由表 Table1,以共享方式打开该表,然后键入 FLOCK()对表加锁,或者键入 RLOCK('0','Table1')对表头加锁。再启动一个VFP窗口,新建一个表单,将 Table1添加到数据环境,运行表单,你会发现系统进入无限等待状态,至到按下 Esc 键。若在表单数据环境的 BeforeOpenTables 事件中输入 Set Reprocess To 0 Seconds,使打开或加锁失败后不再重试,则运行表单时会立刻返回1881号错误,在编译成EXE文件后,返回2005号错误。

系统进入无限等待状态,是由于 Set Reprocess to Automatic,在其他用户使用表而无法打开表或加锁失败时无限重试。在我编写的程序中,一般设置 Set Reprocess to 0 Seconds,禁止系统重试,而完全由我们自己来处理共享冲突。

上述代码中,共重试了 5 次,每次间隔 0.5 秒,若仍无法运行表单,则给出提示并退出。

我们都不是完人,无论你在程序的开发和调试阶段花费多少精力,程序中都或多或少存在Bug,特别是一些逻辑错误很难发现。当程序发生运行错误时,我一般将错误信息记录到一个表文件中,通过定期查看该文件,来排除错误。上述错误,就是我通过跟踪错误日志文件发现的。错误捕获可通过在主程序中添加如下语句来实现的: ON ERROR DO ErrHandler WITH SYS(16),LINENO(1),MESSAGE(1),ERROR(),MESSAGE(),gcUserName

很多状态设置命令都和数据工作期有关,由于表单多采用私有数据工作期,因此我一般在数据环境的 BeforeOpenTables事件中运行一个自定义函数 SetStat()来初始化系统状态。

程序代码:
* 状态设置---------------------------------------------------------------------------------------------------
FUNCTION StatSet()
    SET HOURS TO 24        && 时间采用 24 小时制
    SET CENTURY ON         && 显示日期中的世纪
    SET DATE ANSI          && 国标日期格式:YYYY.MM.DD
    SET SAFETY OFF         && 关闭安全提示
    SET EXCLUSIVE OFF      && 多用户方式
    SET TALK OFF           && 不反馈命令结果
    SET DELETED ON         && 不对有删除标记的记录进行操作
    SET EXACT OFF          && 只比较字符串的前面部分
    SET AUTOSAVE ON        && 自动保存
    SET CONFIRM ON         && 每个控件都需确认
    SET REPROCESS TO 0 SECONDS   && 对表锁定失败后不自动重试
    SET DECIMALS TO 6            && 默认 6 位小数
    SET COLLATE TO "MACHINE"     && 按机器码排序
    SET NULLDISPLAY TO ''        && 不显示空值
    SET ESCAPE OFF               && 程序运行时禁止按 Esc 键中断
ENDFUNC

对于影响全局的系统设置,我一般放在 Config.fpw 中,内容如下:

程序代码:
SCREEN = OFF
SYSMENU = OFF
RESOURCE = OFF
STATUS = OFF
NOTIFY = ON
NOTIFY CURSOR = OFF

下面说一说我在使用表单控件中的一些心得体会:

1. 选定多个控件左对齐时,系统会与最左边控件的左边界对齐。若按下 Ctrl键单击布局工具栏上的左对齐按钮,则选定的控件会与最右边控件的左边界对齐。该技巧也适应于其他对齐方式。
2. 若多个控件有相同的属性和属性值,可以先选定这些控件,然后在属性窗口中输入新值,则所有选定控件的该属性都会被修改,这要比逐个修改来得快。
3. 按下Ctrl键移动控件则可以忽略网格设置,将控件“平滑”地移动到任意位置。同理,按下Ctrl键拖动控件四周的“锚点”,则可以“平滑”地缩放控件的大小。
4. 选定控件后,每按一下光标键(→、←、↑、↓),则控件移动一个像素。按下Shift键不放,每按一下光标键,则控件缩放一个像素。这在精确调整控件的大小和位置时特别有用。
5. 当按下Ctrl键不放,再按光标键时,则控件会按照网格的大小“跳跃”式移动。按下Ctrl+Shift不放,再按光标键时,控件会按照网络的大小“跳跃”式缩放。
6. 按下 Ctrl+Shift 不放,单击容器控件,可直接选定容器中的子控件。
7. 当控件有重叠时,可以通过布局工具栏上的“Bring to Front(置前)”或“Send to Back(置后)”来调整控件的前后顺序,以防止前面的控件挡住后面的控件造成后者无法选定。
8. 大部分控件都有一个TabIndex属性。以交互方式设定TabIndex值时,不一定非要单击数字框,单击控件本身也可以。
9. 通过单击方式设置好最后一个控件的 TabIndex后,单击一下表单即可退出,不一定非要单击布局工具栏上的“Set Tab Order”按钮。
10.设置好TabIndex后,若要将某个控件的TabIndex值调整为 n,则可以在属性窗口中将该控件的值修改为 n-1,则系统会自动调整其他控件的TabIndex值,原来TabIndex为 n 的控件会自动调整为 n+1,其他控件依次类推。这在设置新“插入”控件的TabIndex属性时非常有用。
11.使用键盘输入时,我们喜欢按回车键移动到下一个控件,但在列表框控件上按下回车键时无效,此时,可在列表框的 Keypress 事件中输入以下代码:

IF nKeyCode = 13
    KEYBOARD '{TAB}'
ENDIF

12.若要按回车键在控件之间移动,请不要设置“缺省按钮”,即:将某个按钮的 Default 属性设为 .t.,否则按下回车键,可能会激活默认按钮的 Click事件。
13.文本框控件有一个 SelectOnEntry 属性,将其设为 .t.后,通过键盘(如:TAB)使文本框获得焦点时,会选定文本框中的内容。但通过鼠标单击使文本框获得焦点时,文本框中的内容没有被选定。可以在文本框中的 GotFoucs 事件中输入以下代码来解决:

IF THIS.SelectOnEntry
    NODEFAULT
    DODEFAULT()
ENDIF

14.我比较喜欢自定义类,这些类都是根据自己的使用习惯由基类派生出来的。我将这些类保存在一个叫 MyClass.vcx 文件中,并加入项目文件。在表单上添加自定义类控件时,直接将项目管理器中的类控件拖放到表单上即可。

表单设计是VFP程序设计的核心,这方面涉及的内容太多,下次咱们接着聊。

[ 本帖最后由 liuxingang28 于 2014-3-6 10:22 编辑 ]
收到的鲜花
  • tlliqi2014-03-06 10:19 送鲜花  20朵   附言:鼓励支持
搜索更多相关主题的帖子: 开发 标签 字母 
2014-03-06 10:03
tlliqi
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
等 级:贵宾
威 望:204
帖 子:15453
专家分:65956
注 册:2006-4-27
收藏
得分:2 
先来补课
2014-03-06 10:19
brownze
Rank: 1
等 级:新手上路
帖 子:20
专家分:6
注 册:2014-2-26
收藏
得分:2 
占位,慢慢的看.
2014-03-06 10:57
flash7914
Rank: 2
等 级:论坛游民
帖 子:40
专家分:14
注 册:2013-4-7
收藏
得分:2 
收藏 ,慢慢看,楼主一如既往的用心良苦。万分感谢。
2014-03-06 13:11
antony521
Rank: 3Rank: 3
等 级:论坛游侠
威 望:1
帖 子:170
专家分:175
注 册:2009-8-20
收藏
得分:2 
楼主能不能介绍一下工具栏上“数据工作期窗口”、“对象浏览器”、“工具箱”、“任务面板”有什么用?一直也不知道它们都是干什么的,放在工具栏上一定是有大用处的。以前点“文档查看窗口”都是显示一个空白窗口看了你的介绍终于会用这个了,楼主再接再励小白们多谢你了!
2014-03-06 22:18
qczx3358
Rank: 2
等 级:论坛游民
帖 子:44
专家分:15
注 册:2014-1-19
收藏
得分:2 
不错,学习了
2014-03-07 10:12
flash7914
Rank: 2
等 级:论坛游民
帖 子:40
专家分:14
注 册:2013-4-7
收藏
得分:0 
认真看完楼主写的东西,感觉您真是研究VFP到了扒皮抽筋的地步。对于我来说,每看一篇文章,头顶都不断的冒出LEVEL UP!
2014-03-07 10:47
cymjx
Rank: 2
等 级:论坛游民
帖 子:74
专家分:29
注 册:2010-11-9
收藏
得分:2 
认真学习,不断提高。
2014-03-07 10:53
asdf_123000
Rank: 4
等 级:业余侠客
威 望:1
帖 子:273
专家分:227
注 册:2012-12-20
收藏
得分:2 
反复学习
2014-03-08 09:45
TonyDeng
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:贵宾
威 望:304
帖 子:25859
专家分:48889
注 册:2011-6-22
收藏
得分:2 
依賴TabIndex順序跳轉控件焦點的設計要小心了,此後你將無法自如地往窗體/容器中增刪控件。

授人以渔,不授人以鱼。
2014-03-08 09:48
快速回复:VFP学习、开发漫谈 (八)
数据加载中...
 
   



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

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