全國最多中醫師線上諮詢網站-台灣中醫網
發文 回覆 瀏覽次數:8877
推到 Plurk!
推到 Facebook!

[轉貼]Writing VCL Component in BCB

 
axsoft
版主


發表:681
回覆:1056
積分:969
註冊:2002-03-13

發送簡訊給我
#1 引用回覆 回覆 發表時間:2002-06-13 09:59:07 IP:61.220.xxx.xxx 未訂閱
這是我很久以前在網路上收集的文章,現在網路上已經找不到這一篇文章了 至於作者也不詳(我忘了) 只有作者的e-mail:s8427154@cycs03.ice.cycu.edu.tw 該作者應該也重學校畢業了!e-mail可能無效了 如作者見此文,請發表一下!謝謝! ========================================= VCL元件DIY         Writing VCL Component in Borland C Builder 1.0 前言 Borland出的Delphi在市場上耕耘了數年了,會用Delphi的人,大都會自己有自己寫的元件,幾年下來,VCL的資源豐富,大部份各位想要的元件大都已有人寫出來了.然而萬一(真的萬一)有一天,你要元件但是找不到.....嘿嘿嘿...就只有DIY了.今天不是給各位魚吃,而是教各位釣魚的方法.那麼就將小弟嘗試(不敢說研究)的結果,供大家參考,也許哪天各位放棄M$派的語言,轉而投向Borland陣營時,這一篇就會有小小的參考價值..... 建立一個新的元件 咱們廢話少說,先New一個新的元件出來吧.在上方選單上有一個"Component",選擇後再選"New",這時會開一個Component Wizard要你定義Class Name(你所要寫的元件的名字),Ancestor type(這個元件的父類別)和Palette Page(你要將元件放於哪一個元件Page).假設我們定Class Name = TMycomponent , Ancestor type = TCustomControl按OK之後出現一個畫面(如圖一). 咱們先儲存起來吧,再把這個CPP檔和H檔打開.這時C Builder已經建立了一個最基本的元件(就是什麼功能都沒有的那一種).想裝裝看嗎??找上方選單的"Component",選擇後選"Install",按"Add"把你的元件加進去,按"OK"等它Compile完就可以了.想知道你的元件在哪出現嗎??到你元件中設定的Palette Page中找找看吧... 繪出元件的外形. 其實對windows程式有點了解的人都知道,攔截WM_PAINT可以重繪外形,做Repaint()的動作.所以我們勢必要Handle這個函數,幸運的是WM_PAINT自動地被C Builder所攔截,我們只要在類別中implement這個Paint()函數就可以了.然後在Paint()中利用Canvas去畫出你的元件的外型. 例如將元件繪成一個黑心實心的矩形: 在H檔的protected中 void __fastcall Paint(); 在CPP檔中 void __fastcall TMycomponent :: Paint() { Canvas->Brush->Color=clBlack; Canvas->Brush->Style=bsSolid; Canvas->Rectangle(0,0,Width,Height); } 不難,對吧?? 增加元件的函數. 平常我們在寫類別時,多少都會帶上一些Method.同樣的VCL也可以,因為VCL本身就是一個類別.那也就是說,我們只要寫類似一般C 類別的Method就可以了.夠簡單吧?? 如何在元件中再加入另一個元件? 這一點我舉一個例子來說明好了. 例如在我們寫的元件(TMycomponent)中加入一個Timer. 請在H檔中的private中加入 TTimer *Timer1; void __fastcall Timer1Timer(TObject *Sender); 請在CPP檔的建構子中加入 Timer1 = new TTimer (this); Timer1->Interval=1000; // 1秒觸發一次 Timer1->Enabled=true; // 允許Timer Enable Timer1->OnTimer= Timer1Timer; // 設定Timer的Event為Timer1Timer函數 然後寫Timer1Timer這個函數. void __fastcall TMycomponent::Timer1Timer(TObject *Sender) { // 你想做的事......... } 不錯吧.當然這只是個例子,你可以加其他的元件進來. 增加Properties 用過Delphi或C Builder的人都該知道每次編寫一個Form時,會有一個視窗(Object Inspector)列出各個元件的Properties,大家都可以在上面改變元件其中幾個Properties的值,那你就會問我,這個東西應該如何做呢?? 其實這個東西不難,但是該注意的地方很多,請君耐心待我說來: 在H檔中的__published或public部份(一般來說是__published)寫下(我們假設要多一個property為Test ,Data type為int ) __property int Test = {read = MyTest ,write = MyTest ,nodefault}; 在H檔中的private部份加入 int MyTest; 這時一個property就加進去了(興奮嗎??Rebuild Library,然後new一個新的Form,去拉你所寫的元件到這個Form,仔細看一下Object Inspector,看到沒??沒關係,你可以靠近一點.沒看到??沒關係,你可以再靠近一點.....^_^) 說明一下: __property int Test = {read = MyTest ,write = MyTest ,nodefault}; 在大括號中 read=MyTest //當有人要讀Test的值時,就傳MyTest的值回去 //這也可以給Function的名稱 . write=MyTest//當有人要寫Test的值時,就寫到MyTest //這也可以給Function的名稱. !![注意] 若要給Function名稱,則此Function宣告必須在private中, 而在function前加入__fastcall. 例如: 在H檔的private中 int MyTest; void __fastcall SetMyTest(int Value); 在H檔的__published中 __property int Test = {read = MyTest,write=SetMyTest,nodefault}; 在CPP檔中 void __fastcall TMycomponent :: SetMyTest(int Value) { MyTest=Value; } 不錯吧.也許你會問我,這個的效果不是和剛剛那個一樣嗎??那我們幹嗎要換??? 這一點請看下一個小主題 < Event > 你就會明白了.一些Event如OnChange等的Event,就是在這裡被觸發的!! 增加新的Event 這是另一個重點,因應需要,很多情形下我們必需要觸發一些自訂的Event.這就會讓人想起了一些問題,我何時才要觸發Event??我如何觸發Event??我的Event的作用是啥??這些想清楚了之後,再來寫會比較好.再回到上一個小主題的最後一部份,我們談到了可以用Function存取Properties時,順帶著觸發Event.那就舉上一個例子做為其之延伸吧!! 例: 我們希望當使用者修改Test的值時會觸發OnChange 的Event. 在H檔的private中加入 TNotifyEvent FOnChange; int MyTest; void __fastcall SetMyTest(int Value); 在H檔的__published中 __property int Test = {read = MyTest,write=SetMyTest,nodefault}; __property TNotifyEvent OnChange = {read=FOnChange, write=FOnChange}; 在CPP檔中 void __fastcall TMycomponent :: SetMyTest(int Value) { MyTest=Value; if ( FOnChange!=NULL) FOnChange(this); } 如此當有人修改了Test的值時,而且Event所指向的Function 有被你所設過的話,就會去執行該Function的程式碼. 如此完成了自訂Event的觸發.帥氣,不是嗎?? 攔截訊息. 在Windows中漫布著Message的流動,我想這是每一個了解Windows程式設計的人都會知道的.因應著某些需要,我們必須去攔截某一些我們要的訊息.例如當元件的大小改變時,我們必須做出相對應的動作,如重繪元件等,那就必須去攔截WM_SIZE.如果我們需要在某個地方設定Focus,那麼我們就必須去攔截WM_SETFOCUS來達到我們的要求. 重點是:我們該如何去攔截我們要的Message呢??我們舉例子說明:以攔截WM_SIZE來說. 在H檔的private中寫入 MESSAGE void __fastcall WMSize(TWMSize &Message); 在__published中寫入 BEGIN_MESSAGE_MAP MESSAGE_HANDLER(WM_SIZE, TWMSize, WMSize); //第一個參數:攔截的訊息名稱 //第二個參數:對應到C Builder中的結構宣告 //第三個參數:攔入訊息的Function名稱. END_MESSAGE_MAP(TCustomControl); ^^^^^^^^^^^^^^^這是父類別 在你的CPP檔中寫入 void __fastcall TMycomponent::WMSize(TWMSize &Message) { //你要的處理 } 大功告成.你已攔截了你要的訊息了.簡單吧,以各位的聰明才智舉一反三,甚至是反十,我想都不會有什麼問題,只是改一些小地方而已. 到此,我們已把最基本的元件寫法,談了一遍,大家可以喝杯茶輕鬆一下,後面的幾個小題將提到一些觀念和一些各位可能會問的問題.先去看個電視再來看其他的吧.....*^_^* 我應該從哪一個類別來繼承呢?? 這是一個好問題,每個人第一次寫元件都會不知道該從哪一個類別繼承..在VCL中有一些所謂的"自訂"類別,許多許多的控制項就直接從這些"自訂類別"裡繼承下來.例如說:TMemo是繼承自TCustomMemo類別 , TRichEdit則是從TCustomRichEdit繼承下來的,如果你寫的元件是寫類似這些功能的話,那你可以直接繼承相對應的自訂類別. 如果你要寫視覺元件,可以繼承自TGraphicControl,不過這有個缺點,就是沒有Window Handle,亦不能接受輸入焦點. 如果你要寫類似Timer元件(拉至Form上還是一樣一個小圖)的話,可以繼承TComponent 如果你要寫有關視窗元件的話,那你可以繼承自TWinControl因為它將已存在的視窗控制項包裝起來,如Windows標準控制項或VBX元件. 為何我的元件不能處理方向鍵?? 這一點你就必須去攔截一個叫WM_GETDLGCODE的訊息才能處理方向鍵的訊息,如果你不這樣做,那方向鍵的功能就只能用來移動視窗的焦點而已. 在H檔案中的private加入 MESSAGE void __fastcall WMGetDlgCode ( TWMGetDlgCode &Message); 在__published的部份 BEGIN_MESSAGE_MAP MESSAGE_HANDLER(WM_GETDLGCODE,TWMGetDlgCode,WMGetDlgCode); END_MESSAGE_MAP(TCustomControl); ^^^^^^^^^^^^^^^ 注意這是你元件的Ancestor type 在CPP檔中 void __fastcall TMycomponent::WMGetDlgCode(TWMGetDlgCode &Message) { Message.Result=DLGC_WANTARROWS|DLGC_WANTCHARS; } [另一種做法] 攔截CM_WANTSPECIALKEY這個元件訊息!! 這一個元件訊息提供給你比攔截WM_GETDLGCODE這個 視窗訊息更容易且靈活的判斸方法來決定是否需要某些特殊 鍵的訊息.特殊鍵抱括:VK_TAB,VK_LEFT,VK_RIGHT, VK_UP,VK_DOWN,VK_RET,VK_ESCAPE和VK_CANCEL. 如果訊息傳回值是非零值,這個鍵就會被送至KeyPress方法 以供處理,否則這個鍵的訊息會被送至元件的父控制項,以預 設方式來處理. // 在H檔的private: Message void __fastcall CMWantSpecialKey(TCMWantSpecialKey &Message); // 在H檔__published: BEGIN_MESSAGE_MAP MESSAGE_HANDLER(CM_WANTSPECIALKEY, TCMWantSpecialKey,CMWantSpecialKey); END_MESSAGE_MAP(TCustomControl); // 在CPP檔中 void __fastcall CMWantSpecialKey(TCMWantSpecialKey &Message) { switch(Message.CharCode) { case VK_LEFT: case VK_RIGHT: case VK_UP: case VK_DOWN: Message.Result=1; break; } } 為何我的元件重繪時的會有閃動的情形?? 引起閃動的原因很多,主要是WM_PAINT和WM_ERASEBKGND這兩個訊息的處理.當VCL控制收到WM_ERASEBKGND這個訊息時,它會將元件背景擦掉,然後設定成背景預設的顏色.也就是說,再整個元件重繪之前,會先被清成背景的顏色,然成再動WM_PAINT予以重繪.如此就是造成閃動的最主要原因了.這個情形尤以繼承自TWinControl的元件較多此類之情形. 如何解決???就是告訴Windows你要自行解決"所有的"繪圖動作,如此Windows就不會做清成背景色的動作.但是有一個很重要的前提,就是你一定要確定你的Paint Method的確把整個元件重繪過,如果漏了什麼地方忘了畫,那麼那個地方的資料會好像透明的元件一樣,有視窗在元件上方就會留下殘影,可以想見其情況否?? 這個方法可以加速元件的繪圖動作,這可以想見的,因為少了填背景色的動作. // 在H檔的private: Message void __fastcall WMEraseBkgnd(TWMEraseBkgnd &Message); // 在H檔__published: BEGIN_MESSAGE_MAP MESSAGE_HANDLER(WM_ERASEBKGND, TWMEraseBkgnd,WMEraseBkgnd); END_MESSAGE_MAP(TCustomControl); // 在CPP檔中 void __fastcall WMEraseBkgnd(TWMEraseBkgnd &Message) { //不要重繪背景,會造成元件閃動地喔!! Message.Result=1; } [另外一種可能] 就是在你寫Paint Method時,在裡面用了類似以下的函數來 繪元件,如Canvas中的FillRect(),這個函數在每次畫繪時會做 類似WM_ERASEBKGND訊息的動作,所以要避開這些動作. VCL在C Builder 1.0和C Builder 3.0的不同點: C Builder1.0 繼承了Delphi 2.0的傳統,C Builder3.0則相似於Delphi 3.0,其主要的不同點在於Package.Borland在推出Delphi3. 0加入Package的觀念,就是將各個類似的元件置於同一個Package中,某天覺得這個Package的元件,暫時不適合留著用,你可以先Disable這個package,而不用把它從Library中移除,若是以後有用到的一天,就把它Enable回來就好了.Package也就提昇了管理上的方便. 然而為了迎合這個目標,在VCL的撰寫上,就有些小地方不一樣,但是大部份是相同的.例如:<圖二> 結論: 林林總總談了一堆,其實還有一些沒有談到的地方,礙於篇幅,只好待以後有機會在談談吧. 有問題的話,可以mail給我:s8427154@cycs03.ice.cycu.edu.tw
dllee
站務副站長


