2008年8月12日 星期二

差異

雖然我的臨場反應很快,可是要短時間做決定時,考慮還是不夠周全的。

跟前一任的主管Jr比起來,能力上多少有點不太夠,尤其是遇到比較大的決策時。Jr是處女座的主管,做事一定要條理分明,是他的原則,所以他是寧願延宕工時,也不願意因為時間壓力而做太半調子的事情。但有時候也許太小心翼翼,有些事情會不敢做。這不是不好,Jr常常也說要保護自己的Team不要受到其他單位的無理要求。

Jr:因為我們不是資訊公司,趕完Case交差了事,還得有許多善後的動作,東西若是做得不夠嚴謹、完整,事後要擦的屁股肯定很多,加上人手不多,不該出差就盡可能不要出差。

當兵時雖然當過管理職(排長),但是距離現在已經快超過10多年了,Fu都快忘了,當然部隊的管理方式在資訊單位也是不太適用的,所以還是得從頭學習。

雖然有我們有自己專業的見解,但是有時候在老董的壓力下,還是會得向不利的時間條件屈服,這時候就很佩服Jr以前能夠說服老董騰出給我們較多的時間來完成CASE。

當然這是我必須歷練的學習,雖然心情很差但還是得克服。

2008年8月8日 星期五

這就是生殺大權吧

任職代理課長到今天大概1/3個月了,人事課送來了一本"員工月考核表",
我想這就是主管的生殺大權吧,看看之前的主管對員工評分幾乎都是滿分,
真是相當疼愛啊~~~(謎之音:我們都很認真的喔~~)。

看看大家都那麼認真的份上我也不好意思去做所謂的"扣分"了。

"舊"這樣子吧(我沒打錯字)

繼續努力吧

2008年5月28日 星期三

DataWindow執行時出現encountered select error錯誤

一般DW如果會跳出這個錯誤,通常是DW中的table定義的欄位長度與SQL執行的欄位長度不符。
如果說有其他原因,也可能是DW與SQL指令搭配不完全。
再者,一般DW執行發生錯誤如果沒有攔截dberror事件,是不會得到SQL error的訊息,然而SQL CODE 2 encountered select error:這種錯誤訊息是DW已經將SQL指令送出執行,在資料庫傳送資料到DW上發生無法處理的錯誤,導致無法繼續(encountered)。
據我的經驗是DW當初"設計"時參照使用的Table,後來因為某些因素做了變更(通常是欄位長度加大),導致DW中記載的欄位長度與實際Table不符合,當資料長度小於DW當初定義的欄位長度時還不會發生問題,但是當資料長度超過DW當初定義欄位的長度時就會出現錯誤。

解決方式:
  1. 重新進入設計DW的data source,簡單的變更或是調整一下SQL部分語法,此時DW painter會重新對應資料庫Table欄位資訊。
  2. 如果擔心有些版面會因為調整過data source就會被破壞(Regenerate),就只好匯出SRD,直接修改SRD檔案中記載TABLE的COLUMN欄位長度,如:CHAR(10) -> CHAR(30) 。使用這種方式要特別注意,修改的欄位長度最好跟資料庫中的Table欄位長度一致,以免後續有問題又需要DEBUG,反而自找麻煩。

2008年5月22日 星期四

Compute欄位小計異常

請問一下,為什麼我在這個DW的[總成本小計]後面的COMPUTE欄位(如下圖所示)加入sum( compute_0024 for group 1 )

但出來的結果卻是
我是很單純的想把COMPUTE_0024加總起來而已!!好怪

********************************************************************************
關於Compute的問題,我也遇過幾次,原因不是很清楚,但是有些做過調整後就可以使用了,我提供幾種解決方法你可以各個去試試:
  1. compute_0024有Null值,因為某些條件下沒有計算值,我推測是Null值,這個Null值可能導致Group1上的compute計算sum值錯誤。解決方式:在compute_0024的公式外面加個if(isnull(xx) , 0 , xx)的判斷,強迫讓Null值的公式出現0值,缺點:畫面上會有"0"值出現。

  2. 在Group1上的compute公式中加入isnull判斷sum(if(isnull(compute_0024),0,compute_0024) for group 1),這方法不會有第一點的問題,但是如果是compute_0024值有問題,依然不能解決。

  3. 在Group1上的compute公式中不要直接使用compute_0024這種計算欄位的值,直接將compute_0024中的公式拿來替代compute_0024,因為經過測試發現計算欄位有時候去取得其他計算欄位的值時會有異常值的出現(原因不明,我猜可能是PB內部運算順序導致),因此我發現這樣雖然公式會"落落長"但是比較不會有問題。

  4. Compute欄位的format不要使用預設的這個也是特例問題,雖然系統在不指定下會使用[general],卻有時候會發生計算小數點的錯誤問題,通常這種錯誤都會只發生在小數點下,我的經驗是有時候去TOTAL整數卻會跑出一堆小數點以下的數值,修改過FORMAT後就好了。例如僅需要整數時把FORMAT設定:###0。

以上四點是我這邊解決compute field的經驗,你可以修正試試看。

2008年5月19日 星期一

ProgressBar設計

說真的,當初在使用PB6.5的時候,常常覺得視覺控制項太少(可能是被VB養成的壞習慣),但是因為PB真的有其獨到MIS快速開發的物件導向功能,所以在設計MIS系統的時候,VB只好被我給秉棄不用了;可是說正格的,有時候視覺控制項卻是在UI的分數中占蠻高的比重的。而今天要設計的ProgressBar也是PB6.5缺少的控制項之一,雖然PB7以上的版本已經有這樣的控制項,不過目前朋友還是在使用PB6.5,所以我還是將它設計出來造福一下人群吧。

要設計ProgressBar並不是什麼難事,包括許多DIY的視覺物件也是,但是難就難在要做好一個完整的物件控制項,考驗設計師對使用者(其它設計師)的操作上手速度(這個應該稱作設計介面):物件功能分明度(A功能與B功能好像類似)、可控制精細度(控制項裡面的物件)、封裝一體性(對控制項裡面的物件控制要如同直接對控制項設定控制般簡單)等等,這部份就會造成程式設計師的極大差異。

