PFC編程
PFC是由Sybase公司提供一些由源代碼組成的基本類庫,該類庫中提供了在項目開發時經常使用的一些功能,這些功能可以直接以特定的方式使用。採用這種方式,不僅可以提高開發效率,而且很容易積累原來的開發成果,並且在代碼的重用性、接口和編碼的標準化及一致性等方面都得到了規範和提高。使用PFC進行程序設計雖然有很多的優點,但是對於大多數的中國用戶來說中文界面還是比英文界面更親切,所以還有個漢化的問題,這也需要不少的工作量,但這個煩瑣的工作並沒有多少難度。
19.1.1 理解PFC
PFC是PowerBuilder Foundation Class的縮寫,是PowerBuilder附帶的一種面向對象的開發框架包。在PowerBuilder的開發環境中可以查看該包中對象的源代碼,但是對該包的修改應該遵循一定的策略,不能任意修改。按照一定的規則對包進行擴展,可以構建更符合自己商業規則的類庫,從而確保以後能夠很好地利用當前的開發成果。
對PFC類庫的修改規定侷限在擴展層,但擴展層的很多對象既是基本類庫中對象的子孫又是它們的祖先,從而確保了用戶在擴展層的修改可以體現在其他子孫對象中,這樣的繼承層次對開發人員的擴充提供了很好的支持。比如,在基本類庫中的窗口pfc_w_master是很多窗口(包括w_master)的父窗口,而w_master又是pfc_w_master的父窗口,所以,對窗口w_master的修改可以自動體現在pfc_w_master的其他子窗口中。
該包的功能嚴格採用PowerBuilder面嚮對象的技術設計,並且採用了類似於C/S模式的服務方式,通過服務嚮應用程序提供功能。開發人員在使用時,首先要初始化相應的服務,然後才能使用該服務所提供的功能。只初始化需要的服務,這樣可以減少計算機資源的消耗,提高程序的執行效率。
19.1.2 PFC的構成
PFC是由一系列的PBL庫、數據表和例程構成。PBL庫可以分爲祖先庫和擴展庫,數據表用來保存錯誤信息和安全信息,例程在PowerBuilder安裝目錄下的pfc\demoapp目錄中。
祖先庫共有七個,文件名都是以pfc開頭。這些庫包含了構成PFC功能的全部方法、屬性和代碼。這些庫中包含的對象是PFC中及最後在用戶應用程序中的其餘所有對象的祖先。這七個祖先庫如表19-1所示。
表19-1 祖先庫
庫 名 |
內 容 |
pfcmain.pbl |
包含標準類用戶對象、窗口對象、菜單和標準的可視用戶對象 |
pfcapsrv. pbl |
包含提供應用程序服務的定製類用戶對象 |
pfcdwsrv. pbl |
包含提供數據窗口服務的定製類用戶對象 |
pfcwnsrv. pbl |
包含提供窗口服務和菜單對象的定製類用戶對象 |
pfcutil. pbl |
包含調試應用對象 |
pfcsecsc. pbl |
包含實現安全性掃描器(安裝在一個單獨的目錄中)所必須的對象 |
pfcsecad. pbl |
包含實現安全性管理服務(安裝在一個單獨的目錄中)所必須的對象 |
擴展庫對應於前五個祖先庫,這些擴展庫包含祖先庫的直接後代,共有以下五個擴展庫:
l pfeapsrv. pbl;
l pfedwsrv. pbl;
l pfemain. pbl;
l pfeutil. pbl;
l pfewnsrv.pbl。
這些擴展庫的目的是爲了用戶修改PFC類庫來更好地爲自己的應用服務,或者構建符合自己商業規則的擴展庫。
PFC的數據表保存在本地數據庫PowerBuilder安裝目錄下的PFC\pfc.db中,共有表19-2所示的幾個數據表。
表19-2 PFC數據表
表 名 |
用 途 |
Messages |
錯誤信息服務 |
Security_apps |
安全服務 |
Security_groupings |
安全服務 |
Security_info |
安全服務 |
Security_template |
安全服務 |
Security_users |
安全服務 |
如果正確安裝了PFC,則在DB Profile中的ODBC聯結中可以找到pfc,使用該配置可以和PFC數據庫建立聯結。
PowerBuilder提供的PFC例程對於學習PFC有很大幫助,可以在學習時參閱。在Library畫板中打開PB目錄下的pfc\demoapp\peat.PBL可查看該例程。
學習PFC的重點應該是理解它所提供的服務,這些服務是PFC的實質。而服務大部分都封裝在PFC的定製類用戶對象中,如表19-3所示。
在使用服務所提供的功能之前必須首先啓動該服務。一般每個對象都提供了啓動服務的
表19-3 PFC提供的服務描述
服 務 |
描 述 |
Application服務 |
通過服務對象提供錯誤處理、數據窗口緩存、安全性、調試和事務處理登記等功能 |
DataWindow服務 |
通過服務對象用數據窗口控件提供數據處理功能 |
Window服務 |
通過函數和時間提供普通的窗口處理 |
Menu服務 |
通過函數、菜單項提供普通的菜單處理 |
其他服務 |
提供擴展的PowerScript語言的功能 |
函數,該函數的格式如下:
of_Set<ServiceName>(flag)
其中,ServiceName爲服務的名稱,flag爲布爾類型參數,表示是啓動(True)還是註銷(False)該服務。比如,要啓動PFC中Application的調試服務,可以使用of_SetDebug(True)語句。關於服務的詳細內容在後面將做較詳細的介紹,更多的信息可以參閱聯機幫助中PowerBuilder->PFC Object Reference->Chapter 9 Custom Class User Object的詳細介紹。
PFC中包含的對象採用自己的命名規則,他們類似於標準的PowerBuilder約定,如表19-4所示。
表19-4 PFC對象名的前綴含義
前 綴 |
意 義 |
前 綴 |
意 義 |
w_ |
窗口 |
u_ |
可視用戶對象 |
m_ |
菜單 |
n_ |
標準類用戶對象 |
S_ |
全局結構 |
n_cst |
定製類用戶對象 |
祖先庫中的所有對象在這些命名約定的前面加上前綴pfc_,例如:
l pfc_w_master:表示PFC層中的主窗口。
l pfc_u_mle:表示PFC層中的可視對象MultiTextEdit。
l u_dw:表示PFC擴展層中的數據窗口可視對象。
l n_cst_dwsrv:表示擴展層中爲數據窗口服務聲明的用戶類對象。
l n_tr:表示擴展層中的Transaction標準對象。
變量的聲明一般遵循下面規則:
<scope><datatype>_variablename
其中,scope的規則和PowerScript中的規則是相同的。
19.1.3 PFC的體系結構
在介紹PFC的體系結構之前,首先明確一下客戶/服務器的服務模式。客戶/服務器當然是由客戶端和服務器端兩部分組成,這兩部分可以在同一臺計算機上,也可以是網絡上的兩臺或者多臺計算機。客戶端的應用程序聯結到服務器端,並請求駐留在服務器上的數據庫管理系統的服務;服務器根據客戶端的請求進行處理,然後將結果返回到客戶端。客戶端的請求或者是一條簡單的SQL語句、一個複雜的計算,或者是數據修改等語句;服務器端的返回信息或者是處理後的結果數據,或者是成功/失敗代碼。這樣,服務器端和客戶端兩部分各司其職、分工明確、協同工作,共同發揮各自的長處來完成整個應用程序的功能。
在PFC中,也可以理解成兩部分的功能,一部分由PFC類庫提供,另一部分通過開發人員開發的程序執行;當需要調用PFC的功能時,PFC以服務的方式提供這些功能。開發人員需要了解在什麼時候啓動哪些服務,適時地發送服務請求,根據返回值做進一步的操作,並在適當的時候取消該服務。這取決於對服務的學習和掌握,在後面將詳細介紹PFC提供的服務。
當需要啓動服務時,應該有一種簡單的啓動方法,並且在以後可以方便地引用該服務。在PFC中提供了一種通用的啓動服務的語句格式,即of_Set<ServiceName>(flag)。其中,<ServiceName>爲服務的名稱,布爾類型變量flag爲啓動或者終止服務的標誌變量,啓動的服務都可以使用一個缺省的實例變量來引用,對功能的引用都應該限制在該服務中。例如,下面語句在Application中編寫來啓動調試服務:
gnv_app.Of_SetDebug(True) //啓動調試服務
gnv_app.inv_debug.of_Message ("登錄錯誤:" + gnv_app.of_GetUserID())
上面腳本中inv_debug是debug服務的缺省實例變量,通過該變量引用該服務提供的功能。在使用服務之前首先判斷該服務是否啓動是一個比較好的習慣:
If IsNULL(inv_base) or Not IsValid(inv_base) Then
inv_base = Create n_cst_dwsrv
inv_base.of_SetRequestor(this)
Return 1
End If
由於PFC採用嚴格的面向對象的設計技術,服務中變量一般不能直接引用,只能通過服務提供的函數。PFC提供了of_SetX()和of_GetX()函數,其中X是變量名。這樣使PB能控制誰訪問了變量以及變量是如何改變的。在一些特殊的情況下,PFC也提供了可以直接訪問的變量。
PFC中除了關啓服務的函數外,還提供了很多以of_開頭的函數來完成服務的其他功能,在服務啓動以後可以調用。
19.2 PFC編程基礎
本節介紹如何使用PFC進行編程,以便對PFC有一個感性認識,在此基礎上更有利於學習後面介紹的PFC服務。
Application是一個應用程序的入口,採用PFC進行程序開發的第一步也是從這裏開始的。創建應用,然後設置該應用的搜索路徑,應該包含如下的類庫:
PFCAPSRV.PBL
PFCDWSRV.PBL
PFCMAIN.PBL
PFCUTIL.PBL
PFCWNSRV.PBL
PFEAPSRV.PBL
PFEDWSRV.PBL
PFEMAIN.PBL
PFEUTIL.PBL
PFEWNSRV.PBL
在PowerBuilder安裝目錄中的pfc目錄下可以找到這些庫文件,如果應用中包含老版本中已經過時的PFC對象,則還應該包含PFCOLD.PBL庫。然後開始編寫腳本。首先聲明一個全局變量:
n_cst_appmanager gnv_app
因爲Application對象不能繼承,所以只能將應用對象中的事件重定向到PFC中的Application對象的事件上,所以必須聲明該全局變量。該變量的名字必須爲gnv_app,因爲在PFC的對象、事件和函數中都使用變量gnv_app來引用該應用用戶對象。在Application對象的Open事件中編寫如下腳本:
gnv_app = Create n_cst_appmanager
gnv_app.Event pfc_Open(commandline)
該腳本創建n_cst_appmanager應用對象管理,並觸發它的事件pfc_Open。在應用的Close事件中編寫腳本註銷n_cst_appmanager,腳本如下:
gnv_app.Event pfc_Close( )
Destroy gnv_app
在應用對象的SystemError事件中編寫如下腳本:
gnv_app.Event pfc_SystemError( )
上面三個事件的腳本有一個共同的特點,就是它們都要調用n_cst_appmanager相應的事件。從這裏可以看出,n_cst_appmanager接管了Application對象中原來的事件處理功能,這主要有兩個原因:要創建的是PFC應用,而Application是不能繼承的。如果Application能夠繼承的話也沒有必要重新定向事件了,只要使用繼承創建一個應用對象就可以了。
在應用對象Open事件的腳本中將事件重定向到了n_cst_appmanager的pfc_Open事件。所以如果還需要啓動其他的服務,就應該在n_cst_appmamanger用戶對象的pfc_Open事件中編寫腳本,該用戶對象在PFC的擴展庫pfeapsrv.PBL中。比如,在應用程序打開主窗口之前首先顯示一個Splash窗口,可以在pfc_Open事件中編寫如下腳本:
This.of_Splash(2) //顯示2秒鐘
Open(w_main) //打開主窗口
再比如,在應用程序運行前需要用戶登錄,可以在pfc_Open事件中編寫如下腳本:
Integer li_return
li_return = gnv_app.of_LogonDlg( )
If li_return = 1 Then
This.SetMicroHelp("Logon successful")
Else
MessageBox("Logon", "Logon failed")
Close(This)
End If
總之,pfc_Open事件是PFC應用程序打開時必定觸發的事件,應該在該事件中編寫腳本進行初始化工作,而不是在Application的Open事件中進行初始化。表19-5是可以在該事件中啓動的服務。
表19-5 pfc_Open事件可用的服務
服 務 |
函 數 |
Application preference |
of_SetAppPreference |
DataWindow caching |
of_SetDWCache |
Error |
of_SetError |
Most recently used object |
of_SetMRU |
Transaction registration |
of_SetTrRegistration |
Security |
of_SetSecurity |
Debug |
of_SetDebug |
另外,通常在n_cst_appmanager的Constructor事件中調用相關函數來初始化ini文件、版本信息與公司名稱等,以便後面Splash窗口中顯示。這些函數有of_SetAppIniFile,of_SetAppKey,of_SetAppPreference,of_SetCopyRight,Of_SetHelpFile和Of_SetVersion等。
事件pfc_PreAbout,pfc_PreLogonDlg,pfc_PreSplash分別在顯示About窗口、登錄窗口和Splash窗口之前觸發,這些事件給了開發人員更靈活的控制機會。通常在pfc_Logon事件中編寫腳本處理登錄的用戶信息,或者聯接數據庫,或者根據用戶的權限初始化界面等。比如,假設應用中事務對象SQLCA爲n_tr類型,ini文件中包含除用戶名稱和口令以外的所有和數據庫相聯的必需信息,下面是pfc_Logon事件中的腳本進行數據庫聯接:
String ls_inifile, ls_userid, ls_password
ls_inifile = gnv_app.of_GetAppIniFile()
//使用ini文件中的database節初始化SQLCA
If SQLCA.of_Init(ls_inifile,"Database") = -1 Then
Return -1
End If
// as_userid和as_password是pfc_Logon事件的參數
SQLCA.of_SetUser(as_userid, as_password)
If SQLCA.of_Connect() = -1 Then
Return -1
Else
gnv_app.of_SetUserID(as_userid)
Return 1
End If
19.2.2 創建應用
MDI和SDI應用是PB中的兩種類型的應用,它們都得到了PFC的支持。在PFC中爲MDI應用提供了w_frame,w_sheet,m_master和m_menu四個已經定義好的對象,爲SDI應用提供了w_main窗口,當創建相應的控件時應該通過從這些對象繼承來創建新對象。
在前面章節中提到MDI應用主要由Frame,Sheet和菜單三個對象構成,PFC中提供了已經定義好的這三個對象,只要使用繼承創建相關的對象就可以生成PFC的MDI應用。關於菜單,可以使用繼承來創建,也可以完全由自己創建,這取決於開發人員的菜單策略。一般在相關的Frame菜單項中編寫腳本來打開Sheet窗口,腳本如下:
n_cst_menu lnv_menu
Message.StringParm = "w_products"
lnv_menu.of_SendMessage(This, "pfc_Open")
在w_frame的pfc_Open事件中編寫如下腳本來處理消息中的信息:
String ls_sheet
w_sheet lw_sheet
ls_sheet = Message.StringParm
OpenSheet(lw_sheet, ls_sheet, This, 0, Layered!)
創建SDI應用,首先使用繼承w_master創建一個窗口,然後根據開發人員的菜單策略創建菜單和附加的其他窗口。打開c_nst_appmanager,在它的pfc_Open事件中編寫腳本打開主窗口。
PFC採用面向對象的設計技術,所以它提供的函數都應該使用界定符來指明要引用哪個對象的函數,並且在調用這些函數之前應該確保啓動了相應的服務。訪問對象中封裝的變量也應該使用of_Set和of_Get之類的函數,而不是直接引用。在使用某些實例變量之前,最好首先調用of_ls函數來判斷要引用的對象是否有效。
PFC提供了很多用戶事件和預先編寫好腳本的事件,這些預先編寫好的腳本用來提供控件相應的PFC服務功能,沒有提供腳本的用戶事件讓開發人員編寫腳本以便能夠更好地使用所開發的應用程序。在PB中,事件的訪問權限總是public,可以使用對象名稱加界定符和事件名稱來執行事件中的腳本。可以修改擴展類庫中事件的腳本,但是不要在子對象中覆蓋這些腳本,這樣會影響PFC的服務功能。
PFC提供很多沒有腳本的用戶事件,開發人員可以根據應用程序的需要在其中編寫腳本。很多這樣的事件是通過消息路由在用戶點擊菜單項時觸發的,還有一些是由應用程序中的腳本來觸發的。比如,可以在u_dw控件的pfc_Retrieve中編寫如下腳本:
Return This.Retrieve()
當調用PFC的事件時,應該提供適當的參數;被調用事件還有可能調用其他事件或者PFC對象的相關函數。當然,開發人員也可以直接調用相關的PFC函數,但是應該儘可能地調用相關事件,因爲事件中已經包含了相關的錯誤處理腳本,功能比較完備。
另外,很多PFC對象提供了pre-事件,爲開發人員提供了更靈活的控制機會。這些事件在相關動作執行之前觸發,一般都有可以自動實例化的引用方式(reference)的參數,該參數一般是事件所在控件的引用,以便在發生動作之前控制控件的屬性。下面是一些這樣的典型事件:
l pfc_PreAbout
l pfc_PreClose
l pfc_PreLogonDlg
l pfc_PreOpen
l pfc_PrePageSetupDlg
l pfc_PrePrintDlg
l pfc_PreRestoreRow
l pfc_PreSplash
l pfc_PreToolbar
l pfc_PreUpdate
比如,在About窗口中可以添加一個附加的信息:用戶標識。首先看pfc_PreAbout事件的參數爲n_cst_aboutattrib類型,這說明需要擴展該對象。打開類庫pfeapsrv.pbl中的n_cst_aboutattrib,聲明一個實例變量:String is_userid。接下來是修改w_about窗口,打開類庫pfeapsrv.pbl中的w_about,在窗口上放置一個名稱爲sle_userid的單行編輯器。然後在該窗口的Open事件中編寫腳本sle_userid.Text = inv_aboutattrib.is_userid,來顯示用戶標識。最後,在n_cst_appmanager的pfc_PreAbout事件中初始化該實例變量,編寫腳本 anv_aboutattrib.is_userid = this.of_GetUserID()。至此,對about窗口的擴充工作全部完成。
在PFC中提供了很多專門用來保存對象屬性的用戶對象,這是PFC特有的取代結構數據類型的一種手段。使用這種方法有以下特性:
l 包含訪問權限爲public的實例變量;
l 自動實例化;
l 通常以attrib爲名字結尾;
l 經常用來向PFC中的pre-事件傳遞參數,比如pfc_PreAbout;
l 是可以擴充的(可以向該用戶對象添加實例變量)。
開發人員可以擴充該用戶對象中的成員變量,而結構類型變量不應該由開發人員隨便修改,所以使用用戶對象取代結構類型數據類型是PFC一種比較方便擴充的選擇。
許多PFC對象中都包含聲明爲常量的實例變量,使用這些實例變量可以編寫可讀性更好的腳本。比如,下面兩個腳本實現同樣的功能,但是第二種編寫方法的可讀性就明顯好於第一種:
// 1 = Filter linkage style.
dw_emp.inv_linkage.of_SetStyle(1)
// FILTER is a constant instance variable
// that is initialized to 1.
dw_emp.inv_linkage.of_SetStyle(dw_emp.inv_linkage.FILTER)
PFC使用消息路由來處理菜單和窗口之間的交互。所謂消息路由是指菜單通過將能完成某個特定過程的消息發送到窗口,窗口通過觸發相應的事件來執行相應的腳本。而開發人員需要知道將要觸發的窗口事件的名稱,然後調用of_SendMessage函數來觸發PFC中的pfc_MessageRouter事件,由該事件選擇適當的對象來接收剛纔的消息。通常的開發習慣是直接在菜單項的Click事件中處理相關的操作,這點區別一定要注意。
消息路由函數of_SendMessage()是從PFC菜單中的每個菜單項調用的,它發送要執行的事件名稱。該函數的語法是instancename.of_SendMessage ( message ),其中instancename是實例n_cst_menu變量的名稱;message是一個String類型的參數,用來指明pfc_MessageRouter事件要觸發的用戶事件的名稱。發送消息後,Pfc_MessageRouter隨後按窗口、當前控件、活動的數據窗口控件的順序激活事件。
如果不想使用PFC菜單,但是仍然想使用消息路由,可以將of_message()和用戶可能需要的任何菜單項代碼移動到自己的菜單中。
19.2.6 PFC的事務管理
PowerScript可以簡單、方便地訪問數據庫,主要是得益於事務對象的中間聯絡功能,缺省的全局事務對象是SQLCA。在PFC應用中可以使用n_tr類型的事務對象,從而能夠利用PFC中的事務對象管理功能。n_tr是PFC中的一個用戶對象,該對象繼承自系統的Transaction對象,並定製了很多的實例變量、事件與函數來實現和數據庫系統的聯接。該對象提供的函數可以管理和數據庫的很多操作,比如數據庫的聯接、斷開聯接、提交與回退等。當使用該類型的事務對象時,應該使用n_tr提供的事務對象管理函數,而不是使用原來的事務對象管理函數。比如,應該使用of_connect和數據庫建立聯接,而不是使用connect。
有兩種n_tr的使用方式,或者替換SQLCA,或者作爲SQLCA的擴充。當需要不止一個事務對象時還可以結合使用兩種方式。兩種使用方式的操作方法如下:
l 替換SQLCA:在Application畫板的屬性對話框中指定缺省的事務對象SQLCA的類型爲n_tr(在Application畫板中顯示屬性對話框,並點擊Additional Properties按鈕,然後在Variable Types屬性頁的SQLCA單行編輯器中輸入n_tr即可)。
l 作爲SQLCA的擴充:定義n_tr類型的實例變量,在適當的時候用腳本創建該對象。
作爲SQLCA的擴充,需要編寫腳本來操作該事務對象。首先是創建事務對象,在適當的事件中編寫如下腳本:
itr_security = CREATE n_tr
當事務對象還和數據庫保持聯接狀態時關閉應用程序或者Destroy事務對象,這時是否自動提交未提交的事務,可以使用函數設定n_tr的成員變量ib_autorollback來指定。如下所示:
itr_security.of_SetAutoRollback(False)
初始化n_tr類型的事務對象是在創建對象之後使用該對象之前的必須步驟,下面是一段典型的初始化腳本:
String ls_inifile
ls_inifile = gnv_app.of_GetAppIniFile()
If SQLCA.of_Init(ls_inifile,"Database") = -1 Then
MessageBox("錯誤提示", "初始化ini錯誤:" + ls_inifile)
Hlat Close
End If
如果能夠正確初始化,就可以調用函數of_Connect和數據庫建立聯接了。腳本如下:
If SQLCA.of_Connect() = -1 Then
MessageBox("錯誤提示", "不能和ini指定數據庫聯接:" + ls_inifile)
Halt Close
Else
gnv_app.of_GetFrame().SetMicroHelp("聯接完成")
End If
在擴充父對象的事件或者函數時,經常需要首先調用父對象的腳本,然後根據腳本的返回值決定如何繼續執行。使用下面的腳本調用父對象的事件並保存返回值:
result = Super::Event eventname ( arguments ... )
可使用如下語句調用父對象的函數,並保存返回值:
result = Super::Function functionname ( arguments ... )
下面的例子是在u_dw的子對象中編寫的,用來擴充u_dw的pfc_Update事件的功能,首先調用父對象的pf_Update事件,根據事件的返回值決定如何執行。腳本如下:
Integer li_return
// 使用相關參數調用父對象的pfc_Update事件
li_return = Super::Event pfc_Update(ab_accepttext, ab_resetflag)
If li_return = 1 Then
// 如果父對象的事件執行成功則調用用戶自定義事件ue_WriteLog
li_return = This.Event ue_WriteLog
End If
Return li_return
19.2.8 爲應用添加在線幫助
對於一個應用程序來說,在線幫助是一個非常重要的部分,它可以讓用戶儘快地掌握應用程序的用法。PFC對此也給予了支持,提供了相關的事件和函數。在PFC的應用程序中,有兩種方式可以爲應用指定在線幫助文件。第一種方式是在n_cst_appmanager或者在它的後代對象中,直接爲實例變量is_helpfile賦值;第二種是用腳本指定幫助文件。
經常在Application對象的Constructor 事件中編寫腳本爲應用指定幫助文件。例如,下面腳本爲應用指定幫助文件爲c:\eis\eisapp.hlp:
This.of_SetHelpFile("c:\eis\eisapp.hlp")
爲窗口指定幫助主題,經常在窗口的pfc_PreOpen事件中編寫腳本,爲窗口指定詳細的幫助主題(該主題位於應用的幫助文件中)。比如,下面腳本爲窗口指定幫助主題爲1020:
Long ll_helpid
ll_helpid = 1020 // 1020是一個幫助主題的標識
ia_helptypeid = ll_helpid
當需要顯示幫助主題對話框時,只需要在窗口的幫助按鈕的Clicked事件中編寫如下代碼即可:
Parent.Event pfc_Help( )
該腳本調用窗口的pfc_Help事件,因爲PFC應用中的所有窗口都繼承自w_master,所以該事件在所有窗口中都可用。
19.2.9 安裝PFC的最新版本
因爲在程序開發過程中很有可能對PFC的擴充類庫進行修改,當升級PFC類庫時應該確保這些修改不被覆蓋。所以,在升級PFC庫時應該做一定的備份工作。最好的建議是,在進行升級之前首先備份PFC擴展庫中的所有庫文件(PBL文件),然後進行升級安裝。
當前PFC的版本號可以在pfcutil.pbl庫文件中的用戶對象pfc_n_cst_debug裏定義的實例變量中找到。版本號包括三部分,主版本號保存在實例變量PFC_MAJOR 中,副版本號保存在PFC_MINOR變量中,實例變量PFC_FIXES 中保存的是修改號。還可以在PFC的幫助文件中找到PFC的版本號,在PowerBuilder安裝目錄下的pfc目錄中打開readme70.txt可以查看版本號。
19.3 Application服務
Application是應用程序的起點,對於PFC應用程序開發人員來說也應該首先從Application服務開始學起。應用服務是應用程序處理所必須的,它向用戶提供了 一種“應用程序對象模型”方式使用繼承性的能力。因爲在PB中不能繼承應用對象,所以應用程序服務就使開發人員能夠創建可重用的應用程序過程。
19.3.1 建立Application Manager
Application Manager服務是必須在用戶應用程序中創建的一個全局變量。在用戶的全局變量聲明中,必須聲明一個引用變量用於指向Application Manager服務。用戶可以使用擴展層服務n_cst_appmanager,但是由於用戶可能會用應用程序處理來擴展功能,因此應該從n_cst_appmanager來繼承自己的Application Manager。當開發人員建立了自己的後代Application Manager(例如名稱爲n_cst_russ_appmanager)後,就必須聲明一個叫做gnv_app的全局引用變量來保存服務實例的地址,就像下面的代碼所示:
n_cst_russ_appmanager gnv_app
當生成Application Manager引用變量後,必須創建實例並將應用程序對象的事件重定向到Application Manager服務。用戶的應用程序的Open事件應用像下面這樣編寫:
gnv_app = Create n_cst_russ_appmanager
gnv_app.Event pfc_Open(commandline)
對於用戶打算使用的其他每一個事件,都應該將它們重定向到Application Manager(一定要傳遞事件參數)。由於Open事件創建了Application Manager,因此應用程序對象的Close事件應該取消它。Close事件應該像下面這樣編寫腳本:
gnv_app.Event pfc_Close()
Destroy gnv_app
儘管在Application畫板中創建Application Manager服務並重定向事件,但是仍然需要調出應用程序對象的屬性表。在Variable Types屬性頁上,將SQLCA數據類型從Transaction改爲n_tr,這樣就確保了SQLCA是用PFC事務對象創建的。n_tr還提供了幾個函數來消除重複性的任務,如聯結和斷開(of_connect()和of_disconnect())以及事務管理(of_commit()和of_rollback())。除了事務對象外的其他全局變量也可以使用PFC中的相關對象來代替,比如Message可以用PFC中的n_msg來代替。
創建Application Manager後,它就保存了應用程序的全局變量。Application Manager有一些Get和Set函數提供對常用全局數據的訪問。如:
l 應用程序.ini文件名;
l 用戶.ini文件名;
l 幫助文件名;
l 應用程序的註冊鍵;
l 應用程序的MDI框架窗口;
l 用戶的ID;
l 應用程序標誌;
l 應用程序的版權信息和版本號。
例如,要設置應用程序的版本信息,則可以使用下面的代碼:
gnv_app.Of_SetCopyRight("PowerBuilder Unleashed 7.0")
Application Manager還允許用戶實例化兩個窗口:w_splash和w_log。這兩個窗口一般和應用程序的啓動相關聯。醒目顯示窗口顯示了使用用戶爲應用程序設置的一些全局變量(如版權語句等)。要打開醒目顯示窗口,使用函數of_splash()並設置醒目顯示窗口持續顯示的秒數。
要顯示登錄窗口並提取用戶的ID和口令,只要調用of_LogonDlg()函數即可。該函數執行一系列隨打開窗口w_logon而設定的步驟。在打開窗口之前,觸發Application Manager的pfc_PreLogonDlg事件,初始化用於在窗口內顯示的值,隨後顯示登錄窗口。當單擊OK按鈕並關閉窗口時,將信息通過pfc_Logon事件發送到Application Manager。事件的參數as_userid和as_password隨後就可以用於產生用戶的事務對象並聯結到數據庫。
除了設置全局數據值和生成醒目顯示及登錄窗口外,Application Manager還允許用戶實例化前面提到的服務。
19.3.2 Application Manager服務
表19-6列出了Application Manager服務。
表19-6 應用對象中的服務
服 務 名 稱 |
描 述 |
Application Manager |
提供對應用程序層變量和所有其他的應用程序服務的訪問 |
Application Preferences |
提供一種方式將應用程序和用戶數據保存到INI文件或者系統註冊表中 |
Datawindow緩存 |
提供一種存儲頻繁訪問的數據窗口對象的數據的方式 |
調試 |
提供跟蹤錯誤的開發工具 |
錯誤處理 |
提供顯示和記錄各種PowerBuilder操作的錯誤的方式 |
安全性 |
提供管理和保護用戶應用程序中對象的方式 |
事務對象 |
提供標準的數據庫處理功能。如數據庫的聯接和事務管理 |
事務註冊 |
提供一種方式來跟蹤用戶應用程序中使用的所有事務對象 |
Application Manager是允許用戶訪問其他所有應用程序服務的門衛。它必須用於訪問許多PFC功能。下面將更深入地剖析兩個應用服務。
1.Datawindow緩存服務
數據窗口緩存服務提供了一種方法緩存來自經常使用的數據窗口對象的數據。這樣就減少了重複性數據庫調用和複製客戶機上的數據的需要。每當用戶需要在應用程序中的幾個位置訪問相同的數據時,數據窗口緩存服務就爲用戶提供瞭解決方法。一個比較典型的應用,是將應用中所有下拉數據窗口都使用緩存服務來解決。
數據窗口緩存服務n_cst_dwcache在Application Manager中通過實例變量inv_dwcache聲明。爲了實例化該服務,需要在Application Manager中的pfc_Open事件中加入下列代碼:
This.of_SetDWCache(True)
下一步就是使用of_Register()函數註冊擁有該服務的數據窗口。數據窗口緩存服務有三種類型的語法,其中最有用的語法爲:
gnv_app.inv_dwcache.of_Register(id,dwobject,trans{,arguments})
其中,id是用於惟一地標識緩存數據的字符串值。dwobject是包含要緩存的數據窗口對象的名字的字符串。trans是n_tr類型的事務對象的名字,用於檢索在dwobject中設置的數據窗口對象的行爲。可選參數arguments爲要檢索數據窗口對象數據的一個或者多個變量,該變量是最多可以有20個元素的任意數據類型的數組。當調用該函數用於某個數據窗口對象時,系統檢索這些數據並用數據窗口緩存服務保存這些數據。例如,爲了緩存數據窗口d_customer中的數據可以使用如下腳本:
gnv_app.inv_dwcache.of_Register("Customer listing", "d_customer",SQLCA)
要在應用程序中的其他地方訪問這些數據,用戶必須調用函數of_GetRegistered()。語法如下:
gnv_app.inv_dwcache.of_GetRegistered(id,datastore)
其中,id是在of_Register()函數中設置的字符串值,用於標識被緩存的數據。datastore是一個n_ds類型的變量,它是由被緩存的數據提供的。在調用該函數後,可以對指定的數據窗口對象執行ShareData()操作。要檢索存儲在一個例子中的數據窗口緩存中的customer數據,應編寫如下腳本:
//實例變量的定義是:n_ds ids_data
DataWindowChild ldwc_child
gnv_app.inv_dwcache.of_GetRegistered("Customer Listing",ids_data)
dw_custlist.GetChild("customer",ldwc_child)
ids_data.ShareData(ldwc_child)
2.錯誤處理服務
錯誤處理服務允許用戶顯示多種錯誤信息類型的錯誤消息:SQL、數據窗口、應用程序(例如證實)和系統錯誤。錯誤信息還可以顯示在消息框內或者PFC的消息窗口內,並可以從數據庫的表上生成。此外,錯誤處理服務還允許用戶記錄錯誤並自動發送電子郵件。
爲了執行錯誤處理服務,調用Application Manager的pfc_Open事件中的of_SetError()。如果用戶想把所有錯誤消息集中到數據庫的某個表內,就需要將Messages表和PFC演示數據庫中的已有數據複製到應用程序數據庫中。 然後可以將該應用程序特有的消息添加到Message數據表中。爲了讓應用程序利用該表,使用下面的腳本:
gnv_app.inv_error.of_SetPredefineSource(trans)
其中,trans爲n_tr類型的事務對象的名稱,它指向包含Messages表的數據庫。調用該函數將在具有所有錯誤信息的服務內生成一個數據倉庫。然後用戶就可以選擇是用標準的PB消息框顯示錯誤信息還是使用PFC的w_message窗口顯示錯誤消息。要做到這一點可以使用如下腳本:
gnv_app.inv_error.of_SetStyle(style)
其中,style爲0表示消息框,爲1表示PFC消息窗口。當遇到一個錯誤時用戶可以用下面的腳本顯示錯誤消息:
gnv_app.inv_error.Of_Message(MessageID,Parameters)
其中MessageID表示要顯示的消息的字符串(它對應於ids_message中的msgnumber)。Parameters是包含可以在指定佔位符放入錯誤消息內的值的一個可選數組。在用戶生成的錯誤消息的文本內可以設置如下代碼:
Value Required!Please enter a value For %s
由於用戶對於多個字段可重用該消息,%s用於表示一個佔位符,當調用of_Message()時將爲該佔位符設置一個值。然後代碼將是下面這個樣子:
String ls_error[]
ls_error[1]= "Customer Name"
gnv_app.inv_error.of_Message("VAL122",ls_error)
錯誤處理服務允許用戶爲特定的錯誤定義嚴重級別和用E_mail通知。
19.3.3 標準類用戶對象
正如用戶在Application Manager服務中看到的那樣,PFC爲許多標準的PowerBuilder不可見類提供子類。用戶可以使用這些子類代替標準的PowerBuilder類對象。
表19-7 子類前綴的含義
前 綴 |
描 述 |
n_cn |
聯結對象後代 |
n_ds |
數據倉庫對象後代 |
n_err |
錯誤對象後代 |
n_ms |
Mail Session對象後代 |
n_msg |
消息對象後代 |
n_pl |
管道對象後代 |
n_tr |
事務對象後代 |
n_trp |
傳輸對象後代 |
每當需要一個標準的PowerBuilder類實例時就應該使用這些不可見類。
19.4 菜 單
PFC提供了兩種類型的菜單:用戶的主應用程序菜單(用作下拉菜單)和彈出菜單。PowerBuilder從6.0版開始提供了一個新服務,即Most Recently Used(MRU,最近使用的)對象服務,該服務在MDI應用程序中的File菜單下列出了5個最近使用的窗口。像PFC窗口一樣,菜單也提供一個類層次,如圖19-1所示。可以看出,菜單層次並不是很深,這與已經知道的菜單性能問題是一致的。記住這點,用戶可以將m_frame直接用於應用程序的MDI框架菜單,或者可以從m_master繼承框架菜單定製後代。所有菜單也都應該從m_master繼承。當開發PFC應用時,一般都應該停留在PFC內(這意味着應該儘量使用PFC對象來開發應用程序)。然而當計算PFC菜單的值時這條規則常常被破壞。菜單包含了大量的有用代碼,但其中的許多代碼可能並不適合用戶的應用程序。因此,用戶可以選擇創建一個PFC菜單的縮微版本或將已經有的菜單框架包補充到PFC內。
PFC中的菜單繼承使用了Shift Over/Down菜單屬性來控制菜單項的放置。PFC使用一個消息路由與PFC窗口通信,它提供了相當多的功能使菜單中的代碼減至最少。PFC中的菜單包括彈出菜單和上下文菜單。表19-8是這些菜單的描述。
表19-8 PFC菜單對象描述
對 象 |
描 述 |
m_dw |
用於從u_dw繼承而來的數據窗口控件的彈出菜單 |
m_edit |
用於特定的標準可見用戶對象的帶有標準編輯選項的彈出菜單 |
m_oc |
用於從u_oc繼承而來的控件的具有OLE控件功能的彈出菜單 |
m_view |
用於從u_lv繼承而來的ListView控件的彈出菜單 |
當在某個窗口上使用相應的用戶對象時這些菜單將自動起作用。
在PFC菜單中實現的消息路由使用戶能夠將完成某個特定過程的消息發送到一個窗口。附加條件是菜單隻需知道執行的事件的名稱即可。消息路由通過使用of_SendMessage()函數搜索合適的對象來接收此消息。
消息路由函數Of_SendMessage()是從PFC菜單中的每個菜單項調用的,它接收要執行的事件名稱。路由反過來調用其對應窗口的pfc_MessageRouter事件。Pfc_MessageRouter隨後就按下列順序激活從菜單傳遞過來的事件:窗口、當前控件、最後是活動的數據窗口。如果用戶不想使用PFC菜單,但仍然想使用消息路由,則用戶所需做的一切就是將of_Message()和用戶可能需要的菜單項代碼移動至自己的菜單。
19.5 窗口和窗口服務
PFC包含若干基類窗口,這些窗口應該用做用戶的所有應用程序窗口的祖先。有若干服務也是提供附加功能的窗口所特有的。
|
PFC中窗口類層次乍一看起來容易引起混淆。所有PFC窗口的基類是pfc_w_master。圖19-2顯示了窗口的層次關係。
所有以pfc_開頭的對象都包含在祖先庫中,其他的對象包含在擴展庫中。這意味着從pfc_w_master到w_master再到pfc_w_main的層次結構是由祖先庫到後代庫再回到祖先庫。這樣做乍一看起來比較奇怪,實際上有很多優點。因爲開發人員對於PFC類庫的擴充應該限制在擴展庫中,而不應該修改祖先庫中的任何對象。但是,如何使對象功能的擴展體現在相關同類的對象中?因爲對父對象的修改可以自動體現在子對象中,所以使用繼承是最好的解決方法。對擴展庫中w_master的修改可以直接擴展祖先對象pfc_w_main等對象,而如果pfc_w_main等對象直接繼承自pfc_w_master,那麼就得在擴展庫中對所有後代窗口做同樣的修改(例如,w_main和w_sheet)。通過在層次中插入w_master,那麼開發人員就有了一個可以修改的共同的祖先,修改時就不必同祖先庫打交道了。
PFC中的每個窗口都提供了既定的功能,創建PFC應用時應該使用繼承從這些窗口來創建自己的窗口,這樣才能在自己的窗口中使用這些既定的功能。
19.5.1 基窗口服務
窗口是一個非常重要的控件,開發人員往往希望PFC中提供很多的基窗口服務功能。但是,查看PFC中的窗口服務(pfc_n_cst_winsrv),它少得讓開發人員出乎意料。主要只提供了一個窗口居中的函數of_Center(),它可以使窗口在用戶的屏幕上居中顯示。要使用基窗口服務,可以在自己窗口的Open事件中加入如下代碼:
This.of_SetBase(True)
This.inv_base.of_Center()
如果希望自己的PFC應用程序中的窗口都居中顯示,可以將上面的代碼添加到相應窗口祖先類中。
PFC中爲窗口提供的功能主要集中在pfc_w_master中,下面對它做詳細介紹。
19.5.2 pfc_w_master
PFC基類窗口pfc_w_master能夠創建和取消不同的窗口服務。此外它還包含了對菜單消息路由的處理,進一步的CloseQuery事件處理以及由PFC觸發的應用程序代碼的空用戶事件的處理。
創建和取消窗口的服務,可以通過調用of_Set<servicename>函數來實現。比如,啓動窗口的調整大小服務可以使用下面的腳本:
This.of_SetResize(True)
菜單消息路由事件pfc_MessageRouter定義在該基類窗口中,是PFC應用程序中菜單和窗口交互的必須事件。該事件接收傳遞過來的事件參數,並調用該參數指定的事件,調用順序是窗口的、活動控件的、活動數據窗口的事件。
當窗口關閉時需要保存一些用戶沒有保存的內容,或者做一些特定的處理工作。PFC提供了這方面的功能,開發人員只需要很少的代碼便可實現該功能。pfc_Save是實現該功能的一個重要事件,邏輯工作單元是實現該功能時用到的一個重要概念。
所謂邏輯工作單元是指爲了保證代碼的重用性和工作的完整性,將完成某工作的代碼分割成若干個組成部分,並採用一定的機制保證這些部分的協作來正確地完成該工作。在PFC中提供了邏輯單元服務,可以在適當的時候啓動該服務。自修改(self-updating)和邏輯工作單元關係緊密。所謂自修改就是指PFC中將控件的修改功能也封裝在控件中,在適當的時候(比如,觸發pfc_Save事件時)修改自修改對象中沒有保存的工作。
pfc_Save事件完成的功能就是由很多函數和事件來共同完成的,該事件檢測是否啓動邏輯工作單元服務,如果沒有啓動則啓動該服務,然後執行其他的腳本來觸發其他相應的事件,調用適當的函數來完成功能。該事件可以完成如下的功能:
l 保存self-updating對象的修改,比如n_ds DataStore,u_tvs TreeView和u_lvs Listview。
l 保存其他控件的改變。
l 控制修改哪些對象以及它們的修改順序。
l 保存窗口中其他對象的修改。
雖然該事件的組成和腳本比較複雜,但是使用卻很簡單。需要保存窗口中的工作時只需要簡單地調用w_master窗口的pfc_Save事件,然後判斷其返回值來決定執行的情況。表19-9是pfc_Save事件返回值的含義。
表19-9 pfc_Save事件返回值的含義
返 回 值 |
含 義 |
注 釋 |
1 |
成功 |
|
0 |
沒有修改 |
|
-1 |
接收文本錯誤 |
pfc_Save事件終止 |
-2 |
pfc_UpdatesPending執行錯誤 |
pfc_Save事件終止 |
-3 |
校驗規則錯誤 |
pfc_Save事件終止 |
-4 |
pfc_PreUpdate執行錯誤 |
pfc_Save事件終止 |
-5 |
pfc_BeginTran執行錯誤 |
pfc_Save事件終止 |
-6 |
pfc_Update執行錯誤 |
pfc_EndTran和pfc_DBError兩個事件完成,事件pfc_PostUpdate還沒有執行 |
-7 |
pfc_EndTran執行錯誤 |
pfc_PostUpdate事件沒有執行 |
-8 |
pfc_PostUpdate執行錯誤 |
|
-9 |
pfc_UpdatePrep執行錯誤 |
pfc_Save事件終止 |
根據返回值可以判斷pfc_Save事件執行的情況。另外,還需要對pfc_Save事件可能觸發的其他事件的情況。表19-10是對這些事件的描述。
表19-10 pfc_Save可能觸發的事件描述
事 件 |
描 述 |
注 釋 |
pfc_AcceptText |
窗口上的自修改對象執行AcceptText函數 |
w_master的of_AcceptText函數調用該事件 |
pfc_UpdatesPending |
判斷哪個自修改對象有可修改內容 |
w_master的of_UpdatesPending函數調用該事件 |
pfc_Validation |
對有修改內容的自修改對象進行校驗 |
非PFC的數據窗口對象可以使用of_Validation函數調用該事件 |
pfc_UpdatePrep |
空用戶事件,可以編寫自己的腳本來擴展邏輯單元的功能 |
當窗口作爲一個自修改對象時纔有必要擴充該事件 |
pfc_PreUpdate |
空用戶事件,可以編寫腳本提供附加的校驗規則 |
返回1表示執行成功,返回其他任意值就可以終止pfc_Save事件的執行 |
pfc_BeginTran |
空用戶事件,可以編寫腳本來和數據庫系統建立聯結 |
同上 |
pfc_Update |
爲所有自修改對象執行數據庫修改操作 |
對於非自修改對象可以擴充該事件來修改對象。返回1表示執行成功,返回-1表示執行失敗。如果返回-1,通過調用函數of_SetDBErrorMsg來創建錯誤錯誤消息,這時pfc_DBError事件將自動顯示錯誤信息 |
pfc_EndTran |
空用戶事件,可以編寫腳本來提交或者回退對數據庫的修改 |
根據從其他腳本傳遞過來的參數來決定是提交還是回退。當然,在其他地方也可以使用提交或者回退語句,但是這裏應該是最合適的地方 |
pfc_DBError |
修改錯誤時該事件顯示相應的錯誤信息 |
如果PFC的錯誤服務啓動則調用of_Message來顯示錯誤信息,否則調用MessageBox函數顯示錯誤信息 |
pfc_PostUpdate |
復位所有已修改對象的修改標記 |
當對pfc_Save事件進行擴充處理其他控件時一定要擴充該事件來複位它們的修改標記 |
pfc_Save該事件看起來可能感覺比較複雜,實際上使用還是比較簡單的。在窗口的pfc_CloseQuery事件中只需要簡單地調用w_master的事件pfc_Save,並根據其返回值決定下一步的操作即可。
19.5.3 其他窗口服務
除了上面介紹的基窗口服務和pfc_w_master外,PFC還提供另外的一些窗口服務,這些服務可以管理窗口的外觀、窗口中的配置信息與設置狀態欄等,可以以較少編碼實現非常友好的窗口界面,是經常用到的一些服務。這些服務如表19-11所示。
表19-11 其他窗口服務描述
服 務 |
功 能 |
Preference服務 |
用來管理ini文件或者系統註冊表中的相關信息 |
Status bar服務 |
狀態條管理,只適用於frame窗口 |
Sheet management服務 |
Sheet窗口管理,只適用於frame窗口 |
Resize服務 |
調整窗口及窗口上某些控件的大小 |
1.Preference服務
窗口Preference服務允許用戶保存和讀取包含在ini文件和Windows Registry中的用戶窗口設置的值。該服務保存諸如窗口大小、工具欄設置和窗口位置這樣的信息。要啓動該服務,在窗口的Open事件中使用如下腳本:
This.of_SetPreference(True)
缺省時,Preference服務保存所有的窗口設置信息,雖然這樣可以毫無遺漏地保存用戶的工作環境,但是這樣會降低程序的運行效率。可以只選擇保存一些重要的信息,或者提供界面讓用戶指定要保存的信息。可以調用相關函數來指定保存哪些信息,如表19-12所示。
表19-12 跟蹤窗口設置信息的函數描述
函 數 |
功 能 |
函 數 |
功 能 |
of_SetMenuItems |
跟蹤菜單設置 |
of_SetToolBars |
跟蹤工具欄位置 |
of_SetToolBarTitles |
跟蹤工具欄標題 |
of_SetToolBarItemOrder |
跟蹤工具欄項目的順序 |
of_SetToolBarItemSpace |
跟蹤工具欄項目間的間距 |
of_SetToolBarItemVisible |
跟蹤工具欄項目的可見性 |
of_SetWindow |
跟蹤窗口的屬性 |
|
|
表19-12所列的函數都有一個類型爲Boolean的參數,來指明是否保存數據。通常可以關閉那些不讓用戶修改的信息,一般工具欄中項目的順序、間距與標題不讓修改,菜單項目也不讓修改,可以調用函數of_SetToolBarItemOrder,of_SetToolBarItemSpace,of_SetToolBarTitles和of_SetMenuItems,並將函數的參數設置爲False。
使用相關函數指定了需要保存的信息後,在適當的事件中可以調用函數of_Save來保存這些信息。該函數的語法如下:
保存到系統註冊表時:instancename.of_Save ( registrykey )
保存到ini文件時: instancename.of_Save ( inifile, section )
其中,registrykey爲一個String型參數,用來指明要保存到系統註冊表的位置;inifile用來指明要保存到的ini文件名稱及其位置,section是該文件中的節。檢索這些取值時使用函數of_Restore,該函數的參數和of_Save完全相同。
2.狀態欄和工具欄服務
當創建一個MDI應用程序時,應該使用繼承從PFC中的w_frame來創建MDI框架,這樣可以利用PFC中爲frame窗口定義的各種服務功能。
Status Bar服務允許用戶在MDI框架的狀態欄中設置多個信息面板,包括當前的日期、時間以及內存信息等的顯示欄。要啓動該服務,在MDI框架的Open事件中編寫下面的腳本:
This.of_SetStatusBar(True)
然後使用表19-13所示的函數來顯示相應的信息。
表19-13 用於顯示信息的函數功能
函 數 |
作 用 |
of_SetGDI() |
在狀態欄中顯示GDI內存(16位) |
of_SetMem() |
在狀態欄中顯示計算機可用的內存 |
of_SetTimer() |
在狀態欄中顯示當前日期和時間 |
of_SetUser() |
在狀態欄中顯示當前用戶可用的內存 |
w_frame的MDI框架後代可以使用的其他增強因素還有Toolbar Control對話框。該對話框允許用戶操縱常用的工具欄屬性,例如工具欄的位置以及是否顯示PowerTips和工具欄中項目的文字。下面腳本可以打開工具欄窗口w_toolbars:
gnv_app.of_GetFrame.Event pfc_Toolbars()
3.Resize服務
當窗口或者標籤的大小改變時,它上面的其他控件的尺寸也應該按照一定的比例調整,否則有些控件就有可能顯示不下了。Resize服務可以實現對指定控件尺寸自動調整的功能。使用of_SetResize(True)啓動該服務,然後指定要調整哪些控件的大小,可以使用of_Register函數。該函數有兩種語法格式,比較常用的一種語法如下:
instancename.of_Register ( control, method )
其中,instancename是n_cst_resize類型變量的名稱,缺省爲inv_resize;control是WindowObject類型變量,是註冊要調整的控件;method是調整大小的方式,爲String類型或者n_cst_resize常量,指明當窗口的Resize事件觸發時以什麼方式來調整註冊控件的尺寸。可用的值如下:
l "FixedToRight"或者FIXEDRIGHT。
l "FixedToBottom"或者FIXEDBOTTOM。
l "FixedToRight&Bottom"或者FIXEDRIGHTBOTTOM。
l "Scale"或者SCALE。
l "ScaleToRight"或者SCALERIGHT。
l "ScaleToBottom"或者SCALEBOTTOM。
l "ScaleToRight&Bottom" or SCALERIGHTBOTTOM。
l "FixedToRight&ScaleToBottom" or FIXEDRIGHT_SCALEBOTTOM。
l "FixedToBottom&ScaleToRight" or FIXEDBOTTOM_SCALERIGHT。
瞭解上述各個項目功能的最好方法就是在腳本中逐個嘗試運行來看效果。缺省時Resize服務允許將窗口和控件縮小得看不清。爲了防止這種情況的發生,可以調用of_SetMinSize()來設置窗口的最小寬度和高度。
19.6 數據窗口服務
數據窗口作爲PB的一個核心控件,其功能在PFC中也得到了增強。PFC爲增強數據窗口功能而提供了一個u_dw用戶對象和一些函數、事件以及服務。要利用這些功能,應用程序中的所有數據窗口控件必須是數據窗口控件用戶對象u_dw的後代,並在適當的事件中調用適當的PFC函數或者事件即可。
在PFC提供的數據窗口服務中,Basic服務是最基本的服務,該服務包含了對所有其他數據窗口服務的引用。此外,該服務還提供了若干使用標準PowerScript函數的選擇方案,如Modify()和Describe(),提供了許多函數用於訪問數據窗口對象值。啓動該服務,只需要使用語句of_SetBase(True)。表19-14是數據窗口服務及其解釋。
表19-14 數據窗口服務
服 務 |
功 能 |
位 置 |
Basic DataWindow service (ancestor For all other services) |
基本數據窗口服務 |
n_cst_dwsrv |
DropDown Search service |
根據輸入的一個或者多個字母在下拉數據窗口中自動滾動 |
n_cst_dwsrv_dropdownsearch |
Filter service |
提供三種方式過濾數據窗口中的數據 |
n_cst_dwsrv_filter |
Find and Replace service |
查找和替換數據窗口中的數據 |
n_cst_dwsrv_find |
Linkage service |
提供一種在數據窗口之間建立聯繫的方法,比如主/從結構 |
n_cst_dwsrv_linkage |
MultiTable Update service |
控制一個數據窗口對象內修改多個數據表 |
n_cst_dwsrv_multitable |
Print Preview service |
提供普通的打印預覽功能 |
n_cst_dwsrv_printpreview |
DataWindow Property service |
數據窗口屬性服務 |
n_cst_dwsrv_property |
QueryMode service |
提供對特定查詢實現Query模式的能力 |
n_cst_dwsrv_querymode |
Reporting service |
提供增強的報表特徵,如添加項目、縮放和打印 |
n_cst_dwsrv_report |
Required Column service |
自動檢查所有指定的數據窗口列的值是否已輸入 |
n_cst_dwsrv_reqcolumn |
DataWindow Resize service |
當調整數據窗口控件大小時調整數據窗口對象中控件的大小 |
n_cst_dwsrv_resize |
Row Management service |
提供普通的數據行處理功能,如插入、刪除和恢復刪除等 |
n_cst_dwsrv_rowmanager |
Row Selection service |
提供數據行的單選、多選和擴展選擇的功能 |
n_cst_dwsrv_rowselection |
Sort service |
提供不同的機制對數據窗口中的數據進行排序 |
n_cst_dwsrv_sort |
下面爲初學者介紹幾個常用的數據窗口服務。
數據窗口的Sort服務使用戶能夠用四種方式指定數據的排序條件,以多種方式進行排序。使用of_SetSort(True)語句啓動數據窗口的Sort服務後,可以在適當控件的適當事件中編寫腳本來實現排序。比如,可以提供按鈕讓用戶來指定排序條件,還可以讓用戶只點擊數據窗口控件的標題欄(header)來完成,具體採用哪種方式排序可由開發人員的開發風格決定。點擊標題欄來排序需要首先調用函數of_SetColumnHeader,函數語法如下:
dwcontrol.instancename.of_SetColumnHeader ( boolean )
其中,dwcontrol爲數據窗口控件名稱(該數據窗口爲u_dw對象的後代);instancename爲用戶對象n_cst_dwsrv_sort的實例變量,缺省爲nv_sort;boolean指定是否以標題欄進行排序。
函數of_SetStyle用來設定要使用哪種方式讓用戶來設定排序條件。函數的語法如下:
dwcontrol.instancename.of_SetStyle ( sortstyle )
其中,dwcontrol和instancename兩個參數與上面的含義完全相同;sortstyle爲一個整型參數,它的取值及含義如下:
DEFAULT或者0 PowerBuilder對話框
DRAGDROP或者1 用w_sortdragdrop進行拖放排序
SIMPLE或者2 用w_sortsingle進行單一排序
DROPDOWNLISTBOX或者3 用w_sortmulti進行多個排序
當參數SortStyle取值爲3時,數據窗口中的每個數據欄都必須有一個對應的文本對象。下面是一段例程:
dw_emplist.of_SetSort(True)
dw_emplist.inv_sort.of_SetColumnNameSource(2)
dw_emplist.inv_sort.of_SetUseDisplay(True)
dw_emplist.inv_sort.of_SetStyle (dw_emplist.inv_sort.DRAGDROP)
19.6.2 查找和替換服務
當需要爲用戶提供在數據窗口中查找或者替換內容時,使用PFC的查找和替換服務可以大大節省編碼的工作量。首先使用of_SetFind(True)來啓動該服務,然後可以編寫腳本來激活該服務。例如:
If IsValid(inv_find) Then
inv_find.Event pfc_ReplaceDLG()
End If
19.6.3 DropDown Search服務
數據窗口對象中使用下拉數據窗口編輯風格的字段,可以方便用戶錄入數據,並能在一定程度上保證錄入數據的規範。但是,如果下拉框中包含的數據過多(3頁以上時),使用這種錄入方式有時還不如直接錄入快捷。如果能夠在用戶輸入前面的字母時下拉框能夠自動顯示與之匹配的選項,無疑可以加快錄入的速度。PFC中提供DropDown Search服務,可以讓用戶在下拉框中鍵入字母時自動進行匹配查找。缺省時,下拉框允許用戶鍵入一個字母,PowerBuilder使用戶移動到所鍵入字母開始的第一行。遺憾的是,用戶無法鍵入多個字母來查找更適合的項目。
首先應該使用of_SetDropDownSearch(True) 啓動該服務。然後,指定想讓數據窗口中哪些欄具有搜索功能,並使用下面函數打開此功能:
dwcontrol.instancename.of_AddColumn ( { column } )
其中,dwcontrol爲基於u_dw用戶對象的數據窗口對象;instancename爲n_cst_dwsrv_dropdownsearch實例變量,缺省爲inv_dropdownsearch;可選參數column是String類型的,用來指定要添加到istr_columns數組中的列,該列應該是下拉數據窗口的編輯樣式,並且包含的數據類型爲String類型,如果省略該參數則添加數據窗口對象中所有的具有下拉數據窗口編輯樣式的字段。
最後一個步驟是將數據窗口控件的EditChanged和ItemFocusChanged事件重定向到其對應的PFC事件pfc_EditChanged和pfc_ItemFocusChanged。例如,在EditChanged事件中可以編寫如下腳本來重定向事件:
inv_dropdownsearch.Event pfc_EditChanged(row,dwo,data)
19.6.4 Required Column服務
爲了保證用戶在非空字段中必須輸入數據,原來常用的方法是將字段的Required屬性設置爲True。但是,這樣做經常在沒有輸入數據的字段失去焦點時顯示提示窗口,這容易導致用戶爲了繞過該信息而隨便輸入數據。爲了解決這個問題,還可以編寫腳本在數據提交之前檢驗是否在所有的必須輸入字段中輸入了數據。Required Column服務爲開發人員解決了該問題。
爲了使用該服務,首先使用of_SetReqColumn(True)來啓動該服務。選中數據窗口對象中字段的Required屬性(使該屬性的取值爲True),當窗口激活pfc_Save事件時,PFC自動進行檢查以確保Required字段都有值。
該服務還提供了幾個函數以便編程靈活控制。比如,當需要使用PowerBuilder本身的處理機制來校驗一些Required字段時,可以調用of_RegisterSkipColumn 函數,該函數的語法如下:
dwcontrol.instancename.of_RegisterSkipColumn ( column )
其中,dwcontrol是基於u_dw 的數據窗口控件名稱;instancename是n_cst_dwsrv_reqcolumn 實例變量名稱,缺省是inv_reqcolumn ;column是String類型的參數,是數據窗口中字段的名稱。例如:
dw_emplist.inv_reqcolumn.of_RegisterSkipColumn ("dept_id")
19.6.5 Linkage服務
數據窗口的Linkage服務對於協調兩個或者多個數據窗口之間的處理是極其方便的。Linkage服務最常見的服務是提供一個主/從關係的兩個數據窗口。下面逐步介紹使用該服務的過程。
a. 調用of_SetLinkage(True)啓動服務。例如:
dw_order_header.of_SetLinkage(True)
dw_order_detail.of_SetLinkage(True)
b. 調用of_SetMaster建立主從數據窗口之間的聯繫。例如:
dw_order_detail.inv_linkage.of_SetMaster(dw_order_header)
主從數據窗口之間的聯繫是通過它們的字段之間的聯繫來實現的。
c. 調用of_SetTransObject爲主從數據窗口設置事務對象。例如:
dw_order_header.of_SetTransObject(SQLCA)
d. 調用of_Register設置主從數據窗口之間相聯繫的字段。例如:
dw_order_detail.inv_linkage.of_Register ("header_emp_id","detail_emp_id")
e. 設置主從數據窗口數據修改的順序。例如:
dw_order_detail.inv_linkage.of_SetUpdateStyle(dw_order_detail.inv_linkage.BOTTOMUP)
當不設置數據的修改順序時,則使用先主後從的缺省修改方法。
f. 調用of_SetStyle來設置當主數據窗口中數據發生改變時如何改變從數據窗口中的數據。例如:
dw_order_detail.inv_linkage.of_SetStyle (dw_order_detail.inv_linkage.RETRIEVE)
該語句指定當主數據窗口中的數據改變時檢索從數據窗口中的數據。函數of_SetStyle可以設置主數據窗口數據行變化時從數據窗口的動作。該函數的參數可用的取值及其含義如下:
1或者FILTER 過濾從數據窗口;
2 或者RETRIEVE 檢索從數據窗口;
3 或者SCROLL 滾動從數據窗口。
前面6個步驟的設置工作可以在一個事件中完成,比如典型情況是在窗口的Open事件中完成。
g. 前面幾個步驟完成了必須的設定,下面就應該檢索數據了。調用of_Retrieve函數檢索數據。例如:
If dw_order_header.of_Retrieve( ) = -1 Then
MessageBox("錯誤","數據檢索錯誤!")
Else
dw_order_header.SetFocus( )
End If
h. 在主數據窗口的pfc_Retrieve事件中編寫腳本檢索數據:
Return This.Retrieve( )
下面介紹一個完整的實例。假設兩個數據窗口建立主從關係,dw_order_header爲主數據窗口,dw_order-detail爲從數據窗口。在窗口的Open事件中編寫如下腳本:
dw_order_header.of_SetLinkage(True)
dw_order_detail.of _SetLinkage(True)
dw_order_header.of_SetTransObject(SQLCA)
dw_order_detail.inv_linkage.of_SetMaster(dw_order_header)
dw_order_detail.inv_linkage.of_Register ("header_emp_id","detail_emp_id")
dw_order_detail.inv_linkage.of_SetStyle(inv_linkage.SCROLL)
dw_order_detail.inv_linkage.of_SetStyle (dw_order_detail.inv_linkage.RETRIEVE)
dw_order_header.of_Retrieve()
19.6.6 MultiTable Update服務
該服務爲用戶提供了在一個數據窗口中修改多個數據表的功能。在過去的開發中,一個數據窗口中要修改多個數據表時,需要使用語句逐個修改數據窗口對象的相關屬性,然後逐個修改數據表,這樣編寫腳本的工作量比較大。PFC爲開發者提供了一種易於使用的方法,讓開發者以較少的腳本就可以實現在一個數據窗口中修改多個數據表的功能。當數據窗口中包含來自多個數據表的字段,並且這些字段都有可能要修改數據表,這時可以考慮使用該服務。
首先應該調用of_SetMultiTable(True)來啓動該服務,該服務不像其他大多數的服務,它可以在數據窗口註銷時自動註銷。接下來調用of_Register函數註冊每個數據表修改時的信息,最後在數據保存時調用pfc_Save事件,該事件可以逐個保存數據窗口中不同數據表的數據。
函數of_Register是該服務中一個非常重要的函數,它的語法格式是:
dwcontrol.instancename.of_Register ( table, keycolumns
{ updatablecolumns {, keyinplace, whereoption } } )
其中,dwcontrol爲基於u_dw的數據窗口控件名稱;instancename爲n_cst_dwsrv_multitable類型的實例變量,缺省爲inv_multitable;table爲要修改的數據表的名稱,爲String類型參數;keycolumns爲String類型的數組,爲要修改的數據表的關鍵字段(Key Column);updatablecolumns爲String類型的數組,用來指定可以修改的字段,缺省情況下爲table參數指定的表中所有字段;keyinplace爲Boolean類型參數,用來表示是先刪除行然後再插入(False)還是在主關鍵字發生變化時就在原位進行更新(True),該參數缺省取值爲False;當指定了參數keyinplace時必須也設定參數whereoption,該參數爲整型,表示如何創建UPDATE和DELETE語句的WHERE子句(0表示關鍵字欄,1表示關鍵字和可更新欄,2表示關鍵字和已更新欄)。後三個參數爲可選參數,如果不指定這些可選參數則使用缺省取值。
下面是一段例程爲數據窗口中註冊可修改表及其關鍵字段:
String ls_projcols[ ] = {"proj_id"}
String ls_taskcols[ ] = {"proj_id", "task_id"}
dw_project.inv_multitable.of_Register("project", ls_projcols)
dw_project.inv_multitable.of_Register("task", ls_taskcols)
該腳本註冊數據窗口dw_project中以proj_id字段爲關鍵字修改數據表project,以proj_id和task_id爲關鍵字修改數據表task。
19.6.7 Row Management 服務
對數據窗口中的數據行經常要進行刪除、插入或恢復刪除等操作。Row Management服務可以提供這些功能。PFC通過n_cst_dwsrv_rowmanager用戶對象來進行行管理。該服務提供的功能具體有:
l 在數據窗口最後一行添加一個空記錄;
l 在已有的數據行之間插入一個空記錄;
l 刪除一行或者多行數據;
l 顯示一個對話框,允許用戶選擇那些已刪除的數據行恢復。
首先調用of_SetRowManager(True)啓動該服務,接下來根據不同的操作調用相應的函數即可。下面對這些功能分別舉例說明。
(1)在數據窗口最後一行添加一個空記錄
只需要調用pfc_AddRow事件即可。例程如下:
Long ll_return
ll_return = dw_emplist.inv_rowmanager.Event pfc_AddRow()
If ll_return = -1 Then
MessageBox("錯誤", "不能正常添加空記錄!")
End If
(2)在已有的數據行之間插入一個空記錄
只需要調用pfc_InsertRow事件即可。例程如下:
Long ll_return
ll_return = dw_emplist.inv_rowmanager.Event pfc_InsertRow()
If ll_return = -1 Then
MessageBox("Error", "Insert error")
End If
(3)刪除一行或者多行數據
只需要調用pfc_DeleteRow事件即可。例程如下:
Long ll_return
ll_return = dw_emplist.inv_rowmanager.pfc_DeleteRow()
If ll_return = -1 Then
MessageBox("Error", "Deletion error")
End If
(4)恢復已刪除數據行
只需要調用pfc_ RestoreRow事件即可。該事件另外打開一個窗口,將最近一次提交後刪除的所有記錄列出,用戶可以指定將哪些數據恢復。如果沒有刪除數據,則直接提示沒有刪除數據而不打開該窗口。例如:
dw_1.inv_rowmanager.Event pfc_RestoreRow()
19.7 可視化控件
PFC中的可視化控件包括標準可視用戶對象和定製可視用戶對象兩種。標準可視用戶對象擴充了PowerBuilder的控件,一般由一個標準控件擴充,爲其提供一些附加的邏輯,增強了控件的可重用性和函數功能。使用PFC提供的TreeView控件u_lb可以充分體現功能的強大。定製可視用戶對象一般是由幾個控件組成一個單元,並增加相應的邏輯結構來完成一定的處理功能。日曆控件u_calculator是一個實例。
對於標準可視控件,本節介紹它的基本函數,作爲一個實例介紹數據窗口控件u_dw。其他內容可以參見相關的PowerBuilder本身提供的Online Books。
19.7.1 標準可視用戶對象的基本函數
標準可視用戶對象繼承自PowerBuilder的標準控件,並進行了適當的擴充。當然,開發人員也可以再做適當的擴充,以使之更適合自己的商業規則。下面分別介紹標準可視用戶對象的基本函數。
1.剪切、拷貝和粘貼
編輯性的控件包括一些基本的編輯函數和其他相關的編輯控制函數。表19-15列出了和PowerBuilder中的控件相對應的PFC控件。
表19-15 控件對照
PB控件 |
PFC控件 |
PB控件 |
PFC控件 |
DropDownListBox |
u_ddlb |
DropDownPictureListBox |
u_ddplb |
DataWindow |
u_dw |
EditMask |
u_em |
MultiLineEdit |
u_mle |
OLE Custom control |
u_oc |
RichTextEdit |
u_rte |
SingleLineEdit |
u_sle |
PFC通過爲PB的標準控件定義事件並提供相應的腳本來提供這些編輯功能。例如,Clear功能是提供pfc_Clear事件及有關的腳本來完成的,開發人員需要完成此功能時只需要調用該事件即可。功能和事件對照如表19-16所示。
表19-16 功能和事件對應關係
功 能 |
事 件 |
功 能 |
事 件 |
Clear |
pfc_Clear |
Copy |
pfc_Copy |
Cut |
pfc_Cut |
Paste |
pfc_Paste |
Select All |
pfc_Select All |
Undo |
pfc_Undo |
Paste Special |
pfc_PasteSpecial |
|
|
當在窗口中使用這些PFC控件並且窗口菜單也是繼承自m_master時,這些編輯功能自動起作用。m_master菜單中包括一個含有所有編輯功能的下拉菜單,只要在控件中通過消息路由發送相應的消息即可調用相關功能。
2.彈出菜單
編輯性的控件提供RbuttonUp事件,在用戶點擊鼠標右鍵時彈出菜單,提供一些編輯命令的快捷使用方式。不同的控件提供不同的右鍵彈出菜單,如表19-17所示。
表19-17 彈出菜單
菜 單 |
控 件 |
m_edit |
u_ddlb,u_ddplb,u_em,u_mle,u_rte,u_sle |
m_dw |
u_dw |
m_lvs |
u_lvs |
m_oc |
u_oc |
m_tvs |
u_tvs |
這些菜單都提供基本的文本編輯功能。但是缺省情況下,並不是所有菜單中的這些基本編輯功能都可用,有些菜單項還是不可見的。這些控件都提供了pfc_PreRMBMenu事件,該事件在菜單創建之後顯示之前觸發,可以在該事件中編寫腳本來定製菜單的顯示。比如,取消m_dw菜單中的插入、刪除菜單項可以在該事件中編寫如下腳本:
am_dw.m_table.m_insert.Enabled = False
am_dw.m_table.m_delete.Enabled = False
其中,am_dw爲pfc_PreRMBMenu事件的參數,該函數是通過引用方式傳遞的。還可以禁用右鍵彈出菜單,尤其在控件中的內容爲只讀時。只需要在有彈出菜單的控件中編寫腳本即可,典型是在Constructor事件中編寫如下腳本:
This.ib_rmbmenu = False
對於數據窗口的菜單m_dw可以省略該腳本,因爲當數據窗口爲只讀時PFC將自動禁用它的右鍵彈出菜單。
另外,還可以在menu畫板中對上面的菜單進行擴充,添加自己的菜單項。
3.自動滾動
DropDownListBox和DropDownPictureListBox兩個控件提供用戶鍵入字母時自動滾動到匹配的選項上。這個功能有點類似於下拉數據窗口中的DropDown and Search服務。比如,當在這兩個控件中鍵入g時自動滾動到以g開頭的第一個選項,繼續鍵入b則滾動到第一個以gb開頭的選項。
缺省情況下,這兩個控件的自動滾動功能不可用。典型編程事件是Constructor,編寫如下腳本即可使該功能可用:
This.ib_search = True
4.自動選中
編輯性的控件獲得焦點時,自動選中其中的文字內容。提供該功能的可編輯性控件有u_ddlb,u_ddplb,u_em,u_mle和u_sle。缺省情況下,這些控件的自動選中功能不可用。典型編程事件是Constructor,編寫如下腳本即可使該功能可用:
This.ib_autoselect = True
5.顯示微幫助
大多數控件都在GetFocus事件中提供了腳本,在相應的Frame窗口中顯示Tag值作爲微幫助。當控件獲得焦點時,觸發GetFocus事件,該事件中提供了已經編寫好的腳本來觸發控件所在窗口的pfc_ControlGotFocus用戶事件。pfc_ControlGotFocus事件將控件的Tag值作爲微幫助顯示在狀態欄中。
開發人員要使用該功能,只需要在適當的事件中編寫腳本。首先應該允許顯示微幫助,使用如下腳本:
gnv_app.of_SetMicroHelp(True)
然後將控件的Tag值作爲微幫助,使用下面腳本:
MicroHelp=tagtext
6.反顯選中項目
ListBox和PictureListBox提供反顯項目的功能。當調用這兩個控件的pfc_InvertSelect事件時,已經高亮顯示的項目取消高亮顯示,沒有高亮顯示的項目高亮顯示。
在菜單或者窗口的這兩種控件中都可以編寫腳本使用該功能。在菜單中只要編寫如下腳本即可:
of_SendMessage("pfc_InvertSelection")
在窗口的控件中,可以編寫如下腳本:
lb_choices.Event pfc_InvertSelection() //在控件lb_choices的適當事件中
19.7.2 數據窗口控件u_dw
PFC提供了高級標準可視控件,這些控件的使用可以更多地提高開發效率,開發出功能更爲強大的應用程序。這些高級控件以及它們和PowerBuilder標準控件的對應關係如表19-18所示。
表19-18 控件對照
PB控件 |
PFC控件 |
PB控件 |
PFC控件 |
DataWindow |
u_dw |
ListView |
u_lvs |
TreeView |
u_tvs |
RichTextEdit |
u_rte |
OleControl |
u_oc |
Tab |
u_tab |
Tab page |
u_Tabpg |
|
|
其中,數據窗口控件u_dw是一個非常重要的控件。在前面一節中已經對數據窗口服務做過了詳細的介紹,這裏只對該控件的其他內容做詳細介紹。其他控件可以參見PowerBuilder自帶的Online Books中的相關章節。
u_dw控件繼承自PB的數據窗口,提供了一些內置的擴展函數或者事件。說明如下。
(1)啓動或者停止數據窗口服務的函數
PFC爲數據窗口提供的服務以及如何停、啓這些服務在前面一節都做過了詳細的介紹,此處不再贅述。
(2)設置事務對象的函數
當事務對象爲n_tr類型時可以爲u_dw設置事務對象。使用函數of_SetTransObject可以設置事務對象,以後可以通過實例變量itr_object來引用該事務對象。
對於使用了Linkage服務的主從數據窗口,只有當主從關係都建立好後才能設置事務對象,只需要調用n_cst_dwsrv_linkage的of_SetTransObject函數爲主窗口設置即可。這些都在前面介紹數據窗口的服務時做過了詳細介紹。
(3)爲數據窗口或者下拉數據窗口檢索數據的事件
當檢索基於u_dw的數據窗口中的數據時,應該調用of_Retrieve函數。該函數根據具體情況或者調用數據窗口的pfc_Retrieve事件,或者調用n_cst_dwsrv_linkage的of_Retrieve函數,這取決於是否啓動了數據窗口的Linkage服務。在pfc_Retrieve事件中應該編寫腳本來檢索數據。比如,在數據窗口的Constructor事件中編寫如下腳本:
Long ll_return
ll_return = This.of_Retrieve()
在數據窗口的pfc_Retrieve事件中編寫如下腳本:
Return This.Retrieve()
當使用Linkage服務建立了主從數據窗口時,如果主從聯結方式爲Retrieve,則只需要在主數據窗口的pfc_Retrieve事件中編寫和上面相同的腳本;主從數據窗口使用其他聯結方式時,則應該在每一個從數據窗口的pfc_Retrieve事件中也編寫和上面相同的腳本。
需要檢索下拉數據窗口中的數據時,在數據窗口的pfc_PopulateDDDW事件中編寫腳本。該事件在彈出下拉數據窗口時觸發。例如,腳本如下:
If as_colname = "dept_id" Then //使用事件參數來判斷是否當前列爲dept_id
adwc_obj.SetTransObject(SQLCA) //使用事件參數爲數據窗口設置事務對象
Return adwc_obj.Retrieve() //返回檢索到的數據
Else
Return 0 //當前是其他列,則直接返回
End If
(4)控制數據窗口數據修改的事件
PFC提供了兩種修改控制數據的方式,一種是通過u_dw的pfc_Update事件;一種是通過w_master窗口的pfc_Save事件。前一種方式中,通過調用相關事件完成數據修改,不需要Logic Unit服務,並且當數據窗口的MultiTable服務啓動時自動調用n_cst_dwsrv_multitable的of_Update來修改各個數據表,這種方式需要數據窗口都是基於u_dw的。後面這種修改方式需要Logic Unit服務(可以自動啓動該服務),自動調用相關函數修改窗口上的所有數據窗口中的數據,對於非基於u_dw的數據窗口自動調用PowerScript函數來修改。使用這種修改方式要求窗口都是繼承自PFC的w_master,因爲在該窗口的子窗口中事件pfc_Save都可用。
當只修改窗口中的一個數據窗口中的數據時可以使用如下腳本:
If dw_emplist.Event pfc_Update (True, True) = 1 Then //如果修改成功
SQLCA.of_Commit() //提交
Else //否則
SQLCA.of_Rollback() //回退
End If
當修改窗口上的多個數據窗口中的數據時,可以調用如下腳本:
Integer li_return
li_return = w_emp.Event pfc_Save() //調用pfc_Save事件
If li_return < 0 Then
MessageBox("錯誤提示", "修改失敗,錯誤代碼爲"+String(li_return))
Else
gnv_app.of_GetFrame().SetMicroHelp ("修改成功")
End If
當窗口中包含多個數據窗口,多數允許保存,少數不允許保存,這時可以使用pfc_Save事件保存,使用函數of_SetUpdateable將少數數據窗口定義爲不可修改的。例如:
dw_emplist.of_SetUpdateable(False)
當數據窗口中的數據發生了修改,並且窗口關閉之前用戶沒有保存數據,系統將觸發CloseQuery事件,該事件調用pfc_Save事件,顯示詢問窗口詢問用戶是否保存數據,根據用戶的選擇決定是否保存。
(5)控制打印的事件
u_dw控件允許用戶以三種方式進行打印前的設置。第一種,顯示一個打印對話框,用戶可以在該窗口中指定打印參數。要使用這種方式,只需要調用pfc_Print事件即可,比如下面設定數據窗口dw_emp以這種方式進行設置:
dw_emp.Event pfc_Print()
用戶指定的打印參數都保存在PFC提供的結構s_printdlgattrib中,可以在pfc_PrePrintDlg事件中修改該結構成員變量的取值來進一步定製打印參數。比如,可以在該事件中編寫如下腳本:
astr_printdlg.l_copies = 2 //定義打印2份
第二種方式是直接打印,不顯示任何信息。要使用這種方式,只需要調用pfc_PrintImmediate事件即可。比如下面事件觸發時立即打印數據窗口dw_emp中的內容:
dw_emp.Event pfc_PrintImmediate()
第三種方式是顯示一個打印紙設置對話框,用戶可以指定打印紙參數。使用這種方式只需要調用數據窗口的pfc_PageSetup()事件即可。比如,下面的語句可以讓用戶在打印之前設定紙張參數:
dw_emp.Event pfc_PageSetup()
在顯示該配置對話框時可以觸發pfc_PrePageSetupDlg事件,可以在該事件中提供一些缺省的或者建議性的參數設置。比如,在事件中編寫下面的腳本可以在紙張設置對話框打開時設定缺省的打印方式:
astr_pagesetup.b_portraitorientation = True
(6)添加服務
明白PFC中的服務和服務所依附的對象並且瞭解PFC的體系結構後,就可以對某種對象增加新的服務形式來提供增強功能。比如,需要爲數據窗口提供一個新的服務時,可以從基類對象n_cst_dwsrv繼承。在u_dw類中添加一個指向該服務的實例引用變量,在u_dw類中聲明一個名稱類似於of_SetXXX的對象函數來停、啓該服務,並編寫相應的代碼即可。