烟丝缭绕 的个人资料dqf01照片日志列表更多 ![]() | 帮助 |
|
12月11日 又是一个不眠夜 今晚又失眠了,脑子里乱糟糟,不知道想些什么。
对与小安子我真的是似乎没有什么脾气,也许就是一物降一物,对于女人真的是笨的很。看到她很开心,看不到她心里烦,我知道我是喜欢她,可是不知道该怎么更好的让她明白我。将来会怎样,我不知道,只是看她现在过的很开心,很充实,也许我并不需要我的照顾。我在她眼里是什么样的角色,也许会有些滑稽。
我的心结有十年了,早该结芭了,也是该划个句号的时候了。都说三十而立,年少轻狂无知固执的岁月过去了,现在的状况和儿时的梦太不一样,也许该抛弃那些梦了。
11月9日 vf&grid 白屏问题数据源表(别名)上记录的物理删除 网格对象对应的是一张表(TABLE)、别名(ALIAS)、视图(VIEW)、查询(QUWRY)之类的二维表格,在实际应用中,必然会遇到表(别名)中记录的删除的情况。我们知道,VFP中有两种记录删除命令:DELETE命令和PACK命令,DELETE命令是给删除的记录作标记,在执行PACK命令前并不从表上做物理删除, 而且做了删除标记的记录可以恢复。 PACK命令从表中物理删除标有删除标记的记录。当我们在表(别名)上用PACK命令删除记录时,会发现以该表(别名)为数据源 的网格控件会显示一片空白。如果我们仔细分析一下PACK命令的工作原理,就不难明白出现这种情况的原因: 当使用PACK命令时,VFP 把所有没有删除标记的记录复制到一个临时表(TEMPORARY TABLE),执行完PACK命令后,VFP 把原表从所在磁盘上删除,同时用原表名命名临时表。可以看出,在执行PACK命令过程中,作为网格对象数据源的表(别名)有过短暂的关闭,导致了网格对象找不到数据源从而显示一片空白,原表(别名)再打开也无济于事。找到了问题的关键所在,也就找到了解决办法: . 在网格清除(DESTROY)之前不使用PACK命令,如果要执行删除操作,可用DELETE命令,为了不在网格上显示被删除的记录,可用SET FILTER TO DELE()=.F.将它们屏蔽掉,在清除网格或其所在的表单时再执行PACK命令。 . 在界面设计时,将网格控件所在的表单或页面暂不显示,待激活显示时在其ACTIVATE事件过程中用命令方式重新设置网格控件的属性,完成网格操作后再隐藏网格对象,PACK命令的使用放在网格对象隐藏时完成。以上两种方法都可以解决由于删除命令而导致网格控件失效的问题。 11月8日 vf 事务处理BEGIN TRANSACTION 命令 启动一个事务处理。仅对数据库中的表支持事务处理。 有关如何在数据库中创建和增加表的详细信息,请参阅CREATE DATABASE 和 ADD TABLE。 1 在事务处理期间执行 CLOSE ALL 命令,则关闭所有打开数据库中的表,但数据库仍保持打开状态;在事务处理期间执行 CLOSE DATABASES 命令,则关闭当前数据库中的所有表,但数据库仍保持打开状态。 示例 * 事务处理只支持数据库 SET MULTILOCKS ON && 要求缓存
BEGIN TRANSACTION =TABLEREVERT(.T.) 11月7日 vf备忘1.菜单. do 菜单名.mpr with this, .t.
2.去掉vf主窗口. application.visible=.f. (执行该命令的form设置为顶层表单)
3.事件循环. do events/clear events
4.sys(2003)当前目录,sys(5)返回当前 Visual FoxPro 的默认驱动器。
5.select distinct * from xxx into tables xx (删除重复记录) 转贴:事件驱动程序设计9.5 事件驱动程序设计 Windows提供了一个多任务的图形用户接口界面(GUI),在其环境下运行的程序是事件 驱动(Event Driven)的。也就是说,这种类型程序的结构和操作主要由用户生成的事件来 控制。Foxpro不仅支持结构化程序设计, 而且也支持事件驱动程序设计( Event- Driven Programming)。 9.5.1 事件驱动的概念 所谓事件(Event)就是一个对象能够识别的一个动作,例如, 单击鼠标或按下键盘上 的某个键等。事件只发生在程序运行阶段,而不会发生在编程阶段。事件驱动指的是程序代 码的执行依赖于一个事件的发生,它是一种非常适合于图形界面的编程方式。在Foxpro中, 一旦某个事件发生后,Foxpro立即调用相应的事件过程中的代码执行。 事件驱动程序设计与传统的程序设计是有区别的。传统的程序设计是一种面向过程按顺 序进行的工作, 必须事先安排好先做什么, 后做什么, 因此属于顺序驱动( Sequence Driven)。顺序驱动在编程时已经规定好了用户必须遵守的操作顺序, 并且只有按照该顺 序操作,才能达到该程序运行的目标。相反,事件驱动程序设计所关心的是某个事件发生后 应该做什么,不必特意去编写调用程序,也不必编写按精确次序执行的每个步骤,只需要编 写响应事件的过程代码就可以了,而这些代码的执行由用户启动的事件来激发。对于事件驱 动程序来说,为完成给定的任务,用户可以自己规定其执行步骤,使用过Windows 应用程序 的读者对此会深有体会的。 下面是一个简单的Foxpro事件驱动程序,读者可以上机运行该程序,从中体会事件驱动 的含义。 SET TALK OFF ON ESCAPE WAIT "这就是事件驱动,按任一键继续..." WINDOW CLEAR I=1 DO WHILE INKEY()<>6 ?"I=",I, "按Esc键响应事件,按End键结束运行" I=I+1 ENDDO 程序中的ON ESCAPE命令是Foxpro事件驱动命令家族中的一员, 利用该命令可在程序运 行期间截取用户按下的Esc键并执行事先设计好的事件过程代码(WAIT " 这就是事件驱动, 按任一键继续..." WINDOW)。执行完事件过程代码后, 程序再从被中断命令的下一行继续 执行。INKEY()为Foxpro的标准函数,它可以返回用户按键的键值。若用户按下了End键(键 值为6),则结束该程序的运行。 在Foxpro程序设计中,事件泛指所有系统内部和外部激发的动作。例如,键盘按键、程 序运行期间出错、激活菜单以及屏幕控制等都可以理解为事件。在此只对键盘、鼠标以及出 错事件的处理加以讨论,有关激活菜单和屏幕控制的事件程序设计将在下一章介绍。 9.5.2 键盘事件处理命令与函数 ⒈ 返回按键的ASCII码──INKEY() 【格式】INKEY([<数值表达式>][,<字符表达式>]) 其中,<数值表达式>用来规定等待按键的时间(秒数),若为0值, 则停止程序运行, 直到按下任一键为止。省略<数值表达式>时立即返回所按下键的ASCII码。<字符表达式> 指 定等待按键期间是否显示光标或检测是否按下鼠标器的左按钮。如果需要显示光标,应使用 "S"(缺省方式)。若隐藏光标,可以使用"H"。如果需要检测是否按下鼠标器的左按钮,可 使用"M"。在允许检测鼠标的情况下,若按下了鼠标器的左按钮,INKEY()将返回151。M也可 以与S和H联用。有关INKEY()函数的返回值见附录C。 【功能】返回用户按键的ASCII码或鼠标按钮值。 例如,下面的程序一直在屏幕上显示“Foxpro 事件驱动程序设计.”,直到按下End 键 或鼠标器的左按钮为止。 SET TALK OFF CLEAR KeyorMouse=0 DO WHILE NOT (KeyorMouse=6 OR KeyorMouse=151) ? "Foxpro 事件驱动程序设计." KeyorMouse=INKEY("HM") ENDDO SET TALK ON RETURN ⒉ 返回结束全屏幕编辑命令时所按下键的值──READKEY() 【格式】READKEY([<数值表达式>]) 其中,<数值表达式>用来确定最后一次的READ是如何被终止的,它可以为任何值。省略 时,返回结束全屏幕编辑命令时所按下键的值。 【功能】返回结束全屏幕编辑命令时所按下键的值。 【说明】 ①该函数用来确定结束全屏幕编辑命令(APPEND、BROWSE、CHANGE、CREATE、 EDIT 、 INSERT、MODIFY和READ等)时所按下的键。 ②结束全屏幕编辑时,若数据未修改,则返回0 ̄36之间的值,否则返回256 ̄292 之间 的值。有关READKEY()函数的返回值见附录D。 ⒊ 返回最后一次按键的ASCII码──LASTKEY() 【格式】LASTKEY() 【功能】返回用户最后一次按键的ASCII码值。 【说明】当需要判断READ命令是否要停止时,可以使用LASTKEY( ) 函数, 其返回值与 INKEY()函数完全相同。 【例9.20】编写一个浏览修改通讯录数据库(TXLK.DBF)记录的程序。在修改过程中, 如果用户按下了Esc键,则对当前记录的修改作废。 程序如下: *PROG9_20.PRG浏览修改数据库记录 SET TALK OFF DIME MA[6] CLEAR USE TXLK SCAN SCATTER TO MA &&将当前要修改的记录存入数组MA @2,10 SAY "姓名:" GET 姓名 @3,10 SAY "性别:" GET 性别 @4,10 SAY "职务:" GET 职务 @5,10 SAY "工作单位:" GET 工作单位 @6,10 SAY "邮政编码:" GET 邮政编码 @7,10 SAY "通讯地址:" GET 通讯地址 @10,20 SAY "按Esc键取消对当前记录的修改,按Ctrl+W结束" READ IF READKEY()=268 &&按下Esc键 GATHER FROM MA &&恢复修改之前记录内容 ENDIF IF LASTKEY()=23 &&按Ctrl+W结束 EXIT ENDIF ENDSCAN USE SET TALK ON RETURN ⒋ 捕获Esc键──ON ESCAPE 【格式】ON ESCAPE [<命令>] ON ESCAPE命令是Foxpro事件驱动命令家族中的一员,<命令>可以是一个用DO 命令调用 的程序、过程或一条其它的Foxpro命令。 【功能】设置和捕获当Esc键被激活时要执行的命令或程序。 【说明】 ⑴当ESCAPE被设置为OFF(即SET ESCAPE OFF)时,ON ESCAPE后面的命令不会执行。 ⑵不带<命令>选项可取消ON ESCAPE的设置。 ⒌ 捕获任一按键──ON KEY 【格式】ON KEY [<命令>] 【功能】设置和捕获在程序运行期间任一键被按下时要执行的命令、程序或过程。 【说明】 ⑴当ON ESCAPE和ON KEY均处于有效状态时,按下Esc键后将优先执行ON ESCAPE 后面的 命令。 ⑵不带<命令>选项可取消ON KEY的设置。 ⒍ 定义热键──ON KEY =|ON KEY LABEL 【格式】ON KEY=[<数值表达式>][<命令>] ON KEY [LABEL<键名>][<命令>] 其中,<数值表达式>为要定义热键的键码,可供使用的键码值见附录E。<键名>为要定 义热键的识别名称,Foxpro中每个按键对应的识别名见附录F。 【功能】设置和捕获在程序运行期间定义的“热键”被按下时要执行的命令、程序或过 程。 【说明】 ⑴利用ON KEY=命令只能定义一个热键,使用ON KEY LABEL命令可以定义多个热键。 ⑵利用ON KEY LABEL命令定义的热键在程序结束后仍然有效,因此在结束程序前应使用 ON KEY命令清除所定义的热键。 【例9.21】热键的使用举例。 程序如下: *PROG9_21.PRG热键的使用举例 SET TALK OFF ON ESCAPE DO STOP ON KEY LABEL F1 DO PROC1 ON KEY LABEL F2 DO PROC2 ON KEY LABEL F3 DO PROC3 CLEAR LP=.T. DO WHILE LP ? "Foxpro 事件驱动程序设计中热键的使用,按Esc键结束" ENDDO ON KEY &&清除ON KEY LABEL命令定义的热键 SET TALK ON RETURN PROCEDURE PROC1 WAIT "用户按下了F1键,按任一键继续..."WINDOW RETURN PROCEDURE PROC2 WAIT "用户按下了F2键,按任一键继续..."WINDOW RETURN PROCEDURE PROC3 WAIT "用户按下了F3键,按任一键继续..."WINDOW RETURN PROCEDURE STOP LP=.F. RETURN ⒎ 按键的堆栈操作──PUSH KEY/POP KEY 在一个程序中,允许使用ON KEY LABEL命令定义多个热键。假如在过程或自定义函数中 定义的热键名与主程序中定义过的热键名相同,则执行过程或自定义函数后,主程序中同名 的热键将会被覆盖。为了解决这一问题,Foxpro提供了按键的堆栈操作命令PUSH KEY和POP KEY。 ⑴PUSH KEY命令 【格式】PUSH KEY [CLEAR] 【功能】将当前所有ON KEY LABEL命令的设置存入堆栈(内存中某个区域), 带CLEAR 选项可清除当前定义的所有热键。 ⑵POP KEY命令 【格式】POP KEY [ALL] 【功能】从堆栈中取出存入的ON KEY LABEL命令的设置,带ALL 选项将清除堆栈中所有 的ON KEY LABEL命令。 通常在过程或自定义函数中定义热键之前先执行PUSH KEY CLEAR命令,而在返回前再执 行POP KEY命令。例如,下面程序中的过程PROC就是一例。 SET TALK OFF ON KEY LABEL F1 DO PROC ON KEY LABEL F2 LP1=.F. LP1=.T. DO WHILE LP1 ? "按F1键执行过程,按F2键结束!" ENDDO ON KEY PROCEDURE PROC PUSH KEY CLEAR &&将当前的ON KEY LABEL命令入栈 ON KEY LABEL F2 LP2=.F. &&重新定义热键F2的功能 LP2=.T. CLEAR DO WHILE LP2 ? "正在执行过程,按F2键返回主程序执行!" ENDDO CLEAR POP KEY &&恢复以前存入的热键 9.5.3 出错事件及相关函数 ⒈ 捕获出错事件──ON ERROR|ON READERROR ⑴ON ERROR命令 【格式】ON ERROR [<命令>] 【功能】设置错误事件发生时要执行的程序、过程或命令。不带<命令>选项时将取消原来 ON ERROR的设置。 通常将ON ERROR命令与出错事件有关的函数联用,来编写错误处理程序。 ⑵ON READERROR命令 【格式】ON READERROR [<命令>] 【功能】设置在执行@…GET期间,出现数据输入错误时要执行的程序、过程或命令。不 带<命令>选项时将取消原来ON READERROR的设置。 ON READERROR命令主要用来定义用户输入错误时的提示信息。输入GET 域时常见的错误 有非法日期、输入的数据超过RANGE选项指定的范围、不符合VALID选项所检查的输入值。 ⒉ 与出错事件有关的函数 ⑴返回错误代码──ERROR() 【格式】ERROR() 【功能】返回错误代码。 ⑵返回错误信息──MESSAGE() 【格式】MESSAGE([1]) 【功能】返回当前的错误信息字符串(不带参数1)或出错的命令行(带参数1)。 ⑶返回当前执行程序的名称──PROGRAM() 【格式】PROGRAM() 【功能】返回当前执行的程序的名称。 ⑷返回当前执行程序的行号──LINENO() 【格式】LINENO() 【功能】返回当前正在执行的程序的行号。 【例9.22】编写一个出错处理程序,要求给出错误代码、出错信息、错误命令行、出错 程序名称及错误程序行等信息。 本例属于错误事件驱动程序设计,可以使用ON ERROR命令和ERROR() 、 MESSAGE( ) 、 PROGRAM()、LINENO()函数来编程。为了捕获出错事件, 可以在程序中人为设置一带错误的 命令行。 程序如下: *PROG9_22.PRG出错处理程序 SET TALK OFF ON ERROR DO ERRPROC WITH ERROR(),MESSAGE(),MESSAGE(1),; PROGRAM(),LINENO() &&设置错误事件发生时要执行的过程 ? A,B,C &&设置一错误命令行 ON ERROR RETURN PROCEDURE ERRPROC &&出错处理过程 PARAMETERS P1,P2,P3,P4,P5 CLEAR @5,5 SAY "错误代码: "+LTRIM(STR(P1)) @6,5 SAY "出错信息: "+P2 @7,5 SAY "错误命令行:"+P3 @8,5 SAY "出错程序名:"+P4 @9,5 SAY "错误程序行:"+LTRIM(STR(P5)) WAIT "按任一键继续..." WINDOW RETURN 转贴:Foxpro备注型字段的编程 9.2 Foxpro备注型字段的编程 在开发数据库管理系统时,有时需要对备注字段进行操作。Foxpro中的备注字段的内容 可以理解为一个长字符串,因此对于字符串操作的有关函数也适用于备注字段。为了便于备 注字段的处理,Foxpro提供了专门用于备注字段操作的命令和函数。 9.2.1 备注字段操作命令及函数 ⒈ 将文件存入备注字段──APPEND MEMO 【格式】APPEND MEMO <备注字段> FROM <文件名> [OVERWRITE] 【功能】将指定文件的内容存入数据库当前记录的一个备注字段中。 【说明】 ⑴指定的<文件名>应为该文件的全名,可以带盘符和路径。 ⑵该命令以追加方式将文件的内容存入备注字段中已存在内容的末尾,带OVERWRITE 选 项将会覆盖原来备注字段的内容。 ⒉ 复制备注字段内容到磁盘文件──COPY MEMO 【格式】COPY MEMO <备注字段> TO <文件名> [ADDITIVE] 【功能】将数据库当前记录中指定备注字段的内容复制到磁盘文件中。 【说明】 ⑴命令中<文件名>前可以带盘符和路径,如果没有指定文件的扩展名,则取缺省扩展名 .TXT。 ⑵如果使用ADDITIVE选项,则以追加方式将备注字段内容添加到文件末尾,否则将会覆 盖原来文件的内容。 ⒊ 备注字段的编辑或浏览──MODIFY MEMO 【格式】MODIFY MEMO <备注字段1> [,<备注字段2>,…] [NOEDIT] [NOWAIT] [RANGE <数值表达式1>,<数值表达式2>] [[WINDOW <窗口名1>] [IN [WINDOW]<窗口名2>|IN SCREEN]] [SAVE] 【功能】利用Foxpro的文本编辑器来编辑或浏览指定备注字段的内容。 【说明】 ⑴如果在命令中指定多个备注字段,则按层叠方式排列备注字段窗口,最后一个备注字 段的窗口在最前端。 ⑵使用NOEDIT选项只能浏览备注字段的内容,不允许进行修改。 ⑶NOWAIT选项仅用于程序方式,允许程序在备注字段窗口打开的同时继续执行。 ⑷使用RANGE选项可以在进入编辑窗口后以突出方式显示要编辑的区域, 编辑区域的起 止位置分别由<数值表达式1>和<数值表达式2>指定。如果指定的两个数值表达式的值相等, 则进入编辑窗口后光标便停留在该位置上。 ⑸缺省情况下(IN SCREEN)是在Foxpro桌面窗口上打开编辑窗口,如果使用 WINDOW < 窗口名1>可将用户定义的窗口作为备注字段的编辑窗口,也可以使用IN [WINDOW]<窗口名2> 在当前活动窗口内打开备注字段编辑窗口。如果希望在完成备注字段的编辑后保留编辑窗口, 可以使用SAVE选项。 ⒋ 关闭备注字段编辑窗口──CLOSE MEMO 【格式】CLOSE MEMO <备注字段1> [,<备注字段2>,…] [ALL] 【功能】关闭使用MODIFY MEMO或BROWSE命令打开的备注字段编辑窗口。如果使用ALL选 项,将关闭所有打开的备注字段窗口。 ⒌ 设置备注字段的输出宽度──SET MEMOWIDTH 【格式】SET MEMOWIDTH TO <数值表达式> 【功能】设置备注字段的输出宽度。 【说明】 ⑴命令中<数值表达式>的取值范围在8 ̄256之间,缺省值为50。 ⑵在Windows下的Foxpro中,输出将受当前系统桌面或窗口的字型、字号大小的限制。 ⒍ 指定备注字段编辑窗口──SET WINDOWS OF MEMO 【格式】SET WINDOWS OF MEMO TO <窗口名> 【功能】指定编辑或浏览备注字段内容时所使用的编辑窗口。 例如: . . . USE MYDBF SET WINDOWS OF MEMO TO memowin &&其中memowin为用户定义的窗口的名称 MODIFY MEMO mymemo NOEDIT &&在memowin窗口内浏览备注字段mymemo的内容 . . . ⒎ 返回备注字段的行数──MEMLINES() 【格式】MEMLINES(<备注字段名>) 【功能】返回指定备注字段中内容的行数。 【说明】该函数的返回值将受当前SET MEMOWIDTH设置的影响。 如果当前指定的备注字 段为空,则返回0值。 例如: CLEAR USE MYDBF SET MEMOWIDTH TO 70 SCAN IF MEMLINES(mymemo)=0 WAIT STR(RECNO())+"号记录的备注字段为空" WINDOW NOWAIT ELSE DISPLAY mymemo ENDIF ENDSCAN . . . ⒏ 返回备注字段中指定行的内容──MLINE() 【格式】MLINE(<备注字段名>,<数值表达式1>[,<数值表达式2>]) 其中,<数值表达式1>表示所取内容的行号,<数值表达式 2>表示从距离备注字段开头< 数值表达式2>个字符位置开始计算行号。 【功能】返回指定备注字段中指定行的内容。 【说明】该函数返回的内容将受当前SET MEMOWIDTH设置的影响。 如果指定的的行数超 出该备注字段的总行数,则返回一个空串。 除了上面介绍的备注字段操作命令和函数以外,Foxpro中的许多命令和函数都与备注字 段有关。下面列出一些常用的命令和函数,供读者编程时参考。 支持备注字段操作的其它命令如下: @…SAY/GET、@…EDIT、?、??、\、\\、LIST、DISPLAY、APPEND、BROWSE、 CHANGE 、 EDIT、REPLACE、SCATTER、GATHER、SAVE TO、RESTORE FROM、 SAVE SCREEN 、 RESTORE SCREEN、SAVE WINDOW、RESTORE WINDOW等。 支持备注字段操作的其它函数如下: AT()、ATC()、ATCLINE()、LEFT()、RIGHT()、SUBSTR()、RAT()、RATLINE()、LEN()、 EMPTY()等。 9.2.2 备注字段编程举例 【例9.13】在计算机上进行某门课程的考试时,首先应该考虑试题的安全问题。假如需 要用Foxpro编写一个“Foxpro程序设计”课程的考试系统,试题内容采用数据库的备注字段 来存放。请编写一个对数据库备注字段进行加密的程序。假设试题库名称为TEST.DBF,每一 道试题的内容存入名为content的备注字段中。 分析:本题求解的关键在于确定加密算法。可以按照这样的思路来确定备注字段的加密 算法:首先计算出备注字段中每个字符的ASCII码,然后用该字符的ASCII码值减去该字符在 备注字段中的位置值被10除后所得到的余数,得到一个新的ASCII码值, 最后再把所得到的 全部ASCII码组合成一个字符串,即为加密结果。 程序如下: *PROG9_13.PRG的功能是实现备注字段的加密 SET TALK OFF USE TEST SCAN length=LEN(content) &&计算备注字段的长度 string="" FOR I=1 TO length string=string+CHR(ASC(SUBSTR(content,I,1))-I % 10) &&加密处理 ENDFOR REPLACE content WITH string &&将加密之后的内容写回原备注字段 ENDSCAN USE SET TALK ON RETURN 【例9.14】在Foxpro程序设计课程上机考试系统中,上机操作的题目存放在名为 EXAM .DBF的数据库中,其中的两个备注字段EXAM_DOC和EXAM_PRG分别用来存放改错题(或编程题) 的试题说明和程序代码(或部分程序代码)。为了便于考生操作,要求在抽取试题时,按照 Foxpro中注释语句的格式将试题说明与程序代码合并后存入一个文件中(试题说明在程序代 码之前)。假设改错题的程序文件名为MODI.PRG,编程题的程序文件名为PROG.PRG。请编写 程序实现这一功能。 程序如下: *PROG9_14.PRG SET TALK OFF CLEAR ?"正在抽取Foxpro程序设计试题,请等候..." SELE 1 USE EXAM INDEX EXAM &&打开试题库及索引文件 MODI_NO="225000" PROG_NO="235000" RANDUM=0 DO WHILE RANDUM=0 RANDUM=INT(RAND(-1)*(90)) &&随机抽取一套试题 ENDDO IF RANDNUM<10 MYSTR="0"+STR(RANDNUM,1) ELSE MYSTR=STR(RANDNUM,2) ENDIF MODI_NO=MODI_NO+MYSTR &&改错题目编号 PROG_NO=PROG_NO+MYSTR &&编程题目编号 SEEK MODI_NO &&抽取改错题目 =MAKEDOC("MODI.PRG") &&对改错题的说明进行注释,并存入MODI.PRG COPY MEMO exam_prg to MODI.PRG ADDI &&将改错题的程序代码追加到试题说明之后 SEEK PROG_NO &&抽取编程题目 =MAKEDOC("PROG.PRG") &&对编程题的说明进行注释,并存入PROG.PRG COPY MEMO exam_prg TO PROG.PRG ADDI &&将编程题的程序代码追加到试题说明之后 USE RETURN FUNCTION MAKEDOC &&建立注释文件 PARA PROGNAME SET TEXT TO &PROGNAME ON NOSHOW &&设置输出命令\将结果存入指定文件中 SET MEMOWIDTH TO 78 &&设置备注字段每行宽度为78个字符 NUM=MEMLINES(exam_doc) &&取备注字段行数 \* ●试题说明● FOR I=1 TO NUM STRING="* "+MLINE(exam_doc,I) &&对该行进行注释说明 \<<STRING>> &&将STRING的内容输出到文件 ENDFOR SET TEXT TO &&关闭建立的输出文件 RETURN 9.3 Foxpro通用型字段的编程 在Foxpro中,对OLE技术的支持是通过通用型字段(General)实现的。使用OLE技 术,可以很方便地将其它Windows 应用程序生成的数据、 图像、 声音等信息链接或嵌入到 Foxpro的数据库中,从而开发出图文声像并茂的数据库应用系统。 9.3.1 在Foxpro中使用OLE技术 ⒈ 什么是OLE 对象的链接和嵌入(OLE──Object Linking and Embedding)是Windows 环境下应 用程序之间传送和共享信息所使用的一种技术。正如其名称所提示的那样,它提供了两种服 务功能。应用程序之间传送的信息可以是一张表格、一幅图像、一段文字或一种声音,这些 信息统称为对象(Object)。对象由Windows应用程序生成。例如,使用Excel制作的表格、 由画图程序产生的位图、由扫描仪扫描的图片等。 嵌入一个对象时,是对源信息的一个拷贝,拷贝过来的信息与源应用程序不再有任何联 系,编辑所嵌入的对象或编辑源文档互不影响。例如,在Foxpro数据库的一个通用字段中嵌 入了一个位图,如果在Foxpro中修改了该位图,源位图文件不会改变,反之亦然。而链接对 象则不同, 它不是源信息的拷贝, 而是只记录了指向源应用程序文档的指针。 因此, 在 Foxpro中编辑一个链接的对象时,实际上是编辑源文档中的信息。而在源应用程序中对该文 档所作的任何修改,也都会直接反映到Foxpro应用程序中。可见,使用对象的链接操作,实 现了信息的共享,保证了数据的一致性。 在Foxpro中,对OLE的支持是借助于通用型字段(General)实现的。General字段的 宽度由系统指定为10,当没有链接或嵌入对象时,该字段以“gen”标识, 若在其中已经存 在链接或嵌入的对象,该字段以“Gen”标识。与备注字段的操作类似, 通用字段也存在输 入、输出和修改等操作。这些操作既可以在Foxpro系统菜单下完成,也可以使用命令编程实 现。 ⒉ 在Foxpro系统菜单下使用OLE ⑴ 嵌入或链接对象 在菜单方式下嵌入或链接指定对象到通用字段分以下两种情况: ①嵌入对象 当对象为一个.BMP(或.PCX)格式文件时,按照图9.1 所示的操作步骤可以嵌入所选对 象,关闭通用字段编辑窗口后,字段标识由“gen”变成“Gen”。 打开要嵌入或链接对象的数据库 ↓ 选择Record菜单中的Append选项 ↓ 双击通用字段中的gen标识,打开通用字段编辑窗口 ↓ 选择Edit菜单中的Insert Object选项 ↓ 单击Insert Object对话框中的File按钮 ↓ 选择.BMP或.PCX文件类型和文件名 ↓ 选定文件后单击Insert按钮将对象嵌入通用字段 图9.1 嵌入对象 ②使用剪贴板嵌入或链接对象 当对象是通过其它应用程序生成时(如由Excel产生的图表或由画图程序生成的位图), 就可以使用剪贴板来嵌入或链接对象。操作步骤如图9.2所示。 在应用程序中选择所需对象并复制到剪贴板 ↓ 进入Foxpro环境打开要嵌入或链接对象的数据库 ↓ 选择Record菜单中的Append选项 ↓ 双击通用字段中的gen标识,打开通用字段编辑窗口 ↓ 选择Edit菜单中的Paste选项或Paste special选项 ↓ ┌────┴─────┐ ↓ ↓ 选择Paste为嵌入对象 选择Paste special选项 ↓ 在Paste special对话框中选择数据类型 ↓ ┌───────────────┐ ↓ ↓ 单击Paste按钮为嵌入对象 单击Paste Link按钮为链接对象 图9.2 利用剪贴板嵌入或链接对象 ⑵ 显示对象 打开所需要的数据库,定位到相应的记录,双击通用字段中的“Gen ”标识即可显示该 对象。在显示过程中,通用字段编辑窗口的大小、位置都可以调整。 ⑶ 编辑对象 打开通用字段编辑窗口后,双击该对象可以自动进入生成该对象的应用程序窗口,此时 可以修改对象。若要删除一个对象,可先显示该对象,然后从Foxpro的Edit菜单中选择 Cut 即可。删除对象后,通用字段的标识又变为“gen”。 9.3.2 Foxpro通用字段的编程命令 在Foxpro中,支持OLE操作的通用字段编程命令有三条,它们分别实现对象的输入、 编辑和输出。 ⒈ 嵌入或链接对象──APPEND GENERAL 【格式】APPEND GENERAL <通用字段> FROM <文件> [LINK] [CLASS<OLE类>] 其中,<通用字段>用来存储输入的OLE对象。<文件>为存有OLE对象的文件名称, 可以包含盘符和路径。使用LINK选项表示链接对象,省略时为嵌入对象。 CLASS<OLE类> 指定OLE对象的类型,省略时由对象文件名的扩展名决定。 【功能】将<文件>指定的对象嵌入或链接到数据库当前记录的通用字段中。 【例9.15】首先在Foxpro环境下建立数据库OLEDBF.DBF的结构,该数据库含有filename (字符型、宽度为12)和object (通用型字段)两个字段。 根据如下要求编程:将C盘上 WINDOW目录下扩展名为.BMP的位图文件以对象方式嵌入到OLEDBF.DBF的通用字段中,并将该 对象的文件名填入filename字段中。 程序如下: *PROG9_15.PRG数据库通用字段的输入 SET TALK OFF CLEAR USE OLEDBF counter=ADIR(bmpfile,"C:\WINDOWS\*.BMP") &&将.BMP文件的各项信息拷贝到数组bmpfile FOR i=1 TO counter &&将.BMP文件的文件名及对象存入数据库 APPEND BLANK REPLACE filename WITH bmpfile[i,1] &&将该对象的文件名填入filename字段 APPEND GENERAL object FROM "C:\WINDOWS\"+bmpfile[i,1] &&对象嵌入 ENDFOR USE SET TALK ON RETURN 例9.15程序中,ADIR()为Foxpro的内部函数,其作用是将C盘WINDOWS目录下所有扩展名 为.BMP的位图文件的各项信息(包括文件名、文件大小、建立文件日期、建立文件时间以及 文件的属性)拷贝到一个5列二维数组(bmpfile)中,并返回拷贝的文件个数(counter)。 二维数组bmpfile的每一行分别用来存储一个文件的文件名(字符型)、文件大小(数值型) 、建立文件日期(日期型)、建立文件时间(字符型)和文件属性(字符型)五项信息。命 令APPEND GENERAL object FROM "C:\WINDOWS\"+bmpfile[i,1] 将指定的对象嵌入到通用字 段object中。 ⒉ 编辑对象──MODIFY GENERAL 【格式】MODIFY GENERAL <通用字段1> [,<通用字段2>,…] [NOMODIFY] [NOWAIT] [WINDOW <窗口名1>] [IN [WINDOW] <窗口名2>|IN SCREEN] 其中,<通用字段1>、<通用字段2>…为要编辑的通用字段。NOMODIFY选项限制通用字段 中的OLE对象只能显示,不能编辑修改。NOWAIT选项允许程序不等待对象编辑窗口的关闭 而继续执行后面的命令,只在程序方式下有效。使用WINDOW <窗口名1>可以指定对象的编辑 窗口,省略时使用系统缺省编辑窗口。使用IN[WINDOW] <窗口名2>可以指定对象编辑窗口的 父窗口,省略时为Foxpro的桌面窗口。使用IN SCREEN选项指定Foxpro 的桌面窗口作为对象 编辑窗口的父窗口。 【功能】打开一个或多个编辑窗口来浏览或编辑一个或多个通用字段中的OLE对象。 【说明】 ⑴利用MODIFY GENERAL命令打开通用字段编辑窗口后,只需用鼠标双击该OLE对象就 可以启动该对象的应用程序窗口进行编辑。 ⑵缺省情况下,Foxpro取当前工作区中数据库的通用字段进行浏览或编辑,如果要浏览 或编辑其它工作区中数据库的通用字段,只需在该字段名前加上所属数据库的别名即可。 【例9.16】根据例9.15所建立的数据库OLEDBF.DBF,编写一个对通用字段(object)中 的OLE对象进行修改的程序。 程序如下: *PROG9_16.PRG的功能是修改通用字段中的OLE对象 SET TALK OFF CLEAR USE OLEDBF SCAN MODIFY GENERAL object &&打开通用字段编辑窗口,编辑其中的OLE对象 WAIT "是否继续修改对象(Y/N)?" window TO yesno IF UPPER(yesno)#"Y" EXIT ENDIF ENDSCAN USE SET TALK ON RETURN ⒊ 输出对象──@...SAY 【格式】@ <行号>,<列号> SAY <通用字段>|<文件名> BITMAP [STYLE <字符表达式>] [SIZE <数值表达式1>,<数值表达式2>] [CENTER] [ISOMETRIC|STRETCH] 其中,<通用字段>指定要显示的OLE对象。使用<文件名> BITMAP可以显示由<文件名> 指定的位图文件。STYLE <字符表达式>用来指定所显示位图的透明属性,<字符表达式>的值 为“T”时表示透明(即显示的位图不覆盖当前位置上原来的位图),为“Q”时表示不透明 (即显示的位图覆盖当前位置上原来的位图)。SIZE <数值表达式1>,<数值表达式2>指定对 象的显示区域(高度和宽度)。CENTER选项控制对象在编辑窗口中央显示。ISOMETRIC 选项 使对象在SIZE指定的区域按比例(即按对象各边等长放缩)显示而不变形。STRETCH 选项使 对象在SIZE指定的区域内显示(即按区域大小进行放缩)。 【功能】在指定的行、列位置显示通用字段中的OLE对象或位图文件。 【例9.17】编程显示通用字段中的OLE对象。 程序如下: *PROG9_17.PRG的功能是显示通用字段中的OLE对象。 SET TALK OFF CLEAR USE OLEDBF SCAN @2,5 SAY object SIZE 20,40 ISOMETRIC &&显示object中的OLE对象 WAIT "是否继续显示对象(Y/N)?" window TO yesno IF UPPER(yesno)<>"Y" EXIT ENDIF ENDSCAN CLEAR USE SET TALK ON RETURN 转贴:Foxpro实用编程技术(1)第九章 Foxpro实用编程技术 本章从应用的角度介绍一些Foxpro实用编程技术,其中包括数组程序设计、备注字段的 编程、通用字段的编程、网络环境下程序设计、事件驱动程序设计和串行通讯程序设计六个 专题。 本章学习要点:在理解有关概念的基础上,重点掌握每个专题所涉及到的编程命令及函 数的使用,掌握每个专题的基本编程方法。 9.1 数组程序设计 同其它高级程序设计语言一样,在Foxpro中也可以使用数组。数组是具有相同名字的有 序数据的集合,由若干个数组元素组成。数组中的每个元素相当于一个内存变量,因此所有 对内存变量进行操作的命令均可适用于数组元素,但数组元素使用起来要比普通的内存变量 方便得多。Foxpro支持一维数组和二维数组,与其它高级语言不同的是,Foxpro中的数组元 素可以具有不同的数据类型,并且允许重复定义数组。利用数组进行程序设计,可以简化程 序的编写,便于复杂问题的求解。 9.1.1 数组的定义 在Foxpro中,使用数组之前通常需要先进行定义。也就是说,使用数组说明命令对数组 的名称、维数、大小(即数组元素的个数)进行说明。定义数组的命令如下: 【格式】 DECLARE|DIMENSION|PUBLIC <数组名1>(<数值表达式1>[,<数值表达式2>]) [,<数组名2>(<数值表达式3>[,<数值表达式4>]),…] 其中,<数组名1>、<数组名2>…为要定义数组的名称,其命名规则同内存变量完全相同。 当同时定义多个数组时,数组名之间用逗号“,”分隔。 数组名后括号内的数值表达式用来 指定所定义数组的维数和大小。若数组名后面的括号内只用一个数值表达式,则表示要定义 一维数组,数值表达式的值代表该数组中元素的个数。若数组名后面的括号内同时使用两个 数值表达式,则表示要定义二维数组,这两个数值表达式的乘积为该二维数组所拥有元素的 个数。 【功能】定义一个或多个一维或二维内存变量数组。 【说明】 ⑴这三条命令都可以用来定义数组。其中,DECLARE命令和DIMENSION命令的功能完全相 同,PUBLIC命令用来定义全局数组变量。 ⑵使用这三条命令所定义的数组,数组元素的初值均初始化成逻辑值.F., 因此引用数 组元素值之前,必须先对其赋值。 ⑶定义数组时,数组名后面的数值表达式必须使用一对小括号或中括号括起来。 例如: DECLARE A[10],B[5] &&定义两个一维数组变量A和B,元素个数分别为10和5 DIMENSION C[4,5] &&定义一个4行5列的二维数组C,元素个数为4*5=20 PUBLIC PA(50) &&定义一个全局一维数组PA,元素个数为50 需要说明的是,有些Foxpro命令或函数也具有定义数组的功能,也就是说,如果指定的 数组不存在,将自动建立该数组。例如,COPY TO ARRAY <数组名>命令、SCATTER TO <数组 名>命令和ACOPY()函数都具有定义数组的功能。 9.1.2 数组元素的引用与赋值 ⒈ 数组元素的引用 由于数组元素在内存中是按顺序存储的,所以引用数组元素时必须指定该元素在数组中 的位置。数组元素在数组中的位置可以用下标来表示,一旦下标确定,数组元素也就确定了。 一维数组的引用格式如下: 数组名称[下标表达式] 或 数组名称(下标表达式) 其中,下标表达式用来指定所引用的元素在数组中的位置,可以是正的数值常量、赋过值的 变量或数值表达式,且下标表达式必须使用一对小括号或中括号括起来。 例如,对于前面定义的数组A,若存取其中第三个元素可用A[3]或A(3)表示,存取数组A 中第I(I=1,2,…,10)个元素可用A[I]或A(I)表示。因此,使用一重循环可以访问数组A 中的所有元素。 二维数组可以理解为由M行N列组成的一张二维表,因此引用二维数组中的某个元素,必 须指定其行、列位置。引用格式如下: 数组名称[行下标表达式,列下标表达式] 或 数组名称(行下标表达式,列下标表达式) 例如,对于前面定义的二维数组C,若存取第二行第三列上的元素可用C[2,3]或C(2, 3) 表示,存取数组C中第I(I=1,2,3,4)行第J(J=1,2,3,4,5)列上的元素可用C[I,J]或C(I,J) 表示。因此,使用二重循环可以访问数组C中的所有元素。 在引用数组元素时,如果指定的下标表达式的值超过定义数组时所规定的最大下标值, 将产生“下标超界”错误信息。例如,对于前面定义的数组A中元素的引用,若使用A[11], Foxpro将报告“下标超界”错误信息。 ⒉ 数组元素的赋值 在Foxpro中,一旦数组定义后其元素自动被初始化成逻辑假值.F., 因此在使用数组元 素的值之前,必须对其重新赋值。对数组元素的赋值既可以通过赋值命令实现,也可以使用 有关数组操作的命令实现。 利用赋值命令为数组元素赋值有以下两种方式: ⑴用变量赋值命令为数组元素赋值。例如: DECLARE MA[10] STORE 1 TO MA[1], MA[3], MA[5], MA[7], MA[9] STORE 2 TO MA[2], MA[4], MA[6], MA[8], MA[10] 以上赋值命令对数组MA中奇数下标元素分别赋值1,偶数下标元素分别赋值2。这两条赋 值命令也可以用下面的FOR循环代替。 FOR I=1 TO 10 IF I % 2<>0 &&I为奇数 MA[I]=1 ELSE MA[I]=2 ENDIF ENDFOR 再如: DIMENSION MT[3,3] MT[1,1]=1 MT[1,2]=2 MT[1,3]=3 MT[2,1]=4 MT[2,2]=5 MT[2,3]=6 MT[3,1]=7 MT[3,2]=8 MT[3,3]=9 以上赋值命令对二维数组MT中的元素按行顺序分别赋值1,2,3;4,5,6;7,8,9 。 上述赋值命令也可以用下面的二重FOR循环代替。 FOR I=1 TO 3 FOR J=1 TO 3 MT[I,J]=(I-1)*3+J ENDFOR ENDFOR ⑵用赋值命令直接对整个数组赋值 当对数组中的元素赋相同的值时,Foxpro允许使用赋值命令直接对数组名进行赋值。 例如: DECLARE MB[20] MB=0 &&将MB数组中的20个元素均赋0值 PUBLIC MC[10,20] MC=" " &&将MC数组中的200个元素均赋为空格。 9.1.3 数组操作函数 为了便于数组操作,Foxpro提供了一些专门用于数组处理的标准函数。下面介绍几个常 用的函数。 ⒈ 确定数组元素的个数或行(列)数──ALEN() 【格式】ALEN(<数组名>[,<数值表达式>]) 其中,<数组名>可以为一维数组或二维数组。<数值表达式>的取值可以为0、1、2,为0 时返回数组元素的个数,为1时返回数组的行数,为2时返回数组的列数。 【功能】返回指定数组的元素个数或数组的行(列)数。 【说明】如果省略<数值表达式>,则返回数组元素的个数。如果对一维数组指定的< 数 值表达式>的值为2,则返回0值。例如: DECLARE MA[10],MB[4,5] ?ALEN(MA),ALEN(MB,0) 10 20 ?ALEN(MA,1),ALEN(MB,1) 10 4 ?ALEN(MA,2),ALEN(MB,2) 0 5 ⒉ 确定数组元素在内存中的序号──AELEMENT() 【格式】AELEMENT(<数组名>,<数值表达式1>[,<数值表达式2>]) 其中,<数值表达式1>和<数值表达式2>分别为数组的行下标和列下标。若<数组名>为一 维数组,则不使用<数值表达式2>。 【功能】根据指定的下标返回数组元素在内存中的排列序号。 【说明】一维数组各元素在内存中的排列序号与其下标值相同,二维数组在内存中按行 顺序存储,即先存储第一行的每个元素,接着是第二行的每个元素,…。 【例9.1】 *PROG9_1.PRG SET TALK OFF DECLARE MA[10],MB[4,5] FOR I=1 TO 10 MA[I]=I ENDIF FOR I=1 TO 4 FOR J=1 TO 5 MB[I,J]=I+J ENDFOR ENDFOR ?AELEMENT(MA,5),AELEMENT(MB,4,3) 运行结果为: 5 18 ⒊ 确定数组元素的下标──ASUBSCRIPT() 【格式】ASUBSCRIPT(<数组名>,<数值表达式1>,<数值表达式2>) 其中,<数组名>为一维或二维数组。<数值表达式1>为数组元素在内存中的排列序号。< 数值表达式2>的取值可以为1或2,为1时返回数组元素的行下标,为2时返回数组元素的列下 标。 【功能】根据数组元素在内存中的序号,确定该元素的行下标或列下标。 【说明】 ⑴对于一维数组,<数值表达式2>的值只能取1,取2将报告错误信息。 ⑵ASUBSCRIPT()和AELEMENT()是功能相反的两个函数,前者是根据数组元素的序号确其 定下标值,后者是根据数组元素的下标值确定其序号。 例如: DECLARE MB[4,5] ?ASUBSCRIPT(MB,18,1),ASUBSCRIPT(MB,18,2) &&显示序号为18的元素的行列下标 4 3 ?AELEMENT(MB,ASUBSCRIPT(MB,18,1),ASUBSCRIPT(MB,18,2)) 18 ⒋ 数组的拷贝──ACOPY() 【格式】ACOPY(<源数组>,<目标数组>[,<数值表达式1>[,<数值表达式2> [,<数值表达式3>]]]) 其中,<数值表达式1>指定要拷贝元素的起始位置,省略时为1。<数值表达式2> 指定要 拷贝的元素个数,省略时为源数组中指定位置开始的全部元素。<数值表达式3> 指定拷贝到 目标数组的起始位置,省略时为1。 【功能】将源数组中的元素拷贝到目标数组中。 【说明】 ⑴当目标数组中的元素多于拷贝过来的元素时,ACOPY()将返回成功拷贝的元素个数。 ⑵当目标数组中的元素少于要拷贝的元素时,ACOPY() 将尽可能的拷贝元素到目标数组 ,并显示“下标超界”出错信息。 ⑶当目标数组不存在时,ACOPY()将自动建立该数组。 【例9.2】 *PROG9_2.PRG SET TALK OFF DECLARE MA[10],MB[10],MC[10],MD[10] &&定义四个一维数组,其初值均为.F. CLEAR FOR I=1 TO 10 MA[I]=I &&对数组MA赋值 ENDFOR =ACOPY(MA,MB) &&拷贝MA数组到MB =ACOPY(MA,MC,2) &&将MA数组第2个位置开始的元素拷贝到MC数组 =ACOPY(MA,MD,3,5,2) &&拷贝MA数组第3个位置开始的5个元素到MD(从第2个位置开始存放) LIST MEMORY LIKE M* &&显示所有以M开头的内存变量 运行结果如下: MA Priv A ma ( 1) N 1 ( 1.00000000) ( 2) N 2 ( 2.00000000) ( 3) N 3 ( 3.00000000) ( 4) N 4 ( 4.00000000) ( 5) N 5 ( 5.00000000) ( 6) N 6 ( 6.00000000) ( 7) N 7 ( 7.00000000) ( 8) N 8 ( 8.00000000) ( 9) N 9 ( 9.00000000) ( 10) N 10 ( 10.00000000) MB Priv A ma ( 1) N 1 ( 1.00000000) ( 2) N 2 ( 2.00000000) ( 3) N 3 ( 3.00000000) ( 4) N 4 ( 4.00000000) ( 5) N 5 ( 5.00000000) ( 6) N 6 ( 6.00000000) ( 7) N 7 ( 7.00000000) ( 8) N 8 ( 8.00000000) ( 9) N 9 ( 9.00000000) ( 10) N 10 ( 10.00000000) MC Priv A ma ( 1) N 2 ( 2.00000000) ( 2) N 3 ( 3.00000000) ( 3) N 4 ( 4.00000000) ( 4) N 5 ( 5.00000000) ( 5) N 6 ( 6.00000000) ( 6) N 7 ( 7.00000000) ( 7) N 8 ( 8.00000000) ( 8) N 9 ( 9.00000000) ( 9) N 10 ( 10.00000000) ( 10) L .F. MD Priv A ma ( 1) L .F. ( 2) N 3 ( 3.00000000) ( 3) N 4 ( 4.00000000) ( 4) N 5 ( 5.00000000) ( 5) N 6 ( 6.00000000) ( 6) N 7 ( 7.00000000) ( 7) L .F. ( 8) L .F. ( 9) L .F. ( 10) L .F. ⒌ 数组元素的插入──AINS() 【格式】AINS(<数组名>,<数值表达式>[,2]) 其中,<数组名>是待插入元素的一维数组或插入一行(或一列)元素的二维数组。< 数 值表达式>指定要插入元素的位置或行号(不带参数2)或列号(带参数2)。 【功能】将一个元素插入到一维数组或将一行(或一列)元素插入到二维数组。 【说明】 ⑴向一维数组中插入一个新元素时,从插入位置开始的所有元素向后移动一个位置,最 后一个元素将丢掉,整个数组大小不变。 ⑵向二维数组中插入一行(不带参数2)或一列(带参数2)元素时,从插入位置开始的 所有行(或列)均向后移动一行(或一列),最后一行(或一列)元素将丢掉,整个数组大 小不变。 ⑶向数组中插入的新元素被设置为逻辑值.F.。 ⑷插入成功时,AINS()返回值1。 【例9.3】 *PROG9_3.PRG SET TALK OFF DECLARE MA[10],MB[4,5] CLEAR FOR I=1 TO 10 MA[I]=I &&对一维数组MA赋值 ENDFOR FOR I=1 TO 4 FOR J=1 TO 5 MB[I,J]=(I-1)*5+J &&对二维数组MB赋值 ENDFOR ENDFOR ?"插入元素之前一维数组MA中各元素情况:" ?MA[1],MA[2],MA[3],MA[4],MA[5] ?MA[6],MA[7],MA[8],MA[9],MA[10] ?"插入元素之前二维数组MB中各元素情况:" FOR I=1 TO 4 ? FOR J=1 TO 5 ?? MB[I,J] ENDFOR ENDFOR =AINS(MA,4) &&在MA数组第四个位置插入一个元素 =AINS(MB,2) &&在MB数组的第二行插入一行元素 ?"插入元素之后一维数组MA中各元素情况:" ?MA[1],MA[2],MA[3],MA[4],MA[5] ?MA[6],MA[7],MA[8],MA[9],MA[10] ?"插入元素之后二维数组MB中各元素情况:" FOR I=1 TO 4 ? FOR J=1 TO 5 ?? MB[I,J] ENDFOR ENDFOR 运行结果如下: 插入元素之前一维数组MA中各元素情况: 1 2 3 4 5 6 7 8 9 10 插入元素之前二维数组MB中各元素情况: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 插入元素之后一维数组MA中各元素情况: 1 2 3 .F. 4 5 6 7 8 9 插入元素之后二维数组MB中各元素情况: 1 2 3 4 5 .F. .F. .F. .F. .F. 6 7 8 9 10 11 12 13 14 15 ⒍ 数组元素的删除──ADEL() 【格式】ADEL(<数组名>,<数值表达式>[,2]) 其中,<数组名>是待删除元素的一维数组或删除一行(或一列)元素的二维数组。< 数 值表达式>指定要删除元素的位置或行号(不带参数2)或列号(带参数2)。 【功能】删除一维数组中的指定元素或二维数组中指定的一行(或一列)元素。 【说明】 ⑴删除数组元素后,数组的大小不变。 ⑵删除一维数组中的元素后,其后面的所有元素自动向前移动一个位置,并将最后一个 元素赋值为.F.。 ⑶删除二维数组中的一行(或一列)后,其后面的行(或列)自动向前移动或一行(或 一列),并将最后一行(或一列)元素赋值为.F.。 ⑷删除成功时,ADEL()返回1。 【例9.4】 *PROG9_4.PRG SET TALK OFF DECLARE MA[6],MB[3,3] CLEAR MA=0 &&将MA数组全部元素置0 MB=1 &&将MB数组全部元素置1 =ADEL(MA,4) &&删除MA数组中第4个元素 =ADEL(MB,2) &&删除MB数组中第2行元素 LIST MEMORY LIKE M* &&显示删除元素后MA和MB数组的内容 SET TALK ON 结果如下: MA Priv A ( 1) N 0 ( 0.00000000) ( 2) N 0 ( 0.00000000) ( 3) N 0 ( 0.00000000) ( 4) N 0 ( 0.00000000) ( 5) N 0 ( 0.00000000) ( 6) L .F. MB Priv A ( 1, 1) N 1 ( 1.00000000) ( 1, 2) N 1 ( 1.00000000) ( 1, 3) N 1 ( 1.00000000) ( 2, 1) N 1 ( 1.00000000) ( 2, 2) N 1 ( 1.00000000) ( 2, 3) N 1 ( 1.00000000) ( 3, 1) L .F. ( 3, 2) L .F. ( 3, 3) L .F. ⒎ 数组元素的查找──ASCAN() 【格式】ASCAN(<数组名>,<表达式>[,<数值表达式1>[,<数值表达式2>]]) 其中,<数组名>为要查找的一维数组或二维数组。<表达式>指定要查找的数组元素,可 以是任何类型的表达式。<数值表达式1>指定查找的起始位置, 省略时从数组中第一个元素 开始查找。<数值表达式2>指定查找的范围,省略时为指定查找位置开始的全部元素。 【功能】在数组中查找指定的数组元素。 【说明】 ⑴如果查找成功,则返回该元素在数组中的序号,否则返回0值。 ⑵若查找的元素为字符类型,则查找结果将受SET EXACT的设置影响。 【例9.5】 *PROG9_5.PRG SET TALK OFF DECLARE MA[10] FOR I=1 TO 10 MA[I]=I*I ENDFOR IP=ASCAN(MA,25) &&在MA数组中查找值为25的元素 IF IP>0 WAIT "查找成功!" WINDOW NOWAIT ELSE WAIT "查找失败!" WINDOW NOWAIT ENDIF SET TALK ON ⒏ 数组的排序──ASORT() 【格式】ASORT(<数组名>[,<数值表达式1>[,<数值表达式2>[,<数值表达式3>]]]) 其中,<数组名>为要排序的一维数组或二维数组。<数值表达式1>表示数组元素的序号, 指定排序的起始位置,省略时从第一个元素开始排序。<数值表达式2> 指定一维数组中要排 序的元素个数或二维数组中要排序的元素的行数,省略时将从指定的起始位置开始,一直到 数组结束。<数值表达式3>指定排序的方向,为0时表示升序(由小到大)排序,为1 时表示 降序(由大到小)排序,省略时按升序排序。 【功能】按升序或降序对数组中的元素进行排序。 【说明】 ⑴参加排序的数组元素必须具有相同的数据类型,否则将产生“数据类型不匹配”错误 信息。 ⑵一维数组是以元素为单位进行排序的,即从<数值表达式1>指定的元素开始,直到<数 值表达式2>指定的元素个数为止。 【例9.6】 *PROG9_6.PRG SET TALK OFF DECLARE MA[10] CLEAR MA[1]=1 MA[2]=3 MA[3]=5 MA[4]=7 MA[5]=9 MA[6]=2 MA[7]=4 MA[8]=6 MA[9]=8 MA[10]=10 =ASORT(MA,1,0,1) &&对MA数组按降序排序 ?MA[1],MA[2],MA[3],MA[4],MA[5] ?MA[6],MA[7],MA[8],MA[9],MA[10] SET TALK ON 运行结果为: 10 9 8 7 6 5 4 3 2 1 如果将例9.6程序中的排序命令改为“=ASORT( MA) ”, 结果将会如何? 如果改为“ =ASORT(MA,3,6,0),结果又将如何?请读者自己分析。 ⑶二维数组是以某列为基准,以行为单位进行排序的,即从<数值表达式1> 指定的元素 所在的行开始,以该元素所在的列上的元素大小为基准,向下排<数值表达式2>行。 在整个 排序过程中,每行中各列元素的次序保持不变。 【例9.7】 *PROG9_7.PRG SET TALK OFF DECLARE MB[4,3] CLEAR MB[1,1]=4 MB[1,2]=2 MB[1,3]=6 MB[2,1]=1 MB[2,2]=5 MB[2,3]=9 MB[3,1]=10 MB[3,2]=8 MB[3,3]=12 MB[4,1]=7 MB[4,2]=11 MB[4,3]=3 ?"排序之前数组MB的各元素如下:" DO DISPMB =ASORT(MB,8,2,1) &&从序号为8的元素开始,降序排2行元素 ?"排序之后数组MB的各元素如下:" DO DISPMB SET TALK ON PROCEDURE DISPMB &&显示数组元素过程 FOR I=1 TO 4 ? FOR J=1 TO 3 ?? MB[I,J] ENDFOR ENDFOR RETURN 运行结果如下: 排序之前数组MB的各元素如下: 4 2 6 1 5 9 10 8 12 7 11 3 排序之后数组MB的各元素如下: 4 2 6 1 5 9 7 11 3 10 8 12 如果将例9.7程序中的排序命令改为“=ASORT( MB) ”, 结果将会如何? 如果改为“ =ASORT(MB,6),结果又将如何?请读者自己分析。 ⒐ 将数据库的结构复制到数组──AFIELDS() 【格式】AFIELDS(<数组名>) 【功能】将当前打开的数据库的结构信息复制到指定的数组。 【说明】 ⑴该函数将当前工作区中打开的数据库的“字段名”、“字段类型”、“字段长度”和 “小数位数”四项信息存入一个n(字段个数)行4列的二维数组数组中。 ⑵如果事先没有定义数组,AFIELDS()将自动建立该数组。若定义的数组不够大, 则自 动调整该数组的大小,以便容纳所有的字段信息。 【例9.8】 *PROG9_8.PRG SET TALK OFF CLEAR USE TXLK =AFIELDS(DBFSTRU) &&取通讯录数据库的结构信息 FOR I=1 TO FCOUNT() ? FOR J=1 TO 4 ?? DBFSTRU[I,J]," " ENDFOR ENDFOR SET TALK ON 运行结果如下: 姓名 C 8 0 性别 C 2 0 职务 C 6 0 工作单位 C 30 0 邮政编码 C 6 0 通讯地址 C 30 0 9.1.4 数组程序设计举例 通过上述介绍可以看出,Foxpro中的数组在操作上非常灵活,这是其它程序设计语言所 无法相比的。另外,Foxpro中的数组还可以与数据库之间进行数据交换,大大方便了数据库 的操作。数组是一种非常有用的数据结构,利用数组进行程序设计,可以简化问题的求解。 【例9.9】假设有两个数据库结构完全相同的数据库RSDA1.DBF和RSDA2.DBF, 为了保证 输入数据的可靠性,这两个数据库中的记录分别由两个操作员按照同样的数据建立。要求编 程检查两个数据库中的记录是否完全相同,如果发现不相同的记录,需要将RSDA2.DBF 中不 一致记录的记录号和记录内容存入另外一个数据库RSDA3.DBF中。 数据库结构如下: Structure for database: C:\PRGDIR\RSDA1.DBF Field Field Name Type Width Dec 1 姓名 Character 8 2 性别 Character 2 3 职称 Character 6 4 出生日期 Date 8 5 工龄 Numeric 2 6 基本工资 Float 6 2 7 奖金 Float 6 2 8 婚否 Logical 1 ** Total ** 40 Structure for database: C:\PRGDIR\RSDA3.DBF Field Field Name Type Width Dec 1 记录号 Numeric 10 2 姓名 Character 8 3 性别 Character 2 4 职称 Character 6 5 出生日期 Date 8 6 工龄 Numeric 2 7 基本工资 Float 6 2 8 奖金 Float 6 2 9 婚否 Logical 1 ** Total ** 50 程序如下: *PROG9_9.PRG的功能是比较两个数据库中的记录是否完全相同 SET TALK OFF DECLARE MA[8],MB[8] SELE 3 USE RSDA3 SELECT 2 USE RSDA2 SELECT 1 USE RSDA1 SET RELATION TO RECNO() INTO RSDA2 &&将RSDA1.DBF与RSDA2.DBF按记录号关联 SCAN SELECT 1 SCATTER TO MA &&将RSDA1.DBF中当前记录中各字段的值存入数组MA SELECT 2 SCATTER TO MB &&将RSDA2.DBF中当前记录中各字段的值存入数组MB IF NOT EQUAL() &&将RSDA2.DBF中不一致记录的记录号和记录存入RSDA3.DBF SELECT 3 APPEND BLANK REPLACE 记录号 WITH RECNO(2) GATHER FROM MB FIELDS 姓名,性别,职称,出生日期,工龄,基本工资,奖金,婚否 ENDIF ENDSCAN CLOSE DATABASE SET TALK ON RETURN FUNCTION EQUAL &&比较数组MA和MB对应元素是否相同,如果相同返回.T.,否则返回.F. PRIVATE I,TRUE TRUE=.T. FOR I=1 TO 8 IF MA[I]<>MB[I] TRUE=.F. ENDIF ENDFOR RETURN TRUE 例9.9程序由一个主程序和一个用户自定义函数EQUAL组成。为了便于处理, 将 RSDA1 .DBF和RSDA2.DBF两个数据库按记录号进行关联,这样就保证了数据库RSDA1.DBF的记录指针 移动时,与之关联的RSDA2.DBF的记录指针也自动指向具有相同记录号的记录。使用SCATTER 命令将数据库的当前记录存入数组,利用GATHER命令把数组的内容写入数据库的当前记录。 使用数组MA和MB,将两个数据库记录的比较,转化为对两个数组对应元素的比较,简化了操 作。 【例9.10】输入一个字符串,统计其中每个字母出现的次数,并按照字母顺序输出统计 的结果。统计时,大小写字母按一个字母计算。 程序如下: *PROG9_10.PRG的功能是统计一个字符串中每个字母出现的次数。 SET TALK OFF CLEAR ACCEPT "输入一个字符串:" TO STRING STRING=UPPER(STRING) &&将字符串中的小写字母转换为大写字母 LENGTH=LEN(STRING) &&计算字符串的长度 DECLARE MA[LENGTH] &&MA数组用来保存字符串中不同的字母,重复出现的字母只存一个 NUM=0 &&保存不同字母的个数 FOR I=1 TO LENGTH CH=SUBSTR(STRING,I,1) &&取字符串中的一个字符 IF ISALPHA(CH) &&判别CH是否为字母,ISALPHA()为Foxpro内部函数 IP=ASCAN(MA,CH) &&查找该字母是否在数组MA中出现过 IF IP=0 &&如果是第一次出现,则将其存入数组MA NUM=NUM+1 MA[NUM]=CH ENDIF ENDIF ENDFOR IF NUM>0 &&如果输入的字符串中含有字母,则统计 DECLARE MB[NUM] &&MB数组用来保存字母的统计结果 MB=0 &&将MB数组全部元素赋0值 =ASORT(MA,1,NUM) &&按照字母顺序排序 FOR I=1 TO LENGTH &&该FOR循环统计字符串中字母的个数 CH=SUBSTR(STRING,I,1) IP=ASCAN(MA,CH) IF IP>0 MB[IP]=MB[IP]+1 &&将该字母的个数加1 ENDIF ENDFOR ?"字母:"+SPACE(10)+"个数:" FOR I=1 TO NUM ?MA[I],MB[I] ENDFOR ELSE ?"输入的字符串中没有字母,无法统计" ENDIF SET TALK ON RETURN 运行情况如下: 输入一个字符串:You have to look before you leap,as the saying goes. 字母: 个数: A 4 B 1 E 6 F 1 G 2 H 2 I 1 K 1 L 2 N 1 O 7 P 1 R 1 S 3 T 2 U 2 V 1 Y 3 【例9.11】编写一个消除指定数据库中相同记录的程序,并且将消除重复记录后剩余的 记录复制到结构相同的TEMPDBF.DBF中。假设数据库中没有备注字段和通用字段。 基本思路:首先打开指定的数据库文件(例如RSDA.DBF),利用COPY TO ARRAY 命令将 数据库中全部记录拷贝到二维数组(如TAB)中。然后在二维数组TAB中逐行检查是否存在完 全相同的两行(或多行)元素,若存在,则保留一行,并删除其余相同的行。最后将TAB 数 组中剩余的元素(不包含元素值全部为.F.的行)拷贝到另外一个二维数组(如MA)中, 并 利用APPEND FROM ARRAY命令将数组MA中的全部元素追加到目标数据库TEMPDBF.DBF中。 程序如下: *PROG9_11.PRG的功能是消除指定数据库中的相同记录 SET TALK OFF USE RSDA COPY TO ARRAY TAB &&将数据库记录拷贝到二维数组TAB M=ALEN(TAB,1) &&计算行数 N=ALEN(TAB,2) &&计算列数 I=1 DO WHILE I<=M AND NOT ALLFALSE(I) &&消除二维数组TAB中完全相同的行 J=I+1 DO WHILE J<=M AND NOT ALLFALSE(J) TRUE=CHECKTAB(I,J) IF TRUE =ADEL(TAB,J) &&删除TAB数组中的第J行 ENDIF J=J+1 ENDDO I=I+1 ENDDO I=1 NUM=0 DO WHILE I<=M AND NOT ALLFALSE(I) &&统计TAB数组中有效数据行数 NUM=NUM+1 I=I+1 ENDDO DECLARE MA[NUM,N] =ACOPY(TAB,MA,1,NUM*N) &&将消除重复后的数据拷贝到二维数组MA COPY STRUCTURE TO TEMPDBF USE TEMPDBF APPEND FROM ARRAY MA &&将二维数组MA中的元素追加到当前数据库 USE SET TALK ON RETURN *函数ALLFALSE判断TAB数组中某行元素是否全部为.F.,若是返回.T.,否则返回.F. FUNCTION ALLFALSE PARAMETERS IP PRIVATE J,TRUE TRUE=.T. FOR J=1 TO N IF NOT EMPTY(TAB[IP,J]) &&不为空值 TRUE=.F. ENDIF ENDFOR RETURN TRUE *函数CHECKTAB检查TAB数组中是否存在两行完全相同的元素,若是返回.T.,否则返回.F. FUNCTION CHECKTAB PARAMETERS X,Y PRIVATE K,TRUE TRUE=.T. FOR K=1 TO N IF TAB[X,K]<>TAB[Y,K] &&数组元素不同 TRUE=.F. ENDIF ENDFOR RETURN TRUE 例9.11程序由一个主程序和两个用户自定义函数组成。自定义函数ALLFALSE()用来判断 TAB数组中某行元素是否全为.F.(删除数组中某行后产生元素值全为.F.的行),若是, 该 行不参与比较。自定义函数CHECKTAB()用来检查TAB中是否存在完全相同的两行, 若存在, 该函数返回逻辑值.T.,否则返回. F. 。 ALLFALSE( ) 的调用出现在 DO WHILE 命令中, CHECKTAB()的调用出现在赋值命令中(TRUE=CHECKTAB(I,J))。它们都属于有参调用,参数 传递情况请读者自己分析。 【例9.12】在港口煤炭货运业务管理中,需要按照收货单位、到达港和煤种统计国内出 口煤炭进出结存日报表。其中,当日调进煤炭吨数可根据当天的水陆联运货票,按照收货单 位、到达港和煤种统计出来。现有一名为HPK.DBF的水陆联运货票数据库, 其数据库结构如 下: Field Field Name Type Width Dec 1 到港日期 Character 10 2 发货日期 Character 10 3 运单号 Character 6 4 车号 Character 8 5 吨数 Numeric 10 6 发站 Character 12 7 到达港 Character 6 8 煤种 Character 10 9 发货单位 Character 30 10 收货单位 Character 30 11 铁路局 Character 12 12 备注 Memo 10 ** Total ** 155 要求按照收货单位、到达港和煤种统计吨数(即把收货单位、到达港和煤种都相同的记录的 吨数字段相加)。 分析:本例属于多个关键字段(即收货单位、到达港和煤种三个字段)的分类求和,显 然,无法利用Foxpro的TOTAL命令实现。 我们可以按照下面的思路求解:首先根据要分类求 和的数据库(HPK.DBF),建立一个用于累加求和目的的数据库(简称累加库), 在累加库 中应包括要分类求和的所有关键字段和数值字段。然后从HPK.DBF中取记录, 并按关键字段 的值查找累加库。若找到,则取出上次求和的结果与本次的吨数相加,结果再写回累加库。 若没有找到,则将关键字段的值和对应的吨数追加到累加库。这样对HPK.DBF 扫描一遍就可 以统计出各类的求和结果。 程序如下: *PROG9_12.PRG按照收货单位、到达港和煤种统计吨数,结果存入COUNTHP.DBF SET TALK OFF SLEECT 1 USE HPK &&打开货票库 COPY STRU TO COUNTHP FIELDS 收货单位,到达港,煤种,吨数 SELECT 2 USE COUNTHP &&打开累加库 INDEX ON 收货单位+到达港+煤种 TO COUNTHP &&按关键字段的组和建立索引 DECLARE OP1[4],OP2[4] SELECT 1 SCAN SCATTER TO OP1 FIELDS 收货单位,到达港,煤种,吨数 SELECT 2 SEEK OP1[1]+OP1[2]+OP1[3] &&按组和关键字查找累加库 IF FOUND() &&若存在,则累加吨数 SCATTER TO OP2 OP2[4]=OP2[4]+OP1[4] &&累加吨数 GATHER FROM OP2 ELSE &&第一次出现追加到累加库 APPEND BLANK GATHER FROM OP1 ENDIF SELECT 1 ENDSCAN CLOSE ALL SET TALK ON RETURN 例9.12程序中,使用了数据库记录与数组之间交换数据的命令SCATTER TO < 数组> 和 GATHER FROM <数组>。本例介绍的方法弥补了Foxpro的TOTAL 命令在多关键字段分类求和方 面的缺陷,为编写通用多关键字段分类求和程序提供了一种有效方法。 vfoxpro grid交替显示不同背景色frmmyform.grdgrid1.setall("dynamicbackcolor", ; "iif(mod(recno( ), 2)=0, rgb(255,255,255) ; , rgb(0,255,0))", "column") && 交替显示白色和绿色的记录 frmmyform.grdgrid1.setall("dynamicbackcolor", ; "iif(mod(recno( ), 2)=0, rgb(255,255,255) ; , rgb(0,255,0))", "column") && 交替显示白色和绿色的记录 8月31日 转引皇明老总黄鸣的“警惕二十九岁现象”以为自勉大家都知道“59岁现象”――许多国企的老总年龄接近60岁时,一改过去勤恳、节俭的本色,盖因在60岁国企老总法定退休年龄之前,他们心态失衡;而“29岁现象”却鲜为人知,但在中国“29岁现象”比“59岁现象”普遍得多。 什么是“29岁现象”? 我在多年培养、使用年轻人尤其是大学生的过程中发现:不少员工在20多岁时,学习工作有激情,工作上勤勤垦垦、踏踏实实,生活有艺术、有情趣,可是到了29岁左右,按说应该更成熟更有价值才对,但反而情绪波动大、工作浮躁急功近利。表现在看书、学习注意力不集中,对外界事物的兴趣忽高忽低,设定的工作目标或高不可攀或放弃追求,对下属或要求过分或听之任之,对亲友不耐烦,对团队尤其是对上级经常抱怨牢骚,对待批评建议经常没有耐性甚至反应过分激烈,老虎屁股摸不得,经常比过去,讲排场慕虚荣,对自己过去的同学朋友羞于提起现在的职位或收入,内心经常将自己与认识不认识的姣姣者做不切实际的比较,比较之后往往自惭形秽、自怨自艾、自我放逐,严重者陷入重度抑郁症。生活没情趣、工作无效率,经常是心里着急行动却无力无效,就像人们梦中经常遇到的紧急情况:想跑迈不开腿,向动动不了,想说张不开嘴,人际关系不是冷漠就是紧张。 过去30岁这个坎之后,这类人有两种结局,一种原来就乐观、平和的,通过及时努力调整一切正常化了。但有很大一部分人挣扎抗争不过,就此消极麻木、一副万事皆休、死猪不怕开水烫的架式。 这又是什么原因呢?我注意到这种状况多发生在30岁左右时,找他们分析原因,他们自已也不是很清楚,但是经常听到这种人哀叹:“快30岁了,成了家没立业,什么时候立得起来呢?我什么时候能像你们一样?” 三十还没立业!对我触动很大,记得我30左右的时候,虽然没有明显上述症状,但也因功未成名不就,失衡焦虑了好一阵,好在及时用“阿Q精神抚慰疗法”调整过来了,都是“三十而立”这句古语害了大家! 20多岁时,都知道是打基础的时候,要想今后有成就,现在就要多付出,心态较平和,也有一定的耐心;当快要到30岁时,眼看自己的梦想和追求的结果没能达到社会上讲得“立业”的期望和标准时,对父母不好交待,不好意思见同学朋友,自己无法面对,自己给自己制造很多无形的压力,而且越来越大。 那什么是社会的“立业”标准为呢?我认为是人们对三十而立要达到的社会期望水平过高。改革开放初期各行业充满了机会,各专业也因沉寂了十年,所以到转型期很多人一夜暴富。时代对77、78级80年代的毕业生格外惠顾,给他们创造了快速立业的机遇,成名成家相对容易;而到90年代末和21世纪,社会经济发展有了一定的基础,各行各业向专业化推进,而且社会竞争变得越来越激烈,这时成名立业的周期在拉长,进入门槛一再提高。 现代社会“五十而立,三十知天命” 针对29岁现象,前些年我提出了“五十而立,三十知天命”的观点,受到了许多朋友的欢迎。古代人均寿命50岁左右,30生命过多半,此时不立则晚矣,如50岁时再不知天乐命,则只有苦熬余生了。而现代人平均寿命已到70岁左右,古代的30岁相当于现在的40-50岁,而且由于知识爆炸、竞争激烈,各专业行当更加复杂化,变数更多,人到40-50岁才能到达事业的高峰。30岁左右时,有的人刚刚拿到博士学位,创业者刚刚挣脱困境赚个温饱;许多公务员刚刚摆脱端茶倒水、打零杂的状态;普通工薪阶层生存问题刚刚得到解决(房价、教育等社会成本增高)。提出“五十而立”是让多数年轻人放平心态,期望不要太高,压力不要太大,不要过分急躁;提出了“三十知天命”,恰恰是因为这个年龄更需要及早知天乐命,看清人生大道,不违天命(自然法则、社会潮流、人生使命)这套理论通过各种论坛和大学演讲,反响很好,还真救了不少人。 但后来我仔细阅读《论语》中孔子的原话,“吾十有五而志于学,三十而立,四十而不惑,五十而知天命,六十而耳顺,七十而从心所欲,不逾矩。”发觉我原来的论点有些缺乏依据,如孔子讲的“30而立”中的“立”指的不是立业,而是立志立身,衔结前后两句就能明白。他的意思是说,我15岁开始做学问,30岁立志(周游列国,布道授业),40岁左右时学问习精,不再受外界诱惑而偏离方向。无论是学问不惑还是人生方向不惑,都不是现代意义上的“立业”层面。大家知道,所谓人生三立——立德、立功、立言。对于孔子来讲,立德算在40多岁后周游列国,50多岁弟子3000,贤人72;立功是孔子在68岁归鲁方被尊以“国老”之后;而立言呢,在公元前722年讫于公元前479年即孔子卒年间,孔子修订六经(《易》、《诗》、《书》、《礼》、《乐》、《春秋》),真正的立言不朽之作《论语》是在他去世后弟子们整理的。可见孔子的“立业”是很晚的。我常以此告诫那些视“30岁立业”为成功标尺的年轻人说:“圣人尚且如此,何况我等凡夫乎?”。 我也拿我的例子(不敢与圣人相提并论,只是为了治病救人,不得已而为之)劝导安慰那些29岁症状的人说,我37岁才真正辞职,下海创办皇明公司是在1995年,当时不但是赤贫而且还负债近百万元,到了2000年也就是我42岁时,公司才有了盈余,但按照大家心目中“立业”的标准还差得很远,即使说立业也应是无论你的公司事业还是专业都立得住、站得固、走得稳。别说42岁时,就算我47岁退出管理一线之前,当我离开公司总裁岗位时,企业稳吗?企业立得住吗?我退出管理一线已近两年了,48岁近50岁了企业才有些“立”的迹象,企业文化、战略模式、管理机制等方面才有些大模样。然而管理体系上的“三机制两原则”虽然提出来了,但真正能可持续发展推行,稳定执行尚需时日,真正应了我提出了的“五十而立”。 我想对年轻一代说的是,你们的梦想追求固然可以理解也值得尊重,但过于急于求成的心理是不切实际的、有害的。希望你们把梦想藏在心底,保持知足长乐、知天乐命又积极进取,相信付出总有回报的心态。走好走实人生的每一步,相信你们的人生能顶天立地,你们的事业能稳健而长足发展,年轻人,你们的路长着呢,一路走好! 7月6日 有病了 我有病了,混身无力,总感觉懒懒的,连键盘的懒的去触动。是相思病吗,会觉的可笑的很。一夜的激情,几日的欢娱,太微不足道了,可我却似乎要被这个微不足道的女人打败了。是生理的需求吗,也许是吧。失落的世界里,失落了我的梦想、我的女人、我的事业。。。一切都好微不足道。我这么的无助,象个斗败的公鸡 ,这个世界已经不再属于我。 6月3日 要和google说再见了吗 好几天了,google.com,gmail都连不上了,只有gmail.cn还正常,上网一查,才明白大家是都被盾了。我实在不明白这是为了什么,可就在前几天,电视上播放的权威发言人还说国内的网络是自由的,想起了常听到的一句话:最不能相信的就是政治家的话。
GFW的机制是怎样的,不清楚,不过看网上的好多人讨论的倒是蛮有兴致。很搞笑的是,有人说用了关键字:8r8c以后,就可以连上了,结果很多人都去跟风,结果却是失望的。有的人说是因为又要到六月四号了,我也试了一下关键字:“六四”,点击搜索之后就没反应了,google.cn就连不上了。幸好还有个baidu,可这个好象搜索和国内相关度高的关键字还可以,好多专业点的关键字搜索实在不能让人满意。前几天想下个SQL SERVER 2k,看了baidu十多页的搜索结果也没有找到一个合适的,而google的结果就好许多了,第一条结果就ok。象baidu关键字"xorg",给出的结果真的好烂,第一页里竟然连个官方的站点都没有,第一条却是个“一个古老木头屋”的blog,真的是不知所谓。“失去的才是最宝贵的”,现在真的怀念google了,不知道我是不是也有必要下个tor了。 5月24日 失败了,还可以再来吗? 不知道为什么,只有在心情不好的时候,才会有冲动来这里敲几个汉字,可能这也是一种发泄心情的好办法。晚上给几个人发短信,竟然都没有人回音,难道是我的人缘很差吗?
小安子,这个小丫头,今天真的是让我很恼火。终于想明白了,原来我也只是被她利用而已,我能帮的也都帮到了,对我也可以置之不理了。真想说你很践,可其实是我自己贱,明知这种女孩的目的,却还傻忽忽的。也许是看到她,我的理智就混乱了,就象个白痴,等待着早已清楚的伤害。算了,长这么大该成熟了,自己的想法还总是单纯的小孩子。不知道是不是我的想法狭隘了,可我今天真的失落了,考试也失败了,心里的梦想一个个远去了,执着的人却成了最失败的人。我的抑郁症越来越重了,有些人,有些事真的不知该如何面对。 4月24日 挣扎的梦,故去的人 终于挣开了眼睛,好长时间缓不过神来,呆呆张望,不知何处。现在不是因为睡的太久,而是清楚的记的梦里的混乱和在一闪而过的人--我的姥姥。
虽然去世两年多了。可也许在清醒中很难想到我的姥姥,是我天生就是冷漠缺乏感情的人,还是这个诱惑的世界填充了的我狭小的心地,而我相信有的人甚至都没有时间去想及父母。
姥姥梦中的面容记不起来了,亦如我现在也很模糊姥姥的摸样。想到这里,我都开始惊诧自己,原来一个人在另一个人心中竟然是如此牢不可靠,是该责怪我的记性差,还是要谴责自己的想法。
我追忆起了小时候的事情,都是些简简单单的小事情,可那是一个人童年记忆的一部分,血液中的一滴。
和姥姥见的机会其实并不多,小时候要上学,大了要工作,所以除了中国人传统的节日——春节,剩下的一年364天里竟然很少有见过,我不知道别人家怎样,可我是这样。
最后一次见到姥姥就是在医院里了,长长皮管,粗重的呼吸,闷热而拥挤的房间,看着昏迷的姥姥,我不知道该说什么,该做什么。病房里其他的病人都清醒着,和家人有一搭没一搭闲聊着,而只有我们坐在或呆站在病床旁边,我羡慕旁边的人,而我再也没有机会能和姥姥说上一句话。之后我就回学校了,约半个月后得知姥姥已经去了,可那个时刻我的心灵却非常的平静,是这样的事实我已经预料到了,还是我相信姥姥一辈子的苦已经彻底结束,脱离这里而上了天堂,如果这样我们真的应该微笑了,可我笑不起来,却也哭不起来。倒是两天年的今天,心里沉沉,敲打着键盘,看着屏幕上一个个的字符,竟然有了哭的冲动。想起来,年龄大了,已经有越来越少的事和人让我欲哭,亦如能让我开心的一笑一样。也许我的感情就是个酿酒的过程,越久越醇,愈久愈烈,慢热的感情常常让我无所适从。不知道是我慢还是别人都快,也许是真的不太适合这个快餐化的社会,面对女人、面对朋友、面对社会都一样的道理。不禁会想起孤身一世的哲人Kant,她的女人都赛不过他的“耐心”而离他而去,我常偏执的想也许是远离女人才让他成为了一代精神的刨析者。别人说我理性,而我也常常这样自嘲,可我不是这样,我宁愿做个无知无畏的白痴,远离这心中的一切混沌。
生命的流逝是老天的规定,可不知老天是仁慈还是残酷,却要把我们的亲人留在心底,是我们想挽留飞去的时间而做的抵抗还是上天想让我们承受思念之苦来抵偿这世或上世欠下的债。面对这些我从来都是矛盾的,也许人类从有意识开始就想要弄清楚“为什么”,可最终迷惑的还是我们。
每年的大年初三,一大家人都会聚在姥姥家,这也是我小时过年最期待的一天,可以见到很多的人,还有我一大帮的弟弟们,也许这一天是我最风光得意的一天,只因为我是老大。压岁钱自然是少不了的,可我最在意的就是姥姥给我的那一份,大多并不多,可我总是惦记着姥姥什么时候会手里捏着几张钱走过来,也许是因为这是我收到的唯一来自上两辈长者的压岁钱。在我还没记事的时候,爷爷奶奶已经不在了,所以对姥姥和老爷,在我心中承负感情要更多。现在能记的起的我最早收到的压岁钱应该是五角的纸币了,记不的几张了,可是现在还能触摸到那种崭新而硬脆的感觉。我还记的,在我北京上学回来的一次,姥姥说我要上学,就开始掏钱,要给我,自然我没有收下。看着姥姥衰老的身躯,岁月磨砺的脸孔,不知道是心里绞痛多一些还是惭愧多一些。面对这么多的孩子,她的一点养老津自然是微不足道,可我看着她的背影却知道我已经收到了一份上天恩赐的厚礼。在心里总想说句什么,是谢谢,还是什么,才知道语言其实是这么无力,也许这些本来就是多余。
本还想还有很多想的东西想写,可却实在写不下去了,是我自己的心承担不下去了,还是我的大脑开始混乱找不到逻辑。只是心里一直是有个愧疚,最后的葬礼没能有机会去送送姥姥,不论是什么原因都显的那么微补足道,也许只有把我的愧疚藏在久违的泪滴。最后想说一句我爱你,姥姥。
附:这是我的开篇blog,倒并不是跟随现在这个web2.0的热潮,早就想开始写blog,而今天却因一个梦而起,有了写的冲动,希望能坚持写下去,不要象以前总也坚持不了多久的日记,也许叫月记或年记更恰当。
|
|
|