好了,廢話結束,進入正題吧。
ProgressBar中文的話應該叫做"處理進度條",既然是處理進度,所以有進度百分比來顯示會比較好一點,如此可以稍微整合一下,設計好的物件控制項,別人在使用時就不需要再去加東加西的了。然而條狀要如何產生呢,簡單的可以用Line這個物件就好了,但是Line的特性太少,表現起來太單調,所以我改用了Rectangle(別說你不知道這叫矩形)來設計,因為Rectagle具有FillPattern的樣式,可以創造較為美觀的ProgressBar,所以初步規劃如下:另外考慮到的一點是當Progress為100%時,rectangle是填滿的狀態,但是若Progress為0%時,則rectangle則為一片空白,這樣設計在某些畫面上會有"空一塊"的感覺,並不是很美觀:

因此我們希望對rectangle保留外框,而在適當的進度下改變FillPattern的範圍:

可是,若是注意看rectangle物件的屬性,是無法這樣操作的,也就是說FillPattern只會全部塗滿,但是無法依照指定範圍塗滿,所以我們必須另外想辦法處理這樣的問題。其實可以用很簡單的方法解決這個問題。
對,你想到了嗎?就是用兩個rectangle,一個當底僅顯示外框,另一個當BAR;當BAR的rectangle需在當底的rectangle上方位置,而當BAR的rectangle,預先設定好fillpattern樣式,也可以依照進度動態調整寬度,就可以做到這樣的效果囉。

再來就是封裝,將上面3向物件設計在一個visual的customer的UserObject上即可完成視覺部分的設計了:實際設計樣式:
接下來就是要設計其使用的方式以及函式了。
因為progressbar主要是顯示工作進度,因此針對他人使用這個物件時僅主要有2個動作需要做:
一、初始化
主要是設定 minimized position(最小位置)、maximized position(最大位置)以及position(最初位置)。
可是有人說:進度只有100%,那麼最小設為1,最大設為100就好了,為什麼還需要設定這些資訊呢?
雖然這樣的說法是沒有錯,但是相對的使用這個物件的程式設計師必須在自己的程式碼加上換算百分比的Script,再將換算出來的百分比數拿來設定progressbar,如此每次使用到這個Progressbar就得加上一段"換算百分比"的script,這樣看來是多麼沒效率,多麼不好用啊!
所以這個初始化函式其意義就在此,當你設定好 minimized 與 maximized 位置時,只要填入目前的position,這個Progressbar就會幫你計算百分比,無須設計師操心。

二、設定ProgressBar位置
設定處理進度的position,這裡的position(位置)指的是在(一)初始化時設定minimized與maximized之間的值,並非實際的百分比值,因為物件會自行換算minimized與maximized與position之間的百分比,並調整bar的寬度。

因此主要函式便有以下幾種:
(a)初始化
@of_initial(minimized position , maximized position , initial position)
@of_initial(minimized position , maximized position)
minimized position(Long) 最小位置
maximized position(Long)最大位置
initial position(long)最初位置,若是不含此參數,則預設為0。

(b)設定位置
@of_SetPosition(Current Position)
Current Position(Long)目前位置,並非百分比位置,而是介於minimized position與maximized position之間的位置。

針對主要函式可以在發展延伸的函式:
(c)重置
@of_reset()
將所有設定清除,回歸預設值。

(d)取得目前設定對小位置
@ minimized position = of_minposition()
minimized position(Long)

(e)取得目前設定對大位置
@maximized position = of_maxposition()
maximized position(Long)

(f)取得目前位置
@current position = of_position()
current position(Long)

(g)取得目前進度百分比值
@percent number = of_percent()
percent number(Integer) 介於0~100之間的數值。

延伸使用
當這個物件設計好了可以使用的時候,你會應用在哪裡呢?我的範例中,將它設計成popup window的 使用或是設計到window上貼合,都是相當不錯的用法喔。

當我設計在展示畫面上時,其背景顏色也會跟著主視窗進行替換,主要是在progressbar中有一些可以變更的instant變數可以當作屬性來設定:

Boolean ib_border = true
Long il_color = 8421376
Long il_bkcolor = 81324524
fillpattern i_fillpattern = vertical!

這些屬性可以變更成不同樣式的ProgressBar,增加ProgressBar的細項設定以及實用性,你可以發現,這些設定並非直接讓使用者(設計師)設定這個ProgressBar內的rectangle屬性,而是透過對外的public instant變數,加上initial的過程才去進行屬性變更,因此使用此物件設計師不需要太深入了解物件內部的東西就可以進行設計了。

範例程式下載

2008年4月30日 星期三

在windows右鍵上增加複製(搬移)到資料夾選項

2011-09-07補充:多年下來使用的時候每當一次選取多個檔案開啟時,就會發生Copy to 和Move to 一直被開啟,真是不勝其擾,最後決定移除掉了。
本篇文章來源 一段影片 看了之後覺得頗為實用的,不過內容太快,又是英文發音,如果英文不好的可以看我下面的作法:

(一)點擊[開始]選擇[執行] --> 請輸入 Regedit 按[確定]開啟登錄編輯程式(二)進入HKEY_CLASSES_ROOT\AllFilesystemObjects\shellex\ContextMenuHandlers一般來說ContextMenuHandlers底下只會有個Send To(傳送到...)的機碼
(三)在ContextMenuHandlers上按右鍵選 [新增] -> [機碼]
(四)請新增"Copy To"以及"Move To"兩個機碼
(五)每個機碼內都會有個"(預設值)"的字串值(六)請在Copy To裡面的字串值點及兩下編輯,輸入 {C2FBB630-2971-11D1-A18C-00C04FD75D13},然後按[確定]
(七)請在Move To裡面的字串值點及兩下編輯,輸入 {C2FBB631-2971-11D1-A18C-00C04FD75D13},然後按[確定]
(八)關閉登錄編輯程式
(九)此後你可以在檔案總管中,將檔案 複製/搬移 到你指定的資料夾去了,不用老是在"複製"->"貼上",搞得很麻煩囉。


(十)你可以發現到,複製/搬移的 對話框Windows居然都已經有現成的可以用,表示其實Windows"暗槓"了不少使用者可以用的東西呢。

2008年4月29日 星期二

