線を引く

対角線を引きます。

0001: /*
0002:   drawline-win32.c
0003:   gcc drawline-win32.c -mwindows
0004:   bcc32 -W drawline-win32.c 
0005: */
0006: 
0007: #include <windows.h>
0008: 
0009: int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
0010:         LPSTR lpCmdLine, int nCmdShow )
0011: {
0012:   HWND hWnd;
0013:   WNDCLASS wndClass;
0014:   static TCHAR szAppName[] = TEXT("OpenWindow");
0015:   HDC hdc;
0016:   PAINTSTRUCT ps;
0017:   HPEN hPen;
0018: 
0019:   /* ウインドウクラスの設定 */
0020:   wndClass.style = 0;
0021:   wndClass.lpfnWndProc = DefWindowProc;
0022:   wndClass.cbClsExtra = 0;
0023:   wndClass.cbWndExtra = 0;
0024:   wndClass.hInstance = NULL;
0025:   wndClass.hIcon = NULL;
0026:   wndClass.hCursor = NULL;
0027:   wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
0028:   wndClass.lpszMenuName = NULL;
0029:   wndClass.lpszClassName = szAppName;
0030: 
0031:   RegisterClass( &wndClass ); /* ウインドウクラスの登録 */
0032: 
0033:   hWnd = CreateWindow( /* ウインドウの作成 */ 
0034:           szAppName, /* 作成するウインドウのクラス名 */
0035:           TEXT("openwin-win32"), /* ウインドウタイトル */
0036:           WS_OVERLAPPEDWINDOW, /* ウインドウスタイル */
0037:           CW_USEDEFAULT, /* 左上頂点のX座標 */
0038:           CW_USEDEFAULT, /* 左上頂点のY座標 */
0039:           CW_USEDEFAULT, /* ウインドウの幅 */
0040:           CW_USEDEFAULT, /* ウインドウの高さ */
0041:           NULL, /* 親ウインドウのハンドル */
0042:           NULL, /* メニューのハンドル */
0043:           hInstance, /* 親モジュールのインスタンスハンドル */
0044:           NULL ); /* ウインドウへの引数 */
0045: 
0046:   ShowWindow( hWnd, nCmdShow ); /* ウインドウの表示 */
0047: 
0048:   hdc = BeginPaint( hWnd, &ps ); /* 描画開始 */
0049: 
0050:   hPen = GetStockObject( BLACK_PEN ); /* ペンの選択 */
0051:   SelectObject( hdc, hPen ); /* ペンの設定 */
0052: 
0053:   MoveToEx( hdc, 0, 0, NULL ); /* ペン座標を原点へ */
0054:   LineTo( hdc, ps.rcPaint.right, ps.rcPaint.bottom ); /* 対角線を描画 */
0055: 
0056:   EndPaint( hWnd, &ps ); /* 描画終了 */
0057: 
0058:   Sleep( 10000 ); /* 表示を10秒間保持 */
0059:   
0060:   DestroyWindow( hWnd ); /* ウインドウの開放 */
0061: 
0062:   return 0;
0063: }

ウインドウを開くのとほとんど一緒です。まずは増えている部分の宣言からです。

0015:   HDC hdc;
0016:   PAINTSTRUCT ps;
0017:   HPEN hPen;

HDCはデバイスコンテキストのハンドルです。デバイスコンテキストというのは、出力デバイスとプログラムの仲介をするものです。プログラムからはGDI描画関数でデバイスコンテキストを指定して描画します。デバイスコンテキストからはデバイスドライバを通じて実際のデバイス上で描画を行います。デバイスコンテキストを取得してGDI関数を呼び出すことによって、実際のデバイスが何であろうと同じようにして出力することができます。

たとえば、カラーディスプレイを想定して書かれたプログラムがモノクロディスプレイしか持たないコンピュータで実行されるとします。この場合、ディスプレイのデバイスドライバがカラー情報を適切に二値化して表示してくれます。プログラマはデバイスコンテキストの向こう側にある実際のデバイスを意識しなくてもいいわけです。(もちろん、限界があるのでデバイス固有の記述がなされることもあります。)

通常、デバイスコンテキストはデバイスひとつに対応していますが、ディスプレイのデバイスコンテキストはウインドウごとに対応しています。

PAINTSTRUCTは塗りつぶしについての情報を保持しています。

HPENはペンの属性を持っています。具体的には線の種類と幅、色についてです。

0048:   hdc = BeginPaint( hWnd, &ps ); /* 描画開始 */
0049: 
0050:   hPen = GetStockObject( BLACK_PEN ); /* ペンの選択 */
0051:   SelectObject( hdc, hPen ); /* ペンの設定 */
0052: 
0053:   MoveToEx( hdc, 0, 0, NULL ); /* ペン座標を原点へ */
0054:   LineTo( hdc, ps.rcPaint.right, ps.rcPaint.bottom ); /* 対角線を描画 */
0055: 
0056:   EndPaint( hWnd, &ps ); /* 描画終了 */

線を描くために増えた部分です。

    HDC BeginPaint(
        HWND hwnd,
        LPPAINTSTRUCT lpPaint
    )

hwndは描画を行うウインドウのハンドルを指定します。するとlpPaintに、描画に関する属性が返ります。

    HGDIOBJ GetStockObject(
        int fnObject
    )

すでに出てきているGetStockObjectは、予約されているGDIオブジェクトの取得に使います。ここではBLACK_PENを指定して、黒の実線を描きます。

    HGDIOBJ SelectObject(
        HDC hdc,
        HGDIOBJ hgdiobj
    )

SelectObjectによって、hgdiobjに選択したものをhdcに設定します。

    BOOL MoveToEx(
        HDC hdc,
        int X, Y
        LPPOINT lpPoint
    )

Windows GDI はプロッタのようにして描画します。直接ペンのアップダウンを指定する関数はありませんが、降りている状態と移動している状態は区別できます。このMoveToExは、ペンがあがった状態で、現在位置を指定できます。hdcが描画対象となるウインドウのデバイスコンテキスト、続く。X,Yが、移動する座標です。最後の。lpPointには移動前の座標が入ります。ここでは以前の座標は必要ないのでNULLを指定しています。

    BOOL LineTo(
        HDC hdc,
        int nXEnd, nYEnd
    )

こちらはペンが下りた状態です。hdcで指定したデバイスの現在ペンがある位置からnXEnd, nYEndで指定された座標へと線を引きます。どのような線が引かれるかは、現在のhdcでのペン状態によります。ここでは、psに返ってきたウインドウの描画領域情報を使用して、ウインドウの対角線を引きます。

    BOOL EndPaint(
        HWND hWnd,
        CONST PAINTSTRUCT *lpPaint
    )

描画が終わったらEndPaintを呼びます。この関数はBeginPaintに対応するもので、描画を終了するウインドウのハンドルhWndと、取得したPAINTSTRUCT構造体のポインタを指定します。

このようにして線をひくことができましたが、ほかのウインドウが重なると、そのグラフィックがそのままその領域に残ってしまいます。これを避けるには、ウインドウが一番上になったらば描きなおすということが必要です。そのためにはメッセージというものの存在を理解する必要があります。

Back to TOP