Windows API Primer   文字列の表示

ホーム   目次

コントロール

ウィンドウ内に表示するボタンや文字列などといった GUI 部品のことを、Windows API ではコントロールと言います。コントロールもウィンドウです。コントロールのウィンドウクラスは、あらかじめシステム(Windows OS)に登録されています。

スタティック

文字列を表示するコントロールはスタティック(static)と言います。スタティックも CreateWindow関数の第1引数に STATIC というウィンドウクラス名を指定して作成します。STATIC ウィンドウクラスは、あらかじめシステム(Windows OS)に登録されています。

static.c


#include <windows.h>

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

int WINAPI WinMain(HINSTANCE hInstance,
		   HINSTANCE hPrevInstance,
		   LPSTR     lpCmdLine,
		   int       nCmdShow)
{
  HWND     hwnd, label;
  WNDCLASS wc;
  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       = NULL;
  wc.hbrBackground = (HBRUSH)COLOR_BACKGROUND + 1;
  wc.lpszMenuName  = NULL;
  wc.lpszClassName = TEXT("LABEL");

  RegisterClass(&wc);

  hwnd             = CreateWindow(TEXT("LABEL"),
				  TEXT("Windows API Primer"),
				  WS_OVERLAPPEDWINDOW | WS_VISIBLE,
				  CW_USEDEFAULT, CW_USEDEFAULT, 300, 200,
				  NULL, NULL, hInstance, NULL);
  
  label            = CreateWindow(TEXT("STATIC"),
				  TEXT("Hello world!"),
				  WS_CHILD |  WS_VISIBLE | SS_CENTER,
				  0, 70, 300, 20,
				  hwnd, 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)
{
  switch (msg)
    {
    case WM_DESTROY:
      PostQuitMessage(0);
      break;
    }
  return DefWindowProc(hwnd, msg, wParam, lParam);
}
    


実行結果


コード説明

  1. label = CreateWindow(TEXT("STATIC"),
    CreateWindow関数の第1引数に STATIC というウィンドウクラス名を指定して文字列コントロールを作成します。STATICウィンドウクラスは、あらかじめシステム(Windows OS)に登録されています。

  2. TEXT("Hello world!"),
    第2引数には、スタティックに表示する文字列を指定します。

  3. WS_CHILD | WS_VISIBLE | SS_CENTER,
    第3引数でコントロールの状態を指定します。
    1. WS_CHILDで、このコントロールが親ウィンドウ内に表示されるように指定します。WS_CHILDを指定しない場合は、親ウィンドウと違う場所に表示されます。
    2. WS_VISIBLEで、このコントロールを可視状態にします。コントロールのデフォルトは不可視状態です。
    3. SS_CETERで、文字列がコントロールの中央寄せで表示されるようにします。

  4. 0, 70, 300, 20,
    なんとかウィンドウの中央に文字列が表示されるように位置やサイズを指定しています。

  5. hwnd, NULL, hInstance, NULL);
    第8引数で親ウィンドウを指定します。親ウィンドウを指定しなければスタティックコントロールは表示できなくなります。

さらに細かく

前述の static.c では、ウィンドウのサイズを変更した場合、文字列が表示される位置は中央ではなくなります。また文字列の大きさもウィンドウ内のラベルとしては少し大きいです。これらの問題を修正したいと思います。

label.c


#include <windows.h>

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

int WINAPI WinMain(HINSTANCE hInstance,
		   HINSTANCE hPrevInstance,
		   LPSTR     lpCmdLine,
		   int       nCmdShow)
{
  HWND     hwnd;
  WNDCLASS wc;
  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       = NULL;
  wc.hbrBackground = (HBRUSH)COLOR_BACKGROUND + 1;
  wc.lpszMenuName  = NULL;
  wc.lpszClassName = TEXT("LABEL");

  RegisterClass(&wc);

  hwnd             = CreateWindow(TEXT("LABEL"),
				  TEXT("Windows API Primer"),
				  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;
         HFONT font;
  
  switch (msg)
    {
    case WM_CREATE:
      GetClientRect(hwnd, &rect);
      font  = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
      label = CreateWindow(TEXT("STATIC"),
			   TEXT("Hello world!"),
			   WS_CHILD | WS_VISIBLE | SS_CENTER,
			   (rect.right  - 75) / 2,
			   (rect.bottom - 10) / 2,
			   75, 10,
			   hwnd, NULL, NULL, NULL);
      SendMessage(label, WM_SETFONT, (WPARAM)font, 0);
      break;
    case WM_SIZE:
      GetClientRect(hwnd, &rect);
      SetWindowPos(label, HWND_TOP,
		   (rect.right  - 75) / 2,
		   (rect.bottom - 10) / 2,
		   0, 0, SWP_NOSIZE);
      break;
    case WM_DESTROY:
      PostQuitMessage(0);
      break;
    }
  return DefWindowProc(hwnd, msg, wParam, lParam);
}
    


実行結果


文字のサイズが適正になり、ウィンドウを拡大しても、ラベルが中央に表示されるようになりました。


コード説明

  1. static HWND label;
    ウィンドウプロシージャの中で、GUI 部品を扱う場合は、そのハンドルを static 指定しなければなりません。

  2. case WM_CREATE:
    今回は、WndProc ウィンドウプロシージャの中の WM_CREATE メッセージの中で、スタティックウィンドウを作ることにします。WM_CREATE は、ウィンドウが作成された時に送られるメッセージです。

  3. GetClientRect(hwnd, &rect);
    GetClientRect関数は、第1引数で指定したウィンドウのクライアント領域の矩形(rectangle)を取得して、その値で第2引数のRECT構造体を初期化します。
    クライアント領域とは、ウィンドウのタイトルバーなどを除いた、GUI 部品を配置できる領域です。

  4. font = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
    ボタンやラベルにちょうど良いサイズの DEFAULT_GUI_FONT を取得しています。フォントを表す型は、HFONTです。

  5. (rect.right - 75) / 2,
    RECT 構造体の right メンバーには、クライアント領域の横のサイズが入っています。

  6. (rect.bottom - 10) / 2,
    RECT 構造体の bottom メンバーには、クラアント領域の縦のサイズが入っています。

  7. hwnd, NULL, NULL, NULL);
    ウィンドウプロシージャの中ではアプリケーションハンドルを表す変数は存在しないので、CreateWindowの第10引数は NULL にしなければなりません。

  8. SendMessage(label, WM_SETFONT, (WPARAM)font, 0);
    SendMessage関数は、プログラムの中からウィンドウへメッセージを送る関数です。引数は次のとおりです。
    1. 第1引数には、メッセージを送るウィンドウ(GUI 部品)を指定します。
    2. 第2引数には、メッセージの種類を定数で指定します。
    3. 第3引数には、WPARAM 型のデータを指定します。ここでは font データを WPARAM 型にキャストしています。
    4. 第4引数には、LPARAM 型のデータを指定します。今回は使用しないので、0 としています。

  9. case WM_SIZE:
    WM_SIZEはウィンドウのサイズが変更された時に送られるメッセージです。

  10. SetWindowPos
    SetWindowPos関数は、ウィンドウ(GUI部品)の位置やサイズを設定します。引数は次のとおりです。
    1. 第1引数に、設定の対象となるウィンドウ(GUI部品)
    2. 第2引数に、設定の種類を表す定数を指定しますが、とりあえず HWND_TOP を指定 すれば大丈夫みたいです。
    3. 第3引数に、横位置
    4. 第4引数に、縦位置
    5. 第5引数に、横サイズ
    6. 第6引数に、縦サイズ
    7. 第7引数に、位置を設定するのか、サイズを設定するのかを定数で指定します。SWP_NOSIZEはサイズの設定は無視されます。第5引数と第6引数を 0 と指定できたのは、このためです。


37922 visits
Posted: Jun. 01, 2020
Update: Jun. 03, 2020

ホーム   目次