TreeView DataWindow設計(二)

看過上一篇的簡單說明後,現在就進行實作了範例程式
※TreeView DataWindow名稱過長,文中會使用TVDW(大寫)來代表其意義。
※DataWindow簡稱DW(大寫)
※DataStore簡稱DS(大寫)

(一)先來看看程式主畫面:

這個畫面的左半邊是展示用的資料,我這邊的展示設定是某家傳直銷的組織圖,因為這樣的組織圖很容易用來表現樹狀結構的特性,如果你不知道傳直銷組織的話,問一下親朋好友應該會有人解釋得很好(?)吧,傳直銷的組織特性就像是樹狀結構圖,基本上分為上線(通常是推薦人)以及下線(通常是所屬會員或是組織成員);上線如同父節點(Parent),下線如同子項目(Child),所以如果能理解的話應該不難理解畫面左邊的列表意思。

現在的目的就是要如何把這樣的條列資料展現成樹狀組織圖,以供列表或是操作了。
主畫面的右半上方是TVDW的產生示範功能,右半下方則是TVDW本身了。
[產生]:用來產生TVDW的樹狀組織圖,資料來源則是依據主畫面左半邊的資料。
[停止]:由於資料多達300多筆,產生會消耗許多時間,如果想中途停止,只要按這個按鈕就好了。
[刪除]:當你選擇了某個項目節點後,按下此鈕,會將該項目連同下屬所有子項目一並全數刪除。
[預覽列印]:列印時的畫面預覽,用來檢視畫面是否超出紙張定義。
[內部資料檢視]:這算是特殊的功能了,上一篇有提到這個TVDW有個DS在儲存實際樹狀資料屬性,理論上使用者不需要也不可以直接檢視或修改該DS內容,這僅是提供程式設計師debug以及理論驗證的用途罷了。
[全部展開]:這個是以最基本的根項目(Root)為展開的動作,展開時各節點全部展開(註一)。
[全部收合]:這個是以最基本的根項目(Root)為收合的動作,收合時各節點全部收合(註一)。
[選擇子項全開]:以選擇的項目下屬項目節點全部展開,展開時各節點全部展開(註一)。
[選擇子項全收]:以選擇的項目下屬項目節點全部收合,收合時各節點全部收合(註一)。
[細部設定變更]:在TVDW產生時會依照某些特性設定值作為基本依據,如果需要更改某些特別屬性可以變更下列屬性質,以達所需要效果,其數值單位為PowerBuilder Unit,特別要注意的是屬性設定必須在TVDW"產生"畫面前進行設定,否則無效:

起始X、起始Y:這是初始項目的繪製起點座標,其它項目節點再進行繪置時將會受此座標值影響。

X間隔、Y間隔:可以決定項目與項目間的顯示距離,若字型放大時通常都需要調整,有時候也是因為版面需要才會進行調整。
項目寬、項目高:可調整的顯示項目寬與高,若字型變更或是項目邊框變更,則可能需要進行調整,另外需要注意的是,最底層項目的寬度不顯示的部份如果超過可列印頁面寬度時,儘管在預覽時,可能沒有跳頁,但實際列印時可能會產生跳頁的現象,此時就得進行調整。

字體:可調整項目文字字體大小,但須注意項目寬度、高度、間隔並不會自動調整。
項目邊框:可以改變項目顯示邊框形式,預設是無邊框。
允許編輯:此TVDW預設可以在項目上點及滑鼠兩次,可以編輯該項目文字(Label)內容,若是不希望使用者編輯可以將此屬性設定關閉(False)。
允許選擇反白:此TVDW在預設情況下使用者使用滑鼠單擊項目時會產生"選擇反白",若是用於列印用途上時,不希望使用者點擊反白,可將此屬性設定關閉(False)。

※註一:若是一般的展開/收合(即是用滑鼠點擊項目節點前面的 +/-圖示)時,僅會對下屬1層進行展開/收合的動作,下屬第2層的展開/收合狀態會予以保留,若是使用全面展開/收合,則會將下屬所有層級項目屬性全部展開/收合。

(二)TVDW的操作Function
(a)新增項目
@new id = of_AddItem(parent id , lebel text)
@new id = of_AddItem(Parent id , Label text , Properties string)
New id(Long)是新增項目成功後會回傳的編號,此編號在TVDW裡面是個唯一值。
Parent id(Long)是你要加入的父節點項目編號,若是要加在根節點(root)下,則設為0即可。
Label text(String)是項目顯示的文字。
Properties String(String)屬性描述字串,若不使用此字串則TVDW會依照預設屬性去新增項目,如果你想對某些項目使用特殊屬性,可以於新增該項目時使用屬性設定,底下簡單介紹屬性名稱與值的意義與用法,設定2個以上的屬性時屬性與屬性間使用"~t"做為區隔,屬性名稱與值使用"="做為區隔。
如:
ll_newid=of_additem(ll_pid,"鑽孔機","FontColor=12639424~tEvent=ue_tool~tExpandBmp=open.bmp")

*CollapseBmp項目收合時使用的圖片(僅BMP檔)。
*ExpandBmp項目展開時的圖片(僅BMP檔)。
**CollapseBmp與ExpandBmp若是只設定其中一個,則展開/收合都視為相同的圖片。
*Width項目寬度,當你有設定此屬性,"此項目"產生的寬度會以此為主,未設定則以預設為主。
*Height項目高度。
*FontColor項目文字顏色。
*FontBackColor項目底色。
*Event事件名稱,當使用者點擊此項目會觸發指定事件名稱的事件。

(b)刪除項目
@retcode = of_DeleteItem(id)
@retcode = of_DeleteItem(id , delete child)
retcode(Integer)是刪除項目回傳狀態1是成功,0是失敗,-1是錯誤。
id(Long)是要刪除的項目編號。
delete child(Boolean)是決定是否刪除下屬所有子項目與節點,如果不使用此參數,則視同為True(下屬子項目全數刪除)。

(c)收合項目
@of_Collapse(id)
@retcode = of_Collapse(id , Collapse All Child)
retcode(Integer)是收合項目回傳狀態1是成功,0是失敗,-1是錯誤。
id(Long)是要收合的項目編號。
Collapse All Child(Boolean)是決定是否收合下屬所有子項目與節點,如果不使用此參數,則視同為True(下屬子項目全數收合)。

