<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Fltk 1.3 系列教程(4)

      原創(chuàng),轉(zhuǎn)載請注明出處。Copyright (c) Dingmaotu(Leading) (dingmaotu@126.com)

      Callback、面向?qū)ο蠛妥址幚?/span>

      以前多在163博客上寫東西,現(xiàn)在發(fā)現(xiàn)對于編程的事,還是在博客園上有人關(guān)注。原來的3個教程轉(zhuǎn)過來,成了轉(zhuǎn)載(雖然是自己轉(zhuǎn)自己的),
      發(fā)到首頁,被警告了……這次在博客園首發(fā)吧

      上一次學(xué)了高級一點(diǎn)的布局,以及怎樣處理resize。現(xiàn)在讀者應(yīng)該能根據(jù)手冊創(chuàng)建任意控件組合的復(fù)雜的對話框了。
      這一節(jié)我主要講一下Fltk對控件事件的處理,順便把上節(jié)課的例子重構(gòu)成面向?qū)ο箫L(fēng)格的。另外Fltk中有些特性(或Bug)
      已經(jīng)過時,很讓人不爽,其中字符串處理就是一個。

      在Fltk中,每一個控件只有一個我們感興趣的事情,比如對于按扭,就是用戶按下它,對于文本輸入框,就是文本改變等。
      所以每一個控件(Fl_Widget)都有一個方法叫callback(Fl_Callback*, void *),指定一個回調(diào)函數(shù)以及傳給這個函數(shù)的參數(shù)。
      回調(diào)函數(shù)的原型是這樣的:

      typedef void (Fl_Callback)(Fl_Widget*, void *);

      第一個參數(shù)是事件發(fā)生的那個控件,第二個是在指定callback時給的任意參數(shù)。這個函數(shù)試用于所有控件,因此,我們這一節(jié)
      課貌似又要結(jié)束了……不過還是那句話,寫代碼時還會遇到問題,下面是所有的代碼(很多注釋,主要內(nèi)容都在這里):

        1 #include "FL/Fl.H"
      2 #include "FL/Fl_Double_Window.H"
      3 #include "FL/Fl_Button.H"
      4 #include "FL/Fl_Input.H"
      5 #include "FL/Fl_Multiline_Input.H"
      6 #include "FL/Fl_Box.H"
      7 #include "FL/Fl_Pack.H"
      8
      9 // 以下文件包含的是常見的顯示消息的函數(shù),例如
      10 // void fl_alert(const char *fmt, ...), 顯示信息,像MessageBox
      11 // int fl_ask(const char *fmt, ...), 問問題(返回1或0)
      12 // void fl_beep(int type), beep一下
      13 // 這些函數(shù)都很方便(printf類型的),但是為什么不放到Fl.H這個大雜燴類呢?
      14 // 可見Fltk的API還有諸多不合理之處
      15 #include "FL/fl_ask.H"
      16
      17 class EscapeChar; // 見下文
      18
      19 // Fltk中最方便的就是繼承已有的類,進(jìn)行各種自定義
      20 class CommentDialog: public Fl_Double_Window
      21 {
      22 public:
      23 // 繼承的構(gòu)造函數(shù)格式也基本是固定的
      24 CommentDialog(int x, int y, int w, int h, const char* title)
      25 :Fl_Double_Window(x, y, w, h, title)
      26 {
      27 CreateUI();
      28 size_range(w, h, 0, 0);
      29 resizable(_comment);
      30 // 對于Window來說,它的Callback就是當(dāng)它被關(guān)閉時要調(diào)用的函數(shù)
      31 // 這對于實(shí)現(xiàn)文檔有改變,問用戶想不想繼續(xù)之類很有用
      32 this->callback(gcallback, (void*)this);
      33 }
      34 // 這是Fltk標(biāo)準(zhǔn)的也是唯一的回調(diào)函數(shù),第一個是指向觸發(fā)回調(diào)的控件,
      35 // 第二個是在綁定回調(diào)時設(shè)置的任意參數(shù)。
      36 //
      37 // 使用面向?qū)ο蟮娘L(fēng)格時,因?yàn)椴荒馨杨惓蓡T函數(shù)作為回調(diào)函數(shù),所以一般使用這種方法:
      38 // 在父控件的類中聲明一個靜態(tài)回調(diào)函數(shù),所有的子控件需要設(shè)置回調(diào)時
      39 // 都使用這個回調(diào),而這個回調(diào)的第二個參數(shù)可以設(shè)為
      40 // 父控件類實(shí)例的指針,通過這個指針調(diào)用相應(yīng)的方法
      41 static void gcallback(Fl_Widget* w, void *data)
      42 {
      43 CommentDialog *d = (CommentDialog*)data;
      44 if(w == d->_name->child(1)) d->OnNameCheck(w);
      45 else if(w == d->_mail->child(1)) d->OnMailCheck(w);
      46 else d->OnOk(w); // “好的”按鈕或者直接關(guān)閉窗口
      47 }
      48
      49 void OnNameCheck(Fl_Widget* w);
      50 void OnMailCheck(Fl_Widget* w);
      51 void OnOk(Fl_Widget* w);
      52
      53 const char* GetName() const {return ((Fl_Input*)_name->child(0))->value();}
      54 const char* GetMail() const {return ((Fl_Input*)_mail->child(0))->value();}
      55 const char* GetComment() const {return _comment->value();}
      56
      57 private:
      58 void CreateUI();
      59 Fl_Pack *CreatePack(int y, const char * item, const char* button);
      60
      61 Fl_Pack * _name;
      62 Fl_Pack * _mail;
      63 Fl_Pack * _ok;
      64 Fl_Multiline_Input * _comment;
      65 };
      66
      67 void CommentDialog::CreateUI()
      68 {
      69 _name = CreatePack(10, "姓名:", "檢查!");
      70 _mail = CreatePack(50, "郵件:", "檢查!");
      71 _comment = new Fl_Multiline_Input(50, 100, w()-60, h()-150, "評論:");
      72 _ok = CreatePack(h()-40, NULL, "好的");
      73 }
      74
      75 Fl_Pack * CommentDialog::CreatePack(int y, const char * item, const char* button)
      76 {
      77 Fl_Pack * pack = new Fl_Pack(50, y, w()-20, 30);
      78 pack->type(Fl_Pack::HORIZONTAL);
      79 pack->spacing(10);
      80 Fl_Widget * itemw;
      81 if(item)
      82 itemw = new Fl_Input(0,0,w()-175, 30, item);
      83 else
      84 itemw = new Fl_Box(0, 0, w()-175, 30);
      85 Fl_Button *b = new Fl_Button(0, 0, 100, 30, button);
      86 b->callback(CommentDialog::gcallback, (void *)this);
      87 pack->end();
      88
      89 pack->resizable(itemw);
      90 return pack;
      91 }
      92 // 以下的檢查代碼只是把輸入顯示出來!因?yàn)楸敬沃饕v回調(diào)函數(shù)的設(shè)置,
      93 // 所以沒有實(shí)現(xiàn)真正的檢查代碼。注意Fltk很方便的顯示信息的函數(shù)
      94 void CommentDialog::OnNameCheck(Fl_Widget* w)
      95 {
      96 EscapeChar name(GetName());
      97 fl_alert("您好: %s!", (const char*) name);
      98 }
      99 void CommentDialog::OnMailCheck(Fl_Widget* w)
      100 {
      101 EscapeChar name(GetName());
      102 EscapeChar mail(GetMail());
      103 fl_alert("%s, 您好! 您的Email是:\n%s!",
      104 (const char*)name,
      105 (const char*)mail);
      106 }
      107 void CommentDialog::OnOk(Fl_Widget* w)
      108 {
      109 EscapeChar name(GetName());
      110 EscapeChar comment(GetComment());
      111 fl_alert("%s 認(rèn)為:\n%s\n多謝您的評論!",
      112 (const char*)name,
      113 (const char*)comment);
      114 // 當(dāng)最后一個窗口隱藏時,F(xiàn)ltk自動退出
      115 hide();
      116 }
      117
      118 int main(int argc, char **argv)
      119 {
      120 CommentDialog *dlg = new CommentDialog(100, 200, 460, 320, "FltkCallback");
      121 dlg->show();
      122 return Fl::run();
      123 }

      大家可以看到,大部分代碼都還是和第三部分所講的一樣的,如果您對任何內(nèi)容不熟悉,可以再復(fù)習(xí)“Fltk 1.3 系列教程(3)”。
      這是代碼運(yùn)行的截圖:

      上面的代碼還展示了怎樣在面向?qū)ο蟮那樾蜗率褂妙惓蓡T方法作為回調(diào)處理函數(shù),因?yàn)镕ltk的回調(diào)機(jī)制比較通用靈活,這些的
      實(shí)現(xiàn)都很簡單。通過封裝已有代碼,就構(gòu)建了一個可重用的對話框,在實(shí)際情況下應(yīng)該比直接過程式代碼好用。

      細(xì)心與好奇的讀者可能注意到那個奇怪的EscapeChar類。如果你不做任何處理,你會發(fā)現(xiàn)在fl_alert不能正確顯示
      email的“@”字符。為什么呢?因?yàn)镕ltk一個過時的特性,label和symbol系統(tǒng)。在任何Fltk控件的label設(shè)置字符串
      中(即構(gòu)造函數(shù)中指定的字符串或者label(const char*)函數(shù)中設(shè)置的字符串),如果有且僅有以下符號(摘自Fltk 1.3 Doc):

      Fltk會把它顯示成這些圖形符號,看起來非常方便,但是實(shí)際上問題很多,例如一但有其他字符串出現(xiàn),就完全
      不顯示了。大家可以參考http://www.fltk.org/str.php?L2689,這種特性問題之多難以處理。所以建議在
      新代碼中,盡量少使用這些功能。Fl_Browser控件中也使用“@”符號來表示字符串的格式,在開頭加上“@.”就
      可以關(guān)閉格式解析,問題不大。但是在我們的代碼中email肯定含有“@”符號,而這個是不能在消息框的label中
      正確顯示的。怎么解決這個問題呢?

      第一種是高手使用的方法,也是比較惡心的方法,就是自己實(shí)現(xiàn)繪制符號的函數(shù),然后替換默認(rèn)的符號處理系統(tǒng),
      這樣一來,一切都清靜了。見Erco的例子大全:http://seriss.com/people/erco/fltk/#DisableSymbols

      第二種就是把字符串中的“@”字符替換成“@@”,這樣就可以轉(zhuǎn)義掉“@”字符,相對于修改整個系統(tǒng)的行為,這個
      方法還是比較容易接受的。但是問題又出來了:如果Fltk提供了字符串處理函數(shù)或者它就是用的ASCII,實(shí)現(xiàn)這個功能是
      很簡單的,但是它使用的是UTF8,于是我們又不得不看看Fltk中的UTF8函數(shù)了。

      大家知道在1.3之前Fltk是不支持Unicode的,這對于CJK國家非常不便。1.3通過utf8支持了unicode,但是這些
      支持是非常基礎(chǔ)的,在"FL/fl_utf8.h"中,只有最底層的utf8處理函數(shù),而不是高層的字符串操作函數(shù)。雖然UTF8
      兼容ASCII,但是即使輸入都是ASCII,你按照默認(rèn)的處理也是不行的(會有亂碼,只能保證它是'\0'結(jié)束的)。

      所以鄙人認(rèn)為實(shí)現(xiàn)一個fl_string類是十分必要的。但是這個教程不能面面俱到,可能以后會專門寫一篇文章講這個
      類的實(shí)現(xiàn)。下面的類是EscapeChar,能轉(zhuǎn)義UTF8字符串中的任何ASCII字符。

       1 // 不得已而為之
      2 #include <cstring> // for strlen strcpy
      3 #include "FL/fl_utf8.h" // for fl_utf8len(char c)
      4 class EscapeChar
      5 {
      6 public:
      7 EscapeChar(const char* text, char c='@')
      8 :_c(c)
      9 {
      10 _text = new char[2*strlen(text)];
      11 int k = 0;
      12 while(*text){
      13 int j = fl_utf8len(*text);
      14 for(int i = 0; i < j; ++i)
      15 _text[k+i] = *text++;
      16 k += j;
      17 if( j == 1 && _text[k-j] == _c){
      18 _text[k] = _c;
      19 k += j;
      20 }
      21 }
      22 _text[k] = '\0';
      23 }
      24 ~EscapeChar()
      25 {
      26 if(_text) delete _text;
      27 }
      28 EscapeChar(const EscapeChar& e)
      29 :_c(e._c)
      30 {
      31 _text = new char[strlen(e._text)];
      32 strcpy(_text, e._text);
      33 }
      34
      35 EscapeChar& operator=(const EscapeChar& e)
      36 {
      37 if(&e == this)
      38 return *this;
      39 _c = e._c;
      40 size_t len = strlen(e._text);
      41 if(strlen(_text) < len){
      42 delete _text;
      43 _text = new char[len];
      44 }
      45 strcpy(_text, e._text);
      46
      47 return *this;
      48 }
      49 operator char*() const {return _text;}
      50
      51 private:
      52 char _c;
      53 char *_text;
      54 };

      這次的教程就這么多內(nèi)容,有任何問題,歡迎指出。以前的教程如下,供感興趣的人參考:
      http://www.rzrgm.cn/leading/archive/2011/10/15/fltk_1_3_tutorial_3.html
      http://blog.163.com/dingmaotu@126/blog/static/2148430201183072750266/ (教程2,因?yàn)樵瓉砭W(wǎng)易圖片不讓外鏈,很難看,干脆鏈原來的網(wǎng)址吧)
      http://www.rzrgm.cn/leading/archive/2011/10/15/fltk_1_3_tutorial_1.html

      posted @ 2011-10-17 10:55  Leading  閱讀(5142)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 老鸭窝在线视频| 99RE8这里有精品热视频| 久久精品国产99精品国产2021| 国产精品成人免费视频网站京东| 国产欧美精品一区二区三区-老狼| 免费午夜无码片在线观看影院 | 亚洲乱码av中文一区二区| 老熟女重囗味hdxx69| 国产精品呻吟一区二区三区| 好姑娘6电影在线观看| 99久久激情国产精品| 国产精品小粉嫩在线观看| 中文字幕在线精品人妻| 99久久激情国产精品| 正在播放肥臀熟妇在线视频| 好男人日本社区www| yyyy在线在片| 芮城县| 色悠久久网国产精品99| 无码日韩av一区二区三区| 国产精品v欧美精品∨日韩| 2022最新国产在线不卡a| 日本久久一区二区免高清| 东京热人妻无码一区二区av| 无线日本视频精品| 亚洲欧洲精品日韩av| 国产成人精品国内自产色| 少妇人妻偷人精品免费| 国内精品伊人久久久久AV一坑 | 欧美熟妇乱子伦XX视频| 亚洲欧洲一区二区免费| 国产成人AV在线免播放观看新| 欧洲熟妇色xxxx欧美老妇免费| 国产精品爱久久久久久久电影| 好爽毛片一区二区三区四| 国产精品成人久久电影| 色综合网天天综合色中文| 色噜噜在线视频免费观看| 乱女乱妇熟女熟妇综合网| 精品无码国产污污污免费| 成人精品久久一区二区三区 |