PB窗口使用技巧

**在打開和關閉窗口時進行數據傳遞

OpenWithParm(windowvar,parmeter{,parent})
其中windowvar是要打開的窗口名稱,可以是window畫板中定義的窗口,也可以是腳本中定義的窗口變量;parameter是要傳遞的參數,只能是String,Numeric或者PowerObject類型,該參數根據類型保存在Message的成員變量中傳遞個要打開的窗口;parent是一個已經打開的窗口名稱,該窗口要成爲windowvar窗口的父窗口。函數執行成功返回1,否則返回-1,如果有參數爲null則返回null。
對象Message是一個結構類型的全局變量,並有很多的成員變量。在傳遞參數時三個成員變量用來讀取傳遞的數據,它們是:
Message.DoubleParm:用來傳遞Numeric類型的數據。
Message.PowerObjectParm:用來傳遞PowerObject對象類型的數據,象數據窗口、按鍵、列表框和擁護自定義的結構等都可以使用該變量進行傳遞。
Message.StringParm:用來傳遞String類型的數據。
當使用函數OpenWithParm打開窗口後,應該在進行其他操作之前首先讀取傳遞過來的參數,以免其他操作修改Message中的成員變量。

CloseWithReturn(windowname,Returnvalue)
其中,windowname是要關閉的窗口的名稱,一般是腳本所在的窗口的名稱;Returnvalue是要返回的數值,和上述函數OpenWithParm的完全相同。函數正確執行返回1,否則返回-1,當有參數爲null時則返回null。
*只要是response類型的窗口,使用該函數就能有效地傳遞參數;該窗口不一定非得是用OpenWithParm打開的。在打開該response的窗口中可以讀取傳遞過來的參數。
總之,使用CloseWithReturn函數時一定要注意,只有被關閉的窗口是response類型纔能有效地獲取返回參數。
另外需要說明一點是,某些情況下需要直接修改Message成員變量的取值才能正確返回值。比如,在一個數據窗口中,經常需要在窗口的CloseQuery事件中判斷數據是否已經修改:如果修改,則直接保存,這時返回是否保存過數據的相應標記。在CloseQuery事件中使用函數CloseWithReturn不能正確返回值,只好直接修改Message成員變量的取值了。


**使用窗口名加界定符再加變量的形式可以應用其他窗口中的變量或者函數。例如,要想在窗口w_parm中引用窗口w_data中的實例變量is_title,可以使用w_data.is_title來引用。引用變量既可以使用其他的取值,也可以給它賦值,只要變量的定義允許這些操作。


**打開多個相同的窗口
打開多個相同窗口,是否可以多次使用open語句來解決這個問題呢?不行,該語句只能激活已經打開的窗口,而不會重新打開一個窗口。只能通過創建實例來解決這個問題。
如:在按鈕的clicked事件中,多次點擊該按鈕就會打開多哥完全相同的實例窗口。
w_edit lw_edit
open(lw_edit)
如果希望一次打開多個實例窗口,可以使用數組:
w_edit lw_edit[3]
int li_i
for li_i = 1 to 3
open(lw_edit[li_i])
next
*在同一事件中(如,點擊一次按鈕)對一個窗口實例變量重複執行open語句也只能打開一個實例
如,下面的腳本只能打開一個實例窗口
w_edit lw_edit
int li_i
for li_i = 1 to 3
open(lw_edit)
next
還可以使用如下的語句打開實例窗口
window lw_edit[3]
string ls_win = "w_main"
int li_i
for li_i = 1 to 3
open(lw_edit[li_i],ls_win)
next
打開一個實例時,可以直接使用實例變量的名字引用實例窗口
w_edit lw_edit
open(lw_edit)
lw_edit.title = "測試"


**窗口的屬性

tag
屬性tag可以應用於所有的控件、用戶對象與菜單,用來保存和控件相關的文本。

