PFC入门
數據庫快速開發工具 PowerBuilder 從5.0版本開始提供了一套基礎類庫PFC(PowerBuilder Foundation Class),使得應用程序的開發速度又提高了一大步。由于PFC使用的不是很廣泛,許多開發者對此還不是很了解。下面就我使用的過程中所得到的心得與遇到的問題,整理出來與大家共享與探討。各位覺得有不合適的地方,希望批評指正。
PFC的幫助對各個獨立服務、事件或者函數有一些實例代碼,但是對于整體的使用幾乎沒有很全面地介紹。因此,我寫這些東西,作為PFC幫助的一個輔助材料,大部分是在PFC幫助上沒有的內容,是我使用PFC的過程中的總結與歸納。
PFC入門
首先,介紹一下如何創建一個簡單的PFC應用程序。
構造一個簡單的PFC程序框架
使用PFC,我們得先學會使用PFC構造一個簡單的應用程序。我們可以根據PFC幫助提供的模式來構造我們的應用程序框架(參見PFC幫助的Overview 中的 For a quick start項),也可以查看PFC例程(Peat、Example等)仿造構造我們的應用程序。下面簡單的陳述一下我通常使用PFC構造應用程序的步驟:
設置n_mdl_app的相關事件的代碼,可參見PFC例程的程序代碼;
- 在Additional Properties中,更改Variable Types 頁中的3個變量(SQLCA->n_tr; Error->n_err; Message->n_msg)(參考PFC例程Peat)
 - 根據需要更改默認字體的類型及大小(由于我們開發的都是中文界面的應用程序,所有字體更改為“宋體 9pt”),根據需要更改應用程序的圖標;
 - 根據需要更改其他的屬性,比如:DisplayName, MicroHelpDefault, 等等;
 - 另外,我還需要更改應用對象的SystemError事件的代碼,我使用的是逄新利編寫的一個錯誤陷阱模塊。
 
好了,到此為止,一個PFC應用程序框架就完成了。試著運行一下,可以看到框架窗口的運行狀態。
添加一個工作區窗口
應用程序框架窗口實現出來了,為了能夠工作,我們還得有工作區窗口(Sheet)。
首相,隨便創建一個Grid型的數據窗口對象,保存為d_demo1。然后從w_sheet窗口繼承出來一個窗口對象,然后在這個窗口中放置一個用戶對象u_dw(數據窗口的基礎祖先對象)。該數據窗口控件的數據對象為剛才創建的數據窗口對象d_demo1。
在窗口的Open事件中編寫如下代碼:
// 開啟Resize服務
 this.of_SetResize(True)
 //設置Resize服務的原始大小
 this.inv_Resize.of_SetOrigsize( dw_Demo.Width + dw_Demo.X * 2, dw_Demo.Height + dw_Demo.Y * 2 )
 //注冊要實施Resize服務的控件及方法
 this.inv_Resize.of_Register(dw_Demo,this.inv_Resize.SCALERIGHTBOTTOM)
 //異步觸發事件,利用消息路由發送消息。該消息是要檢索數據
 this.Event Post pfc_MessageRouter('pfc_Retrieve')
在數據窗口控件的Constructor事件中編寫如下代碼:
this.of_SetTransObject(SQLCA)??????? // 設置事物對象
 this.of_SetBase(True)??????? // 開啟數據窗口基本服務
 this.of_SetPrintPreView(True)??????? // 打印預覽服務
 this.of_SetRowManager(True)??????? // 行管理服務
 this.of_SetRowSelect(True)??????? // 行選擇服務
 this.of_SetFind(True)??????? // 查找服務
 this.of_SetSort(True)??????? // 排序服務
 this.of_SetFilter(True)??????? // 篩選服務
 this.inv_RowSelect.of_SetStyle(this.inv_RowSelect.EXTENDED)??????? // 設置行選擇服務為高級選擇模式,支持Ctrl & Shift鍵
 this.inv_Sort.of_SetStyle(this.inv_Sort.DROPDOWNLISTBOX)??????? // 設置排序服務的對話框樣式
 this.inv_Filter.of_SetStyle(this.inv_Filter.SIMPLE)??????? // 設置篩選服務的對話框樣式
 this.inv_Sort.of_SetColumnDisplayNameStyle(this.inv_Sort.HEADER)??????? // 設置排序服務的顯示內容
 this.inv_Filter.of_SetColumnDisplayNameStyle(this.inv_Filter.HEADER)??????? // 設置篩選服務的顯示內容
 
