分享

VFP表单问题(一)

 忘情天宫 2014-02-21
 VFP表单问题(一)
 

1.VFP表单卸载时显示确认对话框

    我们有时希望表单在被关闭前能显示确认信息,给用户留有选择的余地。这在Windows程序中非常普遍,作用也是显而易见的。在VFP中要实现此功能,方法也很简单。
  首先,让我们来看一个VFP表单的卸载步骤:表单在卸载前,首先要询问表单的QueryUnload事件,然后再卸载表单。也就是说,QueryUnload事件是表单卸载时第一个被触发的事件。在 QueryUnload 事件过程中执行 NODEFAULT命令可以阻止表单卸载。这样我们通过在QueryUnload 事件中巧妙包含NODEFAULT,就能避免直接卸载表单。
  QueryUnload是怎样被触发的呢?当在代码中执行 CLEAR WINDOWS,RELEASE WINDOWS 或 QUIT 等命令时、或者当用户双击控制菜单框时、或者当用户从表单的控制菜单中选择执行“关闭”命令时,都会触发表单的 QueryUnload 事件。
  先在表单的QueryUnload事件中包含下面代码:
  *-- 显示包含“是”、“否”两个按钮的对话框
  If MessageBox("确定要退出吗?",4+48+256,"提示")=6
   ThisForm.Release &&如果选取了“是”,则退出
    Else  &&选取了“否”
   NODEFAULT && 不退出
  EndIf
    这样当有卸载表单的事件发生时,都会显示确认要退出的对话框:只有选取“是”,才能卸载表单。
  这样做是非常有用的,例如我们为了避免正在操作的数据没有保存就退出,可以在程序中使用这段代码,至于如何保存数据,不同的程序采取的方法不尽相同,这里我们不做详细讨论。
  需要说明的是,当在代码中直接执行 RELEASE 命令或直接调用表单的 Release 方法时,不会触发 QueryUnload 事件。因此,我们应尽量避免在代码中直接执行RELEASE 命令或调用表单的 Release 方法。取代的方法是,当要卸载表单时,转向调用表单的QueryUnload方法。
  例如,我们要在表单中放置一个标题为“退出”的命令按钮,用来退出这个表单,并希望在退出时能显示确认对话框,可以在这个“退出”命令按钮的Click事件代码中包含下面的命令:  ThisForm.QueryUnload &&执行表单的QueryUnload事件,询问用户是否真的要退出。
2.做两个表单,在表单1text1text2输入数字,按按钮后把加得的结果输入表单2text1中。

在表单1的command1的click事件中写入:

with thisform
     a=.text1.value+.text2.value
     do form 表单2 with a
endwith

在表单2的INIT里写入:
LPARAMETERS clsj
thisform.text1.value=clsj

3. 创建表单集时, 没有明确的办法添加已存在的表单到表单集.本文向你展示如何添加已存在的表单到表单集.

假设要添加表单 MyForm 到表单集, 按以下步骤:

1 打开 MyForm.

2 在文件菜单中, 单击另存为类, 并单击保存表单.

3 为新类取一个类名和要保存的类库文件名(.VCX 文件).

4 关闭 MyForm.

5 进入表单设计器,打开你的表单集,单击表单设计工具条中的"查看类",然后单击添加.

6 选择你保存 MyForm 类的类库文件 .VCX, 并单击打开.

7 选择工具条中的 MyForm ,并将该表单类拖放到表单集中.

这样就把 MyForm 类的一个实例添加到了表单集中.

4.想做一个全屏大小的表单,该用什么方法?

答:在form的init时间中加入:thisform.xxx..(某控件).setfocus    WindowMode=2这两句。

5 怎样从表单返加一个值?

可以在模式表单的unload事件中用return来返回一个值。

6. 怎样在表单设计器中把属性或方法添加到表单中?

用表单设计器窗口或属性/事件/激活的方法窗口,从菜单中选择表

单。最初的两个选择是新属性和新方法。选择你想要加入的一个并填写属性

或方法的名称,新建的属性将出现在属性窗口的最底部。

7. 模式表单和非模式表单的区别是什么?

答案5: 模式表单一般地被用来处理错误报告,或者请求用户确认操作等。

在模式表单中,菜单不能使用。如果需要,模式表单也提供应用'等待状态'。

非模式表单提供更多的灵活性,它允许用户通过菜单操作,在表单中移动。

8.表单A调用表单B:
在表单A中需要之处写上:
Do Form frmA With para1,para2 To retu
在表单B的Init事件的第一行写上:
lParamters txPara2,txPara2
在表单B的Unload事件的最后一行写上:
Return  lxRetu
其中,para1,para2为你要从表单A中传递过去的实际参数;retu为你想从表单B中得回的数据。txPara2,txPara2为你在表单B中接收的形式参数。就这么简单。

