本章說(shuō)明 本章共分十一節(jié)。闡述了與VFP工作環(huán)境有關(guān)的細(xì)節(jié)問(wèn)題,其中一至七節(jié)為一般描述適用于一般使用者,第八、九兩節(jié)適用于中、高級(jí)開(kāi)發(fā)者,第十節(jié)是四個(gè)具體的實(shí)例,可用于任何應(yīng)用程序,第十一節(jié)是"選項(xiàng)"對(duì)話(huà)框的說(shuō)明性表格,是手冊(cè)性質(zhì)的資料。 第一節(jié) 概述 工作環(huán)境規(guī)定了 VFP 工作時(shí)的某些行為。配置工作環(huán)境意味著您可以通過(guò)某些方法使 VFP 的行為滿(mǎn)足自己的需要 - 必須的或者是某些個(gè)人偏好的。 與任何完善的開(kāi)發(fā)工具一樣,VFP 也是一個(gè)復(fù)雜的系統(tǒng),復(fù)雜的一個(gè)方面就表現(xiàn)在它具有極大的靈活性 - 同一種工作,由于"環(huán)境"的不同,可能會(huì)產(chǎn)生不同的效果。 工作環(huán)境是個(gè)整體的概念,我們使用"環(huán)境參數(shù)"一詞來(lái)描述構(gòu)成工作環(huán)境的個(gè)體。那么就可以說(shuō),工作環(huán)境就是由一組環(huán)境參數(shù)來(lái)決定的,配置工作環(huán)境就是設(shè)置這組環(huán)境參數(shù),以滿(mǎn)足不同的需求。這顯然有兩方面的任務(wù),第一、您要知道有那些環(huán)境參數(shù),第二、明確怎樣配置這些參數(shù)。 工作環(huán)境涉及到很多方面,例如輸入輸出、數(shù)據(jù)處理、開(kāi)發(fā)、調(diào)試等等??梢酝ㄟ^(guò)分類(lèi)對(duì)所有環(huán)境參數(shù)進(jìn)行描述。所有的環(huán)境參數(shù)都有一個(gè)原始的默認(rèn)值,一般的環(huán)境配置工作,事實(shí)上只需要修改少量的環(huán)境參數(shù)即可。 有一個(gè)問(wèn)題需要明確,"VFP 的工作環(huán)境"是指 Visual FoxPro 工具的開(kāi)發(fā)環(huán)境。另外一種情況,使用 VFP 開(kāi)發(fā)的應(yīng)用程序,在編譯成執(zhí)行文件后,工作在 VFP 運(yùn)行時(shí)的工作環(huán)境下。這兩者是有區(qū)別的,顯而易見(jiàn)的區(qū)別是,運(yùn)行時(shí)環(huán)境涉及的問(wèn)題比開(kāi)發(fā)環(huán)境少得多,例如開(kāi)發(fā)、調(diào)試方面的問(wèn)題。一般來(lái)講,運(yùn)行時(shí)的環(huán)境是開(kāi)發(fā)環(huán)境的一個(gè)子集,但嚴(yán)格說(shuō)來(lái)這是不對(duì)的,二者仍存在一些差別,不僅在環(huán)境參數(shù)的類(lèi)別與數(shù)量方面,也存在于配置方法上。本文的敘述主要針對(duì)開(kāi)發(fā)環(huán)境而進(jìn)行,對(duì)二者存在的差別也將被提及。 [dvnews_page=VFP 高級(jí)教程:VFP 開(kāi)發(fā)技巧] 第二節(jié) 默認(rèn)的工作環(huán)境 VFP 安裝完成后,其"內(nèi)部"保存著對(duì)所有環(huán)境參數(shù)的設(shè)置,這些參數(shù)可以稱(chēng)做是原始設(shè)置。您永遠(yuǎn)也不能夠去修改這些原始設(shè)置。但 VFP 提供一種機(jī)制允許您每次啟動(dòng)時(shí)用自己的設(shè)置去覆蓋這組原始設(shè)置。方法是是使用 Windows 注冊(cè)表及配置文件。 啟動(dòng)時(shí),VFP 首先會(huì)檢查 Windows 注冊(cè)表中的有關(guān)設(shè)置,然后據(jù)此修改環(huán)境參數(shù)。然后還會(huì)查找一個(gè)配置文件,該文件默認(rèn)的名字為 config.fpw,其中也存放著一些環(huán)境配置信息。VFP 將讀取這些信息,并再次修改環(huán)境參數(shù)。如果 VFP 在Windows 注冊(cè)表中沒(méi)有找到配置信息或者沒(méi)有找到配置文件,這沒(méi)有關(guān)系,VFP 將以原始配置進(jìn)行工作。您甚至可以主動(dòng)讓 VFP 在啟動(dòng)時(shí)放棄讀取注冊(cè)表及配置文件。 VFP 不會(huì)主動(dòng)把環(huán)境參數(shù)寫(xiě)進(jìn) Windows 注冊(cè)表中,但它提供了一種方法使您方面地將環(huán)境參數(shù)寫(xiě)進(jìn)注冊(cè)表,寫(xiě)入不僅針對(duì)修改過(guò)的參數(shù),而是所有參數(shù),您沒(méi)有去修改的參數(shù)值將以原始值寫(xiě)入。配置文件則不同,它只保存您寫(xiě)入的參數(shù),某種意義上,它相當(dāng)是一份注冊(cè)表中的環(huán)境參數(shù)表的勘誤。 保存在 Windows 注冊(cè)表中的環(huán)境參數(shù)以及配置文件中的設(shè)置稱(chēng)做"默認(rèn)工作環(huán)境" 第三節(jié) 配置文件 先讀取注冊(cè)表再查找配置文件的方法似乎有點(diǎn)復(fù)雜,但有些時(shí)候需要這樣做,例如工作在運(yùn)行時(shí)環(huán)境的應(yīng)用程序,啟動(dòng)時(shí)不去讀取注冊(cè)表,這使得配置文件成為必須。另外,配置文件創(chuàng)建于 FoxPro 的早期版本,兼容性使它必須被保留。VFP6 以前的版本在安裝時(shí)將自動(dòng)建立一個(gè)這樣的文件(在安裝目錄下),而到了 VFP6,系統(tǒng)不再自動(dòng)建立該文件,需要時(shí)由用戶(hù)自行建立。該文件是一個(gè)文本文件,可以使用任何文本編輯器來(lái)建立它。 VFP 啟動(dòng)時(shí)將按照下列路徑查找該文件: 當(dāng)前工作目錄 安裝 Visual FoxPro 的目錄 DOS 路徑中列出的目錄 配置文件有默認(rèn)的名字(config.fpw),"默認(rèn)"意味著你可以去改變它。這有利于您同時(shí)擁有多個(gè)配置文件,以便滿(mǎn)足不同的需要。指定另外不同于config.fpw名字的配置文件的方法是在啟動(dòng) VFP 時(shí)增加命令行開(kāi)關(guān)項(xiàng),例如 VFP6.EXE -Cc:\myprg\myconfig.fpw 配置文件中不僅僅存放環(huán)境配置信息,例如可以在配置文件中設(shè)置 VFP 啟動(dòng)后立即去執(zhí)行一個(gè)程序文件。這使得您可以在配置環(huán)境方面使用一種技巧,即將環(huán)境設(shè)置命令保存在一個(gè)程序文件中,然后讓 VFP 啟動(dòng)時(shí)去執(zhí)行它。 啟動(dòng)過(guò)程也可以通過(guò)使用命令行參數(shù)來(lái)定制,通過(guò)定制啟動(dòng)過(guò)程,可以得到不同的環(huán)境默認(rèn)設(shè)置,以下是對(duì)環(huán)境配置有影響的一些情況:
[dvnews_page=VFP 高級(jí)教程:VFP 開(kāi)發(fā)技巧]
第四節(jié) 更改默認(rèn)設(shè)置 VFP 啟動(dòng)完成后,工作環(huán)境被設(shè)置成默認(rèn)狀態(tài)。您可以即時(shí)地更改環(huán)境參數(shù),這有幾種方法,各種方法可能適合于不同的情況。 交互式修改 在命令窗口輸入環(huán)境設(shè)置命令,執(zhí)行后該修改會(huì)立即生效。絕大部分的環(huán)境參數(shù)是通過(guò) SET 命令設(shè)置的,另外還有一些通過(guò)系統(tǒng)變量存儲(chǔ)以及極少數(shù)的函數(shù)設(shè)置。在早期的XBASE 工具中,例如dBASEII中,僅有 20 幾條 SET 命令,而今天,VFP 中已經(jīng)有 120 多個(gè) SET 命令了。交互式的修改方法是枯燥的,因此只用于臨時(shí)性的修改,例如調(diào)試等。 程序化執(zhí)行修改 可以將一組環(huán)境設(shè)置命令組織成一個(gè)程序文件,運(yùn)行該程序,就相當(dāng)于在命令窗口一一輸入執(zhí)行了這組命令,有些情況下是需要這樣做的,例如在開(kāi)發(fā)環(huán)境下同時(shí)調(diào)試多于一個(gè)項(xiàng)目的時(shí)候??梢詫⒃摥h(huán)境設(shè)置程序存為一個(gè)過(guò)程或直接寫(xiě)在項(xiàng)目的主文件中。事實(shí)上,對(duì)于應(yīng)用程序,因?yàn)樽罱K要脫離開(kāi)發(fā)環(huán)境運(yùn)行,所以大部分都是這樣做的。 用命令方式讀取Windows 注冊(cè)表中的設(shè)置 讓 Visual FoxPro 再次讀取自己的注冊(cè)表設(shè)置,并且使用當(dāng)前的注冊(cè)表設(shè)置更新自己。 語(yǔ)法為: SYS(3056 [,1]) 說(shuō)明:包含1選項(xiàng)可以只根據(jù)注冊(cè)表設(shè)置進(jìn)行更新,不包括 SET 命令和文件位置。Visual FoxPro 在 Windows 注冊(cè)表的選項(xiàng)對(duì)話(huà)框中保存設(shè)置。當(dāng)Visual FoxPro 啟動(dòng)時(shí),讀取這些設(shè)置,并利用這些設(shè)置進(jìn)行配置。SYS(3056)可更新包含有文件名和路徑的系統(tǒng)變量,而系統(tǒng)變量由SET命令和注冊(cè)表設(shè)置。當(dāng)您選擇設(shè)置為默認(rèn)值時(shí),選項(xiàng)對(duì)話(huà)框指定的設(shè)置寫(xiě)入注冊(cè)表。其中一些影響Visual FoxPro環(huán)境的設(shè)置含有SET 命令,例如SET BELL,SET LOCK等。注意 SYS(3056)不更新來(lái)自Config.fpw(即 Visual FoxPro 配置文件)的設(shè)置。 有關(guān)環(huán)境設(shè)置的命令 有很多環(huán)境設(shè)置的命令,在本文的附表中,以"選項(xiàng)"對(duì)話(huà)框中的分類(lèi)列出了相應(yīng)的環(huán)境設(shè)置命令,還有一些命令沒(méi)有包含在"選項(xiàng)"對(duì)話(huà)框中,但它們也是關(guān)于環(huán)境的設(shè)置命令,本文僅將它們列出來(lái),具體的意義及語(yǔ)法可參見(jiàn)隨機(jī)文檔。
無(wú)論是交互式還是程序化執(zhí)行命令,其修改都是臨時(shí)的,只對(duì)當(dāng)前工作有效,VFP 系統(tǒng)關(guān)閉后,這種修改不能被保存,下一次運(yùn)行,如果需要同樣的設(shè)置,您不得不再一次輸入該命令或執(zhí)行該程序。要想使修改成為永久,必須將修改保存在 Windows 注冊(cè)表中或構(gòu)建配置文件。 修改注冊(cè)表 有兩種方法:直接修改 Windows 注冊(cè)表或使用 VFP 開(kāi)發(fā)環(huán)境提供的"選項(xiàng)卡"對(duì)話(huà)框。對(duì)于直接修改 Windwos 注冊(cè)表的方法,沒(méi)有人會(huì)建議您這樣做,除非您首先對(duì) Windwos 注冊(cè)表的結(jié)構(gòu)非常熟悉,其次對(duì) VFP 在 Windows 注冊(cè)表中的各種參數(shù)的意義比較了解,第三有某些特殊需要以至于不能使用常規(guī)的方法完成。常規(guī)的方法,是使用 VFP 的"選項(xiàng)卡"對(duì)話(huà)框來(lái)完成環(huán)境配置。 直接修改注冊(cè)表 VFP 環(huán)境設(shè)置信息在 Windows 注冊(cè)表的目錄如下: HKEY_CURRENT_USER\Software\Microsoft\VisualFoxPro\6.0\Options 主鍵名稱(chēng)在本文附表中有詳細(xì)介紹。 使用"選項(xiàng)"對(duì)話(huà)框 使用"選項(xiàng)卡"對(duì)話(huà)框來(lái)進(jìn)行系統(tǒng)的配置比直接修改 Windows 注冊(cè)表的方法至少有兩個(gè)好處,第一,很多配置參數(shù)在"選項(xiàng)卡"上是以一種"易于理解的方式"表達(dá)的,您只需在某些"問(wèn)題"前打勾或者在很多答案中選擇一個(gè),這就象您填一份表格一樣來(lái)得輕松。第二,在"選項(xiàng)卡"上進(jìn)行的配置,一旦完成后,立即生效,而直接修改 Windows 注冊(cè)表的方法卻不是這樣,只能是在下一次運(yùn)行 VFP 時(shí)生效。 在開(kāi)發(fā)環(huán)境下,執(zhí)行"工具"菜單中的"選項(xiàng)"菜單項(xiàng),會(huì)出現(xiàn)"選項(xiàng)"對(duì)話(huà)框。對(duì)話(huà)框上有12個(gè)卡頁(yè),分12個(gè)方面對(duì)環(huán)境進(jìn)行配置。本文附表中詳細(xì)描述了其中的每一項(xiàng)設(shè)置。事實(shí)上,真正需要修改的并不多,很多項(xiàng)設(shè)置,原始值應(yīng)該能滿(mǎn)足要求。現(xiàn)在的問(wèn)題是,當(dāng)你修改完成后,可有兩種選擇,按"確定"按鈕退出對(duì)話(huà)框,您的修改只會(huì)保存在當(dāng)前環(huán)境中,隨著系統(tǒng)的關(guān)閉而失效;按"設(shè)置為默認(rèn)值"按鈕退出對(duì)話(huà)框,當(dāng)前的設(shè)置將會(huì)被寫(xiě)進(jìn) Windows 注冊(cè)表從而成為新的默認(rèn)值。 第六節(jié) ON命令 ON ERROR 命令 設(shè)計(jì)得再好的程序,在運(yùn)行時(shí)也不可避免地會(huì)發(fā)生錯(cuò)誤,這些錯(cuò)誤可能是程序自身的錯(cuò)誤,也可能是系統(tǒng)環(huán)境引起的或是用戶(hù)錯(cuò)誤地操作(如錯(cuò)誤地移動(dòng)/刪除文件等)引起的等。 因此,程序員有責(zé)任編寫(xiě)出可以捕捉錯(cuò)誤的程序并盡可能地處理這些錯(cuò)誤。要捕捉程序中發(fā)生的錯(cuò)誤使用 ON ERROR 命令。你可以在 ON ERROR 命令后跟隨一個(gè)錯(cuò)誤處理程序的名字:ON ERROR DO ERRORHANDLER,或者在 ON ERROR 命令后跟隨一條賦值語(yǔ)句:ON ERROR glError = .T.。 注意,在程序中全程使用類(lèi)似于ON ERROR glError = .T.的命令是極不負(fù)責(zé)任的和令人憎惡的,這有可能會(huì)使用程序陷入死循環(huán)而使用用戶(hù)不得不強(qiáng)行退出系統(tǒng)(強(qiáng)行關(guān)斷電源等),這樣做極有可能破壞用戶(hù)的數(shù)據(jù)文件。 ON ESCAPE 命令 指定在程序或命令運(yùn)行過(guò)程中,按下 ESC 鍵時(shí)所執(zhí)行的命令。 語(yǔ)法為:ON ESCAPE [Command] ON SHUTDOWN 命令 指定當(dāng)試圖退出 Visual FoxPro 時(shí)所要執(zhí)行的命令。 語(yǔ)法為:ON SHUTDOWN [Command] 第七節(jié) 一些重要的設(shè)置 以下是幾乎每一個(gè)應(yīng)用程序都要進(jìn)行的設(shè)置: _VFP 系統(tǒng)變量 指向當(dāng)前運(yùn)行的Visual FoxPro應(yīng)用程序?qū)ο蟆? 語(yǔ)法 參數(shù)描述 eValue 指定屬性的值。Method指定應(yīng)用程序?qū)ο蟮姆椒ā? 說(shuō)明 通過(guò)_VFP,您可以訪(fǎng)問(wèn)對(duì)象集合(Objects collection)。 可設(shè)置的屬性有:
SET SAFETY 決定改寫(xiě)已有文件之前是否顯示對(duì)話(huà)框,或者決定當(dāng)用表設(shè)計(jì)器或用 ALTER TABLE 命令對(duì)表結(jié)構(gòu)進(jìn)行修改后,是否重新計(jì)算表或字段規(guī)則、默認(rèn)值以及錯(cuò)誤信息。 語(yǔ)法為:SET SAFETY ON | OFF SET PROCEDURE TO 設(shè)置運(yùn)行時(shí)的命令文件 SET CLASSLIB TO 設(shè)置運(yùn)行時(shí)的類(lèi)庫(kù)文件 SET MEMOWIDTH TO 指定備注字段和字符表達(dá)式的顯示寬度。 語(yǔ)法為:SET MEMOWIDTH TO nColumns SET MULTILOCKS ON 決定能否使用 LOCK ()或 RLOCK () 鎖定多個(gè)記錄。 語(yǔ)法為:SET MULTILOCKS ON | OFF 若要在程序中使用表緩存必須設(shè)置SET MULTILOCKS 為 ON。 SET HELP TO 激活或廢止 Visual FoxPro 聯(lián)機(jī)幫助或指定的幫助文件。 語(yǔ)法為 SET HELP ON | OFF - 或者 - SET HELP TO [FileName] SET DELETED 指定 Visual FoxPro 是否處理標(biāo)有刪除標(biāo)記的記錄,以及其他命令是否可以操作它們。 語(yǔ)法為:SET DELETED ON | OFF SET EXCLUSIVE 指定 Visual FoxPro 在網(wǎng)絡(luò)上以獨(dú)占方式還是共享方式打開(kāi)表文件。 語(yǔ)法為:SET EXCLUSIVE ON | OFF SET NOTIFY 確定是否顯示某種系統(tǒng)信息。 語(yǔ)法為:SET NOTIFY ON | OFF SET BELL 關(guān)掉或打開(kāi)計(jì)算機(jī)鈴聲,并設(shè)置鈴聲屬性。 語(yǔ)法為: SET BELL ON | OFF - 或者 - SET BELL TO [nFrequency, nDuration | cWAVFileName, nDuration] SET NEAR FIND 或 SEEK 查找記錄不成功時(shí),確定記錄指針停留的位置。 語(yǔ)法為:SET NEAR ON | OFF SET EXACT 指定比較不同長(zhǎng)度兩個(gè)字符串時(shí),Visual FoxPro 使用的規(guī)則。 語(yǔ)法為:SET EXACT ON | OFF SET CONFIRM 指定是否可以用在文本框中鍵入最后一個(gè)字符的方法退出文本框。 SET ESCAPE 決定是否可以通過(guò)按 ESC 鍵中斷程序和命令的運(yùn)行。 語(yǔ)法為:SET ESCAPE ON | OFF SET DATE 設(shè)置日期格式 語(yǔ)法為:SET DATE [TO] AMERICAN | ANSI | BRITISH | FRENCH | GERMAN | ITALIAN | JAPAN | USA | MDY | DMY | YMD SET CENTURY 設(shè)置是否在日期的年中顯示世紀(jì)值 語(yǔ)法為:SET CENTURY ON | OFF ON SHUTDOWN DO 指定當(dāng)試圖退出 Visual FoxPro 時(shí)所要執(zhí)行的命令。 語(yǔ)法為:ON SHUTDOWN [Command] 第八節(jié) 進(jìn)一步訂制VFP的向?qū)Ш蜕善?/strong> 作為最好的數(shù)據(jù)庫(kù)管理系統(tǒng),VFP 給我們提供了高度的可自定義的交互式的開(kāi)發(fā)環(huán)境(interactive development environment IDE)。你可以修改菜單,安裝新的生成器和向?qū)?,?shí)現(xiàn)開(kāi)發(fā)工具條,修改項(xiàng)目管理器的行為,以及很多其它事來(lái)使你的IDE 更高效。這些定制甚至比我們所知道的和喜歡的VFP語(yǔ)言更好,連相對(duì)不熟煉的VFP 開(kāi)發(fā)者都可以按他們自己的方法定制開(kāi)發(fā)環(huán)境。 本節(jié)將配合實(shí)際程序示例,向你展示如何建立簡(jiǎn)單的工具增加你和你的開(kāi)發(fā)組的效率。我們將著眼于修改VFP 的向?qū)Ш蜕善鱽?lái)提供額外的或自定義功能,并使用VFP 6中的BuilderD 技術(shù)創(chuàng)建你自己的生成器。 修改VFP 的向?qū)Ш蜕善?/strong> 如果你象我一樣,你可能不常用VFP 的生成器和向?qū)?,因?yàn)樗鼈儾煌耆軡M(mǎn)足你的需要??赡芩鼈儾痪邆渥銐虻撵`活性或可能你只是不喜歡他們的工作方式。直到VFP 6以前,沒(méi)有辦法改變生成器和向?qū)У男袨?,因?yàn)镸icrosoft 沒(méi)有提供源代碼。但是,現(xiàn)在我們不但獲得了生成器和向?qū)У脑创a,也獲得了類(lèi)瀏覽器,組件管理器的源代碼。 生成器和向?qū)У脑创a可以在VFP主目錄下的TOOLS\XSOURCE目錄中的XSOURCE.ZIP 文件中找到。當(dāng)你解壓該文件時(shí),它建立一個(gè)VFPSOURCE 目錄,其中包含了所有的源代碼。向?qū)У脑创a 可以在WIZARDS 目錄下找到,生成器的在BUILDERS目錄下 (雖然一些WIZARDS目錄中的公共文件也被生成器使用)。 因此,現(xiàn)在我們有了源代碼,我們可個(gè)按我們的需要來(lái)修改生成器和向?qū)?,?duì)嗎? 好了,一個(gè)較好的辦法是建立新的生成器和向?qū)r(shí),使用源代碼中的大多數(shù)類(lèi)和程序,但以派生子類(lèi)并復(fù)制和修改PRGs 或建立封裝PRGs的方法來(lái)忽略他們?cè)械男袨椤1疚膶⒃敿?xì)說(shuō)明如何對(duì)各生成器和向?qū)н@樣做。 一但你建立了你自己的生成器和向?qū)В鯓痈嬖VVFP 使用你的而不是原來(lái)的嗎? 生成器是注冊(cè)在BUILDER.DBF 且向?qū)窃赪IZARD.DBF中,兩個(gè)表都在VFP主目錄下的WIZARDS 子目錄中。這些表具有相同的結(jié)構(gòu),如下表所示。
表 1. BUILDER.DBF 和 WIZARD.DBF的結(jié)構(gòu) 當(dāng)你調(diào)用一個(gè)生成器時(shí),VFP 調(diào)用_BUILDER 系統(tǒng)變量中指定的程序 (默認(rèn)是BUILDER.APP)。BUILDER.APP 查看它所在的環(huán)境 (例如,生成器是被那一個(gè)對(duì)象調(diào)用),在BUILDER.DBF 表中查找與環(huán)境匹配的記錄 (例如,在TYPE 字段中查找對(duì)象的基類(lèi)),并調(diào)用注冊(cè)后的生成器。除系統(tǒng)變量_WIZARD外,向?qū)б彩且韵嗤姆椒ㄌ幚?,_WIZARD是用于指向可在WIZARD.DBF找到的WIZARD.APP。 要告訴VFP 使用一個(gè)不同的生成器或向?qū)?,插入一條說(shuō)明如何運(yùn)行你的生成器或向?qū)У男掠涗浀紹UILDER.DBF或 WIZARD.DBF表中。如果你想在運(yùn)行新的向?qū)Щ蛏善鞯耐瑫r(shí)也可以選擇運(yùn)行原有的生成器或向?qū)?,在WIZARD.DBF表中保留原有的生成器或向?qū)в涗洝H绻阆胩鎿Q原有的,簡(jiǎn)單的修改它的TYPE值為另外的值(我使用一個(gè)"X"前綴,如 "XGRID"),而不是刪除該記錄; 使用該方法,你可以簡(jiǎn)單的以恢復(fù)TYPE 的值來(lái)恢復(fù)使用原來(lái)的生成器或向?qū)А?我們將考查創(chuàng)建一個(gè)Grid 生成器的替代物,參照完整性生成器,Upsizing 向?qū)?,和WWW 搜索頁(yè)向?qū)А? 創(chuàng)建更有用的Grid 生成器 VFP Grid 生成器提供了一種快速方法來(lái)整合grid 的列并建立你所希望的視覺(jué)外觀。但是,關(guān)于該生成器,有我所不喜歡的一些東西:
要建立一個(gè)VFP Grid 生成器的替代物,首先建立了SFGRIDBLDR 項(xiàng)目(它在你解壓該文檔所附的示例程序時(shí)建立的GRID 子目錄中) 并添加以下文件: BUILDER.VCX (在VFP 向?qū)г茨夸浿械腂UILDERS\BUILDERS 子目錄中),GRIDBLDR.VCX (在 BUILDERS\GRIDBLDR 目錄中),THERM.VCX,WIZCTRL.VCX,WIZMOVER.VCX (所有都在WIZARDS\WZCOMMON目錄中),DUMMY.PRG,和 WBGRID.PRG (在BUILDERS目錄中)。我如何知道要添加那些文件到項(xiàng)目中呢? 這很簡(jiǎn)單:只需要查看GRIDBLDR 項(xiàng)目的內(nèi)容。 其次,派生GridBuilder 類(lèi)到SFGridBuilder (在 SFGRIDBLDR.VCX類(lèi)庫(kù)中) 并復(fù)蓋ResetColumns 方法,該方法用于調(diào)整選定列的寬度到適當(dāng)?shù)拇笮?(我只實(shí)現(xiàn)了該想法,未實(shí)現(xiàn)上述列表中的其它兩個(gè))。該方法的代碼在下面列出。這里要注意兩個(gè)有趣的東西。首先,我希望寫(xiě)很多復(fù)雜的代碼,根據(jù)字段寬度、字體和字號(hào)來(lái)計(jì)算出列的寬度,等等。有趣的是,它放棄了生成器中已存在的任務(wù)的方法 (SetColWidth),而只是傳遞字段寬度到該方法中,生成器傳給它一個(gè)不同的值。其它事情是分配到loColumn。Width 的計(jì)算寬度被注釋了。理由是我還沒(méi)有調(diào)試好,改變列寬后,當(dāng)生成器關(guān)閉時(shí),會(huì)造成問(wèn)題,所以我把列寬設(shè)置為,列寬是保存在wbaCols中。(如果你需要,wbaCols 是一個(gè)公共數(shù)組。我沒(méi)有創(chuàng)建生成器,因此不要責(zé)怪我采用這種方式) 因此,效果是當(dāng)一個(gè)字段添加網(wǎng)格中時(shí),它沒(méi)有立即獲得適當(dāng)?shù)牧袑?,但是一但你?zhí)行了一些其它操作 (添加另一個(gè)字段,轉(zhuǎn)到生成器的另一個(gè)頁(yè)面中,關(guān)閉生成器等等。)它就會(huì)取得適當(dāng)?shù)牧袑挕?
最后我為我的生成器建立了GRIDMAIN.PRG (使用了BUILDERS\GRIDBLDR 中的GRIDMAIN.PRG 的辦法) 并使它成為項(xiàng)目的主文件。該程序用SET CLASSLIB命令添加SFGRIDBLDR.VCX 到打開(kāi)的類(lèi)庫(kù)中,這樣它可以找到我們的SFGridBuilder 類(lèi)。GRIDMAIN 也自動(dòng)注冊(cè)它自己到VFP BUILDER 表中(如果是直接運(yùn)行該APP 文件)。 要查看該生成器的行為,建立并運(yùn)行SFGRIDBLDR.APP 來(lái)作為grids生成器注冊(cè)它。如果你在運(yùn)行該APP后,觀察觀查BUILDER.DBF,你會(huì)發(fā)現(xiàn)它是"未注冊(cè)的" ,原始的grid 生成器的 TYPE 字段由"GRID" 改成了"XGRID" 并在它后面為它自己添加了一條TYPE 字段為"GRID"的新記錄。下一步,新建一個(gè)表單,拖動(dòng)grid 到表單中,并調(diào)用生成器。新的生成器看起來(lái)與原來(lái)的沒(méi)有任何區(qū)別,但是當(dāng)你添加字段到表格時(shí),你會(huì)發(fā)現(xiàn)字段寬度自動(dòng)調(diào)整到了適當(dāng)大小。 創(chuàng)建一個(gè)更好的參照完整性生成器 我有一小點(diǎn)關(guān)于VFP自身的參照完整性(RI)生成器的問(wèn)題:
修正這些項(xiàng)相對(duì)容易些,因?yàn)槲覀冇蠷I 生成器的源代碼。我建立了SFRIBUILDR.APP,一個(gè) VFP RIBUILDR.APP的替換物。我沒(méi)有實(shí)現(xiàn)附加的規(guī)則 (上面提及的最后一項(xiàng)) 但是我處理了其它的所有項(xiàng)。我首先建立了SFRIBUILDR 項(xiàng)目(它在解壓后的程序的主目錄下的RI 目錄中) 并添加了VFP的RIBUILDR.VCX(在VFP向?qū)г闯绦蛩谀夸浵碌腂UILDERS\RIBUILDR 目錄中)。 接著,我派生VFP RI生成器類(lèi)到 SFRIBUILDR.VCX 類(lèi)庫(kù)中的SFRIBuildr。我忽視(overrode)了Load 方法以便在數(shù)據(jù)庫(kù)中有被刪除的記錄時(shí)不會(huì)發(fā)生錯(cuò)誤 (你可以參見(jiàn)我注釋的已存在的代碼)。我忽視了確認(rèn)按鈕的Click 方法,以便不出現(xiàn)確認(rèn)對(duì)話(huà)框和不復(fù)制當(dāng)前的儲(chǔ)存過(guò)程到RISP.OLD中,并修復(fù)了生成的代碼中的錯(cuò)誤。同時(shí),如果它檢查到NEWRI.PRG 存在于你的系統(tǒng)中 (與SFRIBUILR.APP在同一目錄),它會(huì)把該代碼放入數(shù)據(jù)庫(kù)的儲(chǔ)存代碼中而不會(huì)生成其它代碼。這個(gè)修改需要一個(gè)新的方法 RIMakeNewTr用一個(gè)不同的名字建立觸發(fā)器(__RI_Handler) 而不是原來(lái)的RI 生成器的生成的(__RI_<action>_<table>,如__RI_Delete_Customer)。因?yàn)檫@些方法中有大量的代碼,在這里就不寫(xiě)出來(lái)了; 但是,如果你查看提供的源代碼,你會(huì)看見(jiàn)我確實(shí)只注釋了很少的代碼行,并添加了很少的代碼。 最后,我從BUILDERS\RIBUILDR目錄中復(fù)制RIMAIN.PRG 到我的生成器所在的目錄,添加它到項(xiàng)目中,并使它面為主程序。我修改了該程序所指向的類(lèi)庫(kù),使它能找到我的VFP RI 生成器類(lèi)的子類(lèi)所在的類(lèi)庫(kù) (SFRIBUILDR.VCX) 并自動(dòng)注冊(cè)該生成器到VFP BUILDER 表中(如果是直接運(yùn)行該APP)。 生成并運(yùn)行SFRIBUILDR.APP 導(dǎo)致該文件作為RI生成器注冊(cè)取代了通常的RIBUILDR.APP。要看這一點(diǎn),按以下步驟進(jìn)行:
創(chuàng)建一個(gè)更好的升遷(Upsizing) 向?qū)? Jim Falino 在使用升遷向?qū)r(shí)失敗了,因此他創(chuàng)建了一個(gè)具有他所希望的行為的版本。
Jim 的修改是讓用戶(hù)指定他們的要求; 你可以使用它們?nèi)绻愕男枰c之相同,或?qū)⑺麄冏鳛槟0迨褂靡员隳阕约盒薷摹? 創(chuàng)建一個(gè)更好用的WWW 搜索頁(yè)向?qū)? 在 "Visual FoxPro 6 企業(yè)開(kāi)發(fā)" (Prima Tech,ISBN 0-7615-1381-7)一書(shū)中,Rod Paddock 和 John Petersen 描述了如何修改WWW 搜索頁(yè)向?qū)?lái)取消只能輸出5個(gè)字段到一個(gè)網(wǎng)頁(yè)的局限。勝于修改向?qū)?,你?huì)希望派生它們。要這樣做,用我派生生成器類(lèi)的相似的方法。WWW 搜索頁(yè)向?qū)У拇a在VFP 向?qū)г茨夸浵碌腤IZARDS\WZINTNET 目錄中。 第九節(jié) 創(chuàng)建你自己的向?qū)? Rod Paddock 和John Petersen 也在他們的書(shū)中也提供了一些使用VFP 向?qū)ь?lèi)來(lái)建立你自己的向?qū)У募?xì)節(jié)。這樣做的優(yōu)點(diǎn)是,有人已經(jīng)建立了所有的"引擎"來(lái)管理向?qū)幚?,且你的向?qū)⑴c其它的VFP向?qū)Ь哂邢嗤母杏^。 用BuilderD 創(chuàng)建生成器 在查看VFP6中的FoxPro基本類(lèi)時(shí)(FFC),我注意到一件事是它們都具有叫做Builder和BuilderX的自定義屬性,并且各個(gè)類(lèi)的BuilderX 是設(shè)置為= HOME() + "Wizards\BuilderD,BuilderDForm"。我知道這些屬性的作用(他們告訴VFP,這個(gè)類(lèi)的生成器名),但為什么每一個(gè)類(lèi)都要指定相同的生成器呢?更有趣的是,各個(gè)類(lèi)以不同的選項(xiàng)調(diào)用類(lèi)似的生成器表單(圖1顯示_HyperLinkLabel 類(lèi)的生成器)。當(dāng)使用相同的類(lèi)時(shí)將會(huì)發(fā)生什么情況呢?
首先介紹一點(diǎn)背境。可能正象你可能意識(shí)到的,VFP 生成器可能以多種方式調(diào)用,但最常見(jiàn)的是可能是在對(duì)象上右擊鼠標(biāo)并從出現(xiàn)的菜單上選擇生成器。這會(huì)使BUILDER.APP 被執(zhí)行。BUILDER.APP 檢查是否選定的對(duì)象(我們稱(chēng)為"目標(biāo)對(duì)象") 具有 BuilderX 屬性,如果有,運(yùn)行該屬性指定的程序或?qū)嵗撛搶傩灾付ǖ念?lèi)(如果生成器是一個(gè)類(lèi),將指定一個(gè)類(lèi)庫(kù),逗號(hào)及類(lèi)名)。如果它沒(méi)有 BuilderX 屬性但有一個(gè) Builder 屬性,生成器運(yùn)行該屬性指定的程序或?qū)嵗撛搶傩灾付ǖ念?lèi)(我們將看到為什么會(huì)同時(shí)用兩個(gè)屬性指定生成器)。如果兩個(gè)屬性都不存在,將使用該對(duì)象基類(lèi)的默認(rèn)生成器。 你可以在你的類(lèi)中建立自定義的 Builder 和 BuilderX 屬性(甚至在你的基類(lèi)中) 然后為每一個(gè)類(lèi)填寫(xiě)適當(dāng)?shù)纳善髅?。要使用兩個(gè)屬性的理由是 BuilderX 為該類(lèi)指定一個(gè)自定義生成器 而B(niǎo)uilder為一組公共的類(lèi)(如comboboxe 或 grid)指定一個(gè)所需的生成器。正如我們稍后會(huì)看到的一樣,我們可以在 BuilderX 屬性中指定的生成器中,單擊一個(gè)按鈕來(lái)調(diào)出在 Builder 屬性中指定的生成器。 因此,我們可以很容易地在 Builder 和 BuilderX 屬性中指定生成器。而不是花很多時(shí)間來(lái)建立你自己的生成器,特別對(duì)于不常使用的類(lèi)。 BuilderD 你可能意識(shí)到了 BuilderB 技術(shù) 用來(lái)建立生成器是容易的和快速的。BuilderB 是一組你可以派生來(lái)建立你自己的生成器的類(lèi)。你可以為你想用生成器維護(hù)的目標(biāo)對(duì)象的各屬性添加一個(gè)控件到生成器子類(lèi)。雖然BuilderB 使得建立生成器更容易,但你必須為每一個(gè)你想用生成器管理的類(lèi)建立一個(gè)新的生成器子類(lèi)。對(duì)于我們這樣的懶人來(lái)說(shuō),幸運(yùn)的是,Ken 以數(shù)據(jù)驅(qū)動(dòng)的方式增強(qiáng)了BuilderB。這種新技術(shù)叫做BuilderD ,"D" 的意思是"動(dòng)態(tài)" (Dynamic),可以在Ken 的網(wǎng)站(www.classx.com)找到,也包含在VFP 6 中(在VFP 主目錄下的WIZARDS 目錄中的BUILDERD.VCX)。 BuilderD 由一系列的類(lèi)組成,但主要的一個(gè)是BuilderDForm; 這是一個(gè)數(shù)據(jù)驅(qū)動(dòng)生成器表單 (注意這是VFP6.0的基本類(lèi)中指定的BuilderX類(lèi))。正如你在圖2中看到,該表單中的文本框用于輸入目標(biāo)類(lèi)的名字和類(lèi)名,按鈕提供的功能可以調(diào)出類(lèi)瀏覽器和顯示幫助,一個(gè)頁(yè)框、兩個(gè)頁(yè)面,但沒(méi)有用于管理屬性值的控件。
以下是該表單在實(shí)例化時(shí),如何組合適當(dāng)?shù)目丶?
這些步驟的結(jié)果是,一個(gè)生成器可以管理目標(biāo)對(duì)象的一個(gè)或更多的屬性。一個(gè)指定的生成器可以事實(shí)上做得比這些還要多,例如放置代碼到目標(biāo)對(duì)象的方法或?qū)ο蟮娜萜髦?,介是目前我們只使用最?jiǎn)單的方法。 BuilderD 表 讓我們進(jìn)一步了解生成器定義表BUILDERD.DBF,因?yàn)槔斫馑慕Y(jié)構(gòu)是建立你自己的生成器的關(guān)鍵。表2 顯示了BUILDERD.DBF表的結(jié)構(gòu); 在該表中,"property control" 意思是生成器中的、維護(hù)一個(gè)目標(biāo)對(duì)象的指定屬性的控件。
表 1. BUILDERD.DBF的結(jié)構(gòu) 表2 和 3 顯示了兩個(gè)生成器的記錄,VFP6.0的基本類(lèi)_HyperLinkBase 和_HyperLinkLabel 類(lèi)。我沒(méi)有顯示BUILDERD.DBF 表中的所有字段,出于空間的考慮; 僅列出與討論有關(guān)的字段。
表 2. _HyperLinkBase 和 _HyperLinkLabel 類(lèi)的生成器記錄
表 3. _HyperLinkBase 和 _HyperLinkLabel 生成器管理的屬性定義記錄 在表2 中的 _HyperLinkBase記錄中,我們看見(jiàn)CLASSNAME 和 CLASSLIB 指定了該生成器使用的類(lèi)(注意CLASSLIB 包含了一個(gè)在運(yùn)行時(shí)求值的表達(dá)式而不是一個(gè)硬編碼值),在LINKS 中列了出該生成器可管理的類(lèi)的屬性。顯示在表3中的cTarget PROPERTY 記錄指明該屬性將被BuilderComboBox 控件管理,且該BuilderComboBox的RowSource 包含一個(gè) Microsoft VFP 網(wǎng)站的URL (目前是msdn.microsoft.com/vfoxpro)。cFrame 將被 BuilderTextBox 對(duì)象管理(因?yàn)樗且粋€(gè)字符串屬性且該類(lèi)沒(méi)有定義),lNewWindow 將有一個(gè)BuilderCheckBox 對(duì)象(因?yàn)樗且粋€(gè)邏輯屬性)。 看起來(lái)是如此簡(jiǎn)單,對(duì)吧? 好了,LINKS 字段事實(shí)上可以更加復(fù)雜。首先,假如在LINKS字段中指定的類(lèi)記錄的ID 沒(méi)有匹配記錄,該ID 就被假設(shè)為屬性名。 這樣,你可以簡(jiǎn)單的在CLASS記錄的LINKS字段中指定它管理的屬性來(lái)實(shí)際建立一個(gè)生成器。當(dāng)然,你必須保持屬性的 captions 和屬性的名字相同,沒(méi)有狀態(tài)條文本、默認(rèn)的類(lèi)和屬性大小,但這些對(duì)于一個(gè)快速的和dirty 生成器來(lái)說(shuō)都不算太壞。 第二個(gè)復(fù)雜之處是,CLASS記錄的LINKS字段中指定的ID 可以指向另一個(gè)CLASS 記錄而不是一個(gè)PROPERTY 記錄。在這種情況下,該類(lèi) "繼承"所有指定類(lèi)的連接。你可以在表2中的_HyperLinkLabel 記錄中看到這一點(diǎn); 它的一個(gè)連接是_HyperLinkBase,因此它不僅用該類(lèi)的生成器來(lái)管理Caption 屬性(specifically 在它的 LINKS 字段中列出),同時(shí)也管理cTarget、cFrame和lNewWindow 屬性,因?yàn)檫@些在_HyperLinkBase 的LINKS 字段中指定。 第三,PROPERTY 記錄可以連接到另一個(gè)PROPERTY 記錄。在這種情況下,記錄"繼承"連接記錄的所有非空字段。最后,如果你用@<caption> 格式指定它,LINKS 可以包含生成器中的頁(yè)框的標(biāo)題 (例如,@Properties 使用"Properties" 作為頁(yè)的標(biāo)題)。 創(chuàng)建一個(gè)生成器 讓我們?cè)赥EST.VCX類(lèi)庫(kù)中創(chuàng)建一個(gè)名為T(mén)estCheck的 VFP CheckBox 的子類(lèi)作為開(kāi)始。在該類(lèi)中添加一個(gè)叫做BuilderX 的自定義屬性并設(shè)置它的值為= HOME() + "Wizards\BuilderD,BuilderDForm"。然后在該類(lèi)上右擊鼠標(biāo)并從快捷菜單中選擇生成器。我們得到一條"沒(méi)有注冊(cè)該類(lèi)型的生成器"的錯(cuò)誤。這也說(shuō)得通,因?yàn)槲覀冞€沒(méi)有定義它 (盡管這令人不愉快,在稍后它將自動(dòng)為我們建立一個(gè))。按以下步驟做:
酷不酷,嗯? 完全是你自己的生成器,僅在一分鐘左右就建立了! 去掉Enabled 的選擇并輸入一個(gè)不同的Caption,并可看到這些屬性已被修改。 注意不要被為屬性建立記錄所迷惑; Enabled 和 Caption 記錄已存在于 BUILDERD.DBF表中,因此我們只需重用它們,而且由于不存在 AutoSize 記錄,BuilderD 只假設(shè)我們想管理那個(gè)屬性。 讓我們?cè)俳⒁粋€(gè)并看看以多小的輸入可以得到一個(gè)可工作的生成器。在TEST.VCX類(lèi)庫(kù)中創(chuàng)建一個(gè)名為T(mén)estText的 VFP TextBox 的子類(lèi),向它添加一個(gè)屬性 BuilderX 并設(shè)置它的值為 = HOME() + "Wizards\BuilderD,BuilderDForm"。在BUILDERD.DBF 中添加一條記錄并只指定 TYPE ("CLASS"),ID ("TestText"),LINKS ("ReadOnly")和 CLASSNAME ("TestText";我們可以跳過(guò) CLASSLIB 但 CLASSNAME 是必須的)。關(guān)閉該表,然后調(diào)出該類(lèi)的生成器。 這也是一個(gè)可以工作的生成器。單擊生成器中的生成器按鈕; 它調(diào)出另一個(gè)生成器(如果Builder屬性存在并非空,在Builder屬性中指定的生成器,否則就是該類(lèi)的基類(lèi)的默認(rèn)生成器,在此例中是 VFP TextBox 生成器)。這樣,即使我們可以為一個(gè)類(lèi)指定生成器,只要愿意,我們?nèi)匀豢梢栽L(fǎng)問(wèn)更多的普通生成器。 預(yù)置-內(nèi)建的生成器 我最近用BuilderD 建立了兩個(gè)生成器,一個(gè)為我的SFGrid 類(lèi)另一個(gè)為SFPageFrame。SFGrid 生成器維護(hù)DeleteMark 和RecordMark 屬性(你可以很容易地添加其它你可能經(jīng)常修改的屬性) 但由于它們?nèi)菀自趯傩源翱谥行薷?,所以這不是我要建立該生成器的真正的理由。真正的理由是因?yàn)槲蚁矚g使用grid 的columns 中的SFGridTextBox 對(duì)象(SFTextBox 的一個(gè)子類(lèi),具有一小部分不同的屬性設(shè)置,以提供它們?cè)?grid中出現(xiàn)的外觀),并盡量用SFGridTextBox對(duì)象替換一般的TextBox 對(duì)象。 因此我建立了一個(gè)按鈕(SFBUILDERS.VCX類(lèi)庫(kù)中的SFGridTextBoxButton類(lèi)) 來(lái)自動(dòng)進(jìn)行該工作。以下是該按鈕的 Click 方法代碼:
BuilderDForm 有一個(gè)引用到目標(biāo)對(duì)象保存在它的 oObject 屬性,因此生成器表單上的許多控件可以引用或修改目標(biāo)對(duì)象的東西。在這些代碼中,Thisform.oObject.Columns 引用grid 的Columns 集合被生成器影響。 這里有一個(gè)副作用:我怎樣才能在我的生成器表單中得到該按鈕? 我可以為我的生成器在BUILDERD表中建立一個(gè)記錄,但那會(huì)添加按鈕到頁(yè)框中的一個(gè)頁(yè)上,而我確希望該按鈕象其它的生成器按鈕一樣出現(xiàn)。 因此我建立了一個(gè) "button loader" 類(lèi) (SFBUILDERS.VCX類(lèi)庫(kù)中的SFBuilderButtonLoader類(lèi)),該類(lèi)添加一個(gè)按鈕到生成器表單然后返回 .F. 這樣,它實(shí)際上沒(méi)有實(shí)例化。SFBuilderButtonLoader 在BUILDERD表的當(dāng)前記錄的備注字段 USER 中查找(使用類(lèi)實(shí)例化的記錄) 要添加到表單的按鈕的類(lèi)名和類(lèi)庫(kù)(注意下面代碼中的 BUILDERD 是以 "BUILDER"別名打開(kāi)的)。對(duì)于SFGridTextBoxButton,例如,我在BUILDERD表中建立一條記錄,以 "SFGridTextBoxButton" 作為它的 ID 但 "SFBuilderButtonLoader" 是一個(gè)類(lèi),并在USER字段中輸入 "SFBuilders, SFGridTextBoxButton"。這告訴 SFBuilderButtonLoader 添加一個(gè) SFGridTextBoxButton 到表單中。以下是SFBuilderButtonLoader的 Init 方法代碼:
在BUILDERD表中 SFGrid 記錄的LINKS字段中有 DeleteMark、RecordMark 和 SFGridTextBox,因此該生成器獲得這些控件。 現(xiàn)在我可以為我的SFGrid對(duì)象調(diào)出我的BuilderD 生成器,使用 VFP Grid 生成器(單擊BuilderD表單上的生成器按鈕) 來(lái)快速建立 grid中的列,然后單擊我的添加SFGridTextBox按鈕來(lái)讓這些列使用 SFGridTextBox 對(duì)象。 對(duì)于 SFPageFrame,我也希望相似的功能:一個(gè)添加代碼到頁(yè)框中各頁(yè)的RightClick方法的按鈕; 這允許在頁(yè)面上右擊鼠標(biāo)明時(shí)為頁(yè)框或整個(gè)表單提供快捷菜單。象SFGrid 生成器一樣,我在BuilderD表中建立了一個(gè)記錄來(lái)實(shí)例化一個(gè) SFBuilderButtonLoader 對(duì)象,然后添加一個(gè) SFCodePageButton 對(duì)象到生成器表單。以下是添加代碼到各頁(yè)的SFCodePageButton的Click方法:
要添加這些新的生成器到你的系統(tǒng)中,復(fù)制 SFBUILDERS.VCX 和 VCT (在本文檔的源代碼文件中可以找到) 到一個(gè)目錄,然后打開(kāi)示例文件提供的NEWBUILDERS 表,并修改 CLASSLIB 字段到包含路徑的 SFBUILDERS.VCX文件名。打開(kāi) BUILDERD 表,然后 APPEND FROM NEWBUILDERS 表,添加Builder 和BuilderX 屬性到你的類(lèi)中,并在BuilderX中輸入 = HOME() + "Wizards\BuilderD,BuilderDForm"。 其它生成器類(lèi) 我早些時(shí)候注意到,SFBUILDERS.VCX 中的BuilderCheckBox 和 BuilderTextBox 類(lèi)都是派生自同一個(gè)BuilderD 類(lèi)。在附加的右擊鼠標(biāo)行為中,這兩個(gè)類(lèi)具有nTop 和 nLeft 屬性,當(dāng)這些屬性改變時(shí),用assign 方法設(shè)置它們的自定義的lMoved 屬性為.T.。這允許我們查覺(jué)到什么時(shí)候一個(gè)屬性控件被移動(dòng)了(在屬性控件生成器中的Left 和Top 是綁定至 nLeft 和 nTop 而不是直接綁定到 Left 和 Top)。只有當(dāng)一個(gè)屬性控件移動(dòng)時(shí),我們保存它的its Left 和 Top 值到 BUILDERD 表。 SFBUILDERS.VCX 中的加一個(gè)類(lèi)是 SFPropertyCaption。該控件用于管理屬性控件的 caption。 為什么用一個(gè)特別的類(lèi)來(lái)做這件事? 為什么不用一個(gè)普通的BuilderTextBox 對(duì)象? 理由是如果屬性控件是一個(gè)BuilderCheckBox,它有一個(gè) Caption 屬性,因此控件管理該屬性。但是,如果屬性控件是一個(gè) BuilderTextBox,它沒(méi)有 Caption 屬性但確有一個(gè)組合的 label 對(duì)象,因此控件必須管理對(duì)象的對(duì)象的 Caption 屬性。由于 BuilderD 類(lèi)只管理單個(gè)對(duì)象的屬性,SFPropertyCaption 不得不超越(override)少量方法來(lái)允許它處理這種情況。 SFBuilderPropertyComboBox 類(lèi)是BuilderComboBox的一個(gè)子類(lèi)。它提供一個(gè)目標(biāo)對(duì)象的所有可寫(xiě)屬性的一個(gè)列表(用 AMEMBERS() 得到所有屬性的列表然后檢查各自的PEMSTATUS()來(lái)排除只讀的)。雖然它的主要目的是修改屬性控件的 cProperty 屬性(用于檢查要管理的屬性),它有兩個(gè)有趣的行為。 首先,如果屬性控件是一個(gè)BuilderTextBox 但你只修改了它管理的邏輯屬性(如 Enabled),它移去BuilderTextBox 及組合的label 對(duì)象,并放一個(gè) BuilderCheckBox 在這個(gè)地方。如果你改變了一個(gè)邏輯屬性為另一個(gè)類(lèi)型它會(huì)做相反的事。 第二,如果你輸入了一個(gè)不存在的屬性名,你會(huì)被提示建立該屬性。如果你同意,生成器使用AddProperty 來(lái)添加新屬性到目標(biāo)對(duì)象。我的確不推薦在一個(gè)拖放到表單中的對(duì)象上這樣做,因?yàn)檫@等于實(shí)例化編程; 如果你真的需要一個(gè)新屬性,你可以考慮用子類(lèi)來(lái)代替。 總之,這是一個(gè)經(jīng)一個(gè)步驟在類(lèi)中建立新屬性并用生成器管理它的快速方法。 SFBuilderAddButton 是一個(gè)為了屬性控件使用 SFBuilderButtonLoader 類(lèi)而添加到生成器表單的按鈕類(lèi) (派生自BuilderCommandButton)。SFBuilderAddButton 的Click方簡(jiǎn)單地調(diào)用屬性控件所在的生成器表單的 AddPropertyControl 方法來(lái)建立一個(gè)新的屬性控件,然后轉(zhuǎn)換當(dāng)前生成器表單來(lái)管理新屬性控件。 這意味著你可以單擊添加屬性按鈕添加一個(gè)新屬性到生成器,并在生成器中管理它。這是一種添加多個(gè)屬性控件的快速方法。 試一試 讓我們看一看SFBuilderBuilderForm; 它實(shí)際上比對(duì)它的描述更易于使用。在TEST.VCX中建立一個(gè)叫做 MyTestText 的VFP TextBox 類(lèi)的子類(lèi)。添加一個(gè) BuilderX 屬性并設(shè)置它的值為 "SFBuilders,SFBuilderBuilderForm",然后調(diào)出該類(lèi)的生成器。 注意盡管我們沒(méi)有在BUILDERD 表中建立任何記錄,我們?nèi)匀坏玫搅艘粋€(gè)生成器表單(當(dāng)然,表單上沒(méi)有控件,但我們馬上會(huì)改變這一切)。 這是因?yàn)?SFBuilderBuilderForm 在不能找到該類(lèi)的記錄時(shí),自動(dòng)地為該類(lèi)在BUILDERD表中建立了一個(gè) CLASS 記錄。 單擊添加屬性控件按鈕。你會(huì)注意到一個(gè)文本框和標(biāo)簽出現(xiàn)在生成器表單上,但隨后另一個(gè)生成器表單出現(xiàn)在該生成器表單的面上。這個(gè)新的表單是我們剛添加的屬性控件的生成器。在屬性 combobox中,選擇 "Tooltiptext" 并修改 Caption 為 "Tool Tip Text" 和 Width 到250。移動(dòng)該生成器表單在一旁并注意原表單上的屬性控件也同樣修改了。 單擊第二個(gè)生成器表單上的添加另一屬性按鈕并注意另一個(gè)屬性控件已添加到原生成器表單中,并且該生成器表單現(xiàn)在可以管理它了。為屬性選擇"Statusbartext" 并修改Caption 為"Status Bar Text" 和Width 到250。添加另一個(gè)屬性控件,并為該屬性選擇 "Readonly" 并修改Caption 到"Read-Only"; 這時(shí),注意原生成器屬性控制改變了checkbox。關(guān)閉新的生成器表單。圖3 顯示了我們建立的生成器,圖4 顯示了屬性控件生成器。
要修改控件的屬性,在控件上右擊鼠標(biāo)并從快捷菜單中選擇修改屬性修改控件; 你以前看到過(guò)的相同的屬性控件生成器會(huì)出現(xiàn)。要移去屬性控件,從菜單中選擇移去屬性控件。要重置目標(biāo)對(duì)象的該屬性的值為默認(rèn)值,選擇重置為默認(rèn)值。 讓我們修改生成器表單的標(biāo)題為更為合適的東西。單擊修改生成器標(biāo)題按鈕并在隨后出現(xiàn)的SFBuilderBuilder生成器表單中輸入 "我的測(cè)試文本框類(lèi)生成器" 。關(guān)閉第二個(gè)生成器。 如果你在關(guān)閉生成器時(shí)沒(méi)有保存,下一次你再調(diào)用 MyTestText 對(duì)象的生成器時(shí),你的設(shè)置不會(huì)起作用。若要保存生成器的定義到 BUILDERD 表中,單擊保存生成器按鈕。如果你想導(dǎo)出生成器定義到另一個(gè)表中,單擊導(dǎo)出生成器按鈕并在出現(xiàn)的對(duì)話(huà)框中輸入文件名。然后你可以發(fā)送該表給一些人,他們可以將其導(dǎo)入他們的 BUILDERD 表并訪(fǎng)問(wèn)你建立的生成器。 說(shuō)明 因?yàn)閂FP的開(kāi)放式IDE,任何人都可以很容易地定制它們的開(kāi)發(fā)環(huán)境,因此他們和他們的開(kāi)發(fā)組可以極大地提高編程效率。 第十節(jié) 示例 例1:在程序開(kāi)始時(shí)設(shè)置系統(tǒng)環(huán)境 *-- 設(shè)置工作目錄 cCurrentProcedure = SYS(16,1) nPathStart = AT(":",cCurrentProcedure) - 1 nLenOfPath = RAT("\", cCurrentProcedure,2) - (nPathStart) SET DEFAULT TO (SUBSTR(cCurrentProcedure, nPathStart, nLenOfPath)) SET PATH TO PROGS,LIBS,MENUS,HELP,INCLUDE,FORMS,BITMAPS *-- 修改程序標(biāo)題并將屏幕放到最大,在編譯成.EXE的文件運(yùn)行時(shí),這是必須的 MODIFY WINDOW SCREEN TITLE "測(cè)試" NOCLOSE ZOOM WINDOW SCREEN MAX *-- 屏蔽系統(tǒng)菜單 SET SYSMENU OFF *--定義用于保存系統(tǒng)設(shè)置的全局變量 PUBLIC ; GcOldTalk,; gcOldPath,; gcOldDir,; gcOldClassLib,; gcOldEscape,; gcOldSafety,; gcOldProc,; gcOldStatus,; gnOldMemo,; gcOldMultiLocks,; gcOldHelp,; gcOldDeleted,; gcOldExclusive,; gcOldNotify,; gcOldBell,; gcOldNear,; gcOldExact,; gcOldIntensity,; gcOldConfirm,; gcOldOnShutDown,; gcOldCompatible *--保存原始的系統(tǒng)狀態(tài),以便在退出時(shí)恢復(fù) GcOldTalk = SET("TALK") gcOldPath = SET("PATH") gcOldDir = FULLPATH(CURDIR()) gcOldClassLib = SET("CLASSLIB") gcOldEscape = SET("ESCAPE") gcOldSafety = SET('SAFETY') gcOldProc = SET('PROCEDURE') gcOldStatus = SET('STATUS BAR') gnOldMemo = SET('MEMOWIDTH') gcOldMultiLocks = SET('MULTILOCKS') gcOldHelp = SET('HELP', 1) gcOldDeleted = SET('DELETED') gcOldExclusive = SET('EXCLUSIVE') gcOldNotify = SET('NOTIFY') gcOldBell = SET('BELL') gcOldNear = SET('NEAR') gcOldExact = SET('EXACT') gcOldIntensity = SET('INTENSITY') gcOldConfirm = SET('CONFIRM') gcOldOnShutDown = ON('SHUTDOWN') gcOldCompatible = SET("COMPATIBLE") gcOldDate = SET("DATE") gcOldCentury = SET("CENTURY") *-- 設(shè)置SET 和ON 命令 SET SAFETY OFF SET PROCEDURE TO UTILITY.PRG SET CLASSLIB TO MAIN SET MEMOWIDTH TO 120 SET MULTILOCKS ON SET HELP TO HELP\MAIN.CHM SET DELETED ON SET EXCLUSIVE OFF SET NOTIFY OFF SET BELL OFF SET NEAR OFF SET EXACT OFF SET INTENSITY OFF SET CONFIRM ON SET COMPATIBLE OFF SET DATE ANSI SET CENTURY ON SET ESCAPE OFF ON SHUTDOWN DO OnShutDown 注意:運(yùn)行上述代碼時(shí)程序文件UTILITY.PRG,OnShutDown,類(lèi)庫(kù)文件MAIN及幫助文件MAIN.CHM必須存在。 例2:在程序結(jié)束時(shí)恢復(fù)系統(tǒng)環(huán)境 LOCAL luTemp SET PATH TO (gcOldPath) luTemp = gcOldClassLib SET CLASSLIB TO &luTemp luTemp = gcOldProc SET PROCEDURE TO &luTemp SET MEMOWIDTH TO gnOldMemo luTemp = gcOldMultiLocks SET MULTILOCKS &luTemp luTemp = gcOldSafety SET SAFETY &luTemp luTemp = gcOldStatus SET STATUS BAR &luTemp CD (gcOldDir) luTemp = gcOldDeleted SET DELETED &luTemp luTemp = gcOldExclusive SET EXCLUSIVE &luTemp IF FILE(gcOldHelp) SET HELP TO (gcOldHelp) ENDIF luTemp = gcOldNotify SET NOTIFY &luTemp luTemp = gcOldBell SET BELL &luTemp luTemp = gcOldNear SET NEAR &luTemp luTemp = gcOldExact SET EXACT &luTemp luTemp = gcOldIntensity SET INTENSITY &luTemp luTemp = gcOldConfirm SET CONFIRM &luTemp luTemp = gcOldOnShutdown ON SHUTDOWN &luTemp luTemp = gcOldEscape SET ESCAPE &luTemp luTemp = gcOldCompatible SET COMPATIBLE &luTemp luTemp = gcOldTalk SET TALK &luTemp luTemp = gcOldDate SET DATE &luTemp luTemp = gcOldCentury SET CENTURY &luTemp CLOSE ALL CLEAR DLLS RELEASE ALL EXTENDED CLEAR ALL 例3:程序崩潰時(shí)恢復(fù)系統(tǒng)環(huán)境 在程序設(shè)計(jì)期間,有時(shí)會(huì)因程序錯(cuò)誤而使系統(tǒng)崩潰。當(dāng)系統(tǒng)崩潰時(shí),可能會(huì)有打開(kāi)的表沒(méi)有關(guān)閉,數(shù)據(jù)工作期不能釋放,表單在屏幕上不能清除,菜單沒(méi)有釋放等一系列令人心煩的事。當(dāng)你要手工地恢復(fù)系統(tǒng)到初使?fàn)顟B(tài)真還要費(fèi)不少事,但是你可以自己編寫(xiě)一個(gè)過(guò)程文件來(lái)自動(dòng)完成這些工作。這樣,當(dāng)系統(tǒng)崩潰時(shí),你只需在命令窗口打入 DO XXX 即可。 *:****************************************************************************** *: *: 過(guò)程文件C:\HIGHMIS\HF.PRG *: *:****************************************************************************** ON ERROR SET PROCEDURE TO POP KEY ALL SET COLOR TO SET SYSMENU TO DEFA CLOSE ALL RELEAS ALL EXTE CLEAR DLLS CLEAR EVENTS CLEAR FIELDS CLEAR GETS CLEAR MACROS CLEAR MEMORY CLEAR MENUS CLEAR POPUPS CLEAR PROGRAM CLEAR PROMPT CLEAR READ ALL CLEAR TYPEAHEAD CLEAR WINDOWS SET DEVICE TO SCREEN CLEAR SET EXCL ON SET TALK ON SET MESSAGE ON RELEASE WINDOW 常用 SET HELP TO SET HELP ON CANCEL 例4:查看系統(tǒng)設(shè)置 *:****************************************************************************** *: *: 過(guò)程文件C:\HIGHMIS\PROGS\SYSTEST.PRG *: * 用途:查看當(dāng)前系統(tǒng)信息 ************************************************************************** PROCEDURE SYSTEST PARAMETERS T__Method, T__File RELEASE ALL EXCEPT T__* PRIVATE ALL LIKE T__* CREATE VIEW it SET TALK OFF CLOSE ALL SET SAFETY OFF SET ALTERNATE TO (IIF(EMPTY(T__File), "SysTest.TXT", T__File)) SET ALTERNATE ON SET SAFETY ON SET EXACT OFF T__IsVisual = .T. T__OutputFile = SET("ALTERNATE", 1) DEFINE WINDOW T__win FROM 0,0 TO SROWS(),SCOLS() TITLE T__OutputFile CLOSE SYSTEM ZOOM ACTIVATE WINDOW T__win ??"*** SysTest Version 2.00","日期",DATE(),"時(shí)間",TIME(),"***" T__IsError = .F. IF (EMPTY(m.T__Method) OR UPPER(m.T__Method)="SET") WAIT WINDOW NOWAIT "*** SET() ***" ? ? "*** SET() ***" ?PADR("SET(ALTERNATE)",30) + " == ", SET("ALTERNATE") ?PADR("SET(ANSI)",30) + " == ", SET("ANSI") ?PADR("SET(AUTOSAVE)",30) + " == ", SET("AUTOSAVE") ?PADR("SET(BELL)",30) + " == ", SET("BELL") ?PADR("SET(BLINK)",30) + " == ", SET("BLINK") ?PADR("SET(BLOCKSIZE)",30) + " == ", SET("BLOCKSIZE") ?PADR("SET(BRSTATUS)",30) + " == ", SET("BRSTATUS") ?PADR("SET(CARRY)",30) + " == ", SET("CARRY") ?PADR("SET(CENTURY)",30) + " == ", SET("CENTURY") ?PADR("SET(CLASSLIB)",30) + " == ", SET("CLASSLIB") ?PADR("SET(CLEAR)",30) + " == ", SET("CLEAR") ?PADR("SET(CLOCK)",30) + " == ", SET("CLOCK") ?PADR("SET(COLOR)",30) + " == ", SET("COLOR") ?PADR("SET(COMPATIBLE)",30) + " == ", SET("COMPATIBLE") ?PADR("SET(CONFIRM)",30) + " == ", SET("CONFIRM") ?PADR("SET(CONSOLE)",30) + " == ", SET("CONSOLE") ?PADR("SET(CURRENCY)",30) + " == ", SET("CURRENCY") ?PADR("SET(CURSOR)",30) + " == ", SET("CURSOR") ?PADR("SET(DATE)",30) + " == ", SET("DATE") ?PADR("SET(DEBUG)",30) + " == ", SET("DEBUG") ?PADR("SET(DECIMALS)",30) + " == ", SET("DECIMALS") ?PADR("SET(DEFAULT)",30) + " == ", SET("DEFAULT") ?PADR("SET(DELETED)",30) + " == ", SET("DELETED") ?PADR("SET(DELIMITERS)",30) + " == ", SET("DELIMITERS") ?PADR("SET(DEVELOPMENT)",30) + " == ", SET("DEVELOPMENT") ?PADR("SET(DEVICE)",30) + " == ", SET("DEVICE") ?PADR("SET(DISPLAY)",30) + " == ", SET("DISPLAY") ?PADR("SET(DOHISTORY)",30) + " == ", SET("DOHISTORY") ?PADR("SET(ECHO)",30) + " == ", SET("ECHO") ?PADR("SET(ESCAPE)",30) + " == ", SET("ESCAPE") ?PADR("SET(EXACT)",30) + " == ", SET("EXACT") ?PADR("SET(EXCLUSIVE)",30) + " == ", SET("EXCLUSIVE") ?PADR("SET(FIELDS)",30) + " == ", SET("FIELDS") ?PADR("SET(FILTER)",30) + " == ", SET("FILTER") ?PADR("SET(FIXED)",30) + " == ", SET("FIXED") ?PADR("SET(FULLPATH)",30) + " == ", SET("FULLPATH") ?PADR("SET(HEADING)",30) + " == ", SET("HEADING") ?PADR("SET(HELP)",30) + " == ", SET("HELP") ?PADR("SET(HISTORY)",30) + " == ", SET("HISTORY") ?PADR("SET(HOURS)",30) + " == ", SET("HOURS") ?PADR("SET(INTENSITY)",30) + " == ", SET("INTENSITY") ?PADR("SET(KEYCOMP)",30) + " == ", SET("KEYCOMP") ?PADR("SET(LIBRARY)",30) + " == ", SET("LIBRARY") ?PADR("SET(LOCK)",30) + " == ", SET("LOCK") ?PADR("SET(LOGERRORS)",30) + " == ", SET("LOGERRORS") ?PADR("SET(MACKEY)",30) + " == ", SET("MACKEY") ?PADR("SET(MARGIN)",30) + " == ", SET("MARGIN") ?PADR("SET(MARK)",30) + " == ", SET("MARK") ?PADR("SET(MEMOWIDTH)",30) + " == ", SET("MEMOWIDTH") ?PADR("SET(MENU)",30) + " == ", SET("MENU") ?PADR("SET(MESSAGE)",30) + " == ", SET("MESSAGE") ?PADR("SET(MOUSE)",30) + " == ", SET("MOUSE") ?PADR("SET(MULTILOCKS)",30) + " == ", SET("MULTILOCKS") ?PADR("SET(NEAR)",30) + " == ", SET("NEAR") ?PADR("SET(NOTIFY)",30) + " == ", SET("NOTIFY") ?PADR("SET(ODOMETER)",30) + " == ", SET("ODOMETER") ?PADR("SET(OPTIMIZE)",30) + " == ", SET("OPTIMIZE") ?PADR("SET(ORDER)",30) + " == ", SET("ORDER") ?PADR("SET(PALETTE)",30) + " == ", SET("PALETTE") ?PADR("SET(PATH)",30) + " == ", SET("PATH") ?PADR("SET(PDSETUP)",30) + " == ", SET("PDSETUP") ?PADR("SET(POINT)",30) + " == ", SET("POINT") ?PADR("SET(PRINTER)",30) + " == ", SET("PRINTER") ?PADR("SET(PROCEDURE)",30) + " == ", SET("PROCEDURE") ?PADR("SET(REFRESH)",30) + " == ", SET("REFRESH") ?PADR("SET(REPROCESS)",30) + " == ", SET("REPROCESS") ?PADR("SET(RESOURCE)",30) + " == ", SET("RESOURCE") ?PADR("SET(SAFETY)",30) + " == ", SET("SAFETY") ?PADR("SET(SCOREBOARD)",30) + " == ", SET("SCOREBOARD") ?PADR("SET(SEPARATOR)",30) + " == ", SET("SEPARATOR") ?PADR("SET(SHADOWS)",30) + " == ", SET("SHADOWS") ?PADR("SET(SPACE)",30) + " == ", SET("SPACE") ?PADR("SET(STATUS)",30) + " == ", SET("STATUS") ?PADR("SET(STATUS BAR)",30) + " == ", SET("STATUS BAR") ?PADR("SET(STEP)",30) + " == ", SET("STEP") ?PADR("SET(STICKY)",30) + " == ", SET("STICKY") ?PADR("SET(SYSMENU)",30) + " == ", SET("SYSMENU") ?PADR("SET(TALK)",30) + " == ", SET("TALK") ?PADR("SET(TEXTMERGE)",30) + " == ", SET("TEXTMERGE") ?PADR("SET(TOPIC)",30) + " == ", SET("TOPIC") ?PADR("SET(TYPEAHEAD)",30) + " == ", SET("TYPEAHEAD") ?PADR("SET(UDFPARMS)",30) + " == ", SET("UDFPARMS") ?PADR("SET(UNIQUE)",30) + " == ", SET("UNIQUE") ?PADR("SET(ALTERNATE,1)",30) + " == ", SET("ALTERNATE",1) ?PADR("SET(CLOCK,1)",30) + " == ", SET("CLOCK",1) ?PADR("SET(CURRENCY,1)",30) + " == ", SET("CURRENCY",1) ?PADR("SET(DELIMITERS,1)",30) + " == ", SET("DELIMITERS",1) ?PADR("SET(FIELDS,1)",30) + " == ", SET("FIELDS",1) ?PADR("SET(HELP,1)",30) + " == ", SET("HELP",1) ?PADR("SET(MESSAGE,1)",30) + " == ", SET("MESSAGE",1) ?PADR("SET(PRINTER,1)",30) + " == ", SET("PRINTER",1) ?PADR("SET(RESOURCE,1)",30) + " == ", SET("RESOURCE",1) ?PADR("SET(TALK,1)",30) + " == ", SET("TALK",1) ?PADR("SET(TEXTMERGE,1)",30) + " == ", SET("TEXTMERGE",1) ENDIF T__IsError = .F. IF (EMPTY(m.T__Method) OR UPPER(m.T__Method)="ON") WAIT WINDOW NOWAIT "*** ON() ***" ? ? "*** ON() ***" ?PADR("ON(ERROR)",30) + " == ", ON("ERROR") ?PADR("ON(ESCAPE)",30) + " == ", ON("ESCAPE") ?PADR("ON(KEY)",30) + " == ", ON("KEY") ?PADR("ON(KEY LABEL)",30) + " == ", ON("KEY LABEL") ?PADR("ON(PAGE)",30) + " == ", ON("PAGE") ?PADR("ON(READERROR)",30) + " == ", ON("READERROR") ?PADR("ON(SHUTDOWN)",30) + " == ", ON("SHUTDOWN") ENDIF T__IsError = .F. IF (EMPTY(m.T__Method) OR UPPER(m.T__Method)="MIS") WAIT WINDOW NOWAIT "其他設(shè)置" ? ? "其他設(shè)置" ?PADR("CAPSLOCK()",30) + " == ", EVALUATE("CAPSLOCK()") ?PADR("CPCURRENT()",30) + " == ", EVALUATE("CPCURRENT()") ?PADR("CPCURRENT(1)",30) + " == ", EVALUATE("CPCURRENT(1)") ?PADR("CPCURRENT(2)",30) + " == ", EVALUATE("CPCURRENT(2)") ?PADR("DISKSPACE()",30) + " == ", EVALUATE("DISKSPACE()") ?PADR("FULLPATH('')",30) + " == ", EVALUATE("FULLPATH('')") ?PADR("GETENV('COMSPEC')",30) + " == ", EVALUATE("GETENV('COMSPEC')") ?PADR("GETENV('FOXPROCFG')",30) + " == ", EVALUATE("GETENV('FOXPROCFG')") ?PADR("GETENV('FOXPROSWX')",30) + " == ", EVALUATE("GETENV('FOXPROSWX')") ?PADR("GETENV('FOXPROX')",30) + " == ", EVALUATE("GETENV('FOXPROX')") ?PADR("GETENV('PATH')",30) + " == ", EVALUATE("GETENV('PATH')") ?PADR("GETENV('TEMP')",30) + " == ", EVALUATE("GETENV('TEMP')") ?PADR("INSMODE()",30) + " == ", EVALUATE("INSMODE()") ?PADR("ISCOLOR()",30) + " == ", EVALUATE("ISCOLOR()") ?PADR("MEMORY()",30) + " == ", EVALUATE("MEMORY()") ?PADR("NUMLOCK()",30) + " == ", EVALUATE("NUMLOCK()") ?PADR("OS()",30) + " == ", EVALUATE("OS()") ?PADR("OS(1)",30) + " == ", EVALUATE("OS(1)") ?PADR("PRINTSTATUS()",30) + " == ", EVALUATE("PRINTSTATUS()") ?PADR("VERSION(1)",30) + " == ", EVALUATE("VERSION(1)") ?PADR("VERSION(2)",30) + " == ", EVALUATE("VERSION(2)") ?PADR("VERSION(3)",30) + " == ", EVALUATE("VERSION(3)") ENDIF T__IsError = .F. IF (EMPTY(m.T__Method) OR UPPER(m.T__Method)="VAR") WAIT WINDOW NOWAIT "系統(tǒng)內(nèi)存變量" ? ? "系統(tǒng)內(nèi)存變量" ?PADR("_ASCIICOLS",30) + " == ", EVALUATE("_ASCIICOLS") ?PADR("_ASCIIROWS",30) + " == ", EVALUATE("_ASCIIROWS") ?PADR("_BROWSER",30) + " == ", EVALUATE("_BROWSER") ?PADR("_BUILDER",30) + " == ", EVALUATE("_BUILDER") ?PADR("_CONVERTER",30) + " == ", EVALUATE("_CONVERTER") ?PADR("_DBLCLICK",30) + " == ", EVALUATE("_DBLCLICK") ?PADR("_GENGRAPH",30) + " == ", EVALUATE("_GENGRAPH") ?PADR("_GENMENU",30) + " == ", EVALUATE("_GENMENU") ?PADR("_GENPD",30) + " == ", EVALUATE("_GENPD") ?PADR("_GENSCRN",30) + " == ", EVALUATE("_GENSCRN") ?PADR("_GENXTAB",30) + " == ", EVALUATE("_GENXTAB") ?PADR("_PDRIVER",30) + " == ", EVALUATE("_PDRIVER") ?PADR("_PDSETUP",30) + " == ", EVALUATE("_PDSETUP") ?PADR("_SHELL",30) + " == ", EVALUATE("_SHELL") ?PADR("_SPELLCHK",30) + " == ", EVALUATE("_SPELLCHK") ?PADR("_STARTUP",30) + " == ", EVALUATE("_STARTUP") ?PADR("_TRANSPORT",30) + " == ", EVALUATE("_TRANSPORT") ?PADR("_WIZARD",30) + " == ", EVALUATE("_WIZARD") ENDIF T__IsError = .F. IF (EMPTY(m.T__Method) OR UPPER(m.T__Method)="FONT") WAIT WINDOW NOWAIT "可用字體" ? ? "可用字體" =AFONT(T__fonts) FOR T__i = 1 TO ALEN(T__fonts) T__string = T__fonts[m.T__i] + ": " IF AFONT(T__sizes, T__fonts[m.T__i]) FOR T__j = 1 TO ALEN(T__sizes) T__string = m.T__string+IIF(m.T__j==1, "", ", ")+; IIF(T__sizes[m.T__j]==-1,"scalable", LTRIM(STR(T__sizes[m.T__j]))) ENDFOR ENDIF ? m.T__string ENDFOR RELEASE T__i, T__j, T__fonts, T__sizes, T__string ENDIF T__IsError = .F. IF (EMPTY(m.T__Method) OR UPPER(m.T__Method)="CONFIG") FOR T__i = 1 TO 3 DO CASE CASE m.T__i==1 T__File = SYS(2019) IF EMPTY(m.T__File) T__File = SYS(2004)+"CONFIG.FPW" ENDIF CASE m.T__i==2 T__File = "C:\CONFIG.SYS" CASE m.T__i==3 T__File = "C:\AUTOEXEC.BAT" ENDCASE WAIT WINDOW NOWAIT "配置文件" ? DO CASE CASE m.T__i==1 T__File = SYS(2019) IF EMPTY(m.T__File) T__File = SYS(2004)+"CONFIG.FPW" ? "*** " + "配置文件" + SYS(2004) + " CONFIG.FPW ***" ELSE ? "*** " + "配置文件" + SYS(2019) + " CONFIG.FPW ***" ENDIF CASE m.T__i==2 T__File = "C:\CONFIG.SYS" ? "*** " + "配置文件" + "C:\CONFIG.SYS ***" CASE m.T__i==3 T__File = "C:\AUTOEXEC.BAT" ? "*** " + "配置文件" + "C:\AUTOEXEC.BAT ***" ENDCASE IF FILE(m.T__File) T__handle = FOPEN(m.T__File) IF m.T__handle>-1 DO WHILE NOT FEOF(m.T__handle) ? FGETS(m.T__handle) ENDDO =FCLOSE(m.T__handle) ELSE ? "不能打開(kāi)文件." ENDIF ELSE ? "不能找到文件." ENDIF ENDFOR RELEASE T__File, T__handle, T__i ENDIF SET CONSOLE OFF ? "完成" SET CONSOLE ON CLOSE ALL T__handle = FOPEN(T__OutputFile, 2) IF NOT m.T__handle==-1 =FSEEK(m.T__handle, -1, 2) IF FREAD(m.T__handle,1)==CHR(26) =FCHSIZE(m.T__handle, FSEEK(m.T__handle, -1, 2)) ENDIF =FCLOSE(m.T__handle) ENDIF ACTIVATE SCREEN SET TALK OFF SET MESSAGE TO "檢查完成,結(jié)果已寫(xiě)至" + T__OutputFile WAIT CLEAR ZOOM WINDOW T__win MAX MODIFY COMMAND (T__OutputFile) NOEDIT WINDOW T__win NOMENU RELEASE WINDOW T__win SET VIEW TO it.vue DELETE FILE it.vue SET MESSAGE TO " " RETURN
包含了有關(guān) Visual FoxPro 中聲音、程序設(shè)計(jì)、數(shù)據(jù)輸入的選項(xiàng)以及其它選項(xiàng)。
包含控制表中數(shù)據(jù)的選項(xiàng)。
遠(yuǎn)程數(shù)據(jù) 包含了有關(guān)遠(yuǎn)程 (ODBC) 視圖和連接默認(rèn)值的選項(xiàng)。
文件位置 包含了 Visual FoxPro 使用文件的目錄位置和名字。可以直接在每個(gè)框中鍵入路徑和文件名,也可以單擊對(duì)話(huà)框按鈕激活對(duì)話(huà)框設(shè)置相應(yīng)的選項(xiàng)。
表單 包含“表單設(shè)計(jì)器”的選項(xiàng)。
項(xiàng)目 包含了有關(guān)“項(xiàng)目管理器”的選項(xiàng)。
控件 包含了為指定“選項(xiàng)”對(duì)話(huà)框中“表單”選項(xiàng)卡上的模板類(lèi)而登記可視類(lèi)庫(kù)的選項(xiàng)。這些選項(xiàng)也指定“表單控件”工具欄上“查看類(lèi)”按鈕中可以選擇的內(nèi)容,這可以簡(jiǎn)化向表單中添加用戶(hù)自定義控件的工作。
區(qū)域
調(diào)試 通過(guò)設(shè)置選項(xiàng)來(lái)定制 Visual FoxPro 調(diào)試器窗口。
語(yǔ)法著色 包含的選項(xiàng)可以指定顏色及字體,用來(lái)區(qū)分 Visual FoxPro 的程序元素,比如關(guān)鍵字和注釋。這些程序元素在命令窗口或所有編輯窗口(除用 MODIFY FILE 或 MODIFY MEMO 命令打開(kāi)的編輯窗口之外)中使用。
字段映象
|
|