control[]
使用該屬性可以引用窗口中的控件,它是一個包含窗口中所有控件的數組,可以按只讀方式引用其中的控件。配合函數TypeOf可以判斷控件的類型,根據類型編寫相應的腳本。
實現對窗口中各個控件復位操作:
Int li_index,li_total
DataWindow ldw_temp
DropDownListbox lddlb_temp
RadioButton lrb_temp
li_total = Upperbound(Parent.Control[])
For li_index = 1 To li_total
Choose Case Parent.Control[li_index].TypeOf()
Case DataWindow!
ldw_temp = Parent.Control[li_index]
ldw_temp.Reset()
Case DropDownListBox!
lddlb_temp = Parent.Control[li_index]
lddlb_temp.SelectItem(0)
Case RadioButTon!
lrb_temp = Parent.Control[li_index]
lrb_temp.Checked = False
Case Else

End Choose
Next

MenuId
該屬性是一個指針,並指向和窗口相關聯的菜單。在MDI應用程序中,多個工作表都能通過該指針引用其他菜單的實例,程序員可以編寫出更爲通用的腳本。

WindowState
該屬性是一個枚舉型屬性,可以取值爲Maximized!,Minimized!和Normal!。通過該屬性可以判斷當前窗口的狀態,也可以使用腳本直接修改該屬性來改變窗口的狀態。


**窗口最小化時設置動態圖標
當應用程序最小化時,程序的圖標如果是動畫的,肯定更能吸引用戶的注意,視覺效果會更好。方法是通過動態修改程序的圖標來實現。
當程序最小化時打開timer(在deactive中加入timer(1)語句),並在timer事件中編寫如下程序:
If This.Icon = "appico.ico" Then
This.Icon = "reverse.ico"
Else
This.Icon = "appico.ico"
End If
程序激活時關閉Timer事件(在Active事件中加入timer(0)語句)。
需要注意,要將上面用到的兩個ico文件放到當前應用程序的目錄中。


**放置閃爍文字
以閃爍文字顯示重要信息可以吸引用戶的注意力,避免這些重要信息被忽略。通過週期性修改visible屬性,可以實現閃爍效果。
在窗口中,假設放置一個靜態文本st_1,在窗口的Open事件中定義Timer事件的間隔:
Timer(1)
然後,在窗口的Timer事件中定期修改靜態文本的visible屬性:
If Mod(Second(Now()),2) = 1 Then
st_1.visible = False
Else
st_1.Visible = True
End If
這樣就可以實現閃爍效果。當然也可以在適當的時候使用timer(1),並在適當的時候關閉Timer事件。


**函數PostEvent和TriggerEvent都可以觸發其他的事件,但是兩者是有區別的。PostEvent觸發的事件不是馬上執行,而TriggerEvent觸發的事件馬上執行。PostEvent向消息隊列中發送消息,等當前腳本執行完畢再觸發消息隊列中等待狀態事件的腳本;而TriggerEvent函數可以中斷當前執行的腳本,轉向被觸發事件,等執行完被觸發事件的腳本後再返回當前腳本繼續執行所以,當需要馬上執行被觸發的事件時使用函數TriggerEvent;當執行完當前腳本後需要觸發某個事件時使用函數PostEvent。但是,當在腳本最後觸發其他事件時不論使用哪個函數,效果都相同。


**移動不帶標題欄的窗口
在開發應用程序中,可能要用到不帶標題欄的窗口,而帶有標題欄的窗口可以通過拖動標題欄來移動窗口,如何移動沒有標題欄窗口呢?這需要編寫代碼來解決。
在要拖動窗口的MouseDown事件中編寫腳本,給窗口發送消息WM_SYSCOMMAND,並將Wordparm設置成SC_MOVE+1,這兩個常數的取值分別爲274和61 457。腳本如下:
Send(handle(this),274,61458,0)
這將通知窗口在鼠標移動時跟隨它一起移動。

