Windows API   コントロール

ホーム   C/C++チュートリアル


Cプログラミンの一環として始めた Windos API ですが、やってみたら面白かったので、もっと詳しく、かつ簡単に、ステップバイステップで学習するコーナーも作りました。
Windows API Primer
Primer は、入門書という意味です。

コントロール

このサイトでは、ユーザーが操作できるGUI部品のことをコントロールと呼ぶことにしています。

Windows APIでは、ボタンなどのコントロールもウィンドウです。

ほとんどのコントロールは、WNDCLASSがデフォルトで登録されていますので、CreateWindow関数ですぐに作成できます。


ボタン

button.c


#include <windows.h>

#define BEEP 100
#define QUIT 200
#define EDIT 300

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

int WINAPI 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            = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor          = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground    = (HBRUSH) (COLOR_APPWORKSPACE + 1);
    wc.lpszMenuName     = NULL;
    wc.lpszClassName    = TEXT("ButtonControl");

    RegisterClass(&wc);

    hwnd = CreateWindow (TEXT("ButtonControl"),
                         TEXT("Button"),
                         WS_OVERLAPPEDWINDOW,
                         (GetSystemMetrics(SM_CXSCREEN) - 400) / 2,
                         (GetSystemMetrics(SM_CYSCREEN) - 250) / 2,
                         400,
                         250,
                         NULL,
                         NULL,
                         hInstance,
                         NULL);
      
    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);    

    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd,
                         UINT msg,
                         WPARAM wParam,
                         LPARAM lParam)
{
    static HWND beep, quit, edit;
    RECT clientRc;
    static HFONT font;
    
    switch (msg)
    {
    case WM_CREATE:
        GetClientRect(hwnd, &clientRc);
        font = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
        beep = CreateWindow(TEXT("Button"),
                            TEXT("ビープ"),
                            WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
                            (clientRc.right - 170),
                            (clientRc.bottom - 30),
                            80, 25,
                            hwnd,
                            (HMENU) BEEP,
                            NULL,
                            NULL);
	SendMessage(beep, WM_SETFONT, (WPARAM)font, MAKELPARAM(FALSE, 0));
        quit = CreateWindow(TEXT("Button"),
                            TEXT("終 了"),
                            WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
                            (clientRc.right - 85),
                            (clientRc.bottom - 30),
                            80, 25,
                            hwnd,
                            (HMENU) QUIT,
                            NULL,
                            NULL);
	SendMessage(quit, WM_SETFONT, (WPARAM)font, MAKELPARAM(FALSE, 0));
	edit = CreateWindow(TEXT("Edit"),
                        NULL,
                        WS_VISIBLE | WS_CHILD |WS_BORDER | ES_MULTILINE,
                        5, 5,
                        (clientRc.right - 10),
                        (clientRc.bottom - 40),
                        hwnd,
                        (HMENU) EDIT,   // 今回の場合はNULLでも良い
                        NULL,
                        NULL);
	SendMessage(edit, WM_SETFONT, (WPARAM)font, MAKELPARAM(FALSE, 0));
        break;
    case WM_SIZE:
        GetClientRect(hwnd, &clientRc);
        SetWindowPos(beep, HWND_TOP,
                    (clientRc.right - 170),
                    (clientRc.bottom - 30), 0, 0, SWP_NOSIZE);
        SetWindowPos(quit, HWND_TOP,
                    (clientRc.right - 85),
                    (clientRc.bottom - 30), 0, 0, SWP_NOSIZE);
        SetWindowPos(edit, HWND_TOP,
                     0, 0,
                    (clientRc.right - 10),
                    (clientRc.bottom - 40),
                    SWP_NOMOVE);		     
        break;
    case WM_COMMAND:
        if (LOWORD(wParam) == BEEP) MessageBeep(MB_OK);
        if (LOWORD(wParam) == QUIT) PostQuitMessage(0);
        break;	    
    case WM_DESTROY:
        DeleteObject(font);
        PostQuitMessage(0);
        break;
    }
    return DefWindowProc(hwnd, msg, wParam, lParam);
}
    


