VFP学习、开发漫谈 (九)
书接上回,咱们继续接着聊有关控件设计方面的问题。请大伙儿先跟着我做一个简单的小实验(运行环境:Windows XP+VFP 9.0 SP2英文版):
1. 新建一个项目 Test,在项目中新建一个表单 Form1
2. 在表单上添加一个标签控件 Label1,设置Label1的Caption为 iii
2. 调整Label1的宽度,使之正好能显示全“iii”。方法是:先将AutoSize设为.t.,再改回默认值.f.
3. 在表单上再添加一个按钮,在其Click事件中输入:MESSAGEBOX(THISFORM.Label1.FontName)
3. 设置表单的 WindowType属性为“1-Modal(模式表单)”
4. 编译项目为 Test.exe,并运行 Test.exe
你发现了没有?在设计环境下,Label1的标题显示的是“iii”,运行时却变成了“ii”。
为什么会这样呢?单击命令按钮,系统显示“宋体”。原因找到了:在设计环境下,Label1的默认字体是“Arial”,而运行时则变成了“宋体”。由于Arial是比例字体,而宋体是等宽字体,比例字体转化为等宽字体时会“变宽”,导致标签的宽度无法容纳显示的内容,所以仅显示了2个i(实际上是1个半)。
类似的情况还有,比如:列表框有2列,若第1列显示的内容宽度不同,则在VFP环境下运行时,分隔线不垂直,如下所示:
但在将项目编译成EXE文件运行时,又变得垂直了,如下所示:
这都是字体转换造成的。所以,我在开发程序时,几乎不使用系统提供的基类,都是使用自定义类。就拿标签类来说吧,我的自定义标签类派生于Label基类,并设置 FontName 为“宋体”,AutoSize = .t.,BackStyle =“0 - Transparent”。因为这更符合大多数人的使用习惯。
VFP 中没有提供类似 VB 中的 GroupBox 分组框控件,但我们可以添加一个Label和一个Shape来实现相似的功能。设置Shape的SpecialEffect为 “0 - 3D”,BackStyle为“0 - Transparent”,也可以将 Style 属性设为“3 - Themed”,使分组框的外观更专业一些。如下图:
从上图可以发现一个问题:将分组框添加到 PageFrame(页框)上时,如何设置Label的背景色问题。若设置BackStyle=0(透明),则标签后面的框线会显示出来,若设置BackStyle=1(不透明),则默认的灰色背景与页框的乳白色又不协调。
解决方法:保持Label的BackStyle=1,设置Style为“3 - Themed”或“4 - Themed Background Only”。设为3时,文字会显示为淡蓝色,并忽略ForeColor属性。设置为4时,背景色与页面颜色相同,前景色为ForeColor的属性值。如下图:
为了使标签与方框的上边线看起来垂直居中,我一般设置 Shape1.Top = Label1.Top + 8。
在上图中,我故意多放置了一个“姓名”标签和一个文本框,并通过布局工具栏上的“Align Horizontal Centers”使二者水平居中。上图是编译成EXE后的运行结果,你觉得二者水平居中了吗?显然没有,标签应该下移一点就好了。根据我的经验,在设计时,先将二者水平居中,再将标签下移2个像素就OK了。
还以上图中的页框控件为例,现在我把其 Page1 的 Caption 设为“1.设置查询条件”,你发现了没有,系统的显示结果却是“设置查询条件.1”。解决方法:将 PageFrame 的 RightToLeft 设置为 .f.就好了。这可能是VFP的一个Bug,因为其他控件(如:文本框)的RightToLeft属性默认都是.f.,唯独PageFrame的该属性被设置成了.t.,没有道理啊!我的自定义页框类,就将 RightToLeft 属性修正为了 .f.
控件的初始值、初始值的数据类型、控件来源是非常重要的三个属性。
以文本框为例,在不设置 InputMask 属性时,若将初始值设为 0,则运行时只能输入整数,不能输入小数。若初始值设为 0.00,则运行时,可输入2位小数。
以选项按钮组(OptionGroup)为例,若初始化时 Value 为数值型,则 Value 返回的是被选定按钮的顺序号;若初始化时 Value 为字符型,则 Value 返回的是被选定按钮的Caption。
不知大家是否注意到:大多数容器控件都有一个 MemberClass(成员类)属性。用好了它可以解决很多问题。以 PageFrame 为例,我们都知道,刷新表单时,仅刷新 PageFrame 活动页上的控件,那么其他页上的控件什么时候刷新合适呢?当然是激活(Activate事件)Page时最合适。但是,在每个页面的 Activate 事件中都加入 THIS.Refresh 也太麻烦了。现在,我们就用 MemberClass 来解决。
先新建一个派生于 Page 的类,将其命名为 MyPage,保存在 MyClass.vcx 中,如下图:
在 MyPage 的 Activate 事件中输入:THIS.Refresh,保存退出。
选定 PageFrame,在属性窗口中选定 MemberClass,单击右上角的“...”按钮,选择“Yes”,单击 MyClass.vcx,并选择 MyPage。
在修改容器控件的 MemberClass 属性时,最好在新建页框时进行,否则,在页面中已添加的控件会被清除。
在 VFP 中,表单文件 *.SCX 其实也是一个表,你可以使用“USE 表单文件.SCX”打开,然后再 Browse。有时候,该操作是必须的。
比如:在修改表单文件时,系统提示打开表单文件出错,并指出错误发生在第几行记录。我们总不能再从头开始设计一个新表单吧。这时候以表方式打开表单文件,定位到记录行,重点查看“Properties”字段值。这类错误一般均可轻松修复。
再比如,我要将表单上的文本框由基类改为自定义类,也只能通过该方法打开表单文件,定位到该记录,修改“Class”字段和“ClassLoc”字段来实现。例如,我要将表单上的所有文本框由基类改为自定义类 MyText,可输入命令:Replace Class WITH 'mytext',ClassLoc WITH '..\class\myclass.vcx' FOR BaseClass = 'textbox '
以文本框为例,很多控件都有 When 事件。利用该事件,可以动态设置文本框是否可修改。比如:文本框的 ControlSource为“员工表.工资”,若只允许用户修改“财务处”人员的工资,则可以在文本框的 When 事件中输入:RETURN 员工表.部门='财务处'
在实际应用中,经常碰到输入“数量”、“单价”和“金额”的情况。输入数量和单价时自动计算金额,输入金额时自动计算单价。这里有一点需要注意:在文本框的 Valid 或 LostFocus 事件中可引用文本框的 Value 属性,在文本框的 InteractiveChange事件中不能直接引用其 Value属性,因为在离开焦点前才更新Value 属性,可以改为引用其 Text属性。对于本例来说,若将计算金额或单价的代码放在 GotFocus 或 Valid事件中,则只有控件失去焦点时才会更新金额或单价,这不是我们想要的。应该将代码放在控件的 InteractiveChange事件中。以下是 txtCount控件中的代码:THIS.Parent.txtAmount.Value = ROUND(VAL(THIS.Text)*THIS.Parent.txtPrice.Value,2)
在 VFP 的所有控件当中,我认为最常用的控件是 Label 和 TextBox,最难以捉摸的控件是 ComboBox,最复杂、功能最强大的控件是 Grid,最常用的 ActiveX 控件是 TreeView。不知大伙儿是否同意我的观点。
[ 本帖最后由 liuxingang28 于 2014-3-7 15:34 编辑 ]