(d)展開項目
@of_Expand(id)
@retcode = of_Expand(id , Expand All Child)
retcode(Integer)是展開項目回傳狀態1是成功,0是失敗,-1是錯誤。
id(Long)是要展開的項目編號。
Expand All Child(Boolean)是決定是否展開下屬所有子項目與節點,如果不使用此參數,則視同為False(只展開下屬1層級的子項目)。

(e)尋找項目
@id = of_FindItem(Label text , Start id)
id(Long)是找到的項目編號,若是找不到則會傳回0。
Label text(string)要尋找的項目內容文字,如果該標籤文字含有此文字,則代表找到。尋找文字的方式類似SQL語法的LIKE %S%。
Start id(Long)起始項目編號位置,如果為0,代表全部尋找,如果為某項目編號,則僅搜尋該項目下所有子項目為主。

(f)取得被選取的項目
@id = of_GetSelectItem()
id(Long)為傳回的項目編號,如果沒有項目被選取,則傳回0。

(g)取得父項目
@pid = of_GetItemParent(id)
pid(Long)為父項目的編號,若是失敗則傳回0,錯誤傳回-1。
id(Long)為尋找的項目編號。

(h)設定標題
此TVDW有個預設的標題可以設定
@of_SetTitle(Title text)
@of_SetTitle(Title text , Font size , Font face , Font color , Font Background color , Label transparent , Label x , Label y , Label width , Label Height)
Title text(String)標題文字內容。若是使用第一種用法,則所有屬性直皆為預設值。
Font size(Integer)字體大小。
Font Face(String)字型名稱。
Font color(Long)文字顏色。
Font Background color(Long)背景顏色。
Label transparent(Boolean)背景透明,當設定為透明(True)時,背景顏色會無效。
Label x(Long)標題標籤起始X座標(單位:powerbuilder unit)。
Label y(Long)標題標籤起始Y座標(單位:powerbuilder unit)。
Label width(Long)標題標籤寬度(單位:powerbuilder unit)。
Label Height(Long)標題標籤高度(單位:powerbuilder unit)。

(i)清除TVDW
@of_reset()

(j)檢視內部資料
@of_DataView(Show data)
Show data(Boolean)如果為true會開啟資料檢視視窗,Fasle則為關閉。

(k)取得項目標籤文字
@Label text = of_GetItemlabel(id)
Label text(String)取得的標籤文字內容。
id(Long)要取得標籤文字的項目編號。

(l)變更項目標籤文字
@retcode = of_SetItemLabel(id , Label text)
retcode(Integer)是變更項目標籤文字回傳狀態1是成功,0是失敗,-1是錯誤。
id(Long)要變更標籤文字的項目編號。
Label text(String)欲變更的標籤文字內容。

(m)取得項目附帶資料
@Data text = of_GetItemData(id)
Data text(String)取得項目的附帶資料。
id(Long)要取得附帶資料的項目編號。

(n)設定項目附帶資料
@retcode = of_SetItemData(id , Data text)
retcode(Integer)是設定項目附帶資料回傳狀態1是成功,0是失敗,-1是錯誤。
id(Long)要設定附帶資料的項目編號。
Label text(String)欲設定的附帶資料內容。

(三)TVDW的事件
雖然TVDW繼承自DataWindow物件,也擁有DataWindow的事件,但是由於使用方式特殊,因此請勿使用DataWindow原本的事件來攔截資料,因為攔截到的資料會有所錯誤。因此TVDW本身有定義好一部份事件以供設計者使用:

(a)ue_ItemClicked(x , y , row , id)滑鼠單擊事件(衍生自DW的Clicked事件)
x(Long)滑鼠X座標。
y(Long)滑鼠Y座標。
row(Long)資料運作DS的ROW位置。
id(Long)項目編號。

(b)ue_ItemDblClicked(x , y , row , id)滑鼠雙擊事件(衍生自DW的DoubleClicked事件)
x(Long)滑鼠X座標。
y(Long)滑鼠Y座標。
row(Long)資料運作DS的ROW位置。
id(Long)項目編號。

(c)retcode = ue_ItemChanging(id , Old Label , New Label)項目標籤變更事件
retcode(Integer)若是回傳非0值,則TVDW會拒絕項目標籤文字的變更。
id(Long)被變更標籤文字的項目編號
Old Label(String)舊的標籤文字資訊
New Label(String)新的標籤文字資訊,在此如果變更此變數內容,將會影響到變更的內容文字。

TreeView DataWindow設計(ㄧ)

開發工具:powerbuilder 6.5
雖然powerbuilder 10.5已經提供了TreeView DataWindow的功能了

畫面也是標準的DataWindow介面,感覺上也很好用?(我還沒用過啦)。可是呢,目前公司提供的工具最高也僅到PB10而已,大多數的程式和工具也都是維持在PB6.5的版本;而且許多朋友也是還在使用PB6.5苦撐...唉!公司預算有限嘛!能用且用囉。

這讓我興起想要建立自己的TreeViewDataWindow物件的想法。雖然說powerbuilder本身就有treeView的物件,但是那不是DataWindow的型態,所以列印的話效果都不好,也很難控制。
難怪powerbuilder敢誇海口DataWindow是MIS開發報表最方便的工具。

由於DataWindow由於名稱過長,因此文中如果有遇到DataWindow如果有遇到字樣的可能會以DW表示。

《一》首先,先來了解一下樹狀結構吧,樹狀結構顧名思義,一定跟樹....有關係 XD
如果把它的葉子全部脫光光........
這樣只剩下之枝幹與枝節,然後再把它右轉90度,是不是很像下面的圖....

那麼這就是所謂樹狀結構圖了,具有相同性質的"節點",每個節點底下還可以再分更多節點,由於看起來像樹一樣,所以就稱為樹狀結構。當然,如果你要表現成TreeView的話,這樣是不行的,因為treeView比較接近條列式,像是下圖:

比較井然有序,比較條列,大部份若要製作成報表,就要使用此種表現方式的報表比較容易看懂。以上的簡單說明主要牽涉到資料存放的方式,如果你對樹狀結構不夠明瞭,那麼當下面設計TreeView的資料結構時候,你就會很難理解。

