概要

ステータスバーは、下図のようなウィンドウの下部に情報を表示します。
ステータスバーは、CreateWindowEx APIを用いるか、CreateStatusWindow APIを使用します。
CreateStatusWindow APIを使用する場合は、プロジェクトにcomctl32.libを加える必要があります。
本プログラムではENABLE_FUNCマクロを定義したばあい、CreateStatusWindow APIを使用、定義しない場合はCreateStatus関数経由でCreateWindowEx APIを使用します。
ウィンドウサイズが変化した時、自動的にステータスバーの位置や大きさは変わらないのでWM_SIZEメッセージを処理する若干のコードが必要になります。
また、ステータスバー分の高さが減るので描画もそれを考慮する必要があります。面倒なのでステータスバーを除いた高さのウィンドウを新たに作成し描画するのが簡単かと思いますが、本プログラムは複雑な描画をするわけではないのでステータスバーを差し引いて描画しています。 ウィンドウにはクライアントサイズの半分の楕円を描画、 ステータスバーにはウィンドウサイズを表示してみました。

テスト環境

コンパイラ

Visual C++ 2008 Standard 32/64bit
Visual C++ 2013 Express 32/64bit

プロジェクトの作成

Win32プロジェクト Windowsアプリケーション

実行環境

Windows 7 EnterPrise Service Pack 1 64bit
Windows 10 Home 32/64bit

プログラムソースの概要

_tWinMain関数

Windowsから最初に_tWinMain関数が呼び出されます。 ウィンドウを作成する場合は、RegisterClass APIによりウィンドウクラスを定義してからCreateWindow APIを呼び出しウィンドウを作成します。 Windowsは入力等のイベントが発生するとアプリケーションにメッセージを送付します。 メッセージはキューに保管されます。アプリケーションはメッセージを取り出し、該当ウィンドウにメッセージを配信します。 メッセージの取り出しから配信までループで処理を行いウィンドウから終了メッセージが届くと、ループを抜けるように記述します。 これらの一連の処理は、通常にCreateWindow APIの後に記述しこれをメッセージループと呼んでいます。 詳細は以下を参照してください。
メッセージループについて

WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)ウィンドウプロシージャー

RegisterClass APIにより登録することによりWindowsから呼び出されます。 第2引数にメッセージの種類が格納されていますので、switchステートメントによりメッセージごとの処理を振り分けます。 自分で処理しないメッセージはDefWindowProc APIに渡せばWindowsが標準的な処理を行ってくれます。

case WM_CREATE:

ウィンドウの初期化時に呼び出されます。
CreateStatusWindow API又はCreateStatus関数を呼び出しステータスバーを作成しステータスバーのハンドルを取得します。ハンドルは後で使用するのでスタティック変数に保存しておきます。
ステータスバーにSB_SETPARTSメッセージを送信し、ステータスバーの分割数と各区画の右座標を設定します。
右座標ですので大きさを設定する配列の値は順番に大きくなっていなければ表示されません。最後に-1を設定するとウィンドウの右端という意味になります。
GetWinRect関数を呼び出しクライアント領域の大きさを取得しスタティック変数に保存しておきます。
ShowWindow APIを呼び出しステータスバーの表示を更新します。

case WM_SIZE:

ウィンドウのサイズが変更されたときに呼び出されます。
ウィンドウサイズが変更されたときステータスバーの位置や大きさは自動的に変更されません。
ステータスバーにWM_SIZEメッセージを渡せば位置や大きさを調整してくれます。
本プログラムでは、ステータスバーにウィンドウサイズを表示していますので、SB_SETTEXTメッセージをステータスバーに送信することにより文字を表示させます。
クライアント領域は、ステータスバーの高さを引いた大きさになりますので、GetWinRectでステータスバーの大きさを取得しステータスバーを除いたウィンドウサイズを計算しスタティック変数wx,wyに保存します。

case WM_DESTROY:

ウィンドウが閉じるときに呼び出されます。 PostQuitMessage APIにより終了コードを指定して、ウィンドウプロシージャーを終了させます。

case WM_CLOSE:

プログラムを終了するときに呼び出されます。
DestroyWindow APIによりステータスバーとウィンドウを閉じます。

case WM_PAINT:

ウィンドウを再描画する必要があるときに呼び出されます。 他のウィンドウに隠れ再びフォアグラウンドになった場合などウィンドウの再描画はWindowsが面倒を見ないのでプログラマの仕事となっています。 BeginPaint APIを呼び出して、描画に必要なデバイスコンテキストのハンドルを取得します。 BeginPaint APIの第2引数のポインタにはPAINTSTRUCT構造体のポインタを渡します。 BeginPaint API終了後、PAINTSTRUCT構造体には再描画が必要な領域の座標等の値が格納されています。 Ellipse APIによりウィンドウサイズの半分の大きさの楕円を描画します。

プログラムソース

statusbar1.cpp

//       ステータスバーの表示
//      Visual C++ 2008/2013 Express 32/64bit UNICODE/マルチバイト

#include <windows.h>
#include <commctrl.h> 
#include <stdio.h>
#include <tchar.h>

//      CreateStatusWindowを使用する場合は以下の定義を有効にする。使用しない場合はコメントアウトする。
#define ENABLE_FUNC 1

#ifdef ENABLE_FUNC
        #pragma comment(lib,"comctl32.lib")