9.为何我设置好FormToolTipText属性后,这些提示总是无法显示出来呢?
这是因为你没有将Form的ShowTips属性没设置为.T.,因为其默认属性是.F.。

10.我在pageframe中的一个页中改变了记录指针,但我转到其他的页时,
其他的页中的数据仍然是原记录的值。为什么?

需要在你的每一页Activate()中放置代码来确信显示当前记录值。
如果你在某处执行了THISFORM.Refresh()命令,VFP仅刷新PageFrame的当前页
面上的内容。试着在每个页(Page)的Activate()中调用THIS.Refresh()。

11.深入VFP类设计数据输入表单

数据输入始终是MIS系统的重要问题,许多MIS系统的数据录入没有充分考虑到重复数据或记录有相当多的共同字段值的输入问题。历经2年之后,终于从VFP的类出发,较好的解决了这一问题,并且在《实验室管理系统Labman2001》中得以成功采用。

类是面向对象程序设计方法中极为重要的部分,也是其精髓所在。如果在可视化编程时代不利用面向对象的编程方法,不采用类来进行系统整体规划,事实上是根本没有发挥先进编程工具的优势。利用类的继承性,可以很方便的修改建立在其上的程序,使之全部更新而无需逐一修改代码,如果需要特殊处理,可以在类基础上重新定义事件处理程序。这样节省了大量的开发时间,并且减少了出错的机会。我们以实例来说明。

先设计如图1表单。

表单包括10个按钮和一个核选框。按钮分为两组,一组是浏览记录的,包括“到首”“前翻”“后翻”“到尾”,另一组包括“增加”“清除”“修改”“删除”“恢复”“退出”,分别实现的相应的功能。核选框则用来控制实现哪组功能。当核选框没有选中时,只有“增加”“清除”“退出”可用,选中核选框,则“到首”“前翻”“后翻”“到尾”“修改”“删除”“恢复”可用。当“增加”可用时,在相关文字框中输入字段值,单击“增加”,一条记录加入表中,再次单击时,提示“已存在该关键字记录,请修改!”,如果下一条记录只有编号不同,修改编号即可,如果还有其他不同,也修改,然后单击“增加”,再次增加一条新记录。如果不想利用前面的记录,单击“清除”,所有字段值清空,重新输入即可。如果想修改记录,可以先浏览到相应的记录,先在文字框中修改完毕,然后按“修改”即可。

下面依次介绍按钮的事件代码,其中夹杂着注释:

“到首”的click事件代码

if reccount()==0

wait nowait windows("表中记录数为0!!!")

return

endif

******当表是空的时候,浏览功能无法使用,并提醒增加记录入表。

thisform.cmdtop.enabled=.f.

thisform.cmdprev.enabled=.f.

thisform.cmdbottom.enabled=.t.

thisform.cmdnext.enabled=.t.

****当单击“到首”后,设置“到首”“前翻”失效。

go top

******下面的小段程序在浏览的四个按钮中均有,为节省篇幅计,以后的均省略。标记为prog01。

dimension m.memc[1] **定义数组,容纳一条记录,定义一个元素即可,如果容纳不下,系统会自动增加。

scatter to m.memc memo ***把内存中记录存放在数组中。

m.nlen=alen(m.memc) ***获取一条记录有多少个字段,存放在m.nlen中。

*****建立循环,将字段逐一放置在表单的相应文字框中。

for m.i=1 to m.nlen

m.nameinput="thisform."+field(i)+'1'+".value" ***获取相关字段的文字框名字

&nameinput = m.memc[m.i] ***将字段放置相应文字框中

endfor

thisform.refresh ***刷新表单。

return

“前翻”的click事件代码

if reccount()==0

wait nowait windows("表中记录数为0!!!")

return

endif

thisform.cmdbottom.enabled=.t.

thisform.cmdnext.enabled=.t.

if recno()==1

thisform.cmdtop.enabled=.f.

thisform.cmdprev.enabled=.f.

else

if bof()==.t. ***单击“前翻”后,如果已经到表开始,设置“到首”“前翻”失效。

thisform.cmdtop.enabled=.f.

thisform.cmdprev.enabled=.f.

else

skip -1

endif

endif

*******下同prog01

“后翻”的click事件代码

if reccount()==0

wait nowait windows("表中记录数为0!!!")

return

endif

thisform.cmdtop.enabled=.t.

thisform.cmdprev.enabled=.t.