《二》了解你的開發工具,雖然學PB的很多人都會使用DataWindow,但是對於DataWindow的運作原理卻不是很熟悉。當然這裡不會介紹DataWindow的原理,而是利用其特性去建構成我們要展現的DataWindow。

這個物件主要是裡用DataWindow的屬性建構,因此主要使用modify這個指令來建構DWO(DataWindow Object)。DataWindow本身可說是一個Paint Container,而這個Container包含了幾個區塊:group、detail、header、fotter、summary,個區塊(band)各有不同展現屬性,這裡不對此進行詳述。而當我們建立(Create) DWO時主要是建立在detail band上的。因為在列印上Detail Band才有分頁的效果,若是建立在Header、Summary、Footer上的話要調整報表就是一件麻煩事了(有興趣的可以自己試試看)。

《三》規劃:
雖然我是在DW上產生TreeView的DWO,但是其實每個DWO都有其屬性(Properties),例如基本屬性:ID(id)、Parent ID(pid)、Name(text),延伸屬性:X、Y、Width、Height、Depth(level)、Expanded Flag、Picture Name等等相當的多。所以使用要產生TreeView本身的DW來承接資料是有技術上的問題,而且如果希望到時候能夠在畫面編輯資料,就更需要保留當作Paint Container的DW本身的column。

因此我使用一個DataStore(ids_node)去記錄其TreeView的資料屬性:
利用這樣的方式,在操作上只要維持這個DataStore的資料正確性,就可以讓TreeView DW正確的畫出該有的樹狀圖。

而這個DataStore的資料排列就跟樹狀結構的順序有相當重要的關係,底下舉個例子:
左邊是TreeView DW顯示的樣子,右邊是其內部資料node properties(DataStore)儲存資料的樣子
發現了有趣的事情了嗎?DataStore的"紀錄順序"居然與TreeView的"展現順序"是相同的,因此DataStore的資料等於是Treeview DataWindow的"內部"資料樣式。

"層"的概念:
其實"樹狀"概念落實在資料儲存中也不過是"資料順序"+"階層"而已,因此內部資料主要是給程式作為繪製TreeView的依據,因此繪製node物件時便是參考此node所存在的"層"數來計算相對位置,所以TreeView DW只需負責"展現"繪製的工作:
因此理論上使用者不需要也不可以去介入這個DataStore的任何運作方式,僅能透過公共(Public)函式來進行TreeView的操作,從另一方面來說,資料的建立與新增主要是針對DataStore來實行的,如此TreeView DW的設計就會比較單純。

再來討論一下這個TreeView DW應該具備的可呼叫功能(提供外部使用者設計使用)應該有哪些:
(1)增加節點項目 of_AddItem
(2)項目展開 of_Expand
(3)項目收合 of_Collapse
(4)尋找項目 of_FindItem
(5)取得項目的父項目 of_Item_Parent
(6)清除TreeView of_Reset

供外部使用事件:
(1) 使用者點擊項目時 ue_ItemClicked

這些設計的功能僅是"基本"產生TreeView的使用所需要功能,其他延伸功能有時間可以自行再研究看看。當然,實際運作時不會僅有上述的Function及Event,當然還有內部使用的Function與Event,因此這部份留待實作時(續篇)再來分析。

2008年4月2日 星期三

『躍升2008打造價值型人才』台中場講座心得紀錄

主辦單位:經理人月刊
時間:2008/3/13
以下是李紹唐先先生與何飛鵬先生講座混合雜記:

◎注重3Q :EQ、AQ、IQ
IQ(Intelligence Quotient)是指一個人在學習、理解、判斷方面的能力。
EQ(Emotion Quotient)是指一個人了解,並主導自己情緒,以及與他人溝通、協調、互動的能力。
AQ(Adversity Quotient) 是指一個人面對挫折、逆境時的處理能力。

◎追逐夢想,永不放棄
俗話說:人有夢想而偉大,但實際上是:人因實現夢想而偉大。
有夢想人人都會有,但是有正確的夢想(方向正確),只剩下20%的人,再因有正確夢想而努力實踐者
只剩4%。(80/20法則)
當你沒有夢想(指的是人生終極目標)時,你很容易就在某種階層就自我滿足。而忘了往更高的地方去。
這讓我想到一個例子:登山者的故事
一群登山客要挑戰很高的山,一同從山腳下出發,當大夥都登到一定高度後往
上看時發現山上下著暴風雪,而此處的風景也相當不錯因此決定故在此紮營休
息,然而再往上攀爬風險太大了許多人因此就決定繼續留在這裡,但少數的挑
戰者卻願意繼續往上挑戰,在這些挑戰者經歷了強風雨打、缺氧、受傷等等狀
況,終於登到了山頂,卻赫然發現山頂竟是晴空高照,往外望去卻是一望無際
的景致,由如眾神矗立於雲端觀看世界的感覺。

◎離開舒適環境,不醉生夢死
許多人在登上高層的職務後,因貪求該職務帶來的權利、舒適、奉承之後,通常都會
醉心於該職位帶來的優渥感。但是卻忘了這樣的優渥感正會抹殺一個人的敏銳度,一
段時間後便無法面對商場產生的變化與洪流。

◎嘗試業務性質的工作
在許多成功領導人的成功背景上,幾乎都有當過業務,為什麼?
因為業務性質的工作就是不斷的自我突破,因其所需要接觸的個人與企業型態各個皆不
同,你不可能用同一種公式化(或說僵化)的說服方式,來達成業績,耐心與不斷的找尋
方式是成功的關鍵,這也是訓練一個人能否接受逆境考驗(Adversity Quotient)的絕佳
方式。
其次,業務性質的工作會有機會認識其他不同工作性質的客戶或是公司,再將來的成為
領導人後,若有需要相關資源或技術上的協助,從曾經認識的客戶來尋找,可以快速的
縮短重新找尋解決方案時間。