在數據窗口控件的pfc_Retrieve事件中編寫如下代碼:
Return this.Retrieve()
 
如果該窗口需要保存數據,在窗口的pfc_EndTrans事件中編寫如下代碼:
Integer li_TransRtn
If ai_Update_Results = 1 Then
 ?? // 如果更新數據庫成功, 則提交事務
 ?? li_TransRtn = SQLCA.Of_Commit()
 Else
 ?? // 否則, 回滾事務,并提示信息
 ?? li_TransRtn = SQLCA.Of_Rollback()
 ?? of_Messagebox('Update DB Failed','提示','數據保存失敗。',Exclamation!,OK!,1)
 End If
 // 返回該事件發生的情況 SUCCESS & FAILURE 是w_master的實例變量
 If li_TransRtn = 0 Then
 ?? Return SUCCESS
 Else
 ?? Return FAILURE
 End If
 
如果該窗口的數據不需要保存,則要將數據窗口控件的ib_UpdateAble屬性選擇為False,這樣在更改了數據以后,關閉窗口是不會提示類似于“數據以更改,是否保存”等的信息了。
將該窗口命名保存為w_Demo1。
在應用程序的主菜單上添加一個項目,編寫該項目的Clicked事件代碼為:
Message.StringParm = 'w_demo'
 of_SendMessage('pfc_open')
 
好了,運行應用程序,看一下運行的效果吧。你可以查看以下的效果:
- 使用鼠標右鍵單擊數據窗口,查看數據窗口的右鍵菜單;
 - 刪除一條數據,然后右鍵單擊數據窗口,選擇“Restore”項,看一看恢復刪除的功能;
 - 點擊窗口菜單上的“Sort”、“Filter”、“Print Preview”,“Find”,“Replace”等菜單項,查看數據窗口的“排序”、“篩選”、“打印預覽”,“查找”,“替換”等的功能;
 - 點擊菜單[View]的[First/Prior/Next/Last]等菜單項,查看數據窗口的翻頁功能;
 - 修改部分數據,關閉窗口,查看提示保存的對話框
 
以上的這些功能,使用PFC的時候,簡單到只需設置某項屬性或者編寫一句開啟某項服務的語句即可實現。如果你想對某項服務提出更高的要求,比如排序服務,你想更改服務的模式由默認的PB拖放排序方式改為下拉列表框方式,還需要一行命令來更改服務的方式。
完善并增加更多的功能
如果您想增加更多的更強大的功能,比如閃屏,登錄窗口等等。下面就簡單的介紹一下增加這些功能的簡單的方法。順便介紹一下我們可也在這些事件中添加的代碼和開啟的服務。涉及到的有關的具體問題會在以后慢慢的了解到。
通過查看PFC例程Peat的代碼,我們知道可以在“應用程序管理器”對象(gnv_App的對象)的Contructor事件中初始化版本、公司、INI文件等的信息(實例變量值,這些值大多可以在屬性窗口中設置),可以在“應用程序管理器”對象的pfc_Open事件中開啟需要的應用程序服務,這些服務包括:應用程序選項服務、數據窗口緩存服務、錯誤信息服務、調試服務、安全服務、事務注冊服務、最近使用對象服務等等。
其次,我們可以在該對象的pfc_PreAbout,pfc_PreSplash,pfc_PreLogonDlg事件中添加代碼來定制“關于”、“登錄”以及閃屏對話框的顯示。在這三個事件中各有一個參考型的參數,這些參數是相應的屬性對象實例,開發人員可以改變這些對象的屬性,來達到控制對話框顯示信息目的。如果不更改,將按照默認的樣式現實。
如果需要,“應用程序管理器”對象的pfc_Idle,pfc_ConnectionBegin、pfc_ConnectionEnd事件中編寫代碼,并在應用的相應事件中觸發這些事件。
如果需要顯示登錄窗口,需要完成以下步驟:
- 在框架窗口的Open事件中調用of_LogonDlg()函數: 
Integer??????? li_Rtn
//調用函數打開登錄對話框
li_Rtn??????? = gnv_App.of_LogonDlg()
If li_Rtn = 1 Then?? this.SetMicroHelp('Logon Successful')
Else?? If li_Rtn = -1 Then
????? MessageBox('Logon','Logon Failure' + String(li_Rtn))
?? End If
?? //Close(this)
?? Halt Close
End If
 - 在“應用程序管理器”對象的pfc_Logon事件中添加代碼來處理用戶的登錄。例如可以是如下的代碼: 