#else
        HWND CreateStatus(HWND hWnd);
#endif

TCHAR szClassName[] = _TEXT("StatusBar1");    //ウィンドウクラス

#define ID_STATUS       100             // ステータスバーのID

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

void GetWinRect(HWND hWnd, int *x, int *y);

int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPreInst,
        TCHAR* lpszCmdLine, int nCmdShow){
        HWND hWnd;
        MSG lpMsg;
        WNDCLASS myProg;

        if (!hPreInst) {
                myProg.style = CS_HREDRAW | CS_VREDRAW;
                myProg.lpfnWndProc = WndProc;
                myProg.cbClsExtra = 0;
                myProg.cbWndExtra = 0;
                myProg.hInstance = hInstance;
                myProg.hIcon = NULL;
                myProg.hCursor = LoadCursor(NULL, IDC_ARROW);
                myProg.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
                myProg.lpszMenuName = NULL;
                myProg.lpszClassName = szClassName;
                if (!RegisterClass(&myProg))
                        return FALSE;
        }
        hWnd = CreateWindow(szClassName,
                TEXT("StatusBar1"),
                WS_OVERLAPPEDWINDOW,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                NULL,
                NULL,
                hInstance,
                NULL);
        ShowWindow(hWnd, nCmdShow);
        UpdateWindow(hWnd);
        while (GetMessage(&lpMsg, NULL, 0, 0)){
                TranslateMessage(&lpMsg);
                DispatchMessage(&lpMsg);
        }
        return int(lpMsg.wParam);
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam){
        HPEN hPen, hOldPen;
        HBRUSH hBrush, hOldBrush;

        HDC hdc;
        TCHAR buf[64];
        PAINTSTRUCT ps;
        static HWND hStatus;
        static int wx, wy;
        int sx, sy;
        int sb_size[] = { 100, 200, -1 };
        switch (msg) {
        case WM_CREATE:
#ifdef ENABLE_FUNC
                hStatus = CreateStatusWindow(WS_CHILD | SBARS_SIZEGRIP | CCS_BOTTOM | WS_VISIBLE, _TEXT(""), hWnd, ID_STATUS);
#else
                hStatus = CreateStatus(hWnd);
#endif
                SendMessage(hStatus, SB_SETPARTS, (WPARAM)3, (LPARAM)(LPINT)sb_size);
                GetWinRect(hWnd, &wx, &wy);
                ShowWindow(hStatus, SW_SHOW);
                break;
        case WM_SIZE:
                wx = LOWORD(lParam);
                wy = HIWORD(lParam);
                GetWinRect(hStatus, &sx, &sy);
                wy -= sy;
                SendMessage(hStatus, WM_SIZE, wParam, lParam);
                _stprintf_s(buf, sizeof(buf) / sizeof(TCHAR), _TEXT("%.4d"), wx);
                SendMessage(hStatus, SB_SETTEXT, (WPARAM)0 | 0, (LPARAM)(LPSTR)buf);
                _stprintf_s(buf, sizeof(buf) / sizeof(TCHAR), _TEXT("%.4d"), wy);
                SendMessage(hStatus, SB_SETTEXT, (WPARAM)1 | 0, (LPARAM)(LPSTR)buf);
                break;
        case WM_DESTROY:
                PostQuitMessage(0);
                break;
        case WM_CLOSE:
                DestroyWindow(hStatus);
                DestroyWindow(hWnd);
                break;
        case WM_PAINT:
                hdc = BeginPaint(hWnd, &ps);
                hPen = CreatePen(PS_SOLID, 1, RGB(255, 0, 0));
                hOldPen = (HPEN)SelectObject(hdc, hPen);
                hBrush = (HBRUSH)CreateSolidBrush(RGB(255, 0, 0)); 
                hOldBrush = (HBRUSH)SelectObject(hdc, hBrush);

                Ellipse(hdc, wx/4, wy/4, wx*3/4, wy*3/4);

                SelectObject(hdc, hOldPen);
                SelectObject(hdc, hOldBrush);
                DeleteObject(hPen);
                DeleteObject(hBrush);

                EndPaint(hWnd, &ps);
                break;
        default:
                return(DefWindowProc(hWnd, msg, wParam, lParam));
        }
        return (0);
}

void GetWinRect(HWND hWnd, int *x, int *y){
        RECT rc;
        GetClientRect(hWnd, &rc);
        *x = rc.right - rc.left;
        *y = rc.bottom - rc.top;
        return;
}

#ifndef ENABLE_FUNC

HWND CreateStatus(HWND hWnd){
        HINSTANCE hInst;
        hInst = (HINSTANCE)GetWindowLongPtr(hWnd, GWLP_HINSTANCE);
        HWND hStatus = CreateWindowEx(
                0,
                STATUSCLASSNAME,
                NULL,
                WS_CHILD | SBARS_SIZEGRIP | CCS_BOTTOM | WS_VISIBLE,
                0,
                0,
                0,
                0,
                hWnd,
                (HMENU)ID_STATUS,
                hInst,
                NULL);
        return hStatus;
}

#endif

ソースファイルと実行ファイルのダウンロード

ダウンロード statusbar1.zip(30.1kByte)
ZIPファイルに含まれるファイル
statusbar1.cpp
statusbar1.exe