Previous: 準備
Up: Xウィンドウ実習
第7回 ペイントツール(その2)
色や線をボタンで選択

Previous Page: 準備
Next Page: Xウィンドウ概論
第8回 アイコンとカーソル

色のボタンと線のボタンを追加

先週作った「ペイント・ツール」は、色は黒だけ、線も細い線しか使えませんでした。 これらの点を改良し、新しい機能を付け加えたプログラムを作ります。
色や線の太さを選択するため、新しいボタンのウィンドウを多数生成します。 数が多いので、いずれもウィンドウの配列になっている点に注意してください。 また、色のボタン color[ ] はウィンドウ palette の サブ・ウィンドウに、 線の太さのボタン pen[ ] はウィンドウ tool の サブ・ウィンドウになるようにします。
先週のプログラム paint1.c を元にして作りますが、 ソース・ファイル名は新たに paint2.c としてください。

paint2.c

#include<stdio.h>
#include<X11/Xlib.h>
#define MAX_COLOR 12   /* 色の個数 */
#define MAX_PEN    6   /* 線の種類の個数 */
main()
{
 Display *dsp;
 Window   frame;
 Window   canvas, command;
 Window   quit, clear;
 Window   palette, tool;                    /* 追加するウィンドウ */
 Window   color[MAX_COLOR], pen[MAX_PEN];   /* 追加するウィンドウ */
 GC       gc;
 XEvent   eve;
 Colormap cmap;                   /* カラーマップ */
 XColor   iro[MAX_COLOR], dummy;  /* 色のデータ */
 static char *cname[] = {
                         "red", "green", "blue", "yellow",
                         "pink", "sky blue", "orange", "violet",
                         "dark green", "gray", "black", "white"
                        };
 static int pen_data[] = { 1, 2, 4, 8 ,12, 20 };  /* 線の太さ */

int x1,y1,x2,y2; int i; /* カウンター */

dsp = XOpenDisplay( NULL );

cmap = DefaultColormap( dsp, 0 ); /* カラーマップを得る */ for( i=0 ; i<MAX_COLOR ; i++ ) /* カラーマップから色を得る */ XAllocNamedColor( dsp, cmap, cname[i], &iro[i], &dummy );

frame = XCreateSimpleWindow( dsp, DefaultRootWindow(dsp), 0, 0, 600, 400, 1, BlackPixel(dsp,0), BlackPixel(dsp,0) ); canvas = XCreateSimpleWindow( dsp, frame, 5, 5, 555, 355, 0, BlackPixel(dsp,0), WhitePixel(dsp,0) ); command = XCreateSimpleWindow( dsp, frame, 565, 265, 30, 95, 0, BlackPixel(dsp,0), WhitePixel(dsp,0) ); quit = XCreateSimpleWindow( dsp, command, 2, 5, 24, 24, 1, BlackPixel(dsp,0), WhitePixel(dsp,0) ); clear = XCreateSimpleWindow( dsp, command, 2, 35, 24, 24, 1, BlackPixel(dsp,0), WhitePixel(dsp,0) );

/* 追加するウィンドウの生成 */

palette = XCreateSimpleWindow( dsp, frame, 5, 365, 590, 30, 0, BlackPixel(dsp,0), WhitePixel(dsp,0) ); tool = XCreateSimpleWindow( dsp, frame, 565, 5, 30, 255, 0, BlackPixel(dsp,0), WhitePixel(dsp,0) ); for( i=0 ; i<MAX_COLOR ; i++ ) { color[i] = XCreateSimpleWindow( dsp, palette, 5+30*i, 2, 24, 24, 1, BlackPixel(dsp,0), iro[i].pixel ); } for( i=0 ; i<MAX_PEN ; i++ ) { pen[i] = XCreateSimpleWindow( dsp, tool, 2, 5+30*i, 24, 24, 1, BlackPixel(dsp,0), WhitePixel(dsp,0) ); }

gc = XCreateGC( dsp, frame, NULL, NULL ); XSetForeground( dsp, gc, BlackPixel(dsp,0) );

XSelectInput( dsp, canvas, ButtonPressMask | Button1MotionMask ); XSelectInput( dsp, quit, ButtonPressMask | ExposureMask ); XSelectInput( dsp, clear, ButtonPressMask | ExposureMask );

/* 追加するボタンのウィンドウへのイベントマスクの設定 */ for( i=0 ; i<MAX_COLOR ; i++ ) XSelectInput( dsp, color[i], ButtonPressMask | ExposureMask ); for( i=0 ; i<MAX_PEN ; i++ ) XSelectInput( dsp, pen[i], ButtonPressMask | ExposureMask );

XStoreName( dsp, frame, "Paint Tool" );

XMapWindow( dsp, frame ); XMapSubwindows( dsp, frame ); XMapSubwindows( dsp, command ); XMapSubwindows( dsp, palette ); /* 追加するウィンドウの表示 */ XMapSubwindows( dsp, tool ); /* 追加するウィンドウの表示 */

XFlush( dsp );

while( True ) { XNextEvent( dsp, &eve ); if( eve.xany.window == canvas ) { switch( eve.type ) { case ButtonPress: switch( eve.xbutton.button ) { case 1: x1=eve.xbutton.x; y1=eve.xbutton.y; break; default: break; } break; case MotionNotify: x2=eve.xbutton.x; y2=eve.xbutton.y; XDrawLine( dsp, canvas, gc, x1, y1, x2, y2 ); x1=x2; y1=y2; break; default: break; } continue; } if( eve.xany.window == clear ) { switch( eve.type ) { case ButtonPress: XClearWindow( dsp, canvas ); break; case Expose: XDrawString( dsp, clear, gc, 4, 16, "Cls", 3 ); break; default: break; } continue; } if( eve.xany.window == quit ) { switch( eve.type ) { case ButtonPress: XCloseDisplay( dsp ); exit(0); case Expose: XDrawString( dsp, quit, gc, 2, 16, "Quit", 4 ); break; default: break; } continue; }

/* 色の選択ボタン color[i] でのイベント処理 */

for( i=0 ; i<MAX_COLOR ; i++ ) if( eve.xany.window == color[i] ) { switch( eve.type ) { case ButtonPress: /* クリックされた時の処理 */ /* 色の変更 */ XSetForeground( dsp, gc, iro[i].pixel ); XFlush(dsp); break; default: break; } break; }

/* 線の太さの選択ボタン pen[i] でのイベント処理 */

for( i=0 ; i<MAX_PEN ; i++ ) if( eve.xany.window == pen[i] ) /* イベントが pen[i] で発生 */ { switch( eve.type ) { case ButtonPress: /* クリックされた時の処理 */ /* 線の太さの変更 */ XSetLineAttributes( dsp, gc, pen_data[i], LineSolid, CapRound, JoinRound ); break; case Expose: /* 再表示の処理 */ XFillArc( dsp, pen[i], gc, (24 - pen_data[i])/2, (24 - pen_data[i])/2, pen_data[i], pen_data[i], 0, 360*64 ); break; default: break; } break; } } }


プログラムができたら、コンパイルして実行してみましょう。

うまくいった人は次の課題に挑んでみてください。

maruyama@wakhok.ac.jp
1995年02月01日 (水) 00時21分18秒 JST