使用XCB編寫X Window程式(02):在視窗中繪圖

來源:互聯網
上載者:User

標籤:style   blog   http   java   color   使用   

  在上一篇中,我展示了怎麼串連X伺服器以及怎麼建立一個視窗。建立視窗是編寫GUI程式的根本。在GUI編程中還有另外兩個重點,其一是事件處理,其二是在視窗中繪圖。這一篇中,將展示如何使用XCB在視窗中進行繪圖。

  先看一個範例程式碼及其運行效果,代碼如下:

  1     #include <stdlib.h>  2     #include <stdio.h>  3   4     #include <xcb/xcb.h>  5   6     int  7     main ()  8     {  9         /* geometric objects */ 10         xcb_point_t          points[] = { 11             {40, 40}, 12             {40, 80}, 13             {80, 40}, 14             {80, 80}}; 15  16         xcb_point_t          polyline[] = { 17             {200, 40}, 18             { 20, 80},     /* rest of points are relative */ 19             {100,-80}, 20             {40, 40}}; 21  22         xcb_segment_t        segments[] = { 23             {400, 40, 560, 120}, 24             {440, 100, 520, 240}}; 25  26         xcb_rectangle_t      rectangles[] = { 27             { 40, 200, 160, 80}, 28             { 320, 200, 40, 160}}; 29  30         xcb_arc_t            arcs[] = { 31             {40, 400, 240, 160, 0, 90 << 6}, 32             {360, 400, 220, 160, 0, 270 << 6}}; 33  34  35         /* Open the connection to the X server */ 36         xcb_connection_t *connection = xcb_connect (NULL, NULL); 37  38         /* Get the first screen */ 39         xcb_screen_t *screen = xcb_setup_roots_iterator (xcb_get_setup (connection)).data; 40  41         /* Create black (foreground) graphic context */ 42         xcb_drawable_t  window     = screen->root; 43         xcb_gcontext_t  gc = xcb_generate_id (connection); 44         uint32_t        mask       = XCB_GC_FOREGROUND | XCB_GC_GRAPHICS_EXPOSURES; 45         uint32_t        values[2]  = {screen->black_pixel, 0}; 46  47         xcb_create_gc (connection, gc, window, mask, values); 48  49  50         /* Create a window */ 51         window = xcb_generate_id (connection); 52  53         mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK; 54         values[0] = screen->white_pixel; 55         values[1] = XCB_EVENT_MASK_EXPOSURE; 56  57         xcb_create_window (connection,                    /* connection          */ 58                            XCB_COPY_FROM_PARENT,          /* depth               */ 59                            window,                        /* window Id           */ 60                            screen->root,                  /* parent window       */ 61                            0, 0,                          /* x, y                */ 62                            800, 600,                      /* width, height       */ 63                            10,                            /* border_width        */ 64                            XCB_WINDOW_CLASS_INPUT_OUTPUT, /* class               */ 65                            screen->root_visual,           /* visual              */ 66                            mask, values );                /* masks */ 67  68  69         /* Map the window on the screen and flush*/ 70         xcb_map_window (connection, window); 71         xcb_flush (connection); 72  73  74         /* draw primitives */ 75         xcb_generic_event_t *event; 76         while ((event = xcb_wait_for_event (connection))) { 77             switch (event->response_type & ~0x80) { 78             case XCB_EXPOSE: 79                 /* We draw the points */ 80                 xcb_poly_point (connection, XCB_COORD_MODE_ORIGIN, window, gc, 4, points); 81  82                 /* We draw the polygonal line */ 83                 xcb_poly_line (connection, XCB_COORD_MODE_PREVIOUS, window, gc, 4, polyline); 84  85                 /* We draw the segments */ 86                 xcb_poly_segment (connection, window, gc, 2, segments); 87  88                 /* draw the rectangles */ 89                 xcb_poly_rectangle (connection, window, gc, 2, rectangles); 90  91                 /* draw the arcs */ 92                 xcb_poly_arc (connection, window, gc, 2, arcs); 93  94                 /* flush the request */ 95                 xcb_flush (connection); 96  97                 break; 98             default:  99                 /* Unknown event type, ignore it */100                 break;101             }102 103             free (event);104         }105 106         return 0;107     }

   運行效果如:

 

  下面,對以上GUI繪圖的程式進行分析:

  1、任何繪圖程式,無論使用的是Win32 API,還是Java Swing,都離不開GC和DC的概念,使用XCB編寫視窗程序也是如此。這兩個概念,一個代表了圖怎麼繪,一個代表了圖繪在哪裡。由於繪圖時需要指定太多的資訊,比如畫筆的粗細、線型、前景色彩、背景色等等,如果把這些資訊統統作為參數傳遞給繪圖函數,就會產生兩個問題:一是調用這些函數太複雜,二是效率太低。所以,目前所有主流的GUI庫都採用了一致的做法,那就是把這些資訊組織成一個context,我們稱之為graphic context,可簡稱gcontext或GC。DC可以認為是繪圖時所用的畫布,我們可以直接把圖繪到螢幕上,也可以把圖繪到視窗中,當然,也可以繪到控制項中(因為控制項的本質也是視窗)。在物件導向的程式設計語言中,可以繪圖的組件往往都繼承自Drawable。在XCB中,從繪圖函數的簽名可以看出,它仍然將繪圖的目標稱為drawable,雖然它只是一個id。

  2、什麼時候繪圖。理論上講,任何時候都可以調用繪圖函數。但是從實踐上來講,所有的GUI程式都是在視窗重繪的事件中調用繪圖函數。視窗重繪事件,有的叫onPaint,有的叫onDraw,XCB中比較奇怪,叫EXPOSE。不管叫什麼,其道理是一樣的。那就是當視窗初次顯示、從隱藏到顯示或視窗內容需要重新整理時,都會觸發該事件,所以在處理該事件的代碼中調用繪圖函數是最好的,既可以保證我們看到繪圖的結果,又兼顧效率(視窗不可見時繪圖函數不用執行,視窗不變化時繪圖函數也不用執行)。MVC模式也是構建在這樣的基礎之上,將資料與顯示分離,資料可以隨時被操作,但是繪圖只在視窗重繪時進行。

  3、調用繪圖函數。這個不需要多講,因為幾乎所有的繪圖函數都是自解釋的,看到函數名,就知道它要進行什麼操作。

 

  在XCB中,建立GC可以通過xcb_create_gc()函數進行,建立視窗可以通過xcb_create_window()函數進行。在這兩個函數中,都有一個比較奇怪的模式,那就是通過一個mask和value數組來設定GC和視窗的具體資訊。在上一篇中,建立的視窗沒有背景,而這一篇中,視窗具有白色背景,就是因為這裡調用xcb_create_window時,在其mask參數中指定了XCB_CW_BACK_PIXEL。

 

  藉助於ctags和Vim的taglist.vim外掛程式,可以非常方便地查看這些mask的取值及其意義,只需按下Ctrl+]就可以跳到相應的定義處。如下兩圖,是enum xcb_gc_t中定義的一系列XCB_GC_***:

 

  再下面兩個圖,是建立視窗是可以用到的mask值:

 

  這些枚舉都有很詳細的注釋,所以我就不在這裡囉嗦了。libxcb的標頭檔中的注釋,本身就是一種很好的學習資料,不是嗎?

 

(京山遊俠於2014-07-05發佈於部落格園,轉載請註明出處。)

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.