◎面對困境不退卻(如果有未來)
人生總是會有高、低潮,俗話說:勝不驕、敗不餒。
每個人、每個工作都會有低潮期,而且時間長短不一,在低潮時便是一種困境,不可消
極面對,反而 要小心行事,隨時注意突破點。
當然困境可以訓練一個人的AQ,如果檢視過方向是沒有錯的,那麼堅持就會成為自己的
最大動力

◎時時對自己發問
時代在進步,社會在改變,因此”變”則是不變的原則。常常找時間與自己對談討論,
將會發現自己會更清楚方向
1.自己的未來:
若在目前的職務上,有什麼樣的未來性?你有可能坐在你上司的位置上嗎?
需要多久的時間?
依照目前的年紀,還有多少時間可以消耗?如果不合理,轉換跑道機會比較大
嗎?
2.不想當棋子:
你只是主管的旗子嗎?隨時可以被當成棄子?會不會變成下棋的人?對主管而
言你只是工具,不是人?
3.未來20年的狀況
你可感覺到未來20年的可能變化嗎?若20年後自己依然如此,而自己又想有更
好的未來,若自己沒有辦法改變環境,那應該考慮讓自己更換環境了。

◎用現在的狀況,當成未來的常態,敏銳察覺未來趨勢
何先生提到:當我看到朱高正在立法院衝上桌子、搶麥克風時,我就已經意識到,未
來,台灣的議會將會是這個樣子的議會了。
世界變化之快,有時是難以預測的,但是敏銳觀察現在的時勢,將不難發現未來的影
子。
長期的觀察,會發現它已經變成自己的<經驗法則>
這讓我想到了電腦業界中的”摩爾定律”:
摩爾定律是由英特爾(Intel)創始人之一戈登•摩爾(Gordon Moore)提出來
的。其內容為:積體電路上可容納的晶體體數目,約每隔18個月便會增加一
倍,性能也將提升一倍,而價格下降一半;或者說,每一美元所能買到的電腦
性能,將每隔18個月翻兩倍以上。
摩爾定律是簡單評估半導體技術進展的<經驗法則>,其重要的意義在於長期,
而IC製程技術是以一直線的方式向前推展,使得IC產品能持續降低成本,提升
性能,增加功能。
台積電董事長張忠謀曾表示,摩爾定律在過去30年相當有效,未來10~15年應依
然適用。
參考Wikipedia
◎所有的事不可能等你準備好
以前我看過一部電影”亡命感應”,當女主角琳達的丈夫因意外死亡,琳達與丈夫的母
親黛西裡面有段對話...
琳達:我不知道要麼準備面對這樣的事情。
黛西:這種事情不可能讓你準備好的,永遠不可能。

當然這是比較極端的例子。
不過應該可以清楚表達工作生活上很多事情不可能等著你準備好去面對,因此準備”
應變”的心態反而比較簡單。許多人因為生活舒適就忘記事皆是一直在變化的。把自己
的心態放在”所有的事情終會發生的”狀態下,反而比較能處變不驚。

◎工作性質產業具有改變人類生活知識
例如何先生提到的文化產業,乍看之下也是普通的出版產業,但是在不同的企業思想目
標下,也是一個影響深遠的產業,影響著多數人的生活品質,其生活品質不在於狹義的
物質生活品質,而在意義重大的精神生活品質。

◎上位者要不斷自問,並在生崖時刻做決策整理
很多人都會做生涯規劃,但是很多人卻不會將生涯規劃作計畫,因為生涯規劃是長期的
功課,既是長期,就會受到時間及環境的考驗,因此對於生涯計畫的執行卻變成遙不可
及或是空頭支票。務實的生涯計畫就像工作計畫一樣,需要階段目標與執行方式,或而
甚者需要進行計畫的調整。因此當一個階段目標達成之後就要訂下一個階段目標,並且
調整實行計畫,因此不斷的自問,是一個提實行依據的準則。

◎一定要有自己的想法,在依想法構築,而非依環境構築
此法因人而異,但大致上來說,既是自己的想法,就是所謂的目標,因此忘目標方向去
構築實行的方針是重要的。
許多人常常因為無法克服環境的干擾,而使自己的想法依照環境去構築,到頭來,目標
達成後,還是很空虛,因為畢竟已經不是當初自己的想法。
這讓我想到目前的政治人物,也許”最早的”出發點是一種美意,但經過政治環境的阿
諛我詐之後,當初正義的想法也蕩然無存,讓人謂之可惜。

◎不要把事情做到結束才轉彎,在高峰時尋找方向
何先生談及此事,並非指工作上的結束,而是指人生道路上的末路,古有言:物極必
反。
當一個人在高峰時,常常會忘記危機意識,因為當在生涯高峰時,卻忘了高峰能夠停多
久?,因此利用高峰當跳板,尋找下一個高峰是最聰明選擇,否則當開始走下坡時,就
很難再轉向另一個高峰了;在人生開始走下坡時,伴隨而來的是失落感,前進動力消
失,目標已經模糊等等因素,導致在下坡轉向已經無法回頭。

◎轉換會失去部分好處,但要快速取得新方向的關鍵道路
電子學裡面這是基本的道理:轉換必定會有能量消耗。
在李先生的四個行動架構中可以得知,轉換生涯跑道時,必有所犧牲,不外乎金錢、環
境,但是就生涯規畫長遠來看,若是這樣的犧牲可以換得新方向上的更高成就,有時來
說,是值得的。
但是要注意的是:新方向帶來的未知感卻是很大的,因此當走向新的方向時,快速取得
關鍵方法,可以讓自己找到定位點,避免被環境所影響。

◎何謂人才:
若專注於工作、專業的人等多算是個頂級員工,但非人才,
人才之於員工,有明顯的特質差異,具有多方面的能力與成長力,甚至領導力。
(團結團隊合作的能力)