if eof( )==.t. and bof()==.f.

thisform.cmdbottom.enabled=.f.

thisform.cmdnext.enabled=.f.

skip -1

else

if reccount()==recno()

thisform.cmdbottom.enabled=.f.

thisform.cmdnext.enabled=.f.

else

if bof()==.t.

else

skip 1

endif

endif

endif

*******下同prog01

“到尾”的click事件代码

if reccount()==0

wait nowait windows("表中记录数为0!!!")

return

endif

thisform.cmdbottom.enabled=.f.

thisform.cmdnext.enabled=.f.

thisform.cmdtop.enabled=.t.

thisform.cmdprev.enabled=.t.

go bottom

*******下同prog01

“增加”的click事件代码

dimension m.memc(FCOUNT()) ***读取打开表的字段数,确定数组元素数

m.nlen=FCOUNT()

for m.i=1 to m.nlen ***建立循环,将字段值写入数组

m.nameinput="thisform."+field(i)+'1'+".value"

m.memc[m.i] = &nameinput ****宏替换,字段值写入数组相应位置

if m.memc[m.i]==NULL

wait nowait windows("无效数据")

return

endif

endfor

go top

m.cfiledname=field(1) ****默认第一字段是主关键字。

locate for &cfiledname==m.memc[1]

if found( )=.t.

if messagebox("已存在该关键字记录,请修改!",48,"增加")=1

return

endif

else

for m.i=1 to m.nlen

m.nameinput="thisform."+field(i)+'1'+".value"

m.memc[m.i] = &nameinput

endfor

thisform.refresh

go bottom

append blank

gather memory from memc

return

endif

“清除”的click事件代码

dimension m.memc(FCOUNT())

m.nlen=FCOUNT()

m.cchushi="thisform."+field(1)+'1'+".setfocus"

&cchushi

scatter to m.memc memo

for m.i=1 to m.nlen

m.nameinput="thisform."+field(i)+'1'+".value"

do case

case type("m.memc[m.i]")=='C'

m.memc[m.i]=""

case type("m.memc[m.i]")=='D'

m.memc[m.i]=date()

case type("m.memc[m.i]")=='N'

m.memc[m.i]=0

case type("m.memc[m.i]")=='T'

m.memc[m.i]=time()

case type("m.memc[m.i]")=='L'

m.memc[m.i]=.T.

otherwise

m.memc[m.i] =""

endcase

&nameinput = m.memc[m.i]

endfor

thisform.refresh

return

“修改”的click事件代码

dimension m.memc[1]

scatter to m.memc memo

m.nlen=alen(m.memc)

for m.i=1 to m.nlen

m.nameinput="thisform."+field(i)+'1'+".value"

m.memc[m.i] = &nameinput

endfor

thisform.refresh

gather memory from memc

return

“删除”的click事件代码

delete

thisform.cmdclear.click

return

“恢复”的click事件代码

recall

return

“退出”的click事件代码

thisform.release()

核选框的click事件代码

if reccount()==0

thisform.cmdqueding.enabled=.t.

thisform.cmdclear.enabled=.t.

thisform.cmdtop.enabled=.f.

thisform.cmdprev.enabled=.f.

thisform.cmdnext.enabled=.f.

thisform.cmdbottom.enabled=.f.

thisform.cmdmodify.enabled=.f.

thisform.cmddelete.enabled=.f.

thisform.cmdrecall.enabled=.f.

thisform.cmdclear.click

wait nowait windows("表中记录数为0!!!")

thisform.check1.value=0

return

endif

if thisform.check1.value==1

thisform.cmdclear.enabled=.f.

thisform.cmdqueding.enabled=.f.

thisform.cmdtop.enabled=.t.

thisform.cmdprev.enabled=.t.

thisform.cmdnext.enabled=.t.

thisform.cmdbottom.enabled=.t.

thisform.cmdmodify.enabled=.t.

thisform.cmddelete.enabled=.t.

thisform.cmdrecall.enabled=.t.

thisform.cmdtop.click

else

thisform.cmdqueding.enabled=.t.

thisform.cmdclear.enabled=.t.

thisform.cmdtop.enabled=.f.

thisform.cmdprev.enabled=.f.

thisform.cmdnext.enabled=.f.

thisform.cmdbottom.enabled=.f.

thisform.cmdmodify.enabled=.f.

thisform.cmddelete.enabled=.f.

thisform.cmdrecall.enabled=.f.

thisform.cmdclear.click

endif

12、表单的init事件

thisform.refresh

set deleted on

thisform.cmdqueding.enabled=.t.