実行結果


「ビープ」ボタンをクリックするとビープ音が鳴ります。「終了」ボタンをクリックするとアプリケーションが終了します。

ウィンドウを拡大してもボタンは右下に表示されます。またエディットコントロールはウィンドウの拡大縮小に合わせてサイズが変わります。


チェックボックス

checkbox.c


#include <windows.h>

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

int WINAPI 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            = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor          = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground    = GetSysColorBrush(COLOR_3DFACE);
    wc.lpszMenuName     = NULL;
    wc.lpszClassName    = TEXT("CheckBox");
    
    RegisterClass(&wc);
    
    hwnd = CreateWindow (TEXT("CheckBox"),
                         TEXT("Check box"),
                         WS_OVERLAPPEDWINDOW,
                         (GetSystemMetrics(SM_CXSCREEN) - 400) / 2,
                         (GetSystemMetrics(SM_CYSCREEN) - 250) / 2,
                         400,
                         250,
                         NULL,
                         NULL,
                         hInstance,
                         NULL);

    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);

    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd,
                         UINT msg,
                         WPARAM wParam,
                         LPARAM lParam)
{
    static HWND check;
    RECT clrc;
    static HFONT font;
    UCHAR checked = 1;
    
    switch (msg)
    {
    case WM_CREATE:
        GetClientRect(hwnd, &clrc);
        font = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
        check = CreateWindow(TEXT("Button"),
                             TEXT("Show title"),
                             WS_VISIBLE | WS_CHILD | BS_CHECKBOX,
                             (clrc.right  - 70) / 2,
                             (clrc.bottom - 20) / 2,
                             70, 20,
                             hwnd,
                             (HMENU) 1,
                             NULL,
                             NULL);
        CheckDlgButton(hwnd, 1, BST_CHECKED);
        SendMessage(check, WM_SETFONT, (WPARAM)font,
                    MAKELPARAM(FALSE, 0));
        break;
    case WM_SIZE:
        GetClientRect(hwnd, &clrc);
        SetWindowPos(check, HWND_TOP,
                    (clrc.right  - 70) / 2,
                    (clrc.bottom - 20) / 2,
                    0, 0, SWP_NOSIZE);
        break;
    case WM_COMMAND:
        checked = IsDlgButtonChecked(hwnd, 1);
        if (checked)
        {
            CheckDlgButton(hwnd, 1, BST_UNCHECKED);
            SetWindowText(hwnd, TEXT(""));
        } else {
            CheckDlgButton(hwnd, 1, BST_CHECKED);
            SetWindowText(hwnd, TEXT("Check box"));
        }
        break;
    case WM_DESTROY:
        DeleteObject(font);
        PostQuitMessage(0);
        break;
    }
    return DefWindowProc(hwnd, msg, wParam, lParam);
}
	


実行結果


チェックボックスがチェックされていれば、ウィンドウのタイトルは表示されます。
チェックボックスがチェックされていなければ、ウィンドウのタイトルは表示されません。


トラックバー

Windows APIでは、スライダーのことをトラックバーと呼びます。

トラックバーは、コモンコントロールというグループに所属しています。コモンコントロールには、ツールバー・ステータスバー、リストビュー・ツリービューなども所属しています。

Visual Studioでコモンコントールを使うには、次のようなコードが必要になります。


// ヘッダーの読み込み
#include <commctrl.h>
// ライブラリーへのリンク
#pragma comment(lib, "ComCtl32.lib")
// コモンコントロールの初期化
InitCommonControls();
    

しかし、Msys2のMinGWのGNUコンパイラを使う場合は、ヘッダーの読み込みだけでOKです。


trackbar.c


#include    <windows.h>
#include    <commctrl.h>
#include    <stdio.h>     // for snprintf

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

int WINAPI 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            = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor          = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground    = GetSysColorBrush(COLOR_3DFACE);
    wc.lpszMenuName     = NULL;
    wc.lpszClassName    = TEXT("TrackBar");

    RegisterClass       (&wc);

    hwnd = CreateWindow (TEXT("TrackBar"),
                         TEXT("TrackBar 50"),
                         WS_OVERLAPPEDWINDOW,
                         (GetSystemMetrics(SM_CXSCREEN) - 400) / 2,
                         (GetSystemMetrics(SM_CYSCREEN) - 250) / 2,
                         400,
                         250,
                         NULL,
                         NULL,
                         hInstance,
                         NULL);

    ShowWindow          (hwnd, nCmdShow);
    UpdateWindow        (hwnd);

    while               (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage (&msg);
    }
    return msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    static HWND trackbar;
    RECT clientRect;
    static HFONT font;
    int Pos;
    char str[16];

    switch(msg)
    {
    case WM_CREATE:
        /* コモンコントロールの初期化 */
        //InitCommonControls(); // なぜかいらない、逆に記述するとエラーになる
        GetClientRect(hwnd, &clientRect);
        trackbar =
        CreateWindow    (TEXT("msctls_trackbar32"), // TRACKBAR_CLASSでもOK
                         TEXT(""), WS_VISIBLE | WS_CHILD | TBS_AUTOTICKS,
                         //TBS_TOOLTIPS これも記述するとトラックバーのつまみの位置に現在の値が表示される
                         (clientRect.right - 360) / 2,
                         (clientRect.bottom - 20) / 2,
                         360, 20,
                         hwnd, (HMENU) 100, NULL, NULL);
        SendMessage(trackbar, TBM_SETRANGE, TRUE, MAKELPARAM(0, 100));
        SendMessage(trackbar, TBM_SETTICFREQ, 10, 0);
        SendMessage(trackbar, TBM_SETPOS, TRUE, 50);
        SendMessage(trackbar, TBM_SETPAGESIZE, 0, 10);
	break;
    case WM_SIZE:
        GetClientRect(hwnd, &clientRect);
        SetWindowPos(trackbar, HWND_TOP,
        20, (clientRect.bottom - 20) / 2,
        (clientRect.right -  40), 20,
        SWP_NOZORDER);  // SWP_SHOWWINDOWでも良い
        break;
    case WM_HSCROLL:
        Pos = SendMessage(trackbar, TBM_GETPOS, 0, 0);
        snprintf(str, -1, "TrackBar %d", Pos);
        SetWindowText(hwnd, TEXT(str));
        break;	
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    }
    return DefWindowProc(hwnd, msg, wParam, lParam);
}
    

実行結果


スライダーを動かすと、その値がウィンドウのタイトルバーに表示されます。
ウィンドウの大きさは指定しているのですが、実際にはまちまちなんですよね...


Code Blocks

このサイトでは、Windowsアプリケーションを作成するためのIDE(統合開発環境)として、Code Blocksを紹介しています。Code Blocksでは前述の button.c、checkbox.c、trackbar.c のソースコードをそのまま使えます。

Code Blocksのダウンロードとインストール方法と設定方法は、 Environment / Windows で 詳しく説明しています。

上記コーナーを参考にして、Code Blocksで wxWidgets アプリケーションか GTK アプリケーションを作成できるようにしてください。その上で、Code Blocks で Windows API のアプリケーションを作成する方法を説明していきます。

コンパイラの設定

Code Blocksを起動して「設定」メニューから「コンパイラ」を選びます。

「グローバルなコンパイラ設定」画面が開きましたら、「コンパイラを選択」で、ご自身で作られた「WX」か「GTK」を選択して、「コピー」をクリックします。

表示される「コンパイラを追加」ダイアログで、WINAPI などと名前をつけて「OK」をクリックします。

「リンカ設定」タブを選んで、「クリア」ボタンをクリックしてすべての設定を削除します。