◎找到對的人,能夠預防事情的發生
管理人最大的挑戰就是找到對的人,在國際級的大企業中,一個管理者手下將會有許許
多多員工,然而,管理者並沒有辦法去了解每個員工的詳細狀況,或是工作上的問題。
但是在這麼龐大的做團隊中若無法事必躬親,那應該怎麼辦呢?
大的工作團隊中通常都會有須多非正式小組織,這些小團體的形成,可能是自然的聚集
(如生活習性相近、老鄉),或是工作性質接近等等,在這些小團體中,通常都會有一個
能夠為中心的員工,他能夠收集到的資訊,相當接近前線,也遠多於部門主管。因此,
管理者需要注意到這樣的人,多去認識了解甚至熟識,並從他們口中得知較為即時的一
線情況,若有事情即將發生時也能夠最快得知狀況以應變處理。
至於為何不找部門主管,這當然也是方式之一,但有時肇因於部門主管對於下屬的反應
處理不當,草草了之,或是某些狀況外的主管把重要的訊息壓住了,管理者完全不知事
情的發生,直到事情爆發才發現難以處理。

◎具備溝通能力、語言能力、國際觀
台灣的地小,大眾消費力有限,因此開發國外市場是必然的趨勢,因此語言能力便不在
話下,去英語系國家,要學好英語,去日本要學日語、去德國要學德語等等,這是等於
是基本的溝通能力,否則光是翻譯就耗掉許多寶貴時間。
然而當具備語言能力後就能在其他國家管理公司嗎?這其實是不完全的,若要在其他國
家成立公司並進行管理,對當地的生活習慣、喜好與步調則必須有一定程度的了解,地
處東南亞的經貿國家生活步調相當的緊湊,時間壓力很大;若是到了法國,慵懶的生活
習慣、緩慢的步調,一定會導致管理者與當地員工發生要求上的衝突;又或,在回教國
家員工餐飲裡面供應豬肉,則會成為對對該國宗教的大不敬。因此,了解當地文化,進
入該國家設立公司,就需要依照當地的狀況進行調整,管理者亦是如此,因此這就是國
際觀。
同理,說話溝通方式也不盡相同,例如西方人實事求是,以前在台灣大概就是主管罵
人,員工也不太敢吭聲,默默接受,回家繼續練功;但是在歐美,若是主管有錯,員工
也會反駁回來,即使如此,下班後也會跟你像朋友一般。因為,這是他們從小接受的教
育:實事求是,不須隱瞞。人情嘛...那是另外一方面的事情。所以溝通上的技巧要相當
注意。

◎怎麼問、怎麼答很重要
這關乎一點:聽的人懂不懂你要描述的狀況,因為這也涉及溝通的一種技巧。
李先生提到一個問題:如果我問你,台中需不需要再加蓋酒店(HOTEL),你該怎麼評估?
很多人都會想出一些點子,如:市場調查、觀察路口車流量、觀察人口密集度、外地人
口進出量等等不同的方式。
但,都不是最佳方式,李先生說:我只要一份報表,那就是”飯店住房率”,當住房率
將近9成以上或更多時,當然就要蓋HOTL啦。所以這代表你問的問題,對方聽懂了沒?
※指標性數字的解讀就是管理人節省時間的方式,一個公司會有許許多多的報表,這些
報表在一般員工眼中沒有意義,但是對管理人來說卻是快速分析的關鍵所在。

在我們IT設計人員身上常常也發生這些事情,有時候要開發一個新的程式時,需要跟使
用者進行一連串的對話與詢問,因為使用者多數不會太懂電腦,因此無法法他們需要的
功能與操作方式描述出來,因此若是IT人員不懂詢問的技巧或是方式,常常會使的程式
開發後再與使用者進行測試磨合週期一延再延,使得開發成本提高。因此有經驗的PM在
與客戶溝通時必須能夠問到對的方向,讓使用者正確答出開發程式時所需要的元素,減
少程式開發成本,提高利潤。

◎專業力(能力)、正確觀念、正確態度
(態度0分 X 任何能力 = 0分)
現在許多人都認為專業勝過一切,若是單打獨鬥的人,也許這句話是確的;但是單打獨
鬥的人,卻是沒有辦法把事情做大的。
在企業中重要的的是合作關係、團隊關係,一個團隊裡面的成員若是彼此間沒有正確的
觀念、態度,團隊如同散沙。
團隊的目標觀念明確,各司其職,溝通良好,這樣的團隊成員就可以互彌長缺,使工作
順利進行。
俗話說:三個臭皮匠,勝過一個諸葛亮。這句話形容得真好:團隊能力可以勝過一個能
力很強的人
常見的業務訓練中常聽到的是王永慶的一天等於一般上班族的多少天:
一個上班族一天上班8小時一個月3萬元
一天8小時x5天x50週x一生40年=8萬小時
一生不吃不喝收入1千4百40萬
 
王永慶
經營多種事業,員工共有6萬多人
6萬x8小時=48萬小時
一天的收入是一個普通人 從出生到終老,人生來回6次

當然這也是極端的例子,但是從例子中不難看出:如果王永慶能力很強,一個人單打獨
鬥,那他會是今天的樣子嗎?事實上是王永慶出身學歷低微,能力也不突出,但是他靠
努力,經營團隊,成就他的大事業。所以,團隊很重要嗎?當然重要囉!


李紹唐先生演講簡報PDF

2008年3月27日 星期四

PB多線程自動排程設計(一)

多線程的設計主要是為了改進單線程自動排程的問題,因此設計成多線程的執行方式來解決,但由於PowerBuilder本身沒有辦法設計MultiThread,因此改用多程式方(MultiProcess)式來模擬此方法。

既然是MultiProcess,那麼需要2支程式,一支是排程程式(Scahdule runner),與工作執行程式(Work Processor)。

排程程式:屬於獨立運作的程式,其內容相當單純,只負責排程表(Scahdule Table)的掃描(Scan)與執行呼叫(Call),由於本身不需要處理工作,因此沒有被工作延滯的可能性,單純的處理排程表的掃描,也可以減少多餘的程式碼維護。

工作執行程式:被動式程式,裡面會撰寫所有的工作程式碼,此程式可以被多次執行,由於在windows下一支程式可以被多次執行,而且不會互相干擾(這是指程式本身,不包含都在讀取相同資料庫的資料表產生的LOCK),所以利用windows的MultiProcess特性來達成模擬multiThread效果。

呼叫意示圖:

多重呼叫亦試圖:

由上圖看,好像需要寫出很多的WorkProcessor程式,但其實不然,在PB的application的OPEN事件中,可以取得CommandLine參數,該Processor程式只需要將所有工作寫在裡面,然後利用CommadnLine來判斷需要執行哪個工作程式碼即可完成。

