第3章 描画コマンドをあやつる


本章では窓に絵を描く具体的な関数を紹介していきます。 その前に2つ基礎事項を説明します。

グラフィックコンテキスト

線や長方形など図形を描く際には、その色や模様や線の太さ、さらに 上重ねの仕方(XORなど)を細かく指定することができます。
図形のこのようなさまざまな性質はXGCValues型の構造体変数に記録、参照 され、これをグラフィックコンテキストと呼びます。
グラフィックコンテキストは同時に複数用意することができ それぞれに異なった指定をいれておくことができます。
描画の際に使用するグラフィックコンテキストを指定することで グラフィックコンテキストの内容を変更することなしに複数の 種類の性質の図形を描くことができます。

新たにグラフィックコンテキストを生成するにはXCreateGC()関数を 使います。

Prototype

GC XCreateGC( Display* display, Window window, unsigned long mask, XGCValues* values );

windowにはルートウィンドウのWindow IDを指定すれば十分です。 この返り値はGC型のグラフィックコンテキストのIDです。 以後、このグラフィックコンテキストのIDのことを単にGCと呼びます。 後続の引数の mask と valueは本書では使用しません。

Example

GC gc;
gc = XCreateGC( dis, DefaultRootWindow(dis), 0, 0 );

これで標準設定されたGCが得られます。

GCの内容を変更するにはいろいろな方法があります。GCが管理している 変数はたくさんあるのでその一部だけを変更する関数を紹介します。

Prototype

XSetFunction( Display* display, GC gc, int function );
XSetForeground( Display* display, GC gc, unsigned long color );
XSetBackground( Display* display, GC gc, unsigned long color );

XSetFunction()は描画の際にxorで書くかandで書くか等の論理の設定を します。functionの値に各論理を表す定数を指定します。 xorはGXxor、copyはGXcopyです。その他に16種類の論理があります。
XSetForeground()は図形の色を設定します。
XSetBackground()は2色の色を使う図形のもう一方の色を設定します。

他にもたくさんのGC変更関数があります。専門書を参照ください。


色の指定の仕方

XSetForeground()で指定する色はその色のpixel値で与えます。 pixel値とはXserverに用意されている色のパレットのセルの番号 のことです。pixel値はunsigned long型です。本書では 8bitモード での使用しか解説しないので pixel値は 0 から 255 までの範囲の 値しか使えません。 使いたい色のpixel値を知るのは少々込み入った手続きが必要です。 以下の関数GetColor()を用意しておきましょう。

Example

unsigned long GetColor( Display* dis, char* color_name )
{
  Colormap cmap;
  XColor near_color, true_color;

  cmap = DefaultColormap( dis, 0 );
  XAllocNamedColor( dis, cmap, color_name, &near_color, &true_color );
  return( near_color.pixel );
}

そしてこの関数にpixel値を知りたい色の名前を文字列で渡すと そのpixel値が返ってきます。

Example

