• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            隨筆 - 16, 文章 - 0, 評(píng)論 - 55, 引用 - 0
            數(shù)據(jù)加載中……

            fltk剖析 main-loop(二)

            做為一個(gè)以c++為目標(biāo)語(yǔ)言且要適配各種平臺(tái)的界面庫(kù),F(xiàn)LTK注定是小眾的,所以寫(xiě)的內(nèi)容要限定一下受眾。如果你對(duì)c/c++比較熟悉,至少對(duì)某一種操作系統(tǒng)的API比較熟悉,希望找到某種一次編寫(xiě)到處編譯的界面庫(kù),同時(shí)對(duì)靈活性和尺寸比較在意,那么這個(gè)文檔就比較適合你。如果你只是希望學(xué)會(huì)怎么使用fltk,并不想深入了解它背后的原理,那么這個(gè)文檔就不太適合,fltk的在線文檔在這里:http://www.fltk.org/documentation.php

            fltk最初的思路來(lái)自于1987年的NeXT系統(tǒng),初始版本針對(duì)的是X,所以代碼里有一些用X開(kāi)頭的函數(shù)名,但隨著代碼的不斷演進(jìn),接口逐漸變得和系統(tǒng)無(wú)關(guān)。

            基本上,fltk認(rèn)為所有的操作系統(tǒng)都會(huì)提供以下幾種功能:
            1.窗口創(chuàng)建和銷(xiāo)毀
            2.繪圖(點(diǎn),直線,曲線,圓...)
            3.字體顯示
            4.輸入設(shè)備交互(鍵盤(pán)、鼠標(biāo))

            只要有這幾種功能,不需要系統(tǒng)提供全套的控件,也可以自行構(gòu)建出界面。另外系統(tǒng)還會(huì)提供一些附加功能,對(duì)于豐富界面也很有幫助,但并不是充分必要條件,比如
            1.圖片讀寫(xiě)
            2.文件操作
            3.打印機(jī)
            4.輸入法

            基于這樣的認(rèn)知,做為一個(gè)GUI庫(kù),fltk需要提供一個(gè)模型,把這些元素組合在一起,既要有足夠的彈性又要足夠簡(jiǎn)單,F(xiàn)LTK采用的是main-loop,相信很多人開(kāi)始學(xué)習(xí)c語(yǔ)言的時(shí)候都會(huì)寫(xiě)下面的代碼:
            #include <stdio.h>
            int main(int argc, char** argv)
            {
               printf("hello world\n");
               return 0;
            }

            fltk所使用的模型就和這個(gè)類(lèi)似,用偽代碼表示就是:
            #include <fltk.h>
            int main(int argc, char **argv)
            {
               create_window(); // 創(chuàng)建窗口
               create_widget(); // 創(chuàng)建控件
               while (1) {
                  if ( wait() ) break; // 事件循環(huán)
               }
               return 0;
            }

            是不是和gtk很類(lèi)似?

            這個(gè)模型的好處是容易理解,如果把所有的流程都用class包裹起來(lái),雖然貌似充滿了oo的味道,但是對(duì)于理解代碼反而是有害的。任何代碼都有一個(gè)入口,為了面向?qū)ο螅踔涟讶肟谝膊仄饋?lái),只會(huì)增加學(xué)習(xí)者的困擾。比如mfc,qt,juce,wxwidgets,如果想分析代碼,光是找到起點(diǎn)就很不容易,尤其為了oo,很多GUI庫(kù)用宏將main都包裹了起來(lái),更增加了理解的難度。代碼不應(yīng)該讓編譯器舒服,也不應(yīng)該屈從于某種思想,而是應(yīng)該以人為本,讓程序員看的輕松用的輕松。人的注意力是有限的,短期記憶大概只有十幾分鐘的時(shí)間,同時(shí)注意到的目標(biāo)也不多,而且似乎人的思維模式是線性的,也就是說(shuō)只能在一條線上做深入思考,并行處理好幾個(gè)問(wèn)題,大腦會(huì)短路。當(dāng)然有些發(fā)達(dá)的大腦有一心多用的本領(lǐng),但是總要照顧大多數(shù)人吧?

            首先談?wù)勥@個(gè)main(),為什么叫這個(gè)名字?這和編譯器和操作系統(tǒng)有關(guān),具體原因可以自行百度,重要的只有一條,這是程序的入口。事實(shí)上并不是所有的操作系統(tǒng)都用這個(gè)名稱(chēng),osx/ios/linux是用main,windows/wince用的是winmain,android/windows phone干脆沒(méi)有main,所以要為所有的平臺(tái)編寫(xiě)統(tǒng)一的main。先看看windows平臺(tái)的實(shí)現(xiàn),打開(kāi)fltk的源代碼,找到src/fl_call_main.c
            extern int main(int, char *[]);
            int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
            {
              int rc, i;
              char **ar;

            #  ifdef _DEBUG
            // 這里用來(lái)創(chuàng)建一個(gè)cmd窗口,或者叫dos窗口,用以輸出調(diào)試結(jié)果,只在debug版里提供
             /*
              * If we are using compiling in debug mode, open a console window so
              * we can see any printf's, etc...
              *
              * While we can detect if the program was run from the command-line -
              * look at the CMDLINE environment variable, it will be "WIN" for
              * programs started from the GUI - the shell seems to run all WIN32
              * applications in the background anyways...
              */

              AllocConsole();
              freopen("conin$", "r", stdin);
              freopen("conout$", "w", stdout);
              freopen("conout$", "w", stderr);
            #  endif /* _DEBUG */

              ar = (char**) malloc(sizeof(char*) * (__argc + 1));
              i = 0;
              while (i < __argc) {
                int l;
                unsigned dstlen;
                if (__wargv ) {
                  for (l = 0; __wargv[i] && __wargv[i][l]; l++) {}; /* is this just wstrlen??? */
                  dstlen = (l * 5) + 1;
                  ar[i] = (char*) malloc(dstlen);
            /*    ar[i][fl_unicode2utf(__wargv[i], l, ar[i])] = 0; */
                  dstlen = fl_utf8fromwc(ar[i], dstlen, __wargv[i], l);
                  ar[i][dstlen] = 0;
                } else {
                  for (l = 0; __argv[i] && __argv[i][l]; l++) {};
                  dstlen = (l * 5) + 1;
                  ar[i] = (char*) malloc(dstlen);
            /*      ar[i][mbcs2utf(__argv[i], l, ar[i], dstlen)] = 0; */
                  ar[i][mbcs2utf(__argv[i], l, ar[i])] = 0;
                }
                i++;
              }
              ar[__argc] = 0;
              /* Run the standard main entry point function... */
              rc = main(__argc, ar);

            #  ifdef _DEBUG
              fclose(stdin);
              fclose(stdout);
              fclose(stderr);
            #  endif /* _DEBUG */

              return rc;
            }

            看起來(lái)很簡(jiǎn)單,就是將winmain包裝了一下,做了一些初始化的工作,再引出main。

            osx/linux直接使用了main,所以沒(méi)什么可解釋的

            接下來(lái)是loop。在windows下面比較好理解,打開(kāi)src/Fl_win32.cxx,找到如下的代碼:
            int fl_wait(double time_to_wait) {
              ...
              if (Fl::idle && !in_idle) { // 若處于空閑時(shí)間且存在idle函數(shù),執(zhí)行之
                in_idle = 1;
                Fl::idle();
                in_idle = 0;
              }
              ... 
              while ((have_message = PeekMessageW(&fl_msg, NULL, 0, 0, PM_REMOVE)) > 0) {
                if (fl_send_system_handlers(&fl_msg))
                  continue;

                // Let applications treat WM_QUIT identical to SIGTERM on *nix
                if (fl_msg.message == WM_QUIT)
                  raise(SIGTERM);

                if (fl_msg.message == fl_wake_msg) {
                  // Used for awaking wait() from another thread
                  thread_message_ = (void*)fl_msg.wParam;
                  process_awake_handler_requests();
                }

                TranslateMessage(&fl_msg);
                DispatchMessageW(&fl_msg);
              }
              ...
              return 1;
            }
            基本上就是<<Windows程序設(shè)計(jì)>>上的那一套,就不做說(shuō)明了

            再打開(kāi)src/Fl_x.cxx,找到fl_wait函數(shù),這里是linux下的loop主體,具體代碼就不分析了,有興趣的可以去找X編程的資料

            最后是osx的loop,在osx下面runlooper是不能由程序直接控制的,只能通過(guò)外圍發(fā)送和接收消息的方式曲線救國(guó),所以FLTK用了一個(gè)線程,然后在線程里和runlooper交互。打開(kāi)src/Fl_cocoa.mm,找到fl_wait函數(shù),再找到DataReady類(lèi),這兩個(gè)部分組合起來(lái)就構(gòu)成了osx的loop功能,具體實(shí)現(xiàn)是用object-c和c/c++混合完成的

            以上是各個(gè)系統(tǒng)各自的loop功能,最后還要將他們整合起來(lái),打開(kāi)src/Fl.cxx:
            int Fl::run() {
              while (Fl_X::first) wait(FOREVER);
              return 0;
            }

            double Fl::wait(double time_to_wait) {
              // delete all widgets that were listed during callbacks
              do_widget_deletion();

            #ifdef WIN32

              return fl_wait(time_to_wait);

            #elif defined(__APPLE__)

              run_checks();
              return fl_mac_flush_and_wait(time_to_wait);

            #else

              if (first_timeout) {
                elapse_timeouts();
                Timeout *t;
                while ((t = first_timeout)) {
                  if (t->time > 0) break;
                  // The first timeout in the array has expired.
                  missed_timeout_by = t->time;
                  // We must remove timeout from array before doing the callback:
                  void (*cb)(void*) = t->cb;
                  void *argp = t->arg;
                  first_timeout = t->next;
                  t->next = free_timeout;
                  free_timeout = t;
                  // Now it is safe for the callback to do add_timeout:
                  cb(argp);
                }
              } else {
                reset_clock = 1; // we are not going to check the clock
              }
              run_checks();
            //  if (idle && !fl_ready()) {
              if (idle) {
                if (!in_idle) {
                  in_idle = 1;
                  idle();
                  in_idle = 0;
                }
                // the idle function may turn off idle, we can then wait:
                if (idle) time_to_wait = 0.0;
              }
              if (first_timeout && first_timeout->time < time_to_wait)
                time_to_wait = first_timeout->time;
              if (time_to_wait <= 0.0) {
                // do flush second so that the results of events are visible:
                int ret = fl_wait(0.0);
                flush();
                return ret;
              } else {
                // do flush first so that user sees the display:
                flush();
                if (idle && !in_idle) // 'idle' may have been set within flush()
                  time_to_wait = 0.0;
                return fl_wait(time_to_wait);
              }
            #endif
            }

            看起來(lái)很明顯,就是將各個(gè)平臺(tái)的fl_wait包裝起來(lái)組合成統(tǒng)一的接口,現(xiàn)在看一個(gè)fltk的示例代碼:test/hello.cxx
            #include <FL/Fl.H>
            #include <FL/Fl_Window.H>
            #include <FL/Fl_Box.H>

            int main(int argc, char **argv) {
              Fl_Window *window = new Fl_Window(340,180);
              Fl_Box *box = new Fl_Box(20,40,300,100,"Hello, World!");
              box->box(FL_UP_BOX);
              box->labelfont(FL_BOLD+FL_ITALIC);
              box->labelsize(36);
              box->labeltype(FL_SHADOW_LABEL);
              window->end();
              window->show(argc, argv);
              return Fl::run();
            }

            將Fl::run()展開(kāi),就是
            int main(int argc, char **argv) {
              .. // create windows and widgets
             
              while (Fl_X::first) wait(FOREVER);
              return 0;
            }

            這就是FLTK的main-loop模型。簡(jiǎn)單,實(shí)用,好理解

            posted on 2015-11-01 11:58 cyantree 閱讀(2254) 評(píng)論(0)  編輯 收藏 引用


            只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問(wèn)   Chat2DB   管理


            熟妇人妻久久中文字幕| 亚洲狠狠婷婷综合久久蜜芽 | 久久精品国产亚洲77777| 久久婷婷激情综合色综合俺也去| 亚洲AV无码久久| 99久久婷婷免费国产综合精品| 久久久久九国产精品| 久久亚洲日韩看片无码| 国产亚洲精品自在久久| 久久93精品国产91久久综合| 一本一本久久A久久综合精品 | 欧洲性大片xxxxx久久久| 亚洲精品tv久久久久久久久| 精品乱码久久久久久夜夜嗨| 久久婷婷五月综合成人D啪| 国产精品久久久久9999| 久久午夜夜伦鲁鲁片免费无码影视| 久久精品国产福利国产秒| 久久久这里只有精品加勒比| AAA级久久久精品无码片| 精产国品久久一二三产区区别| 94久久国产乱子伦精品免费| 亚洲中文字幕无码久久精品1| 久久久国产精品| 99国内精品久久久久久久| 韩国免费A级毛片久久| 国产亚洲美女精品久久久2020| 理论片午午伦夜理片久久 | 久久精品欧美日韩精品| 久久99九九国产免费看小说| 久久久久国色AV免费看图片| 精品国产婷婷久久久| 91精品久久久久久无码| 久久精品a亚洲国产v高清不卡| 久久久亚洲欧洲日产国码是AV| 亚洲国产一成久久精品国产成人综合 | 久久精品国产99久久丝袜| 国产精品成人精品久久久| 色偷偷888欧美精品久久久| 97精品国产97久久久久久免费| 94久久国产乱子伦精品免费 |