thisform.cmdclear.enabled=.t.

thisform.cmdtop.enabled=.f.

thisform.cmdprev.enabled=.f.

thisform.cmdnext.enabled=.f.

thisform.cmdbottom.enabled=.f.

thisform.cmdmodify.enabled=.f.

thisform.cmddelete.enabled=.f.

thisform.cmdrecall.enabled=.f.

thisform.cmdclear.click

13、表单的unload事件

pack

use

set deleted off

close all

上述工作完成后,将表单另存为“类”,将出现图2,填入类名为“数据输入类”,类库为“xgjbase”。

现在数据输入类已经做好,接下来的工作是以数据输入类为表单模板,创建具体的数据输入表单。先从VFP系统菜单的“tools"菜单中选择“options”菜单项,出现图3,单击“forms”帧,在模板类中的“form”前核选框选中,并且在其后找对“数据输入类”的位置。单击“OK”,模板类设置完成。以后新建的表单都是以数据输入类为模板。下面创建一个“借用表”表单,外形如图4,

表单load事件代码为:

use 借用表.dbf exclusive

另外增加一个按钮“打印借条”,其click事件代码如下:

if thisform.check1.value==1

jy1=thisform.登记序号1.value

jy2=thisform.仪器编号1.value

jy3=thisform.仪器名称1.value

jy4=thisform.借用人1.value

jy5=thisform.用途1.value

jy6=thisform.借用日期1.value

jy7=thisform.归还日期1.value

jy8=thisform.经手人1.value

jy9=thisform.备注1.value

REPORT FORM 仪器借条.FRX NOCONSOLE PREVIEW

thisform.check1.value=0

else

if messagebox("该资料不存在!",48,"借用表")=1

return

endif

endif

只需要这么一点代码就可以实现数据输入、编辑等诸多功能,如果不要打印借条,甚至这一段都可以不要,只须表单的load事件便可,是不是很爽啊?

12.如何使用全局变量获取表单的返回值(做的是一个删除对话框)?(注:这个表单完全可以用messagebox()函数来代替。作者的用意是讲述表单怎样返回一个值,格式就是:do form 表单 to 变量。然后调用表单再根据这个变量的值作出相应的反应。采用的是全局变量,比表单间的数值传递与返回好理解掌握。)

创建一个“删除确认”表单。

 “删除确认”表单的init 事件程序代码:

        public sure_delete                 &&定义删除确认变量

        sure_delete =.f.                   && .f.为不删除

 “删除确认”表单的Destroy事件程序代码:

        return sure_delete                 &&返回sure_delete变量的值

 “删除确认”表单的“确定”按钮的Click事件程序代码:

        sure_delete =.t.                   &&删除该记录

        thisform.release

 “删除确认”表单的“取消”按钮的Click事件程序代码:

        sure_delete =.f.                   &&不删除该记录

        thisform.release

 调用表单的“删除”按钮的Click 事件代码:

  *执行表单程序,弹出“删除确认”对话框

  do form 删除确认.scx to sure_delete        &&该表单返回sure_delete

  *如果从“删除确认”对话框返回值是确定删除

  if sure_delete  then &&如果sure-delete为.t. ,那么…….

    delete                         

  endif

 Release sure_delete

13.VFP中怎样获取表单的返回值(不使用全局变量)

浏览器不支持嵌入式框架,或被配置为不显示嵌入式框架。 ----在调用自定义的对话框表单时,我们往往需要获得该表单执行后的选择结果或是某些控件的值等等。许多人采用的方法是设置一个全程变量,然后在对话框表单内部修改该标志变量,进而获得需要的结果(说的就是上面的例子)。其实VFP提供了一种更为安全的方法,使得表单不光能够接收参数,而且能够返回值。由于不使用全程变量,表单的通用性和独立性得以增强要使得一个表单能够返回值,必须满足以下条件: 
----1.该表单的窗体类型必须是模式窗体;
----2.调用该表单的命令为 
DO FORM frmName[WITH
参数列表] TO VarName
----其中frmName是被调用表单的名称(若表单有参数应正确指定实参),VarName就是用来接收表单返回值的变量名。如果该变量原先没有定义,则会被自动创建。
----3.被调用表单必须在unload方法的代码中使用返回语句:return表达式
----并且应保证该语句一定能够被执行到,以将表达式的值送入指定的变量中。return命令后的表达式可以是任意类型的合法表达式,如果省略了return语句后的表达式,则表单将返回值逻辑值.T.。下例简要说明了获取表单返回值的方法:
一、创建循环调用程序test.prg
----填写代码:
do while .T. &&什么意思?答:do while .t. …… enddo,表示无条件循环,如果不在其内部

          &&设置一个exit,则成为死循环。

