程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> 使用XCB編寫X Window程序(二) 在窗口中繪圖

使用XCB編寫X Window程序(二) 在窗口中繪圖

編輯:關於C++

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

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

#include <stdlib.h>
    #include <stdio.h>
    
    #include <xcb/xcb.h>
    
    int
    main ()
    {
        /* geometric objects */
        xcb_point_t          points[] = {
            {40, 40},
            {40, 80},
            {80, 40},
            {80, 80}};
    
        xcb_point_t          polyline[] = {
            {200, 40},
            { 20, 80},     /* rest of points are relative */
            {100,-80},
            {40, 40}};
    
        xcb_segment_t        segments[] = {
            {400, 40, 560, 120},
            {440, 100, 520, 240}};
    
        xcb_rectangle_t      rectangles[] = {
            { 40, 200, 160, 80},
            { 320, 200, 40, 160}};
    
        xcb_arc_t            arcs[] = {
            {40, 400, 240, 160, 0, 90 << 6},
            {360, 400, 220, 160, 0, 270 << 6}};
    
    
        /* Open the connection to the X server */
        xcb_connection_t *connection = xcb_connect (NULL, NULL);
    
        /* Get the first screen */
        xcb_screen_t *screen = xcb_setup_roots_iterator (xcb_get_setup (connection)).data;
    
        /* Create black (foreground) graphic context */
        xcb_drawable_t  window     = screen->root;
        xcb_gcontext_t  gc = xcb_generate_id (connection);
        uint32_t        mask       = XCB_GC_FOREGROUND | XCB_GC_GRAPHICS_EXPOSURES;
        uint32_t        values[2]  = {screen->black_pixel, 0};
    
        xcb_create_gc (connection, gc, window, mask, values);
    
    
        /* Create a window */
        window = xcb_generate_id (connection);
    
        mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
        values[0] = screen->white_pixel;
        values[1] = XCB_EVENT_MASK_EXPOSURE;
    
        xcb_create_window (connection,                    /* connection          */
                           XCB_COPY_FROM_PARENT,          /* depth               */
                           window,                        /* window Id           */
                           screen->root,                  /* parent window       */
                           0, 0,                          /* x, y                */
                           800, 600,                      /* width, height       */
                           10,                            /* border_width        */
                           XCB_WINDOW_CLASS_INPUT_OUTPUT, /* class               */
                           screen->root_visual,           /* visual              */
                           mask, values );                /* masks */
    
    
        /* Map the window on the screen and flush*/
        xcb_map_window (connection, window);
        xcb_flush (connection);
    
    
        /* draw primitives */
        xcb_generic_event_t *event;
        while ((event = xcb_wait_for_event (connection))) {
            switch (event->response_type & ~0x80) {
            case XCB_EXPOSE:
                /* We draw the points */
                xcb_poly_point (connection, XCB_COORD_MODE_ORIGIN, window, gc, 4, points);
    
                /* We draw the polygonal line */
                xcb_poly_line (connection, XCB_COORD_MODE_PREVIOUS, window, gc, 4, polyline);
    
                /* We draw the segments */
                xcb_poly_segment (connection, window, gc, 2, segments);
    
                /* draw the rectangles */
                xcb_poly_rectangle (connection, window, gc, 2, rectangles);
    
                /* draw the arcs */
                xcb_poly_arc (connection, window, gc, 2, arcs);
    
                /* flush the request */
                xcb_flush (connection);
    
                break;
            default: 
                /* Unknown event type, ignore it */
                break;
            }

    
            free (event);
        }
    
        return 0;
    }

運行效果如下圖:

下面,對以上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模式也是構建在這樣的基礎之上,將數據與顯示分離,數據可以隨時被操作,但是繪圖只在窗口重繪時進行。

返回欄目頁:http://www.bianceng.cn/Programming/cplus/

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的頭文件中的注釋,本身就是一種很好的學習資料,不是嗎?

作者:cnblogs 京山游俠

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved