Software Design 2010年8月号 サンプルプログラムダウンロードページ

このページは、Software Design 2010年8月号の第2特集 「達人に学ぶきれいなコードを書くための17の約束」の サンプルプログラムのダウンロードページです。

ダウンロードはこちらから

DRW.zip

このサンプルプログラムはWindows上で動作します。 他のプラットフォームの方にも ヘッダファイルの作り方等で参考になる可能性はあります。

解説

このプログラムは何?

詳細はSoftware Design 8月号の方を見ていただきたいのですが、 このサンプルプログラムが提供しているのは、 ウィンドウに対し、実数のユーザ座標系による描画を可能にするライブラリです。

ライブラリだけでは何ですので、最低限のテストドライバも付けています。

動作環境

私のところでは、Windows上のCコンパイラとしてMinGWを使用しています。 Visual Studio等でも動作すると思いますが、ビルドの方法等については ここでは詳述しません。提供しているのは所詮小規模なライブラリなので、 自由にビルドしていただければよろしいかと。

MinGWの公式ページはこちらです。

http://www.mingw.org/

上記リンクからからダウンロードできるフォルダの内容物は 下記のとおりです。

DRW
│  DRW.h
│  DRW_windows.h
│  main.c
│  main_win.c
│  Makefile
└─DRW
        create_window.c
        draw.c
        drw_pri.h
        mainloop.c
        Makefile

まず、下の階層のDRWでmake(私の場合、MinGWでデフォルトで インストールされる「mingw32-make.exe」を「gmake.exe」 にリネームして使用しています)を実行すると、「drw.o」が 生成されます。

上層のDRWでmakeを実行すると、 「drwtest.exe」という実行可能プログラムが生成されます。

テスト用のメインルーチンはmain.cとmain_win.cの2種類が存在します。 main.cはDRWの機能を使用してウインドウを開くもの、 main_win.cは自力でウインドウを作ってからそれを DRW_Windowに割り当てるものです。 Makefileを書き換えて作り変えてください。

ライブラリDRWの使用法

記事中にも説明はありますが、 Windowsのようなイベントドリブンのプログラムに固有の話については 本筋から外れるので説明を省いています。 ここではそれについて簡単に説明します。

DRWの機能を使用して新規ウインドウを開く場合、以下のように記述します (DRW.zipに添付されたテストドライバからの抜粋です)。

DRW_Window *win;

/* 800×600ピクセルのウインドウを作る */
win = DRW_create_window(800, 600, -1, -1, 1, 1);
/* ウインドウに対し、再描画用のコールバックルーチンを指定する */
DRW_set_redraw_callback(win, redraw_proc);
/* メインループに入る */
DRW_main_loop();

イベントドリブンのプログラミングでは、通常、プログラムは最終的に 「メインループ」に入ります。DRWの場合、DRW_main_loop()関数が メインループの関数です。 DRWの目的はウインドウにいろいろな図形を描画することなのですが、 そのためには、描画の関数をDRW_set_redraw_callback()関数により 事前登録することになります。

DRWをこの使用法で利用する限り、DRWの利用者は、 Windowsが提供する各種関数を呼び出す必要がありません (言い換えれば、windows.hを#includeする必要がありません)。

とはいえ場合によってはWindowsの機能を直接使って作成したウインドウに DRWの機能を使用して描画したい場合もあるでしょう。 そのような場合は、windows.hとDRW_windows.hを#includeしたうえで、 以下のように書きます。

(前略)
/* Windowsの機能でウインドウを開く */
hwnd = CreateWindow(TEXT("TestWindowClass"), TEXT("DRW Test Driver"),
                    WS_OVERLAPPEDWINDOW | WS_VISIBLE,
                    CW_USEDEFAULT, CW_USEDEFAULT,
                    CW_USEDEFAULT, CW_USEDEFAULT,
                    NULL, NULL, NULL, NULL);
if (hwnd == NULL) {
    return -1;
}
/* Windowsの機能で作成したウインドウとDRW_Windowを対応付ける */
g_window = DRW_set_canvas(hwnd, -1, -1, 1, 1);
DRW_set_redraw_callback(g_window, redraw_proc);

/* メインループは自分で書く */
while (GetMessage(&msg, NULL, 0, 0)) {
    DispatchMessage(&msg);
}

上記のようにした上で、ウインドウプロシージャを以下のように書きます。 まず、メッセージをDRWに引き渡し、 処理されなかったメッセージについてのみ自力で処理をする、 という流れになります。

LRESULT CALLBACK
WndProc(HWND hwnd , UINT msg , WPARAM wp , LPARAM lp) {
    if (DRW_window_procedure(g_window, msg, wp, lp) == DRW_MESSAGE_IGNORED) {
        switch (msg) {
        case WM_DESTROY:
            PostQuitMessage(0);
            return 0;
        }
    }
    return DefWindowProc(hwnd , msg , wp , lp);
}

ついでに、再描画ルーチンの例も貼っておきます。

void redraw_proc(DRW_Window *window)
{
    int i;
    double angle;
    double radius;
    DRW_Point points[1000];
    
    DRW_draw_line(window, 0, 0, 0.5, 0.5);

    angle = 0;
    radius = 0;
    for (i = 0; i < 1000; i++) {
        points[i].x = cos(angle) * radius;
        points[i].y = sin(angle) * radius;
        angle += 0.1;
        radius += 0.001;
    }
    DRW_draw_polyline(window, 1000, points);

    for (i = 0; i < 10; i++) {
        DRW_draw_circle(window, 0, 0, i * 0.1);
    }
    DRW_draw_rect(window, 0, 0, -0.5, 0.5);
    DRW_fill_circle(window, 0.5, 0.5, 0.5);
    DRW_fill_rect(window, 0, 0, 0.5, -0.5);
}

これの実行結果は以下のようになります。


著者のWebページトップはこちら

ご意見、ご質問、不具合連絡等は掲示板にお願いいたします。