發表:321
回覆:2519
積分:1711
註冊:2002-04-15

發送簡訊給我
#2 引用回覆 回覆 發表時間:2002-06-14 10:12:31 IP:61.231.xxx.xxx 未訂閱
真是有用的內容,目前我最最不會的就是去攔截視窗的訊息,只會繼承原元件的事件。有了這份文件,就可以新增更多的事件了 
------
http://www.ViewMove.com
axsoft
版主


發表:681
回覆:1056
積分:969
註冊:2002-03-13

發送簡訊給我
#3 引用回覆 回覆 發表時間:2002-06-17 08:35:28 IP:61.220.xxx.xxx 未訂閱
希望您也能將您的製作元件心得說給大家參考一下喔!這樣大家就多一個學習的機會嘍!
dllee
站務副站長


發表:321
回覆:2519
積分:1711
註冊:2002-04-15

發送簡訊給我
#4 引用回覆 回覆 發表時間:2002-06-19 09:57:22 IP:61.231.xxx.xxx 未訂閱
引言: 希望您也能將您的製作元件心得說給大家參考一下喔!這樣大家就多一個學習的機會嘍!
說真的,我用 BCB 近 5 年了,直到最近才開始學寫 VCL 元件。 因為我對於 OO 的感覺還是太少... 在沒 OO 的 DOS 時代實在是奮鬥太久了,用 BCB 只因懶得再學 Object Pascal... 對於之前開發的程式,大多沿用沒有 OO 的架構,會寫一些 functions 給 VCL 元件的某事件去叫用,都沒有想過要把 VCL 改寫或增強。 之前有想過要寫 VCL 元件,但在網路中可下載的 VCL 元件含原始碼的,大多都是 Delphi 的原始碼,好像很少人用 BCB 在寫 VCL 元件~~ 大部分賣 VCL 元件的軟體公司也都是使用 Delphi 在開發,其商用完整版所附的都是 Delphi 的原始碼... 如果我是軟體商,而且要賣 VCL 元件,那我也會要求使用 Delphi 來開發,這樣才能同時賣給 Delphi 使用者及 BCB 的使用者。 ... 如果當完兵時 BCB 還沒出,那我可能就會去學 Delphi 了 ... 會開始學寫 VCL 元件,是因為公司的同事開始寫 VCL 元件了,如果再不自學就來不及了...
------
http://www.ViewMove.com
GGump
一般會員


發表:2
回覆:16
積分:8
註冊:2006-08-04

發送簡訊給我
#5 引用回覆 回覆 發表時間:2008-03-17 02:56:49 IP:118.166.xxx.xxx 訂閱
我依該校的校友服務資訊網頁查到了,文章來源是:

http://wwwsrv.cc.cycu.edu.tw/ALUMNI_SCRIPT/AL20000.asp?STDNO=8427154

希望並不會造成他的困擾
編輯記錄
GGump 重新編輯於 2008-03-17 02:58:23, 註解 無‧
GGump 重新編輯於 2008-03-17 02:59:35, 註解 無‧
系統時間:2024-05-03 5:25:23
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!