Win16 API   /   ラベル

ホーム     Windows API Primer

ラベル

Windows APIでウィンドウを表示するには、独自のウィンドウクラスを作成して、そのウィンドウクラスをシステム(Windows OS)に登録します。そして、その登録されたウィンドウクラスからウィンドウを作成して表示します。

  1. ウィンドウクラスを作成する。
  2. 作成したウィンドウクラスをシステム(Windows OS)に登録する。
  3. システム(Windows OS)に登録されたウィンドウクラスからウィンドウを作成して表示する。

イベントループ

GUI アプリケーションは、終了メッセージを受け取るまで、イベントループなどと呼ばれる無限ループで起動し続けます。

このような無限ループをプログラミング用語ではイベントループやメインループと言いますが、Windows APIでは、メッセージループとも言います。

label.c


#include <windows.h>

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

int     PASCAL   WinMain(HINSTANCE hInstance,
						 HINSTANCE hPrevInstance,
						 LPSTR     lpCmdLine,
						 int       nCmdShow)
{
    WNDCLASS wc;
    HWND     hwnd;
    MSG      msg;

    wc.style         = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc   = WndProc;
    wc.cbClsExtra    = 0;
    wc.cbWndExtra    = 0;
    wc.hInstance     = hInstance;
    wc.hIcon         = NULL;
    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    wc.lpszMenuName  = NULL;
    wc.lpszClassName = "LABEL";
    
    RegisterClass(&wc);
    
    hwnd             = CreateWindow("LABEL",
                                    "Label",
                                    WS_OVERLAPPEDWINDOW | WS_VISIBLE,
                                    CW_USEDEFAULT, CW_USEDEFAULT, 300, 200,
                                    NULL, NULL, hInstance, NULL);
    while (GetMessage(&msg, NULL, 0, 0))
    {
        DispatchMessage(&msg);
    }
    
    return msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    static HWND label;
           RECT rect;
    
    switch (msg)
    {
    case WM_CREATE:
        GetClientRect(hwnd, &rect);
        label = CreateWindow("STATIC",
                             "Hello",
                             WS_CHILD | WS_VISIBLE | SS_CENTER,
                             (rect.right  - 50) / 2,
                             (rect.bottom - 15) / 2,
                             50, 15,
                             hwnd, NULL, NULL, NULL);
        break;
    case WM_SIZE:
        GetClientRect(hwnd, &rect);
        SetWindowPos (label, HWND_TOP,
                      (rect.right  - 50) / 2,
                      (rect.bottom - 15) / 2,
                      0, 0, SWP_NOSIZE);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    }
    
    return DefWindowProc(hwnd, msg, wParam, lParam);
}

    


実行結果

ウィンドウのサイズを変更しても、「Hello」というラベルは常に中央に表示されます。


コード説明

  1. static HWND label;
    Windows API では、GUI 部品をコンポーネント(component)と呼びます。それぞれのコンポーネントもウィンドウなので HWND 型で取り扱います。
  2. case WM_CREATE:
    WM_CREATE はメインウィンドウが作られた時に発生するメッセージです。 ウィンドウに配置するコンポーネントは、このメッセージの時に作るのが便利です。
  3. GetClientRect(hwnd, &rect);
    メインウィンドウのクライアント領域を取得しています。クライアント領域とはウィンドウからタイトルバーなどを除いた、コンポーネントを配置できる領域です。
  4. label = CreateWindow("STATIC",
    ラベルもウィンドウなので、CreateWindow 関数で作ります。ラベルのクラスはすでに用意されていて、STATIC という名前です。
  5. WS_CHILD | WS_VISIBLE | SS_CENTER,
    ウィンドウのスタイルを設定しています。各設定値の意味は次のとおりです。
    1. WS_CHILD
      このコンポーネントがメインウィンドウに配置される子コンポーネントであることを表しています。
    2. WS_VISIBLE
      コンポーネントを表示状態にします。コンポーネントのデフォルトは非表示です。
    3. SS_CENTER
      ラベルの中の文字列を、ラベルに割り当てられた領域の中央に表示します。
  6. (rect.right - 50) / 2
    CreateWindow の第4引数でコンポーネントの横の位置を指定します。rect.right でクライアント領域の右端の数値を取得できます。本来クライアント領域の横幅を取得するには rect.right - rect.left になりますが、rect.left は常に 0 なので、結果として rect.right がクライアント領域の横幅を表すことになります。
  7. (rect.bottom - 15) / 2
    CreateWindow の第5引数でコンポーネントの縦の位置を指定します。rect.bottom でクライアント領域の下端の数値を取得できます。本来クライアント領域の高さを取得するには rect.bottom - rect.topp になりますが、rect.top は常に 0 なので、結果として rect.bottom がクライアント領域の高さを表すことになります。
  8. hwnd, NULL, NULL, NULL);
    1. CreateWindow 関数の第8引数には親ウィンドウを指定します。
    2. 第9引数にメニューを指定します。メニューがない場合は NULL を指定します。
    3. 第10引数にアプリケーション自体のハンドルを指定します。hInstance はメインウィンドウが使っていますので、ここでは NULL を指定します。
    4. 第11引数の使い方は良く分かりません。通常 NULL を指定します。
  9. case WM_SIZE:
    WM_SIZE はウィンドウのサイズが変更された時に発生するメッセージです。
  10. SetWindowPos 関数でコンポーネントの位置とサイズを設定できます。引数は次のとおりです。
    1. label
      第1引数に設定するコンポーネントを指定します。
    2. HWND_TOP
      第2引数に設定方法を定数で指定します。色々な定数がありますが、実際にどう違うか良くわかりません。多くの場合 HWND_TOP で大丈夫です。
    3. (rect.right - 50) / 2
      第3引数でコンポーネントの横の位置を指定します。rect.right でクライアント領域の右端の数値を取得できます。本来クライアント領域の横幅を取得するには rect.right - rect.left になりますが、rect.left は常に 0 なので、結果として rect.right がクライアント領域の横幅を表すことになります。
    4. (rect.bottom - 15) / 2
      第四引数でコンポーネントの縦の位置を指定します。rect.bottom でクライアント領域の下端の数値を取得できます。本来クライアント領域の高さを取得するには rect.bottom - rect.topp になりますが、rect.top は常に 0 なので、結果として rect.bottom がクライアント領域の高さを表すことになります。
    5. 0
      第5引数でコンポーネントの横幅を指定します。0 になっていることは第7引数で説明します。
    6. 0
      第6引数でコンポーネントの高さを指定します。0 になっていることは第7引数で説明します。
    7. SWP_NOSIZE
      第7引数で SWP_NOSIZE 定数を指定すると、コンポーネントのサイズは変更されなくなります。第5引数と第6引数で 0 を指定できたのはこのためです。なお、コンポーネントの位置を変更したくない場合は、SWP_NOMOVE 定数を使います。


14761 visits
Posted: Jul. 17, 2020
Update: Jul. 18, 2020

ホーム    Windows API Primer     目次