新控件的創(chuàng)建是通過繼承已經(jīng)存在的控件來得到的,一般控件繼承Fl_Widget得到,組合控件繼承Fl_Group得到
一個(gè)普通控件一般通過接收和顯示一個(gè)值來與用戶交互
一個(gè)組合控件包含一組子控件并處理子控件的移動(dòng),改變大小,顯示或隱藏事件。Fl_Group是所有組合控件的基類,其他組合控件比如Fl_Pack, Fl_Scroll, Fl_Tabs , Fl_Tile, Fl_Window都是他的子類
你也可以通過繼承其他的已存在控件來得到你要的控件,通過提供不同的外觀和接口。比如Button 控件都是 Fl_Button類的子類。他們的共同點(diǎn)是都是通過鼠標(biāo)點(diǎn)擊事件與用戶交互。唯一不同的是按鈕的外觀。
如何開發(fā)一個(gè)控件的子類
你的子類可以直接繼承Fl_Widget 類,也可以繼承任何Fl_Widget類的子類。Fl_Widget只有四個(gè)虛擬函數(shù),子類必須重載所有的或部分的這些函數(shù)。
構(gòu)造函數(shù)
構(gòu)造函數(shù)應(yīng)該有以下參數(shù)
MyClass(int x, int y, int w, int h, const char *label = 0);
這就允許該類能很好的應(yīng)用于FLUID中
這個(gè)構(gòu)造函數(shù)必須調(diào)用基類的構(gòu)造函數(shù)并傳遞相同的參數(shù)
MyClass::MyClass(int x, int y, int w, int h, const char *label)
: Fl_Widget(x, y, w, h, label) {
// do initialization stuff...
}
Fl_Widget的保護(hù)構(gòu)造函數(shù)通過傳遞的參數(shù)x,y,w,h,label分別設(shè)置x(),y(),w(),h()和label()并初始化其他的屬性如:
type(0);
box(FL_NO_BOX);
color(FL_BACKGROUND_COLOR);
selection_color(FL_BACKGROUND_COLOR);
labeltype(FL_NORMAL_LABEL);
labelstyle(FL_NORMAL_STYLE);
labelsize(FL_NORMAL_SIZE);
labelcolor(FL_FOREGROUND_COLOR);
align(FL_ALIGN_CENTER);
callback(default_callback,0);
flags(ACTIVE|VISIBLE);
image(0);
deimage(0);
Fl_Widget的保護(hù)成員函數(shù)
以下的成員函數(shù)是Fl_Widget提供給子類的:
Fl_Widget::clear_visible
Fl_Widget::damage
Fl_Widget::draw_box
Fl_Widget::draw_focus
Fl_Widget::draw_label
Fl_Widget::set_flag
Fl_Widget::set_visible
Fl_Widget::test_shortcut
Fl_Widget::type
void Fl_Widget::damage(uchar mask)
void Fl_Widget::damage(uchar mask, int x, int y, int w, int h)
uchar Fl_Widget::damage()
第一個(gè)函數(shù)是指對(duì)象的部分需要更新。參數(shù)mask中的位設(shè)置傳遞給damage().draw()函數(shù)能根據(jù)該值得到哪些需要重畫。公共成員函數(shù)Fl_Widget::redraw()只是簡(jiǎn)單的做Fl_Widget::damage(FL_DAMAGE_ALL),即所有的都重畫,但是你的控件真正執(zhí)行的時(shí)候會(huì)調(diào)用私有成員函數(shù)damage(n).
第二個(gè)函數(shù)指某個(gè)區(qū)域無效,需要重畫。
第三個(gè)函數(shù)返回所有damage(n)的調(diào)用所產(chǎn)生的位。
當(dāng)重新畫一個(gè)控件時(shí),你應(yīng)該先看看無效位,再?zèng)Q定你的控件的哪部分需要重新畫。Handle()函數(shù)能夠設(shè)置單獨(dú)的無效位限制需要重畫的數(shù)量。
MyClass::handle(int event) {
...
if (change_to_part1) damage(1);
if (change_to_part2) damage(2);
if (change_to_part3) damage(4);
}
MyClass::draw() {
if (damage() & FL_DAMAGE_ALL) {
... draw frame/box and other static stuff ...
}
if (damage() & (FL_DAMAGE_ALL | 1)) draw_part1();
if (damage() & (FL_DAMAGE_ALL | 2)) draw_part2();
if (damage() & (FL_DAMAGE_ALL | 4)) draw_part3();
}
void Fl_Widget::draw_box() const
第一個(gè)函數(shù)根據(jù)該控件的尺度畫他的box().第二個(gè)函數(shù)根據(jù)box的類型b ,顏色c畫box.
void Fl_Widget::draw_focus() const
void Fl_Widget::draw_focus(Fl_Boxtype b, int x, int y, int w, int h) const
在一個(gè)空間的限制box中畫出焦點(diǎn)筐。第二個(gè)函數(shù)允許指定另一個(gè)不同box來畫焦點(diǎn)
Fl_Widget::draw_label() const
void Fl_Widget::draw_label(int x, int y, int w, int h) const
void Fl_Widget::draw_label(int x, int y, int w, int h, Fl_Align align) const
Draw()函數(shù)調(diào)用該函數(shù)來畫一個(gè)控件的label,如果標(biāo)簽出了該控件的box 范圍,將不會(huì)被畫出。
第二種形式自定義一個(gè)box來畫標(biāo)簽,比如用于移動(dòng)的滑塊
第三種形式可以將標(biāo)簽畫在任意的地方
void Fl_Widget::set_visible()
void Fl_Widget::clear_visible()
與Fl_Widget::show() Fl_Widget::hide()作用相同,但不發(fā)送FL_SHOW,FL_HIDE事件。
int Fl_Widget::test_shortcut() const
static int Fl_Widget::test_shortcut(const char *s)
uchar Fl_Widget::type() const
void Fl_Widget::type(uchar t)
返回一個(gè)8位的標(biāo)示符,用于與Forms兼容,你也可以同于其他任何目的,設(shè)置的值應(yīng)該小于100,以免與系統(tǒng)的保留值沖突
處理事件
虛擬函數(shù)int handle(int event)被用來處理任何發(fā)送給控件的事件.他能:
改變控件的狀態(tài)
調(diào)用Fl_Widget::redraw()如果該控件需要重新顯示
調(diào)用Fl_Widget::damage(n)當(dāng)控件需要部分更新時(shí)(假如你在Fl_Widget::draw()函數(shù)中提供了對(duì)該函數(shù)的支持)
調(diào)用Fl_Widget::do_callback()如果一個(gè)回調(diào)函數(shù)產(chǎn)生時(shí).
調(diào)用Fl_Widget::handle()對(duì)子控件
事件用一個(gè)整數(shù)來標(biāo)識(shí).最近事件產(chǎn)生的其他消息靜態(tài)存儲(chǔ)在本地,調(diào)用Fl::event_*()可以得到.
以下是一個(gè)利用handle()處理事件的例子,該控件的行為類似按鈕同時(shí)接收x按鍵并調(diào)用回調(diào)函數(shù)
int MyClass::handle(int event) {
switch(event) {
case FL_PUSH:
highlight = 1;
redraw();
return 1;
case FL_DRAG: {
int t = Fl::event_inside(this);
if (t != highlight) {
highlight = t;
redraw();
}
}
return 1;
case FL_RELEASE:
if (highlight) {
highlight = 0;
redraw();
do_callback();
// never do anything after a callback, as the callback
// may delete the widget!
}
return 1;
case FL_SHORTCUT:
if (Fl::event_key() == 'x') {
do_callback();
return 1;
}
return 0;
default:
return Fl_Widget::handle(event);
}
}
當(dāng)你的handle()函數(shù)處理某事件后不能返回0,若是返回0,父控件將會(huì)把該事件發(fā)送給其他控件。
畫控件
當(dāng)FLTK需要重畫控件時(shí)將調(diào)用虛擬函數(shù)draw().只有在damage()返回非0值時(shí)調(diào)用該函數(shù),draw()返回后,damage()被清0。Draw()應(yīng)該被聲明為保護(hù)成員函數(shù),避免在不需要寫畫圖代碼時(shí)用到。
Damage()將包含從最后一次調(diào)用draw()后damage(n)調(diào)用產(chǎn)生的所有與或位信息,根據(jù)該信息只重畫需要重畫的位置,只有FLTK認(rèn)為需要全部重畫時(shí)才打開FL_DAMAGE_ALL位,比如收到expose事件。
修改控件的尺寸
resize(int x,int y,int w,int h)在控件被移動(dòng)和改變大小時(shí)被調(diào)用,這些參數(shù)分別是新位置,寬度和高度。但是x(),y(),w(),h(),還是以前的值,若要改變這些值,必須在基類中也調(diào)用resize()函數(shù)
不需要調(diào)用redraw()函數(shù),至少只改變x(),y()時(shí)不需要,因?yàn)橐粋€(gè)組合控件有一套更有效的方法來畫新的位置
如何制作一個(gè)組合控件
一個(gè)組合控件包括一個(gè)或多個(gè)子控件。制作組合控件必須繼承Fl_Group類.不繼承Fl_Group類當(dāng)然也可能可以制作一個(gè)組合控件,但是你還是要重新寫Fl_Group類里面的工作
子控件可能在類里面聲明
class MyClass : public Fl_Group {
Fl_Button the_button;
Fl_Slider the_slider;
...
};
構(gòu)造函數(shù)要初始化這些子控件。他們將被自動(dòng)的add()到group中。因?yàn)?/span>Fl_Group構(gòu)造函數(shù)調(diào)用了begin().在構(gòu)造函數(shù)中不要忘記調(diào)用end()函數(shù)
MyClass::MyClass(int x, int y, int w, int h) :
Fl_Group(x, y, w, h),
the_button(x + 5, y + 5, 100, 20),
the_slider(x, y + 50, w, 20)
{
...(you could add dynamically created child widgets here)...
end(); // don't forget to do this!
}