「ディレクトリの検索」タブを選んで、「クリア」ボタンをクリックしてすべての設定を削除します。そして「OK」ボタンをクリックして、「グローバルなコンパイラ設定」画面を閉じます。

コンパイラの設定は以上です。

Windows API プロジェクトの作成

「ファイル」メニューから「新規」→「プロジェクト...」を選びます。

表示される「テンプレートから新規作成」画面で「Win32 GUI project」を選択して「Go」ボタンをクリックします。

次の画面では何もせずに「Next>」をクリックします。

次の画面では「Frame based」を選択して「Next>」をクリックします。

次の画面では「プロジェクトのタイトル」と「プロジェクトを作成するフォルダ」を決め「Nexe>」をクリックします。なおこの「プロジェクトのタイトル」がアプリケーションの名前になります。

次の画面の「コンパイラ」で、先ほど作った WINAPI を選び、「"Release"設定を作成」のみにチェックを入れます。そして「Finish」をクリックします。

Code Blocksのメイン画面に戻りますので、左ペインで「プロジェクト」タブを選び、プロジェクトの「Sources」の「main.cpp」を右クリックして「ファイルをプロジェクトから削除する」を選んで、main.cppを削除します。

次に「ファイル」メニューから「新規」→「空のファイル」を選びます。

「プロジェクトにファイルを追加」ダイアログが表示されますので、「はい」をクリックしてください。

次の画面で「ファイル名」に任意のファイル名を入力します。拡張子は .c にしてください。

Code Blocksのメイン画面に戻りますので、左ペインで「プロジェクト」タブを選びます。プロジェクトの「Sources」グループの中に、先ほど作成したファイルが出来ていますので、ダブルクリックします。

右ペインが編集画面になりますので、前述の button.c や checkbox.c や trackbar.c などのソースコードを記述してください。

ソースコードの記述が終わりましたら「ファイル」メニューから「すべてを保存」を選びます。

ビルドと実行

「ビルド」メニューから「ビルドして実行」を選びます。しばらくすると作成したアプリケーションが起動します。

また、プロジェクトフォルダの中の「bin」フォルダの中の「Release」フォルダの中に、.exe 実行ファイルが出来ていますので、それをダブルクリックしても実行できます。


Visual Studio

Windows アプリケーションを作るなら、やっぱりMicrosoft社製のVisual Studioについて説明しないわけにはいかないだろうとのことで Visual Studio をいろいろ試してみました。

まず次のサイトからVisual Studio Express版をダウンロードします。

以前の Visual Studio ソフトウェアのダウンロード | Visual Studio - Visual Studio

私の環境では、Windows 7でVisual Studio 2010 Express、Windows 8.1とWindows 10ではVisual Studio 2012 Expressしか正しくインストールできませんでした。

Visual StudioにはVB(Visual Basic)版も存在しますので、Infoをよく読んでVC版であることを確認してダウンロードしてください。

なお、Visual Studio Expressは、Visual Studioの無料評価版です。

プログラミングの学習や、趣味としてアプリケーションを作ることは無料のExpress版でできます。しかし、作ったアプリケーションを配布したり販売する場合は、Visual Studioの有料正規版を購入しなければなりません。


win32プロジェクトの作成

Visual Studioを起動して、「新しいプロジェクト...」→「インストール済み」→「テンプレート」→「Visual C++」→「Win32」と進んで、「Win32 プロジェクト」を選び、「名前(N):」を決めて「OK」をクリックします。

Vsual Studio 2010では、「新しいプロジェクト...」→「インストールされたテンプレート」→「Visual C++」→「Win32」と進み、「Win32 プロジェクト」を選び、「名前(N):」を入力して「OK」をクリックしてください。

次の画面では「完了」を押さず「次へ>」をクリックします。

次の画面では、「空のプロジェクト」にチェックを入れて「完了」をクリックします。

次の画面の右ペインの「ソリューションエクスプローラ」で、作成したプロジェクトを右クリックして、「追加」→「新しい項目」を選びます。

なお、Visual Studio 2010では「ソリューションエクスプローラ」ペインは左側にあります。

