第1章 Windowsプログラミングを学ぼう

1-3.スケルトンプログラムを改造しよう

(a) 背景色を変える

InitApp関数内のGetStockObject関数でウィンドウの背景色を変更できる

// ウィンドウの背景(黒に設定)
wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);

《定義できる色(wingdi.hで定義されているブラシの色)》

ブラシの種類
DKGRAY_BRUSH ダークグレイ
GRAY_BRUSH グレイ
LTGRAY_BRUSH ライトグレイ
WHITE_BRUSH
BLACK_BRUSH
NULL 最初に表示したときの下の画像をそのまま背景にする(中空)

(b) ウィンドウの大きさを変える

CreateWindow関数の第6,7引数に横幅、高さをそれぞれ指定することにより、ウィンドウの大きさを制御する。
「CW・・・」はデフォルト値で、通常640×480ピクセルのウィンドウが表示される。

《例1》任意の大きさにする

/* ウィンドウクラスの登録ができたので、ウィンドウを生成する */
hWnd = CreateWindow(
    szWinName, // ウィンドウクラスの名前
    "Skeleton 背景を黒に", // ウィンドウタイトル
    WS_OVERLAPPEDWINDOW, // ウィンドウスタイル
    CW_USEDEFAULT, // ウィンドウの左角X座標(Windowsに任せる)
    CW_USEDEFAULT, // ウィンドウの左角Y座標(Windowsに任せる)
    320, // ウィンドウの幅(320に固定)
    240, // ウィンドウの高さ(240に固定)
    HWND_DESKTOP, // 親ウィンドウ(なし)
    NULL, // メニュー(なし)
    hThisInst, // このプログラムのインスタンスのハンドル
    NULL // 追加引数(なし)
);

《例2》常にその解像度で最大の大きさにする

RECT rcRect;  ←InitAppの最初で宣言

/* ディスクトップの大きさを取得 */  ←CreateWindow関数の直前に追加
hWnd = GetDesktopWindow(); // デスククトップのハンドルを取得
GetWindowRect(hWnd, &rcRect); // デスクトップの矩形を得る(left,topは常に0)

/* ウィンドウクラスの登録ができたので、ウィンドウを生成する */
hWnd = CreateWindow(
    szWinName, // ウィンドウクラスの名前
    "Skeleton 背景を黒に", // ウィンドウタイトル
    WS_OVERLAPPEDWINDOW, // ウィンドウスタイル
    CW_USEDEFAULT, // ウィンドウの左角X座標(Windowsに任せる)
    CW_USEDEFAULT, // ウィンドウの左角Y座標(Windowsに任せる)
    rcRect.right, // デスクトップの幅
    rcRect.bottom, // デスクトップの高さ
    HWND_DESKTOP, // 親ウィンドウ(なし)
    NULL, // メニュー(なし)
    hThisInst, // このプログラムのインスタンスのハンドル
    NULL // 追加引数(なし)
);

(c) 表示位置を変える

CreateWindow関数の第4,5引数に表示位置のX座標、Y座標をそれぞれ指定することにより、ウィンドウの表示位置を制御する。
「CW・・・」はデフォルト値。

《例1》任意の位置へ表示する

/* ウィンドウクラスの登録ができたので、ウィンドウを生成する */
hWnd = CreateWindow(
    szWinName, // ウィンドウクラスの名前
    "Skeleton 背景を黒に", // ウィンドウタイトル
    WS_OVERLAPPEDWINDOW, // ウィンドウスタイル
    0, // ウィンドウの左角X座標(一番左)
    0, // ウィンドウの左角Y座標(一番上)
    CW_USEDEFAULT, // ウィンドウの幅(Windowsに任せる)
    CW_USEDEFAULT, // ウィンドウの高さ(Windowsに任せる)
    HWND_DESKTOP, // 親ウィンドウ(なし)
    NULL, // メニュー(なし)
    hThisInst, // このプログラムのインスタンスのハンドル
    NULL // 追加引数(なし)
);

《例2》常に画面の中央へ表示する

// マクロの定義  ←includeの次に指定
#define WINDOW_WIDTH 640        // ウィンドウの幅
#define WINDOW_HEIGHT 480       // ウィンドウの高さ

RECT rcRect;  ←InitAppの最初で宣言

/* ディスクトップの大きさを取得 */  ←CreateWindow関数の直前に追加
hWnd = GetDesktopWindow(); // デスククトップのハンドルを取得
GetWindowRect(hWnd, &rcRect); // デスクトップの矩形を得る(left,topは常に0)