呼叫方式:
假設排程程式是app.exe,工作執行程式是proc.exe,當排程掃描到此時該執行A工作時,只需要執行
Run('proc.exe A')

當proc.exe執行時,在其OPEN事件的參數CommandLine即可得到一個字串"A",在使用Choose Case來判定執行的程式碼片段。

當然這樣的程式設計也有它的優缺點

優點:排程、工作獨立分離,不互相干擾時序,運作流暢度高。

缺點:程式維護複雜、錯誤追蹤相當困難。

範例程式下載

2008年3月26日 星期三

PB單線式自動排程程式設計(二)

繼上一篇PB單線式自動排程程式設計(一)

這篇來談談如何改進上一篇的STACK溢位問題吧。
其實這個方法並不難,但是要有足夠的觀念。

1.在原來的window上增加一個自訂事件ue_process
2.在window的共用變數(Instance variables)增加一個布林值
Boolean ib_busy = false

3.把原本在timer事件中的 程式碼全部移動到 ue_process事件中
4.在ue_process事件中的程式碼(不包含變數定義)開頭加入:
ib_busy = true

在程式碼最後加入:
ib_busy = false

5.在原本的timer事件中寫下下列程式碼:

If ib_busy = false Then
post event ue_process()
End If


原理是利用旗標變數ib_busy來阻擋事件被觸發,當ue_process被執行時 ib_busy被設定為true,假設此時工作A發生問題時,timer事件的再觸發執行時可以透過ib_busy避免ue_process被觸發,如此ue_process就不會有一直被stack起來的問題。

那為何程式要移至ue_process事件?這是因為程式若移至ue_process事件後該工作被執行時stack指標是處在ue_process上,當clock觸發timer事件時,由於timer事件並無被stack住,所以可以順利的執行,因此不會被擋住,該事件可以被順利處理不會stack起來。

當然此法是可以避免timer觸發事件無法消化的問題導致stack溢位而crash發生,但是卻也沒辦法保證其它工作可以正常執行,因為只要有其中一個工作不正常,整個程式依然處在停擺狀態。

比較好的方式就是利用多執行緒撰寫程式,可惜powerbuilder並非用來設計低階處理的程式工具,因此無法像C/C#班可以設計多執行緒;當然山不轉路轉,不能設計多執行緒,但可以設計多執行程式,所以另一種方法便是利用多程式執行方式達到此效果。

PB單線式自動排程設計(一)

簡介:
這裡所謂單線式排程程式,意指排程掃描與工作處理程式都寫在同一支程式裡面,由於PowerBuild 6程式本身無法像C#般寫成多執行緒的能力,因此在同時處理許多作業時,都得依照程式碼執行的STACK順序執行,故名為"單線式"

準備與設計:
1.首先必須要有一分工作排程清單,例如每日工作

這樣的資料表結構你可以設計成DataWindow,當然你如果要增加欄位或是功能,都是可以的,不過基本上的結構是如此。

結構中"時"、"分"的欄位是用來比對是否進行工作的時間點,當時間行程到達該時間點時就得進行該工作的執行。

"執行時間"則是代表此工作"被執行完成"的時間點,這個用來判斷該工作是否已經被執行,而不會被重複執行的要件。

"啟用"則是決定該工作是否需要被執行,有的人會以另一種觀點"暫停"來設計。

"工作名稱"顧名思義只是用來顯示的名稱,讓人一目瞭然知道此工作的用途。

"代號"則是代表該工作在程式碼運作時的實際作業。

2.設計視窗:
設計一個window(w_app),並將上述排程DataWindow(dw_1)加入裡面。











另外設計一個MultiLineEdit,用以觀察執行結果。

3.程式碼撰寫:
OPEN事件
由於排單位是以"分"為基礎比對單位,故時間的區隔就以"分"為準則,因此在w_app的Open事件中寫入Timer(60),表示以60秒觸發一次Timer事件。

TIMER事件

Long    ll_count , ll_row

ll_count = dw_1.RowCount()
For ll_row = 1 to ll_count
// 檢查該工作是否啟用,若不啟用則跳過
If dw_1.GetItemString(ll_row , 'active') <> '1' Then Continue

// 檢查當天是否已經被執行過,若執行過者不再被執行
If date(dw_1.GetItemDatetime(ll_row , 'work_time')) >= today() then Continue

// 檢查是否符合執行時間,需要被執行
If dw_1.GetItemNumber(ll_row , 'hour') = Hour(now()) and &
dw_1.GetItemNumber(ll_row , 'min') = Minute(now()) then


// 填入/覆寫執行時間
dw_1.SetItem(ll_row , 'work_time' , Datetime(today() , now()))

// 顯示執行訊息
mle_1.text += String(now() , 'hh:mm') + &
' 執行工作[' + dw_1.GetItemString(ll_row , 'name') + '] ~r~n'

// 依照代號執行需要做的事情
Choose Case dw_1.GetItemString(ll_row , 'code')
Case 'A'
// 執行工作A的程式碼......
Case 'B'
// 執行工作B的程式碼......
Case 'C'
// 執行工作C的程式碼......
Case 'D'
// 執行工作D的程式碼......
Case 'E'
// 執行工作E的程式碼......
End Choose
end if

Next


4.以上只要在各執行工作的Case中寫入程式碼就完成基本的單線自動排程程式,其他的部份再依照個人需求去增減功能即可,如排程增減/維護/存檔。

優點:
原理簡單、撰寫設計容易,維護也容易,適合於資料處理量少的工作。

缺點:
每次增加工作都必須修改程式碼。
遇到單一工作處理資料量過大需要較長的工作時間時(超過1分鐘者),排程容易崩潰,使排程失效,甚而使程式CRASH掉。

程式為何會CRASH?原因出在TIMER指令,假設第一次觸發TIMER事件後執行其中一個工作A,而A工作剛好發生問題(讀資料過久、無限回圈等等),當然程式主執行緒會一直處在等待A工作完成才能繼續,但是TIMER指令是由系統CLOCK觸發,因此在每分鐘觸發一次的情況下,TIMER事件的STACK會不斷累積直到溢位,當溢位發生時程式便CRASH了。

範例程式下載