**閃爍窗口標題欄
可以使用API函數FlashWindow來實現閃爍窗口標題欄的功能,使用該功能可以在重要窗口或者特殊情況下吸引用戶的注意力。首先聲明Locat External Function,語句如下:
Function boolean FlashWindow (Uint handle, boolean flash) Library"user.exe"
然後在適當的時候(比如,用戶點擊了某個按鍵後)使用下面語句設置Timer事件的間隔:
Timer(1)
然後在窗口的Timer事件中編寫如下腳本:
FlashWindow(Handle(This),True)
在適當的時候使用timer(0)語句關閉Timer事件。

**給窗口添加自動滾動條功能
因爲窗口沒有自動滾動條功能,如果設置窗口的HScrollBar或者VScrollBar屬性,在不需要滾動條時也顯示滾動條,很不美觀。可以在窗口的Resize事件中編寫腳本,根據當前窗口的大小來設置是否顯示滾動條。如果用戶調整窗口的寬度,當小於打開時的寬度時顯示水平滾動條,當大於打開時的寬度時,如果有水平滾動條,則取消該滾動條;如果用戶調整窗口的高度,當小於打開時的高度時顯示垂直滾動條,當大於打開時的高度時,如果有垂直滾動條,則取消該滾動條。
腳本主要編寫在窗口的Resize事件中,需要兩個判斷滾動條滾動範圍和滾動條當前位置的API函數,聲明這兩個本地外部函數的語句是:
Subroutine GetScrollRange(Uint hWindow,Int nScrollBarFlag,ref Int nMin,ref IntnMax) Library "user.exe"
Function Int GetScrollPos(Uint hWindow,Int nScrollBarFlag) Library"user.exe"
是否需要顯示滾動條,可以通過和窗口剛打開時的寬度、高度相比較來判斷。所以,定義兩個實例變量:
Int ii_width,ii_height
在窗口的Open事件中初始化這兩個變量:
ii_width = This.Width
ii_height = This.Height
然後是腳本的主要部分,在窗口的Resize事件中實現。腳本如下:
Uint hwindow
Int nScrollPos,nMinPos,nMaxPos
If This.WindowState = Minimized! Then //如果正在進行最小化,則直接返回
Return
End If
HWindow = Handle(This) //獲取當前窗口的句柄
//下面開始處理水平滾動條
If This.Width < i_Width Then //如果小於打開時的寬度
This.HscrollBar = True //則顯示水平滾動條
Elseif This.HscrollBar Then //如果大於或等於打開時的寬度,並且已經有滾動條
NScrollPos = GetScrollPos(hwindow,0) //使用API函數獲取當前滾動條位置
GetScrollRange(hwindow,0,nMinPos,nMaxPos) //使用API函數獲取滾動範圍
If nScrollPos > nMinPos Then //如果用戶滾動了滾動條並且此時不需要顯示滾動條
Post(hwindow,276,6,0) //則在水平方向調整窗口中的內容到原來的位置
End If
This.HscrollBar = False //取消滾動條特性
End If
//下面開始處理垂直滾動條
If This.Height < i_Height Then //如果小於打開時的高度
This.VscrollBar = True //則顯示垂直滾動條
Elseif This.VscrollBar Then //如果大於或等於打開時的高度,並且已經有滾動條
NScrollPos = GetScrollPos(hWindow,1) //使用API函數獲取當前滾動條位置
GetScrollRange(hwindow,1,nMinpos,nMaxPos) //使用API函數獲取滾動範圍
If nScrollPos > nMinPos Then //如果用戶滾動了垂直滾動條且不需再顯示
Post(hwindow,277,6,0) //則垂直調整窗口中的內容到原來的位置
End If
This.VscrollBar = False //取消滾動條特性
End If