次の画面では「C++ファイル(.cpp)」を選び、名前を trackbar.c などとします。この名前は任意で決められてます。拡張子は .c で大丈夫です。そして「追加」をクリックします。


Visual Studio用ソースコード

上記の手順でプロジェクトを作成した場合、Visual Studioの画面は、ソースコードの編集画面になっていると思います。その編集画面に次のソースコードを記述してください。


#include    <windows.h>
#include    <commctrl.h>
#include    <stdio.h>     // for sprintf

#pragma comment(lib, "ComCtl32.lib")

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

int WINAPI 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            = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor          = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground    = GetSysColorBrush(COLOR_3DFACE);
    wc.lpszMenuName     = NULL;
    wc.lpszClassName    = TEXT("TrackBar");

    RegisterClass       (&wc);

    hwnd = CreateWindow (TEXT("TrackBar"),
                         TEXT("TrackBar 50"),
                         WS_OVERLAPPEDWINDOW,
                         (GetSystemMetrics(SM_CXSCREEN) - 400) / 2,
                         (GetSystemMetrics(SM_CYSCREEN) - 250) / 2,
                         400,
                         250,
                         NULL,
                         NULL,
                         hInstance,
                         NULL);

    ShowWindow          (hwnd, nCmdShow);
    UpdateWindow        (hwnd);

    while               (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage (&msg);
    }
    return msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    static HWND trackbar;
    RECT clientRect;
    static HFONT font;
    int Pos;
	char str[128] = "";

    switch(msg)
    {
    case WM_CREATE:
		InitCommonControls();   // コモンコントロールの初期化
        GetClientRect(hwnd, &clientRect);
        trackbar =
        CreateWindow    (TEXT("msctls_trackbar32"), // TRACKBAR_CLASSでもOK
                         TEXT(""), WS_VISIBLE | WS_CHILD | TBS_AUTOTICKS,
                         //TBS_TOOLTIPS これも記述するとトラックバーのつまみの位置に現在の値が表示される
                         (clientRect.right - 360) / 2,
                         (clientRect.bottom - 20) / 2,
                         360, 20,
                         hwnd, (HMENU) 100, NULL, NULL);
        SendMessage(trackbar, TBM_SETRANGE, TRUE, MAKELPARAM(0, 100));
        SendMessage(trackbar, TBM_SETTICFREQ, 10, 0);
        SendMessage(trackbar, TBM_SETPOS, TRUE, 50);
        SendMessage(trackbar, TBM_SETPAGESIZE, 0, 10);
	break;
    case WM_SIZE:
        GetClientRect(hwnd, &clientRect);
        SetWindowPos(trackbar, HWND_TOP,
        20, (clientRect.bottom - 20) / 2,
        (clientRect.right -  40), 20,
        SWP_NOZORDER);  // SWP_SHOWWINDOWでも良い
        break;
    case WM_HSCROLL:
        Pos = SendMessage(trackbar, TBM_GETPOS, 0, 0);
        sprintf(str, "TrackBar %d", Pos);
		SetWindowText(hwnd, str);
        break;	
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    }
    return DefWindowProc(hwnd, msg, wParam, lParam);
}
	

ソースコードの記述が終わりましたら、「ファイル」メニューから「[あなたが決めた任意の名前].cの保存」か「すべてを保存」を選びます。


Visual Studio 2012でのビルドと実行

「ビルド」メニューから「ソリューションのビルド」を選びます。そして左下の「出力」ペインに次のように表示されたらビルドは成功しています。


========== ビルド: 1 正常終了、0 失敗、0 更新不要、0 スキップ ==========
    

ビルドしたアプリケーションを実行するには、「デバッグ」メニューで「デバッグなしで開始」を選びます。また、Windowsの「Documents」→「Visual Stduio 2012(もしくは2010)」→「Projects」→「[プロジェクト名]」→「Debug(もしくはRelease)」に「[プロジェクト名].exe」という実行ファイルが作成されていますので、ダブルクリックで起動することができます。

