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;
}
}
}
プログラムができたら、コンパイルして実行してみましょう。
うまくいった人は次の課題に挑んでみてください。