概要

ウィンドウに連続直線で囲まれた閉じた図形を描画するサンプルです。
ここでは猫のbmpファイルをブラシとして使用しています。

テスト環境

コンパイラ

Visual C++ 2008 Standard 32/64bit
Visual C++ 2013 Express 32/64bit

実行環境

Windows 8.1 Enterprise 64bit
Windows 7 EnterPrise Service Pack 1 64bit
Windows Vista Ultimate Service Pack 2 32bit
Windows XP Professional Service Pack 3 32bit

プログラムソースの概要

_tWinMain関数

Windowsから最初に_tWinMain関数が呼び出されます。
ウィンドウを作成する場合は、RegisterClass APIによりウィンドウクラスを定義してからCreateWindow APIを呼び出しウィンドウを作成します。
Windowsは入力等のイベントが発生するとアプリケーションにメッセージを送付します。
メッセージはキューに保管されます。アプリケーションはメッセージを取り出し、該当ウィンドウにメッセージを配信します。
メッセージの取り出しから配信までループで処理を行いウィンドウから終了メッセージが届くと、ループを抜けるように記述します。 これらの一連の処理は、通常にCreateWindow APIの後に記述しこれをメッセージループと呼んでいます。
詳細は以下を参照してください。
メッセージループ

WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)ウィンドウプロシージャー

RegisterClass APIにより登録することによりWindowsから呼び出されます。
第2引数にメッセージの種類が格納されていますので、switchステートメントによりメッセージごとの処理を振り分けます。
自分で処理しないメッセージはDefWindowProc APIに渡せばWindowsが標準的な処理を行ってくれます。

case WM_CREATE:

ウィンドウの初期化時に呼び出されます。
point_calc関数で多角形の頂点座標を計算しPOINT構造体の配列に座標を設定します。
上記の配列は、WM_PAINTメッセージで使用するのでstatic変数で定義しておきます。

case WM_DESTROY:

ウィンドウが閉じるときに呼び出されます。
PostQuitMessage APIにより終了コードを指定して、ウィンドウプロシージャーを終了させます。

case WM_PAINT:

ウィンドウを再描画する必要があるときに呼び出されます。
他のウィンドウに隠れ再びフォアグラウンドになった場合などウィンドウの再描画はWindowsが面倒を見ないのでプログラマの仕事となっています。
BeginPaint APIを呼び出して、描画に必要なデバイスコンテキストのハンドルを取得します。
BeginPaint APIの第2引数のポインタにはPAINTSTRUCT構造体のポインタを渡します。
BeginPaint API終了後、PAINTSTRUCT構造体には再描画が必要な領域の座標等の値が格納されています。
線を使用して描画するには、ペンを作成します。
ペンの作成方法の詳細は以下を参照してください。
GDIのペンの作成方法
ペンを作成したらそのペンで描画させるためにSelectObject APIによりペンを選択します。戻り値は、前回のペンのハンドルですので保存しておき、デバイスコンテキストの解放前にペンの設定をもとに戻すときに使用します。
塗りつぶしを行うためにブラシの作成を行う必要があります。
ブラシの作成方法の詳細は以下を参照してください。
GDIのブラシの作成方法
ここではリソースに組み込まれたビットマップをブラシにしています。
コンパイル時にリソースファイルとneko.bmpファイルが必要です。
ブラシを作成したらそのブラシで描画させるためにSelectObject APIによりブラシを選択します。戻り値は、前回のブラシのハンドルですので保存しておき、デバイスコンテキストの解放前にブラシの設定をもとに戻すときに使用します。
PolyGon APIに頂点座標を個数を渡して連続直線に囲まれた閉じた図形を描画します。 SelectObject APIでペンを元に戻します。
SelectObject APIでブラシを元に戻します。
再描画が終了したことをWindowsに知らせるためにEndPaint APIを使用してます。このAPIを呼び出さないと何度もWM_PAINTメッセージが発生し暴走します。