もしアプリケーションの表示で文字化けが起こる場合は、ソリューションエクスプローラでプロジェクトを右クリックして「プロパティ」→「構成プロパティ」→「全般」→「文字セット」→「マルチバイト文字セットを使用する」を選び、再度ビルドしてください。


Visual Studio 2010でのビルドと実行

Visual Studio 2010の場合は、次の図のように緑色の右三角の右横を「Release」変えて、緑色の右三角をクリックします。

「ビルドしますか?」というダイアログが表示されますので、「はい」をクリックします。

しばらくするとアプリケーションがビルドされて実行されます。

また、Windowsの「Documents」→「Visual Studio 2010」→「[プロジェクト名]」→「Release」に「[プロジェクト名].exe」という実行ファイルが出来上がっていますので、それをダブルクリックして実行することもできます。

もしアプリケーションの表示で文字化けが起こる場合は、ソリューションエクスプローラでプロジェクトを右クリックして「プロパティ」→「構成プロパティ」→「全般」→「文字セット」→「マルチバイト文字セットを使用する」を選び、再度ビルドしてください。


ラジオボタン

ラジオボタンは複数の項目の中から、一つだけを選択するに使われます。

radiobutton.c


#include <windows.h>

#define ID_BLUE   1
#define ID_YELLOW 2
#define ID_ORANGE 3

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

HINSTANCE g_hinst;
COLORREF  g_color;

int WINAPI WinMain      (HINSTANCE hInstance,
			 HINSTANCE hPrevInstance,
			 LPSTR lpCmdLite,
			 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            = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor          = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground    = GetSysColorBrush(COLOR_3DFACE);
    wc.lpszMenuName     = NULL;
    wc.lpszClassName    = TEXT("RadioButton");

    g_hinst             = hInstance;

    RegisterClass(&wc);

    hwnd = CreateWindow (TEXT("RadioButton"),
                         TEXT("Radio Button"),
                         WS_OVERLAPPEDWINDOW,
                         (GetSystemMetrics(SM_CXSCREEN) - 400) / 2,
                         (GetSystemMetrics(SM_CYSCREEN) - 250) / 2,
                         400,
                         250,
                         NULL,
                         NULL,
                         hInstance,
                         NULL);

    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);

    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd,
                         UINT msg,
                         WPARAM wParam,
                         LPARAM lParam)
{
  RECT clientRect;
  static HFONT font;
  static HWND box, blue, yellow, orange;

  HDC hdc;
  PAINTSTRUCT ps;
  HBRUSH hBrush, holdBrush;
  HPEN hPen, holdPen;
  
    switch(msg)
    {
    case WM_CREATE:
        GetClientRect(hwnd, &clientRect);
        font = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
        box  = CreateWindow(TEXT("Button"), TEXT("Choose color"),
		       WS_CHILD | WS_VISIBLE | BS_GROUPBOX,
		       10, 10, 120, (clientRect.bottom - 20), hwnd, (HMENU) 0, g_hinst, NULL);
        blue = CreateWindow(TEXT("Button"), TEXT("Blue"),
		       WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON,
		       20, 30, 100, 30, hwnd, (HMENU) ID_BLUE, g_hinst, NULL);
        yellow = CreateWindow(TEXT("Button"), TEXT("Yellow"),
		         WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON,
		         20, 55, 100, 30, hwnd, (HMENU) ID_YELLOW, g_hinst, NULL);
        orange = CreateWindow(TEXT("Button"), TEXT("Orange"),
		         WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON,
		         20, 80, 100, 30, hwnd, (HMENU) ID_ORANGE, g_hinst, NULL);
        SendMessage(box, WM_SETFONT, (WPARAM)font, MAKELPARAM(FALSE, 0));
        SendMessage(blue, WM_SETFONT, (WPARAM)font, MAKELPARAM(FALSE, 0));
        SendMessage(yellow, WM_SETFONT, (WPARAM)font, MAKELPARAM(FALSE, 0));
        SendMessage(orange, WM_SETFONT, (WPARAM)font, MAKELPARAM(FALSE, 0));
        break;
    case WM_SIZE:
        GetClientRect(hwnd, &clientRect);
        SetWindowPos(box, HWND_TOP,
                     0, 0, 120, (clientRect.bottom - 20), SWP_NOMOVE);
    case WM_COMMAND:
        if (HIWORD(wParam) == BN_CLICKED)
        {
            switch (LOWORD(wParam))
            {
	        case ID_BLUE:
	            g_color = RGB(0, 76, 255);
	            break;
	        case ID_YELLOW:
	            g_color = RGB(255, 255, 0);
	            break;
	        case ID_ORANGE:
	            g_color = RGB(255, 123, 0);
	            break;
	        }
        InvalidateRect(hwnd, NULL, TRUE);
	}
        break;
    case WM_PAINT:
        GetClientRect(hwnd, &clientRect);
        hdc = BeginPaint(hwnd, &ps);
        hBrush = CreateSolidBrush(g_color);
        hPen = CreatePen(PS_NULL, 1, RGB(0, 0, 0));
        holdPen = SelectObject(hdc, hPen);
        holdBrush = (HBRUSH) SelectObject(hdc, hBrush);

        Rectangle(hdc, 140, 15, (clientRect.right  - 10),
		                        (clientRect.bottom - 10));

        SelectObject(hdc, holdBrush);
        SelectObject(hdc, holdPen);
        DeleteObject(hPen);
        DeleteObject(hBrush);
        EndPaint(hwnd, &ps);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    }
    return DefWindowProc(hwnd, msg, wParam, lParam);
}
	