tempvar=’’&&接收表单返回值的变量 (此句不要亦可。)

do form test to tempvar &&:调用表单,返回值送入变量tempvar

if empty(tempvar) &&若直接关闭了表单则

exit &&表单退出

else

wait window ‘表单返回值是’+tempvar

endif

enddo

二、创建示例表单test
----1.添加新属性uRetuVal;
----2.在unload方法中添加代码:
----retu this.uRetuVal
----注意:由于表单的unload事件发生在destroy事件之后,而此时依附于表单的其他控件都已经释放,只能引用表单的属性,而不能引用这些控件的任何属性值,如command1.caption等等。因此一定要先将需要返回的值送入表单的公共属性uRetuVal中,这样才能够获得表单的返回值。
----3.设置表单属性windowtype的值为1,即表单为模式表单。
----4.添加三个按钮command1,command2,command3。
设置其属性如下:
command1.caption="OK"
command1.caption="CANCEL"
command1.caption="HELP"
在这三个按钮的click方法里填写相同的代码
thisform.uRetuVal=this.caption
rele thisform
三、保存退出,执行test.prg。
----可以观察到,按下不同的按钮时,变量tempvar将返回不同的值,这证明表单的确可以返回值到调用过程。利用这种方法,我们可以从表单中返回任何类型的值。

14.设定表单间参数传递及返回变量的代码及其含义:(电脑中有自己做的实例)
do form locfile('paramask.scx') with cparam1,nparam2 to nretvalue

&&调用查找到的表单'paramask.scx' ,并将cparam1,nparam2 两个参数传递给表单'paramask.scx',并指定表单'paramask.scx'在其Unload 事件过程中使用 RETURN 命令来指定返回值的变量为nretvalue 。(根据范例,在表单'paramask.scx'中,新建属性retvalue,在其 Uload事件中加上代码:

return thisform.retvalue  &&返回选择值)

具体代码如下:

--------------------------------------------------------------------------

表单frmPara的“提问”按钮的click事件代码

*****定义常量

#define user_response_loc "用户的回答为:"

#define yes_loc "yes."

#define no_loc "no."

#define maybe_loc "maybe."

******清空回答信息标签

thisform.labRetResponse.caption=''

****取参数

cParam1=thisform.txtpassvalue1.value

nParam2=thisform.opgpassvalue2.value

****调用另一表单并向表单'paramask.scx'传递参数,并设置表单'paramask.scx'返回参数

do form locfile('paramask.scx') with cparam1,nparam2 to nretvalue  &&返回参数为nretvalue

****根据返回参数设置回答信息标签

DO CASE

CASE nretvalue=1

thisform.labRetResponse.caption=user_response_loc+yes_loc

CASE nretvalue=2

thisform.labRetResponse.caption=user_response_loc+no_loc

CASE nretvalue=3

thisform.labRetResponse.caption=user_response_loc+maybe_loc

ENDCASE

表单'paramask.scx'的init事件代码:

#define pass_value_loc "该表单不能独立运行,要由表单‘param.scx’调用。"

parameters cQuestion,nbuttons  &&设置接收参数

 

if type('cQuestion')='L'.or.type('nbuttons')='L' &&如果没有参数传递,该参数变量自动设置为逻辑.F.

       messagebox("该表单不能独立运行,要由表单‘param.scx’调用。",64,'')

       return .f.

endif

thisform.txtquestion.caption=cquestion &&在'paramask.scx'上显示表单frmPara上所提出过的问题

*********根据所接收的数据,分情况显示或隐藏三个按钮

DO CASE

CASE nbuttons=1

       thisform.cmdMaybe.visible=.f.

CASE nbuttons=3

       thisform.cmdNo.visible=.f.

       thisform.cmdMaybe.visible=.f.

CASE nbuttons=4

       thisform.cmdYes.visible=.f.

       thisform.cmdMaybe.visible=.f.

ENDCASE

在表单'paramask.scx'中,新建属性retvalue 意为返回值

表单'paramask.scx'的uload事件代码:

return thisform.retvalue  &&返回选择值

 

表单'paramask.scx'的cmdYes的click代码:

thisform.retvalue=1

thisform.release  &&置返回值为1,关闭并释放该表单

表单'paramask.scx'的cmdNo的click代码:

thisform.retvalue=2

thisform.release  &&置返回值为2,关闭并释放该表单

表单'paramask.scx'的Maybe的click代码:

thisform.retvalue=3

thisform.release  &&置返回值为3,关闭并释放该表单

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多