/* ウィンドウクラスの登録ができたので、ウィンドウを生成する */
hWnd = CreateWindow(
    szWinName, // ウィンドウクラスの名前
    "Skeleton 背景を黒に", // ウィンドウタイトル
    WS_OVERLAPPEDWINDOW, // ウィンドウスタイル
    (rcRect.right - WINDOW_WIDTH) / 2, // 画面中央の左角X座標
    (rcRect.bottom - WINDOW_HEIGHT) / 2, // 画面中央の左角Y座標
    WINDOW_WIDTH, // ウィンドウの幅
    WINDOW_HEIGHT, // ウィンドウの高さ
    HWND_DESKTOP, // 親ウィンドウ(なし)
    NULL, // メニュー(なし)
    hThisInst, // このプログラムのインスタンスのハンドル
    NULL // 追加引数(なし)
);

(d) オリジナルアイコンを使う

アイコンには次の2種類がある。

1.ラージアイコン
デスクトップやエクスプローラ上に表示されるアイコン
2.スモールアイコン
実行時のタスクバーやタイトルバー上に表示されるアイコン

スケルトンプログラムでは、システムが用意したアイコンを使うよう設定してある。

/* ウィンドウクラスを定義する */
・
・
wc.hIcon = LoadIcon(hThisInst, IDI_APPLICATION); // ラージアイコン
wc.hIconSm = LoadIcon(hThisInst, IDI_WINLOGO); // スモールアイコン
・
・

《POINT》LoadIcon関数

アイコンオブジェクト = LoadIcon(インスタンス名, リソース名);

オリジナルアイコンを作成し、利用するには次の作業が必要。

  1. アイコンをリソースとしてプロジェクトに組み込む。
    「挿入」→「リソース」を選択し、「リソースのタイプ」ウィンドウでIconを選択して「新規作成」ボタンをクリック。
  2. エディタが開くので、アイコンを作成する。
  3. アイコンリソース名をデフォルトで指定している名前からダブルクォーテーションを付けた"XXXXXX"の形(例、"ICON")に変更する。リソースを右クリックし、プロパティを開き、IDを変更する。(デフォルトの名前を使うのはプログラム的に面倒になる)
  4. リソースファイルを保存。
    「保存」ボタンをクリックし、「Script1.rc」という名前で保存。
  5. 作成したりソースをプロジェクトへ追加。
    「プロジェクト」→「プロジェクトへ追加」→「ファイル」→「ファイルの選択」で、作成したリソースファイル「Script1.rc」とヘッダファイル「resource.h」を選択。
  6. リソースに追加したアイコンを使うよう、プログラムを修正。
    #include "resource.h"
    ・
    ・
    
    /* ウィンドウクラスを定義する */
    ・
    ・
    wc.hIcon = LoadIcon(hThisInst, "ICON"); // ラージアイコン
    wc.hIconSm = LoadIcon(hThisInst, "ICON"); // スモールアイコン
    ・
    ・

(e) Windowesメッセージを発行させて処理する

(1)ウィンドウ内に文字列を表示する

//=============================================================================
//      Windows関数
//=============================================================================
LRESULT CALLBACK WinProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    HDC hdc; // デバイスコンテキスト
    PAINTSTRUCT ps; // 再描画用構造体
    char str[] = "Hello World"; // 表示文字列

    switch (message)
    {
        case WM_PAINT:
            hdc = BeginPaint(hWnd, &ps); // 描画開始
            TextOut(hdc, 1, 1, str, strlen(str));
            EndPaint(hWnd, &ps); // 描画終了
            break;
        case WM_DESTROY: // 閉じるボタンをクリックした時
            PostQuitMessage(0); // WM_QUITメッセージを発行
            break;
        default: // 上記以外のメッセージはWindowsへ処理を任せる
            return DefWindowProc(hWnd, message, wParam, lParam);
    }

    return 0;

}

(2)マウスクリックに対応する(左ボタンクリックで1文字表示)

(1)のプログラムを改造し、マウスの左ボタンをクリックすると表示文字列がy方向(縦)に下がって表示されるようにする。