実行結果


トグルボタン

トグルボタンは、押された状態と、押されていない状態があるボタンです。

togglebutton.c


#include <windows.h>

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

HINSTANCE g_hinst;
COLORREF  g_color;

int WINAPI 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              = LoadIcon(NULL, IDI_APPLICATION);
  wc.hCursor            = LoadCursor(NULL, IDC_ARROW);
  wc.hbrBackground      = GetSysColorBrush(COLOR_3DFACE);
  wc.lpszMenuName       = NULL;
  wc.lpszClassName      = TEXT("ToggleButton");

  g_hinst = hInstance;

  RegisterClass(&wc);

  hwnd = CreateWindow  (TEXT("ToggleButton"),
			TEXT("ToggleButton"),
			WS_OVERLAPPEDWINDOW,
			(GetSystemMetrics(SM_CXSCREEN) - 400) / 2,
			(GetSystemMetrics(SM_CYSCREEN) - 250) / 2,
			400,
			250,
			NULL,
			NULL,
			hInstance,
			NULL);

  ShowWindow(hwnd, nCmdShow);
  UpdateWindow(hwnd);

  while (GetMessage(&msg, NULL, 0, 0))
    {
      TranslateMessage(&msg);
      DispatchMessage (&msg);
    }
  return msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
  static HWND red, green, blue;
  static HFONT font;
  static UCHAR r = 0;
  static UCHAR g = 0;
  static UCHAR b = 0;
  UCHAR toggled = 1;
  HDC hdc;
  PAINTSTRUCT ps;
  HBRUSH hBrush, holdBrush;
  HPEN hPen, holdPen;
  #define RED   1
  #define GREEN 2
  #define BLUE  3
  
  switch (msg)
    {
    case WM_CREATE:
      font   = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
      red    = CreateWindow(TEXT("Button"),
			    TEXT("Red"),
			    WS_VISIBLE | WS_CHILD | BS_CHECKBOX | BS_PUSHLIKE,
			    20, 20,
			    100, 30,
			    hwnd,
			    (HMENU) RED,
			    NULL,
			    NULL);
      green = CreateWindow(TEXT("Button"),
			   TEXT("Green"),
			   WS_VISIBLE | WS_CHILD | BS_CHECKBOX | BS_PUSHLIKE,
			   20, 70,
			   100, 30,
			   hwnd,
			   (HMENU) GREEN,
			   NULL,
			   NULL);
      blue  = CreateWindow(TEXT("Button"),
			   TEXT("Blue"),
			   WS_VISIBLE | WS_CHILD | BS_CHECKBOX | BS_PUSHLIKE,
			   20, 120,
			   100, 30,
			   hwnd,
			   (HMENU) BLUE,
			   NULL,
			   NULL);
      CheckDlgButton(hwnd, RED,   BST_UNCHECKED);
      CheckDlgButton(hwnd, GREEN, BST_UNCHECKED);
      CheckDlgButton(hwnd, BLUE,  BST_UNCHECKED);
    SendMessage(red,   WM_SETFONT, (WPARAM)font, MAKELPARAM(FALSE, 0));
    SendMessage(green, WM_SETFONT, (WPARAM)font, MAKELPARAM(FALSE, 0));
    SendMessage(blue , WM_SETFONT, (WPARAM)font, MAKELPARAM(FALSE, 0));
      break;
    case WM_COMMAND:
      if (LOWORD(wParam) == RED)
	{
	  toggled = IsDlgButtonChecked(hwnd, RED);
	  if (toggled)
	  {
	    CheckDlgButton(hwnd, RED, BST_UNCHECKED);
	    r = 0;
	  } else {
	    CheckDlgButton(hwnd, RED, BST_CHECKED);
	    r = 255;
	  }
	}
      if (LOWORD(wParam) == GREEN)
	{
	  toggled = IsDlgButtonChecked(hwnd, GREEN);
	  if (toggled)
	  {
	    CheckDlgButton(hwnd, GREEN, BST_UNCHECKED);
	    g = 0;
	  } else {
	    CheckDlgButton(hwnd, GREEN, BST_CHECKED);
	    g = 255;
	  }
	}
      if (LOWORD(wParam) == BLUE)
	{
	  toggled = IsDlgButtonChecked(hwnd, BLUE);
	  if (toggled)
	  {
	    CheckDlgButton(hwnd, BLUE, BST_UNCHECKED);
	    b = 0;
	  } else {
	    CheckDlgButton(hwnd, BLUE, BST_CHECKED);
	    b = 255;
	  }
	}
      g_color = RGB(r, g, b);
      InvalidateRect(hwnd, NULL, TRUE);
      break;
    case WM_PAINT:
      hdc = BeginPaint(hwnd, &ps);
      hBrush = CreateSolidBrush(g_color);
      hPen = CreatePen(PS_NULL, 1, RGB(r, g, b));
      holdPen = SelectObject(hdc, hPen);
      holdBrush = (HBRUSH) SelectObject(hdc, hBrush);
      Rectangle(hdc, 140, 20, 365, 190);
      SelectObject(hdc, holdBrush);
      SelectObject(hdc, holdPen);
      DeleteObject(hPen);
      DeleteObject(hBrush);
      EndPaint(hwnd, &ps);
      break;	   
    case WM_DESTROY:
      PostQuitMessage(0);
      return 0;
    }
  return DefWindowProc(hwnd, msg, wParam, lParam);
}
	



コード説明


      red    = CreateWindow(TEXT("Button"),
			    TEXT("Red"),
			    WS_VISIBLE | WS_CHILD | BS_CHECKBOX | BS_PUSHLIKE,
                            ・・・
    

      if (LOWORD(wParam) == RED)
	{
	  toggled = IsDlgButtonChecked(hwnd, RED);
	  if (toggled)
	  {
	    CheckDlgButton(hwnd, RED, BST_UNCHECKED);
	    r = 0;
	  } else {
	    CheckDlgButton(hwnd, RED, BST_CHECKED);
	    r = 255;
	  }
	}
    


34703 visits
Posted: Jan. 29, 2020
Update: Mar. 14, 2020

ホーム   C/C++チュートリアル   目次