XSetForeground( dis, gc, GetColor( dis, "yellow");

色の操作については後でより詳しく解説します。

描画関数の紹介

多くの種類がある描画関数のうち基本的なものをいくつか紹介します。 どの関数も引数にDisplayポインタとWindow IDとGCを与えます。これらの引数で どの画面のどの窓にどのように描くかを指定します。

  • 点を描く関数

    一つの点

    void XDrawPoint( Display* display, Window window, GC gc, int x, int y );
    (x,y)に点を描きます。

    複数の点

    void XDrawPoints( Display* display, Window window, GC gc, XPoint* points, int num, int mode );
    XPoint型の構造体は下記のように定義されています。
    typedef struct {
    short x, y;
    } XPoint;
    numの値は描く点の数、modeの値が CoordModeOrigin なら絶対座標で 点を描き、modeの値が CoordModePrevious なら前の点からの相対座標で 点を描きます。

  • 直線を描く関数

    一本の線分

    void XDrawLine( Display* display, Window window, GC gc, int xs, int ys, int xe, int ye );
    (xs,ys)-(xe,ye)に直線を引きます。

    連続直線

    void XDrawLines( Display* display, Window window, GC gc, XPoint* points, int num, int mode );
    points,num,modeはXDrawPoints()と同じでそれらの点を線で結びます。

    複数の線分

    void XDrawSegments( Display* display, Window window, GC gc, XSegment* segments, int num );
    XSegment型の構造体は下記のように定義されています。
    typedef struct { short x1, y1, x2, y2; } XSegment;
  • 長方形を描く関数

    一つの長方形の境界線

    void XDrawRectangle( Display* display, Window window, GC gc, int xo, int yo, unsigned int width, unsigned int height );
    (xo,yo)を左上隅の座標とし横 width 縦 height の長方形を描きます。

    複数の長方形の境界線

    void XDrawRectangles( Display* display, Window window, GC gc, XRectangle* rectangles, int num );
    XRectangle型の構造体は下記のように定義されています。
    typedef struct {
    short x, y;
    unsigned short width, height;
    } XRectangle;

    一つの長方形を塗り潰す

    void XFillRectangle( Display* display, Window window, GC gc, int xo, int yo, unsigned int width, unsigned int height );

    複数の長方形を塗り潰す

    void XFillRectangles( Display* display, Window window, GC gc, XRectangle* rectangles, int num );

  • 円弧を描く関数

    一つの円弧

    void XDrawArc( Display* display, Window window, GC gc, int xo, int yo, unsigned int width, unsigned int height, int start_angle, int draw_angle );
    (xo,yo)を左上隅の座標とし横 width 縦 height の長方形にぴったり 収まる楕円弧で、開始角度がx軸より左周りstart_angle/64度で左回り にdraw_angle/64度だけの楕円弧を描きます。

    複数の円弧

    void XDrawArcs( Display* display, Window window, GC gc, XArc* arcs, int num );
    XArc型の構造体は下記のように定義されています。
    typedef struct { short x, y; unsigned short width, height; short angle1, angle2; } XArc;

    円弧を塗り潰す

    void XFillArc( Display* display, Window window, GC gc, int xo, int yo, unsigned int width, unsigned int height, int start_angle, int draw_angle );
    複数の円弧を塗り潰す
    void XFillArcs( Display* display, Window window, GC gc, XArc* arcs, int num );
  • 多角形を塗り潰す関数

    void XFillPolygon( Display* display, Window window, GC gc, XPoint* points, int num, int shape, int mode );
    shapeの値は凸多角形の時はConvexにしてください。 そうでない時やわからない時はComplexにしてください。


  • お絵描きの例

    これら描画関数を使ってダイアモンドパターンを描く プログラムを示します。名前はdiamond.ccです。是非おためしください。

    diamond.ccのダウンロード

    diamond.ccの内容

    /* diamond.cc */
    
    #include <X11/Xlib.h>
    #include <X11/Xutil.h>
    #include <stdio.h>
    #include <math.h>
    
    #define N 16
    
    
    unsigned long GetColor( Display* dis, char* color_name )
    {
        Colormap cmap;
        XColor near_color, true_color;
    
        cmap = DefaultColormap( dis, 0 );
        XAllocNamedColor( dis, cmap, color_name, &near_color, &true_color );
        return( near_color.pixel );
    }
    
    
    int main( void )
    {
        Display* dis;
        Window win;
        XSetWindowAttributes att;
        GC gc;
        XEvent ev;
    
        int x[N],y[N];
        int i,j;
    
        dis = XOpenDisplay( NULL );
        win = XCreateSimpleWindow( dis, RootWindow(dis,0), 100, 100,
          256, 256, 5, WhitePixel(dis,0), BlackPixel(dis,0) );
    
        att.backing_store = WhenMapped;
        XChangeWindowAttributes( dis, win, CWBackingStore, &att );
    
        XSelectInput( dis, win, ExposureMask );
        XMapWindow( dis, win );
    
        do{
            XNextEvent( dis, &ev);
        }while( ev.type != Expose );
    
        gc = XCreateGC( dis, DefaultRootWindow(dis), 0, 0 );
        XSetForeground( dis, gc, GetColor( dis, "green")  );
    
    
        for( i=0 ; i<N ; i++ ){
            x[i] = (int)(128*cos(2*M_PI*i/N))+128;
            y[i] = (int)(128*sin(2*M_PI*i/N))+128;
        }
    
        for( i=0 ; i<N ; i++ ){
            for( j=i+1 ; j<N ; j++ ){
                XDrawLine( dis, win, gc, x[i], y[i], x[j], y[j] );
            }
        }
    
        XFlush( dis );
    
        printf("Push return key.");
        getchar();
        XDestroyWindow( dis , win );
        XCloseDisplay( dis );
    
        return(0);
    }
    

    これで緑色でダイアモンドパターンが描かれます。


  • 第4章 イベントを聞く
  • 目次
    Copyright(C) by Naoki Watanabe. Oct 21st, 1995.
    渡辺尚貴 naoki@cms.phys.s.u-tokyo.ac.jp