Integer??????? li_Rtn
String??????? ls_IniFile
ls_IniFile??????? = this.of_GetAppIniFile()
If SQLCA.of_Init(ls_IniFile,"DataBase") = -1 Then
?? li_Rtn??????? = FAILURE
End If
//as_UserID & as_Password為傳遞給事件的參數
SQLCA.of_SetUser(as_UserID,as_Password)
If SQLCA.of_Connect() = -1 Then
?? li_Rtn??????? = FAILURE
Else
?? gnv_App.of_SetUserID(as_UserID)
?? li_Rtn??????? = SUCCESS
End If
Return??????? li_Rtn
 
其實,在我們大多開發的應用程序中,登錄窗口檢驗的是我們存放在數據庫中的用戶列表,而不是登錄數據庫的用戶身份驗證。開發人員可根據需要自行更改。
另外,我們可以開啟框架窗口的狀態條服務和工作區窗口(Sheet)管理服務。要開啟這兩個服務,我們只需在框架窗口的Open事件中編寫相應的代碼。不過,PFC的狀態條實在是差強人意。
消息路由器
CSDN上曾有網友提問要知道PFC消息路由器的機制問題,下面我從《PowerBuilder 基礎類庫技術詳解》一書摘抄一節介紹消息路由器的部分。
PFC使用消息路由器來處理菜單和窗口之間的通信。這種定制的消息傳送機制內至于所有PFC菜單和窗口中。
雖然消息路由器可以用于任何對象與一個窗口的通信,但是他通常用來將消息從菜單傳遞給窗口。消息路由器根據一種定制的搜索算法來決定接受該消息的對象。
使用消息路由器有以下優點:
- 菜單的腳本只需要知道要調用的用戶事件,而不必知道當前窗口或相關控件的名稱;
 - 窗口不必保留那些只是簡單地調用數據窗口的用戶事件。這樣,窗口所保留的用戶事件的數目就減少了。
 
消息路由器函數傳遞的消息實際上就是一個字符串,該字符串包含窗口或窗口的控件要激活的用戶事件的名稱。消息路由器包括內置的調試信息,從而可以提供錯誤信息。
當用戶選中一個菜單項時,該菜單項的Clicked事件調用該菜單的of_SendMessage函數,并傳遞要調用的用戶事件的名稱。 of_SendMessage函數調用n_cst_menu的of_SendMessage函數,該函數調用窗口的pfc_MessageRouter事件,該事件再調用制定的用戶事件。
根據應用程序是MDI程序還是SDI程序,of_SendMessage調用的pfc_MessageRouter用戶事件的方式有所不同,如圖:
pfc_MessageRouter用戶事件調用窗口、當前控件以及最近即獲得數據窗口中傳遞的用戶事件,如圖:
消息路由器提供一種菜單和窗口之間的通信機制。除了數據窗口中的命令按鈕之外,沒有按鈕能夠調用pfc_MwssageRouter事件。這是因為詳細函數調用GetFocus事件來的到當前的控件,而實際上點中一個命令按鈕之后,當前的控件就是該命令按鈕本身。
 
以上內容摘自《PowerBuilder 基礎類庫技術詳解》,電子工業出版社出版,王梅君 等編著。
該書是 劉紅巖 主編的《PowerBuilder 7.0 與 Sybase Internet 技術叢書》系列中的一員。
源文檔 <http://dev.csdn.net/article/12/12674.shtm>
總結
                            
                        - 上一篇: python wxpy_【微信辅助】吃鸡
 - 下一篇: the 95th-percentile