//=============================================================================
//      Windows関数
//=============================================================================
LRESULT CALLBACK WinProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    HDC hdc; // デバイスコンテキスト
    PAINTSTRUCT ps; // 再描画用構造体
    char str[] = "Hello World"; // 表示文字列
    static int y = 0; // 表示座標

    switch (message)
    {
        case WM_LBUTTONDOWN:
            if (y < 430)
                y += 18;
            else
                y = 0;
            InvalidateRect(hWnd, NULL, 1);
            break;
        case WM_PAINT:
            hdc = BeginPaint(hWnd, &ps); // 描画開始
            TextOut(hdc, 0, y, str, strlen(str));
            EndPaint(hWnd, &ps); // 描画終了
            break;
        case WM_DESTROY: // 閉じるボタンをクリックした時
            PostQuitMessage(0); // WM_QUITメッセージを発行
            break;
        default: // 上記以外のメッセージはWindowsへ処理を任せる
            return DefWindowProc(hWnd, message, wParam, lParam);
    }

    return 0;

}

(3)キーボード入力に対応する

(1)のプログラムを変更し、最初に文字「+」を表示し、カーソルキーを押すことによりその文字を上下左右に動かすプログラムを作る。

//=============================================================================
//      Windows関数
//=============================================================================
LRESULT CALLBACK WinProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    HDC hdc; // デバイスコンテキスト
    PAINTSTRUCT ps; // 再描画用構造体
    char str[] = "+"; // 表示文字列
    static int x = 0, y = 0;

    switch (message)
    {
        case WM_KEYDOWN:
            switch (wParam)
            {
                case VK_LEFT:
                    x -= 5;
                    if (x < 0)
                        x = 0;
                    break;
                case VK_RIGHT:
                    x += 5;
                    if (620 < x)
                        x = 620;
                    break;
                case VK_UP:
                    y -= 5;
                    if (y < 0)
                        y = 0;
                    break;
                case VK_DOWN:
                    y += 5;
                    if (435 < y)
                        y = 435;
                    break;
            }
            InvalidateRect(hWnd, NULL, 1);
            break;
        case WM_PAINT:
            hdc = BeginPaint(hWnd, &ps); // 描画開始
            TextOut(hdc, x, y, str, strlen(str));
            EndPaint(hWnd, &ps); // 描画終了
            break;
        case WM_DESTROY: // 閉じるボタンをクリックした時
            PostQuitMessage(0); // WM_QUITメッセージを発行
            break;
        default: // 上記以外のメッセージはWindowsへ処理を任せる
            return DefWindowProc(hWnd, message, wParam, lParam);
    }

    return 0;

}

※「VK_LEFT」「VK_RIGHT」などは仮想キーコードといい、標準ライブラリに定義されている。詳しくは用語集の「仮想キーコード」の項を参照。

(4)1文字を一定時間ごとに移動させる(タイマーの使用)

(1)のプログラムを変更し、一定時間ごとに文字「+」を移動させる。

// マクロの定義
#define WS_WIDTH 630 // ウィンドウの大体の横幅
#define WS_HEIGHT 460 // ウィンドウの大体の高さ
#define TIMER_ID 1 // タイマーID
#define TIMER_RATE 100 // タイマーの間隔(ミリ秒)
#define SPEED 10 // 文字の移動量


/* タイマーをセットする */
SetTimer(hWnd, TIMER_ID, TIMER_RATE, NULL); ←WinMain関数のメッセージループの前に追加


/* タイマーを削除する */
KillTimer(hWnd, TIMER_ID); ←WinMain関数のメッセージループの後に追加


//=============================================================================
//      Windows関数
//=============================================================================
LRESULT CALLBACK WinProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    HDC hdc; // デバイスコンテキスト
    PAINTSTRUCT ps; // 再描画用構造体
    char str[] = "+"; // 表示文字列
    static int x = 0, y = 0; // 表示座標

    switch (message)
    {
        case WM_TIMER:
            x += SPEED;
            if (WS_WIDTH < x)
                x = 0;
            InvalidateRect(hWnd, NULL, TRUE);
            break;
        case WM_PAINT:
            hdc = BeginPaint(hWnd, &ps); // 描画開始
            TextOut(hdc, x, y, str, strlen(str));
            EndPaint(hWnd, &ps); // 描画終了
            break;
        case WM_DESTROY: // 閉じるボタンをクリックした時
            PostQuitMessage(0); // WM_QUITメッセージを発行
            break;
        default: // 上記以外のメッセージはWindowsへ処理を任せる
            return DefWindowProc(hWnd, message, wParam, lParam);
    }

    return 0;

}

[ TOP ]