point_calc

正多角形の頂点座標を計算します。
正多角形ですので360度を辺数で割り返し、sin、cos関数で頂点座標を計算します。
Polygon APIは閉じた図形を描画するので、開始点と終了点は自動的に結ばれます。
Polyline APIで閉じた図形を描画するときは、頂点数+1の座標が必要ですが、Polygon APIの場合、頂点数となります。

プログラムソース

polygon.cpp

//       Polygonの描画
//      Visual C++ 2008/2013    32/64bit

#include <windows.h>
#include <tchar.h>
#include <math.h>

//      ウィンドウプロシージャー
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

//      正多角形の各頂点の座標を計算
void point_calc(POINT* point, int n, int cx, int cy, double r1);

TCHAR szClassNme[] = TEXT("Polygon");

#define NUM 10

HINSTANCE hinst;
int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPreInst,
                TCHAR* lpszCmdLine, int nCmdShow){
        HWND hWnd;
        MSG lpMsg;
        WNDCLASS myProg;
        hinst=hInstance;

        if (!hPreInst) {
                myProg.style = CS_HREDRAW | CS_VREDRAW;
                myProg.lpfnWndProc = WndProc;
                myProg.cbClsExtra = 0;
                myProg.cbWndExtra = 0;
                myProg.hInstance = hInstance;
                myProg.hIcon = NULL;
                myProg.hCursor = LoadCursor(NULL, IDC_ARROW);
                myProg.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
                myProg.lpszMenuName = NULL;
                myProg.lpszClassName = szClassNme;
                if (!RegisterClass(&myProg))
                        return FALSE;
        }
        hWnd = CreateWindow(szClassNme,
                TEXT("Polygon"),
                WS_OVERLAPPEDWINDOW,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                220,
                240,
                NULL,
                NULL,
                hInstance,
                NULL);
        ShowWindow(hWnd, nCmdShow);
        UpdateWindow(hWnd);
        while (GetMessage(&lpMsg, NULL, 0, 0)) {
                TranslateMessage(&lpMsg);
                DispatchMessage(&lpMsg);
        }
        return int(lpMsg.wParam);
}

//      ウィンドウプロシージャー

LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam){
    HDC hdc;
    PAINTSTRUCT ps;
        static POINT p1[NUM];
        static HBITMAP hbitmap;
        static HBRUSH hbrush;
        HBRUSH old;
    switch (msg) {
                case WM_CREATE:
                        hbitmap = LoadBitmap(hinst, TEXT("BMP_RC"));
                        hbrush = CreatePatternBrush(hbitmap);
                        point_calc(p1, NUM, 100, 100, 90);
                        break;
        case WM_DESTROY:
                        DeleteObject(hbrush);
                        DeleteObject(hbitmap);
                        PostQuitMessage(0);
            break;
        case WM_PAINT:{
            hdc = BeginPaint(hWnd, &ps);
                        old = (HBRUSH)SelectObject(hdc, hbrush);
                        Polygon(hdc,p1,NUM);

                        SelectObject(hdc,old);
                        EndPaint(hWnd, &ps);
                        break;
                }
        default:
            return(DefWindowProc(hWnd, msg, wParam, lParam));
    }
    return (0L);
}

//      正多角形の各頂点の座標を計算

void point_calc(POINT* point, int n, int cx, int cy, double r1){
        double qn = 2 * 3.14 / double(n);
        double q = 0;
        int u = 0;
        int i;
        for (i = 0; i<n; i++){
                int x1 = int(r1*cos(q)) + cx;
                int y1 = int(r1*sin(q)) + cy;
                q += qn;
                point[u].x = x1;
                point[u++].y = y1;
        }
}

ソースファイルと実行ファイルのダウンロード

ダウンロード polygon.zip(45.2kByte)

ZIPファイルに含まれるファイル
polygon.cpp
polygon.exe
resource.rc
neko.bmp