**自動調整窗口
在一定的屏幕分辨率下開發的應用程序到別的計算機上運行時,很可能遇到和開發環境中的分辨率不同的情況,這時要保證窗口界面仍然顯示居中,就得在開發時考慮這個問題。解決方法是在窗口打開時判斷屏幕的分辨率,根據分辨率來決定窗口顯示的位置。要用到兩個單位換算函數和一個獲取運行環境信息的函數。
在PowerBuilder中所有尺度都是用PowerBuilder單位(PBU)計量的,惟一例外是Window和DataWindow畫扳網格尺寸,這是用像素計量。PowerBuilder中的計量使用和Windows中相同的技術,都是基於系統字體。不同的是,Windows中採用系統字體寬度的1/4和高度的1/8,而PowerBuilder中採用系統字體寬度的1/32和高度的1/64,從而可以提供比Windows中更高的分辨率。但是,用戶在PowerBuilder應用程序中調用外部函數來獲取對象的尺寸或位置時就應該進行相應的轉換。好在PowerBuilder本身也提供了進行單位換算的函數,所以應該儘量使用PowerBuilder本身的單位換算函數。
函數UnitsToPixels()用於將PBU值換算成像素值。它的語法格式是:
UnitsToPixels(units,type)
其中,Units是一個整型數值,是要轉換成像素值的PBU值;Type是一個ConvertType類型的枚舉值,可以是:
XUnitsToPixels!表示要轉換成水平方向上的像素值;
YUnitsToPixels!表示要轉換成垂直方向上的像素值。
函數成功執行將返回轉換後的像素值,如果執行錯誤,則返回-1,如果有參數NULL,則返回NULL。
函數PixelsToUnits用於將像素值轉換算成PBU值。它的語法格式是:
PixelsToUnits(pixels,type)
各個參數的意義和上面函數的完全相同,執行的功能相反,是將指定像素值轉換成指定方向上的PBU值。
因爲所有窗口在打開時都有居中問題,所以可以使用全局函數解決這個問題,以便在應用中的所有窗口都可以調用該函數。該函數的腳本如下:
//------------------------------------------------
//功能:將窗口移到屏幕的中央
//參數:aw_window 要處理的窗口
//返回值:(none)
//調用舉例:gf_window_center(w_pay_mode)
//------------------------------------------------
Environment le_env
integer li_iscreenHeight,li_screenWidth
long ll_posx,ll_posy

GetEnvironment(le_env)
li_screenHeight = PixelsToUnits(le_env.screenHeight,YPixelsToUnits!)
li_screenWidth = PixelsToUnits(le_env.screenWidth,XPixelsToUnits!)

if aw_window.width > li_screenWidth then
ll_posx = 1
else
ll_posy = (li_screenWidth - aw_window.width)/2
end if

if aw_window.height > li_screenHeight then
ll_posy = 1
else
ll_posy = (li_screenHeight - aw_window.Height)/2
end if

aw_window.Move(ll_posx,ll_posy)

上面的腳本用函數GetEnvironment獲取當前的環境信息,並將其成員變量ScreenWidth和ScreenHeight轉換成PBU值,然後減去當前窗口的寬(高),取差值的1/2即爲窗口居中時的起始座標。
有時窗口的位置要恢復到用戶上次使用時的情況,可以藉助於ini文件。在窗口關閉時將窗口的位置信息保存在一個特定的ini文件中,當窗口打開時再將這些位置信息讀出並用來設置窗口的位置。
當用戶對窗口的大小進行調整時,窗口中的控件也應該相應地調整其大小和位置,這樣才能保證整個窗口中控件的佈局相對不動。可以在調整窗口大小的同時調整窗口中的控件及其相對位置,可以在窗口的Resize事件中編寫腳本。首先定義如下實例變量:
integer ii_width,ii_height
在窗口的open事件中:
ii_width = this.width
ii_height = this.height
在窗口的Resize事件中:
integer li_value
DragObject lw_obj
for li_value = 1 to upperbound(this.control[])
lw_obj = control[li_value]
lw_obj.x = lw_obj.x * (newwidth / ii_width)
lw_obj.width = lw_obj.width * (newwidth / ii_width)
lw_obj.y = lw_obj.y * (newheight / ii_height)
lw_obj.height = lw_obj.height * (newheight / ii_height)
next
ii_width = newwidth
ii_height = newheight
其中,NewWidth和NewHeight是窗口Resize事件的參數,可以直接使用。NewWidth/ii_width是橫向變動比例,NewHeight/ii_height是縱向變動比例。Control[]是窗口的一個屬性,用來標識窗口中的所有控件。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章