| 本章說明 本章共分十一節(jié)。闡述了與VFP工作環(huán)境有關的細節(jié)問題,其中一至七節(jié)為一般描述適用于一般使用者,第八、九兩節(jié)適用于中、高級開發(fā)者,第十節(jié)是四個具體的實例,可用于任何應用程序,第十一節(jié)是"選項"對話框的說明性表格,是手冊性質的資料。 第一節(jié) 概述 工作環(huán)境規(guī)定了 VFP 工作時的某些行為。配置工作環(huán)境意味著您可以通過某些方法使 VFP 的行為滿足自己的需要 - 必須的或者是某些個人偏好的。 與任何完善的開發(fā)工具一樣,VFP 也是一個復雜的系統(tǒng),復雜的一個方面就表現(xiàn)在它具有極大的靈活性 - 同一種工作,由于"環(huán)境"的不同,可能會產生不同的效果。 工作環(huán)境是個整體的概念,我們使用"環(huán)境參數"一詞來描述構成工作環(huán)境的個體。那么就可以說,工作環(huán)境就是由一組環(huán)境參數來決定的,配置工作環(huán)境就是設置這組環(huán)境參數,以滿足不同的需求。這顯然有兩方面的任務,第一、您要知道有那些環(huán)境參數,第二、明確怎樣配置這些參數。 工作環(huán)境涉及到很多方面,例如輸入輸出、數據處理、開發(fā)、調試等等??梢酝ㄟ^分類對所有環(huán)境參數進行描述。所有的環(huán)境參數都有一個原始的默認值,一般的環(huán)境配置工作,事實上只需要修改少量的環(huán)境參數即可。 有一個問題需要明確,"VFP 的工作環(huán)境"是指 Visual FoxPro 工具的開發(fā)環(huán)境。另外一種情況,使用 VFP 開發(fā)的應用程序,在編譯成執(zhí)行文件后,工作在 VFP 運行時的工作環(huán)境下。這兩者是有區(qū)別的,顯而易見的區(qū)別是,運行時環(huán)境涉及的問題比開發(fā)環(huán)境少得多,例如開發(fā)、調試方面的問題。一般來講,運行時的環(huán)境是開發(fā)環(huán)境的一個子集,但嚴格說來這是不對的,二者仍存在一些差別,不僅在環(huán)境參數的類別與數量方面,也存在于配置方法上。本文的敘述主要針對開發(fā)環(huán)境而進行,對二者存在的差別也將被提及。 [dvnews_page=VFP 高級教程:VFP 開發(fā)技巧] 第二節(jié) 默認的工作環(huán)境 VFP 安裝完成后,其"內部"保存著對所有環(huán)境參數的設置,這些參數可以稱做是原始設置。您永遠也不能夠去修改這些原始設置。但 VFP 提供一種機制允許您每次啟動時用自己的設置去覆蓋這組原始設置。方法是是使用 Windows 注冊表及配置文件。 啟動時,VFP 首先會檢查 Windows 注冊表中的有關設置,然后據此修改環(huán)境參數。然后還會查找一個配置文件,該文件默認的名字為 config.fpw,其中也存放著一些環(huán)境配置信息。VFP 將讀取這些信息,并再次修改環(huán)境參數。如果 VFP 在Windows 注冊表中沒有找到配置信息或者沒有找到配置文件,這沒有關系,VFP 將以原始配置進行工作。您甚至可以主動讓 VFP 在啟動時放棄讀取注冊表及配置文件。 VFP 不會主動把環(huán)境參數寫進 Windows 注冊表中,但它提供了一種方法使您方面地將環(huán)境參數寫進注冊表,寫入不僅針對修改過的參數,而是所有參數,您沒有去修改的參數值將以原始值寫入。配置文件則不同,它只保存您寫入的參數,某種意義上,它相當是一份注冊表中的環(huán)境參數表的勘誤。 保存在 Windows 注冊表中的環(huán)境參數以及配置文件中的設置稱做"默認工作環(huán)境" 第三節(jié) 配置文件 先讀取注冊表再查找配置文件的方法似乎有點復雜,但有些時候需要這樣做,例如工作在運行時環(huán)境的應用程序,啟動時不去讀取注冊表,這使得配置文件成為必須。另外,配置文件創(chuàng)建于 FoxPro 的早期版本,兼容性使它必須被保留。VFP6 以前的版本在安裝時將自動建立一個這樣的文件(在安裝目錄下),而到了 VFP6,系統(tǒng)不再自動建立該文件,需要時由用戶自行建立。該文件是一個文本文件,可以使用任何文本編輯器來建立它。 VFP 啟動時將按照下列路徑查找該文件: 當前工作目錄 安裝 Visual FoxPro 的目錄 DOS 路徑中列出的目錄 配置文件有默認的名字(config.fpw),"默認"意味著你可以去改變它。這有利于您同時擁有多個配置文件,以便滿足不同的需要。指定另外不同于config.fpw名字的配置文件的方法是在啟動 VFP 時增加命令行開關項,例如 VFP6.EXE -Cc:\myprg\myconfig.fpw 配置文件中不僅僅存放環(huán)境配置信息,例如可以在配置文件中設置 VFP 啟動后立即去執(zhí)行一個程序文件。這使得您可以在配置環(huán)境方面使用一種技巧,即將環(huán)境設置命令保存在一個程序文件中,然后讓 VFP 啟動時去執(zhí)行它。 啟動過程也可以通過使用命令行參數來定制,通過定制啟動過程,可以得到不同的環(huán)境默認設置,以下是對環(huán)境配置有影響的一些情況: 
 
 [dvnews_page=VFP 高級教程:VFP 開發(fā)技巧] 
 第四節(jié) 更改默認設置 VFP 啟動完成后,工作環(huán)境被設置成默認狀態(tài)。您可以即時地更改環(huán)境參數,這有幾種方法,各種方法可能適合于不同的情況。 交互式修改 在命令窗口輸入環(huán)境設置命令,執(zhí)行后該修改會立即生效。絕大部分的環(huán)境參數是通過 SET 命令設置的,另外還有一些通過系統(tǒng)變量存儲以及極少數的函數設置。在早期的XBASE 工具中,例如dBASEII中,僅有 20 幾條 SET 命令,而今天,VFP 中已經有 120 多個 SET 命令了。交互式的修改方法是枯燥的,因此只用于臨時性的修改,例如調試等。 程序化執(zhí)行修改 可以將一組環(huán)境設置命令組織成一個程序文件,運行該程序,就相當于在命令窗口一一輸入執(zhí)行了這組命令,有些情況下是需要這樣做的,例如在開發(fā)環(huán)境下同時調試多于一個項目的時候??梢詫⒃摥h(huán)境設置程序存為一個過程或直接寫在項目的主文件中。事實上,對于應用程序,因為最終要脫離開發(fā)環(huán)境運行,所以大部分都是這樣做的。 用命令方式讀取Windows 注冊表中的設置 讓 Visual FoxPro 再次讀取自己的注冊表設置,并且使用當前的注冊表設置更新自己。 語法為: SYS(3056 [,1]) 說明:包含1選項可以只根據注冊表設置進行更新,不包括 SET 命令和文件位置。Visual FoxPro 在 Windows 注冊表的選項對話框中保存設置。當Visual FoxPro 啟動時,讀取這些設置,并利用這些設置進行配置。SYS(3056)可更新包含有文件名和路徑的系統(tǒng)變量,而系統(tǒng)變量由SET命令和注冊表設置。當您選擇設置為默認值時,選項對話框指定的設置寫入注冊表。其中一些影響Visual FoxPro環(huán)境的設置含有SET 命令,例如SET BELL,SET LOCK等。注意 SYS(3056)不更新來自Config.fpw(即 Visual FoxPro 配置文件)的設置。 有關環(huán)境設置的命令 有很多環(huán)境設置的命令,在本文的附表中,以"選項"對話框中的分類列出了相應的環(huán)境設置命令,還有一些命令沒有包含在"選項"對話框中,但它們也是關于環(huán)境的設置命令,本文僅將它們列出來,具體的意義及語法可參見隨機文檔。 
 
 
 無論是交互式還是程序化執(zhí)行命令,其修改都是臨時的,只對當前工作有效,VFP 系統(tǒng)關閉后,這種修改不能被保存,下一次運行,如果需要同樣的設置,您不得不再一次輸入該命令或執(zhí)行該程序。要想使修改成為永久,必須將修改保存在 Windows 注冊表中或構建配置文件。 修改注冊表 有兩種方法:直接修改 Windows 注冊表或使用 VFP 開發(fā)環(huán)境提供的"選項卡"對話框。對于直接修改 Windwos 注冊表的方法,沒有人會建議您這樣做,除非您首先對 Windwos 注冊表的結構非常熟悉,其次對 VFP 在 Windows 注冊表中的各種參數的意義比較了解,第三有某些特殊需要以至于不能使用常規(guī)的方法完成。常規(guī)的方法,是使用 VFP 的"選項卡"對話框來完成環(huán)境配置。 直接修改注冊表 VFP 環(huán)境設置信息在 Windows 注冊表的目錄如下: HKEY_CURRENT_USER\Software\Microsoft\VisualFoxPro\6.0\Options 主鍵名稱在本文附表中有詳細介紹。 使用"選項"對話框 使用"選項卡"對話框來進行系統(tǒng)的配置比直接修改 Windows 注冊表的方法至少有兩個好處,第一,很多配置參數在"選項卡"上是以一種"易于理解的方式"表達的,您只需在某些"問題"前打勾或者在很多答案中選擇一個,這就象您填一份表格一樣來得輕松。第二,在"選項卡"上進行的配置,一旦完成后,立即生效,而直接修改 Windows 注冊表的方法卻不是這樣,只能是在下一次運行 VFP 時生效。 在開發(fā)環(huán)境下,執(zhí)行"工具"菜單中的"選項"菜單項,會出現(xiàn)"選項"對話框。對話框上有12個卡頁,分12個方面對環(huán)境進行配置。本文附表中詳細描述了其中的每一項設置。事實上,真正需要修改的并不多,很多項設置,原始值應該能滿足要求?,F(xiàn)在的問題是,當你修改完成后,可有兩種選擇,按"確定"按鈕退出對話框,您的修改只會保存在當前環(huán)境中,隨著系統(tǒng)的關閉而失效;按"設置為默認值"按鈕退出對話框,當前的設置將會被寫進 Windows 注冊表從而成為新的默認值。 第六節(jié) ON命令 ON ERROR 命令 設計得再好的程序,在運行時也不可避免地會發(fā)生錯誤,這些錯誤可能是程序自身的錯誤,也可能是系統(tǒng)環(huán)境引起的或是用戶錯誤地操作(如錯誤地移動/刪除文件等)引起的等。 因此,程序員有責任編寫出可以捕捉錯誤的程序并盡可能地處理這些錯誤。要捕捉程序中發(fā)生的錯誤使用 ON ERROR 命令。你可以在 ON ERROR 命令后跟隨一個錯誤處理程序的名字:ON ERROR DO ERRORHANDLER,或者在 ON ERROR 命令后跟隨一條賦值語句:ON ERROR glError = .T.。 注意,在程序中全程使用類似于ON ERROR glError = .T.的命令是極不負責任的和令人憎惡的,這有可能會使用程序陷入死循環(huán)而使用用戶不得不強行退出系統(tǒng)(強行關斷電源等),這樣做極有可能破壞用戶的數據文件。 ON ESCAPE 命令 指定在程序或命令運行過程中,按下 ESC 鍵時所執(zhí)行的命令。 語法為:ON ESCAPE [Command] ON SHUTDOWN 命令 指定當試圖退出 Visual FoxPro 時所要執(zhí)行的命令。 語法為:ON SHUTDOWN [Command] 第七節(jié) 一些重要的設置 以下是幾乎每一個應用程序都要進行的設置: _VFP 系統(tǒng)變量 指向當前運行的Visual FoxPro應用程序對象。 語法 參數描述 eValue 指定屬性的值。Method指定應用程序對象的方法。 說明 通過_VFP,您可以訪問對象集合(Objects collection)。 可設置的屬性有: 
 
 
 SET SAFETY 決定改寫已有文件之前是否顯示對話框,或者決定當用表設計器或用 ALTER TABLE 命令對表結構進行修改后,是否重新計算表或字段規(guī)則、默認值以及錯誤信息。 語法為:SET SAFETY ON | OFF SET PROCEDURE TO 設置運行時的命令文件 SET CLASSLIB TO 設置運行時的類庫文件 SET MEMOWIDTH TO 指定備注字段和字符表達式的顯示寬度。 語法為:SET MEMOWIDTH TO nColumns SET MULTILOCKS ON 決定能否使用 LOCK ()或 RLOCK () 鎖定多個記錄。 語法為:SET MULTILOCKS ON | OFF 若要在程序中使用表緩存必須設置SET MULTILOCKS 為 ON。 SET HELP TO 激活或廢止 Visual FoxPro 聯(lián)機幫助或指定的幫助文件。 語法為 SET HELP ON | OFF - 或者 - SET HELP TO [FileName] SET DELETED 指定 Visual FoxPro 是否處理標有刪除標記的記錄,以及其他命令是否可以操作它們。 語法為:SET DELETED ON | OFF SET EXCLUSIVE 指定 Visual FoxPro 在網絡上以獨占方式還是共享方式打開表文件。 語法為:SET EXCLUSIVE ON | OFF SET NOTIFY 確定是否顯示某種系統(tǒng)信息。 語法為:SET NOTIFY ON | OFF SET BELL 關掉或打開計算機鈴聲,并設置鈴聲屬性。 語法為: SET BELL ON | OFF - 或者 - SET BELL TO [nFrequency, nDuration | cWAVFileName, nDuration] SET NEAR FIND 或 SEEK 查找記錄不成功時,確定記錄指針停留的位置。 語法為:SET NEAR ON | OFF SET EXACT 指定比較不同長度兩個字符串時,Visual FoxPro 使用的規(guī)則。 語法為:SET EXACT ON | OFF SET CONFIRM 指定是否可以用在文本框中鍵入最后一個字符的方法退出文本框。 SET ESCAPE 決定是否可以通過按 ESC 鍵中斷程序和命令的運行。 語法為:SET ESCAPE ON | OFF SET DATE 設置日期格式 語法為:SET DATE [TO] AMERICAN | ANSI | BRITISH | FRENCH | GERMAN | ITALIAN | JAPAN | USA | MDY | DMY | YMD SET CENTURY 設置是否在日期的年中顯示世紀值 語法為:SET CENTURY ON | OFF ON SHUTDOWN DO 指定當試圖退出 Visual FoxPro 時所要執(zhí)行的命令。 語法為:ON SHUTDOWN [Command] 第八節(jié) 進一步訂制VFP的向導和生成器 作為最好的數據庫管理系統(tǒng),VFP 給我們提供了高度的可自定義的交互式的開發(fā)環(huán)境(interactive development environment IDE)。你可以修改菜單,安裝新的生成器和向導,實現(xiàn)開發(fā)工具條,修改項目管理器的行為,以及很多其它事來使你的IDE 更高效。這些定制甚至比我們所知道的和喜歡的VFP語言更好,連相對不熟煉的VFP 開發(fā)者都可以按他們自己的方法定制開發(fā)環(huán)境。 本節(jié)將配合實際程序示例,向你展示如何建立簡單的工具增加你和你的開發(fā)組的效率。我們將著眼于修改VFP 的向導和生成器來提供額外的或自定義功能,并使用VFP 6中的BuilderD 技術創(chuàng)建你自己的生成器。 修改VFP 的向導和生成器 如果你象我一樣,你可能不常用VFP 的生成器和向導,因為它們不完全能滿足你的需要??赡芩鼈儾痪邆渥銐虻撵`活性或可能你只是不喜歡他們的工作方式。直到VFP 6以前,沒有辦法改變生成器和向導的行為,因為Microsoft 沒有提供源代碼。但是,現(xiàn)在我們不但獲得了生成器和向導的源代碼,也獲得了類瀏覽器,組件管理器的源代碼。 生成器和向導的源代碼可以在VFP主目錄下的TOOLS\XSOURCE目錄中的XSOURCE.ZIP 文件中找到。當你解壓該文件時,它建立一個VFPSOURCE 目錄,其中包含了所有的源代碼。向導的源代碼 可以在WIZARDS 目錄下找到,生成器的在BUILDERS目錄下 (雖然一些WIZARDS目錄中的公共文件也被生成器使用)。 因此,現(xiàn)在我們有了源代碼,我們可個按我們的需要來修改生成器和向導,對嗎? 好了,一個較好的辦法是建立新的生成器和向導時,使用源代碼中的大多數類和程序,但以派生子類并復制和修改PRGs 或建立封裝PRGs的方法來忽略他們原有的行為。本文將詳細說明如何對各生成器和向導這樣做。 一但你建立了你自己的生成器和向導,怎樣告訴VFP 使用你的而不是原來的嗎? 生成器是注冊在BUILDER.DBF 且向導是在WIZARD.DBF中,兩個表都在VFP主目錄下的WIZARDS 子目錄中。這些表具有相同的結構,如下表所示。 
 
 
 
 表 1. BUILDER.DBF 和 WIZARD.DBF的結構 當你調用一個生成器時,VFP 調用_BUILDER 系統(tǒng)變量中指定的程序 (默認是BUILDER.APP)。BUILDER.APP 查看它所在的環(huán)境 (例如,生成器是被那一個對象調用),在BUILDER.DBF 表中查找與環(huán)境匹配的記錄 (例如,在TYPE 字段中查找對象的基類),并調用注冊后的生成器。除系統(tǒng)變量_WIZARD外,向導也是以相同的方法處理,_WIZARD是用于指向可在WIZARD.DBF找到的WIZARD.APP。 要告訴VFP 使用一個不同的生成器或向導,插入一條說明如何運行你的生成器或向導的新記錄到BUILDER.DBF或 WIZARD.DBF表中。如果你想在運行新的向導或生成器的同時也可以選擇運行原有的生成器或向導,在WIZARD.DBF表中保留原有的生成器或向導記錄。如果你想替換原有的,簡單的修改它的TYPE值為另外的值(我使用一個"X"前綴,如 "XGRID"),而不是刪除該記錄; 使用該方法,你可以簡單的以恢復TYPE 的值來恢復使用原來的生成器或向導。 我們將考查創(chuàng)建一個Grid 生成器的替代物,參照完整性生成器,Upsizing 向導,和WWW 搜索頁向導。 創(chuàng)建更有用的Grid 生成器 VFP Grid 生成器提供了一種快速方法來整合grid 的列并建立你所希望的視覺外觀。但是,關于該生成器,有我所不喜歡的一些東西: 
 要建立一個VFP Grid 生成器的替代物,首先建立了SFGRIDBLDR 項目(它在你解壓該文檔所附的示例程序時建立的GRID 子目錄中) 并添加以下文件: BUILDER.VCX (在VFP 向導源目錄中的BUILDERS\BUILDERS 子目錄中),GRIDBLDR.VCX (在 BUILDERS\GRIDBLDR 目錄中),THERM.VCX,WIZCTRL.VCX,WIZMOVER.VCX (所有都在WIZARDS\WZCOMMON目錄中),DUMMY.PRG,和 WBGRID.PRG (在BUILDERS目錄中)。我如何知道要添加那些文件到項目中呢? 這很簡單:只需要查看GRIDBLDR 項目的內容。 其次,派生GridBuilder 類到SFGridBuilder (在 SFGRIDBLDR.VCX類庫中) 并復蓋ResetColumns 方法,該方法用于調整選定列的寬度到適當的大小 (我只實現(xiàn)了該想法,未實現(xiàn)上述列表中的其它兩個)。該方法的代碼在下面列出。這里要注意兩個有趣的東西。首先,我希望寫很多復雜的代碼,根據字段寬度、字體和字號來計算出列的寬度,等等。有趣的是,它放棄了生成器中已存在的任務的方法 (SetColWidth),而只是傳遞字段寬度到該方法中,生成器傳給它一個不同的值。其它事情是分配到loColumn。Width 的計算寬度被注釋了。理由是我還沒有調試好,改變列寬后,當生成器關閉時,會造成問題,所以我把列寬設置為,列寬是保存在wbaCols中。(如果你需要,wbaCols 是一個公共數組。我沒有創(chuàng)建生成器,因此不要責怪我采用這種方式) 因此,效果是當一個字段添加網格中時,它沒有立即獲得適當的列寬,但是一但你執(zhí)行了一些其它操作 (添加另一個字段,轉到生成器的另一個頁面中,關閉生成器等等。)它就會取得適當的列寬。 
 
 
 最后我為我的生成器建立了GRIDMAIN.PRG (使用了BUILDERS\GRIDBLDR 中的GRIDMAIN.PRG 的辦法) 并使它成為項目的主文件。該程序用SET CLASSLIB命令添加SFGRIDBLDR.VCX 到打開的類庫中,這樣它可以找到我們的SFGridBuilder 類。GRIDMAIN 也自動注冊它自己到VFP BUILDER 表中(如果是直接運行該APP 文件)。 要查看該生成器的行為,建立并運行SFGRIDBLDR.APP 來作為grids生成器注冊它。如果你在運行該APP后,觀察觀查BUILDER.DBF,你會發(fā)現(xiàn)它是"未注冊的" ,原始的grid 生成器的 TYPE 字段由"GRID" 改成了"XGRID" 并在它后面為它自己添加了一條TYPE 字段為"GRID"的新記錄。下一步,新建一個表單,拖動grid 到表單中,并調用生成器。新的生成器看起來與原來的沒有任何區(qū)別,但是當你添加字段到表格時,你會發(fā)現(xiàn)字段寬度自動調整到了適當大小。 創(chuàng)建一個更好的參照完整性生成器 我有一小點關于VFP自身的參照完整性(RI)生成器的問題: 
 修正這些項相對容易些,因為我們有RI 生成器的源代碼。我建立了SFRIBUILDR.APP,一個 VFP RIBUILDR.APP的替換物。我沒有實現(xiàn)附加的規(guī)則 (上面提及的最后一項) 但是我處理了其它的所有項。我首先建立了SFRIBUILDR 項目(它在解壓后的程序的主目錄下的RI 目錄中) 并添加了VFP的RIBUILDR.VCX(在VFP向導源程序所在目錄下的BUILDERS\RIBUILDR 目錄中)。 接著,我派生VFP RI生成器類到 SFRIBUILDR.VCX 類庫中的SFRIBuildr。我忽視(overrode)了Load 方法以便在數據庫中有被刪除的記錄時不會發(fā)生錯誤 (你可以參見我注釋的已存在的代碼)。我忽視了確認按鈕的Click 方法,以便不出現(xiàn)確認對話框和不復制當前的儲存過程到RISP.OLD中,并修復了生成的代碼中的錯誤。同時,如果它檢查到NEWRI.PRG 存在于你的系統(tǒng)中 (與SFRIBUILR.APP在同一目錄),它會把該代碼放入數據庫的儲存代碼中而不會生成其它代碼。這個修改需要一個新的方法 RIMakeNewTr用一個不同的名字建立觸發(fā)器(__RI_Handler) 而不是原來的RI 生成器的生成的(__RI_<action>_<table>,如__RI_Delete_Customer)。因為這些方法中有大量的代碼,在這里就不寫出來了; 但是,如果你查看提供的源代碼,你會看見我確實只注釋了很少的代碼行,并添加了很少的代碼。 最后,我從BUILDERS\RIBUILDR目錄中復制RIMAIN.PRG 到我的生成器所在的目錄,添加它到項目中,并使它面為主程序。我修改了該程序所指向的類庫,使它能找到我的VFP RI 生成器類的子類所在的類庫 (SFRIBUILDR.VCX) 并自動注冊該生成器到VFP BUILDER 表中(如果是直接運行該APP)。 生成并運行SFRIBUILDR.APP 導致該文件作為RI生成器注冊取代了通常的RIBUILDR.APP。要看這一點,按以下步驟進行: 
 創(chuàng)建一個更好的升遷(Upsizing) 向導 Jim Falino 在使用升遷向導時失敗了,因此他創(chuàng)建了一個具有他所希望的行為的版本。 
 Jim 的修改是讓用戶指定他們的要求; 你可以使用它們如果你的需要與之相同,或將他們作為模板使用以便你自己修改。 創(chuàng)建一個更好用的WWW 搜索頁向導 在 "Visual FoxPro 6 企業(yè)開發(fā)" (Prima Tech,ISBN 0-7615-1381-7)一書中,Rod Paddock 和 John Petersen 描述了如何修改WWW 搜索頁向導來取消只能輸出5個字段到一個網頁的局限。勝于修改向導,你會希望派生它們。要這樣做,用我派生生成器類的相似的方法。WWW 搜索頁向導的代碼在VFP 向導源目錄下的WIZARDS\WZINTNET 目錄中。 第九節(jié) 創(chuàng)建你自己的向導 Rod Paddock 和John Petersen 也在他們的書中也提供了一些使用VFP 向導類來建立你自己的向導的細節(jié)。這樣做的優(yōu)點是,有人已經建立了所有的"引擎"來管理向導處理,且你的向導將與其它的VFP向導具有相同的感觀。 用BuilderD 創(chuàng)建生成器 在查看VFP6中的FoxPro基本類時(FFC),我注意到一件事是它們都具有叫做Builder和BuilderX的自定義屬性,并且各個類的BuilderX 是設置為= HOME() + "Wizards\BuilderD,BuilderDForm"。我知道這些屬性的作用(他們告訴VFP,這個類的生成器名),但為什么每一個類都要指定相同的生成器呢?更有趣的是,各個類以不同的選項調用類似的生成器表單(圖1顯示_HyperLinkLabel 類的生成器)。當使用相同的類時將會發(fā)生什么情況呢? 
 首先介紹一點背境。可能正象你可能意識到的,VFP 生成器可能以多種方式調用,但最常見的是可能是在對象上右擊鼠標并從出現(xiàn)的菜單上選擇生成器。這會使BUILDER.APP 被執(zhí)行。BUILDER.APP 檢查是否選定的對象(我們稱為"目標對象") 具有 BuilderX 屬性,如果有,運行該屬性指定的程序或實例化該該屬性指定的類(如果生成器是一個類,將指定一個類庫,逗號及類名)。如果它沒有 BuilderX 屬性但有一個 Builder 屬性,生成器運行該屬性指定的程序或實例化該該屬性指定的類(我們將看到為什么會同時用兩個屬性指定生成器)。如果兩個屬性都不存在,將使用該對象基類的默認生成器。 你可以在你的類中建立自定義的 Builder 和 BuilderX 屬性(甚至在你的基類中) 然后為每一個類填寫適當的生成器名字。要使用兩個屬性的理由是 BuilderX 為該類指定一個自定義生成器 而Builder為一組公共的類(如comboboxe 或 grid)指定一個所需的生成器。正如我們稍后會看到的一樣,我們可以在 BuilderX 屬性中指定的生成器中,單擊一個按鈕來調出在 Builder 屬性中指定的生成器。 因此,我們可以很容易地在 Builder 和 BuilderX 屬性中指定生成器。而不是花很多時間來建立你自己的生成器,特別對于不常使用的類。 BuilderD 你可能意識到了 BuilderB 技術 用來建立生成器是容易的和快速的。BuilderB 是一組你可以派生來建立你自己的生成器的類。你可以為你想用生成器維護的目標對象的各屬性添加一個控件到生成器子類。雖然BuilderB 使得建立生成器更容易,但你必須為每一個你想用生成器管理的類建立一個新的生成器子類。對于我們這樣的懶人來說,幸運的是,Ken 以數據驅動的方式增強了BuilderB。這種新技術叫做BuilderD ,"D" 的意思是"動態(tài)" (Dynamic),可以在Ken 的網站(www.classx.com)找到,也包含在VFP 6 中(在VFP 主目錄下的WIZARDS 目錄中的BUILDERD.VCX)。 BuilderD 由一系列的類組成,但主要的一個是BuilderDForm; 這是一個數據驅動生成器表單 (注意這是VFP6.0的基本類中指定的BuilderX類)。正如你在圖2中看到,該表單中的文本框用于輸入目標類的名字和類名,按鈕提供的功能可以調出類瀏覽器和顯示幫助,一個頁框、兩個頁面,但沒有用于管理屬性值的控件。 
 以下是該表單在實例化時,如何組合適當的控件: 
 這些步驟的結果是,一個生成器可以管理目標對象的一個或更多的屬性。一個指定的生成器可以事實上做得比這些還要多,例如放置代碼到目標對象的方法或對象的容器中,介是目前我們只使用最簡單的方法。 BuilderD 表 讓我們進一步了解生成器定義表BUILDERD.DBF,因為理解它的結構是建立你自己的生成器的關鍵。表2 顯示了BUILDERD.DBF表的結構; 在該表中,"property control" 意思是生成器中的、維護一個目標對象的指定屬性的控件。 
 
 
 表 1. BUILDERD.DBF的結構 表2 和 3 顯示了兩個生成器的記錄,VFP6.0的基本類_HyperLinkBase 和_HyperLinkLabel 類。我沒有顯示BUILDERD.DBF 表中的所有字段,出于空間的考慮; 僅列出與討論有關的字段。 
 
 
 表 2. _HyperLinkBase 和 _HyperLinkLabel 類的生成器記錄 
 
 
 表 3. _HyperLinkBase 和 _HyperLinkLabel 生成器管理的屬性定義記錄 在表2 中的 _HyperLinkBase記錄中,我們看見CLASSNAME 和 CLASSLIB 指定了該生成器使用的類(注意CLASSLIB 包含了一個在運行時求值的表達式而不是一個硬編碼值),在LINKS 中列了出該生成器可管理的類的屬性。顯示在表3中的cTarget PROPERTY 記錄指明該屬性將被BuilderComboBox 控件管理,且該BuilderComboBox的RowSource 包含一個 Microsoft VFP 網站的URL (目前是msdn.microsoft.com/vfoxpro)。cFrame 將被 BuilderTextBox 對象管理(因為它是一個字符串屬性且該類沒有定義),lNewWindow 將有一個BuilderCheckBox 對象(因為它是一個邏輯屬性)。 看起來是如此簡單,對吧? 好了,LINKS 字段事實上可以更加復雜。首先,假如在LINKS字段中指定的類記錄的ID 沒有匹配記錄,該ID 就被假設為屬性名。 這樣,你可以簡單的在CLASS記錄的LINKS字段中指定它管理的屬性來實際建立一個生成器。當然,你必須保持屬性的 captions 和屬性的名字相同,沒有狀態(tài)條文本、默認的類和屬性大小,但這些對于一個快速的和dirty 生成器來說都不算太壞。 第二個復雜之處是,CLASS記錄的LINKS字段中指定的ID 可以指向另一個CLASS 記錄而不是一個PROPERTY 記錄。在這種情況下,該類 "繼承"所有指定類的連接。你可以在表2中的_HyperLinkLabel 記錄中看到這一點; 它的一個連接是_HyperLinkBase,因此它不僅用該類的生成器來管理Caption 屬性(specifically 在它的 LINKS 字段中列出),同時也管理cTarget、cFrame和lNewWindow 屬性,因為這些在_HyperLinkBase 的LINKS 字段中指定。 第三,PROPERTY 記錄可以連接到另一個PROPERTY 記錄。在這種情況下,記錄"繼承"連接記錄的所有非空字段。最后,如果你用@<caption> 格式指定它,LINKS 可以包含生成器中的頁框的標題 (例如,@Properties 使用"Properties" 作為頁的標題)。 創(chuàng)建一個生成器 讓我們在TEST.VCX類庫中創(chuàng)建一個名為TestCheck的 VFP CheckBox 的子類作為開始。在該類中添加一個叫做BuilderX 的自定義屬性并設置它的值為= HOME() + "Wizards\BuilderD,BuilderDForm"。然后在該類上右擊鼠標并從快捷菜單中選擇生成器。我們得到一條"沒有注冊該類型的生成器"的錯誤。這也說得通,因為我們還沒有定義它 (盡管這令人不愉快,在稍后它將自動為我們建立一個)。按以下步驟做: 
 酷不酷,嗯? 完全是你自己的生成器,僅在一分鐘左右就建立了! 去掉Enabled 的選擇并輸入一個不同的Caption,并可看到這些屬性已被修改。 注意不要被為屬性建立記錄所迷惑; Enabled 和 Caption 記錄已存在于 BUILDERD.DBF表中,因此我們只需重用它們,而且由于不存在 AutoSize 記錄,BuilderD 只假設我們想管理那個屬性。 讓我們再建立一個并看看以多小的輸入可以得到一個可工作的生成器。在TEST.VCX類庫中創(chuàng)建一個名為TestText的 VFP TextBox 的子類,向它添加一個屬性 BuilderX 并設置它的值為 = HOME() + "Wizards\BuilderD,BuilderDForm"。在BUILDERD.DBF 中添加一條記錄并只指定 TYPE ("CLASS"),ID ("TestText"),LINKS ("ReadOnly")和 CLASSNAME ("TestText";我們可以跳過 CLASSLIB 但 CLASSNAME 是必須的)。關閉該表,然后調出該類的生成器。 這也是一個可以工作的生成器。單擊生成器中的生成器按鈕; 它調出另一個生成器(如果Builder屬性存在并非空,在Builder屬性中指定的生成器,否則就是該類的基類的默認生成器,在此例中是 VFP TextBox 生成器)。這樣,即使我們可以為一個類指定生成器,只要愿意,我們仍然可以訪問更多的普通生成器。 預置-內建的生成器 我最近用BuilderD 建立了兩個生成器,一個為我的SFGrid 類另一個為SFPageFrame。SFGrid 生成器維護DeleteMark 和RecordMark 屬性(你可以很容易地添加其它你可能經常修改的屬性) 但由于它們容易在屬性窗口中修改,所以這不是我要建立該生成器的真正的理由。真正的理由是因為我喜歡使用grid 的columns 中的SFGridTextBox 對象(SFTextBox 的一個子類,具有一小部分不同的屬性設置,以提供它們在 grid中出現(xiàn)的外觀),并盡量用SFGridTextBox對象替換一般的TextBox 對象。 因此我建立了一個按鈕(SFBUILDERS.VCX類庫中的SFGridTextBoxButton類) 來自動進行該工作。以下是該按鈕的 Click 方法代碼: 
 
 
 BuilderDForm 有一個引用到目標對象保存在它的 oObject 屬性,因此生成器表單上的許多控件可以引用或修改目標對象的東西。在這些代碼中,Thisform.oObject.Columns 引用grid 的Columns 集合被生成器影響。 這里有一個副作用:我怎樣才能在我的生成器表單中得到該按鈕? 我可以為我的生成器在BUILDERD表中建立一個記錄,但那會添加按鈕到頁框中的一個頁上,而我確希望該按鈕象其它的生成器按鈕一樣出現(xiàn)。 因此我建立了一個 "button loader" 類 (SFBUILDERS.VCX類庫中的SFBuilderButtonLoader類),該類添加一個按鈕到生成器表單然后返回 .F. 這樣,它實際上沒有實例化。SFBuilderButtonLoader 在BUILDERD表的當前記錄的備注字段 USER 中查找(使用類實例化的記錄) 要添加到表單的按鈕的類名和類庫(注意下面代碼中的 BUILDERD 是以 "BUILDER"別名打開的)。對于SFGridTextBoxButton,例如,我在BUILDERD表中建立一條記錄,以 "SFGridTextBoxButton" 作為它的 ID 但 "SFBuilderButtonLoader" 是一個類,并在USER字段中輸入 "SFBuilders, SFGridTextBoxButton"。這告訴 SFBuilderButtonLoader 添加一個 SFGridTextBoxButton 到表單中。以下是SFBuilderButtonLoader的 Init 方法代碼: 
 
 
 在BUILDERD表中 SFGrid 記錄的LINKS字段中有 DeleteMark、RecordMark 和 SFGridTextBox,因此該生成器獲得這些控件。 現(xiàn)在我可以為我的SFGrid對象調出我的BuilderD 生成器,使用 VFP Grid 生成器(單擊BuilderD表單上的生成器按鈕) 來快速建立 grid中的列,然后單擊我的添加SFGridTextBox按鈕來讓這些列使用 SFGridTextBox 對象。 對于 SFPageFrame,我也希望相似的功能:一個添加代碼到頁框中各頁的RightClick方法的按鈕; 這允許在頁面上右擊鼠標明時為頁框或整個表單提供快捷菜單。象SFGrid 生成器一樣,我在BuilderD表中建立了一個記錄來實例化一個 SFBuilderButtonLoader 對象,然后添加一個 SFCodePageButton 對象到生成器表單。以下是添加代碼到各頁的SFCodePageButton的Click方法: 
 
 
 要添加這些新的生成器到你的系統(tǒng)中,復制 SFBUILDERS.VCX 和 VCT (在本文檔的源代碼文件中可以找到) 到一個目錄,然后打開示例文件提供的NEWBUILDERS 表,并修改 CLASSLIB 字段到包含路徑的 SFBUILDERS.VCX文件名。打開 BUILDERD 表,然后 APPEND FROM NEWBUILDERS 表,添加Builder 和BuilderX 屬性到你的類中,并在BuilderX中輸入 = HOME() + "Wizards\BuilderD,BuilderDForm"。 其它生成器類 我早些時候注意到,SFBUILDERS.VCX 中的BuilderCheckBox 和 BuilderTextBox 類都是派生自同一個BuilderD 類。在附加的右擊鼠標行為中,這兩個類具有nTop 和 nLeft 屬性,當這些屬性改變時,用assign 方法設置它們的自定義的lMoved 屬性為.T.。這允許我們查覺到什么時候一個屬性控件被移動了(在屬性控件生成器中的Left 和Top 是綁定至 nLeft 和 nTop 而不是直接綁定到 Left 和 Top)。只有當一個屬性控件移動時,我們保存它的its Left 和 Top 值到 BUILDERD 表。 SFBUILDERS.VCX 中的加一個類是 SFPropertyCaption。該控件用于管理屬性控件的 caption。 為什么用一個特別的類來做這件事? 為什么不用一個普通的BuilderTextBox 對象? 理由是如果屬性控件是一個BuilderCheckBox,它有一個 Caption 屬性,因此控件管理該屬性。但是,如果屬性控件是一個 BuilderTextBox,它沒有 Caption 屬性但確有一個組合的 label 對象,因此控件必須管理對象的對象的 Caption 屬性。由于 BuilderD 類只管理單個對象的屬性,SFPropertyCaption 不得不超越(override)少量方法來允許它處理這種情況。 SFBuilderPropertyComboBox 類是BuilderComboBox的一個子類。它提供一個目標對象的所有可寫屬性的一個列表(用 AMEMBERS() 得到所有屬性的列表然后檢查各自的PEMSTATUS()來排除只讀的)。雖然它的主要目的是修改屬性控件的 cProperty 屬性(用于檢查要管理的屬性),它有兩個有趣的行為。 首先,如果屬性控件是一個BuilderTextBox 但你只修改了它管理的邏輯屬性(如 Enabled),它移去BuilderTextBox 及組合的label 對象,并放一個 BuilderCheckBox 在這個地方。如果你改變了一個邏輯屬性為另一個類型它會做相反的事。 第二,如果你輸入了一個不存在的屬性名,你會被提示建立該屬性。如果你同意,生成器使用AddProperty 來添加新屬性到目標對象。我的確不推薦在一個拖放到表單中的對象上這樣做,因為這等于實例化編程; 如果你真的需要一個新屬性,你可以考慮用子類來代替。 總之,這是一個經一個步驟在類中建立新屬性并用生成器管理它的快速方法。 SFBuilderAddButton 是一個為了屬性控件使用 SFBuilderButtonLoader 類而添加到生成器表單的按鈕類 (派生自BuilderCommandButton)。SFBuilderAddButton 的Click方簡單地調用屬性控件所在的生成器表單的 AddPropertyControl 方法來建立一個新的屬性控件,然后轉換當前生成器表單來管理新屬性控件。 這意味著你可以單擊添加屬性按鈕添加一個新屬性到生成器,并在生成器中管理它。這是一種添加多個屬性控件的快速方法。 試一試 讓我們看一看SFBuilderBuilderForm; 它實際上比對它的描述更易于使用。在TEST.VCX中建立一個叫做 MyTestText 的VFP TextBox 類的子類。添加一個 BuilderX 屬性并設置它的值為 "SFBuilders,SFBuilderBuilderForm",然后調出該類的生成器。 注意盡管我們沒有在BUILDERD 表中建立任何記錄,我們仍然得到了一個生成器表單(當然,表單上沒有控件,但我們馬上會改變這一切)。 這是因為 SFBuilderBuilderForm 在不能找到該類的記錄時,自動地為該類在BUILDERD表中建立了一個 CLASS 記錄。 單擊添加屬性控件按鈕。你會注意到一個文本框和標簽出現(xiàn)在生成器表單上,但隨后另一個生成器表單出現(xiàn)在該生成器表單的面上。這個新的表單是我們剛添加的屬性控件的生成器。在屬性 combobox中,選擇 "Tooltiptext" 并修改 Caption 為 "Tool Tip Text" 和 Width 到250。移動該生成器表單在一旁并注意原表單上的屬性控件也同樣修改了。 單擊第二個生成器表單上的添加另一屬性按鈕并注意另一個屬性控件已添加到原生成器表單中,并且該生成器表單現(xiàn)在可以管理它了。為屬性選擇"Statusbartext" 并修改Caption 為"Status Bar Text" 和Width 到250。添加另一個屬性控件,并為該屬性選擇 "Readonly" 并修改Caption 到"Read-Only"; 這時,注意原生成器屬性控制改變了checkbox。關閉新的生成器表單。圖3 顯示了我們建立的生成器,圖4 顯示了屬性控件生成器。 
 
 要修改控件的屬性,在控件上右擊鼠標并從快捷菜單中選擇修改屬性修改控件; 你以前看到過的相同的屬性控件生成器會出現(xiàn)。要移去屬性控件,從菜單中選擇移去屬性控件。要重置目標對象的該屬性的值為默認值,選擇重置為默認值。 讓我們修改生成器表單的標題為更為合適的東西。單擊修改生成器標題按鈕并在隨后出現(xiàn)的SFBuilderBuilder生成器表單中輸入 "我的測試文本框類生成器" 。關閉第二個生成器。 如果你在關閉生成器時沒有保存,下一次你再調用 MyTestText 對象的生成器時,你的設置不會起作用。若要保存生成器的定義到 BUILDERD 表中,單擊保存生成器按鈕。如果你想導出生成器定義到另一個表中,單擊導出生成器按鈕并在出現(xiàn)的對話框中輸入文件名。然后你可以發(fā)送該表給一些人,他們可以將其導入他們的 BUILDERD 表并訪問你建立的生成器。 說明 因為VFP的開放式IDE,任何人都可以很容易地定制它們的開發(fā)環(huán)境,因此他們和他們的開發(fā)組可以極大地提高編程效率。 第十節(jié) 示例 例1:在程序開始時設置系統(tǒng)環(huán)境 *-- 設置工作目錄
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
*-- 修改程序標題并將屏幕放到最大,在編譯成.EXE的文件運行時,這是必須的
MODIFY WINDOW SCREEN TITLE "測試" NOCLOSE
ZOOM WINDOW SCREEN MAX
*-- 屏蔽系統(tǒng)菜單
SET SYSMENU OFF
*--定義用于保存系統(tǒng)設置的全局變量
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),以便在退出時恢復
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")
*-- 設置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
注意:運行上述代碼時程序文件UTILITY.PRG,OnShutDown,類庫文件MAIN及幫助文件MAIN.CHM必須存在。例2:在程序結束時恢復系統(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:程序崩潰時恢復系統(tǒng)環(huán)境 在程序設計期間,有時會因程序錯誤而使系統(tǒng)崩潰。當系統(tǒng)崩潰時,可能會有打開的表沒有關閉,數據工作期不能釋放,表單在屏幕上不能清除,菜單沒有釋放等一系列令人心煩的事。當你要手工地恢復系統(tǒng)到初使狀態(tài)真還要費不少事,但是你可以自己編寫一個過程文件來自動完成這些工作。這樣,當系統(tǒng)崩潰時,你只需在命令窗口打入 DO XXX 即可。 *:******************************************************************************
*:
*: 過程文件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)設置
*:******************************************************************************
*:
*: 過程文件C:\HIGHMIS\PROGS\SYSTEST.PRG
*:
*       用途:查看當前系統(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(),"時間",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 "其他設置"
?
? "其他設置"
?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)內存變量"
?
? "系統(tǒng)內存變量"
?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
? "不能打開文件."
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 "檢查完成,結果已寫至" + 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
 
 包含了有關 Visual FoxPro 中聲音、程序設計、數據輸入的選項以及其它選項。 
 
 
 包含控制表中數據的選項。 
 
 
 遠程數據 包含了有關遠程 (ODBC) 視圖和連接默認值的選項。 
 
 
 文件位置 包含了 Visual FoxPro 使用文件的目錄位置和名字??梢灾苯釉诿總€框中鍵入路徑和文件名,也可以單擊對話框按鈕激活對話框設置相應的選項。 
 
 
 表單 包含“表單設計器”的選項。 
 
 
 項目 包含了有關“項目管理器”的選項。 
 
 
 控件 包含了為指定“選項”對話框中“表單”選項卡上的模板類而登記可視類庫的選項。這些選項也指定“表單控件”工具欄上“查看類”按鈕中可以選擇的內容,這可以簡化向表單中添加用戶自定義控件的工作。 
 
 
 區(qū)域 
 
 
 調試 通過設置選項來定制 Visual FoxPro 調試器窗口。 
 
 
 語法著色 包含的選項可以指定顏色及字體,用來區(qū)分 Visual FoxPro 的程序元素,比如關鍵字和注釋。這些程序元素在命令窗口或所有編輯窗口(除用 MODIFY FILE 或 MODIFY MEMO 命令打開的編輯窗口之外)中使用。 
 
 
 字段映象 
 
 
 | 
|  |