【MFC】OnCtlColor: コントロールの背景色を変える

【MFC】OnCtlColor: コントロールの背景色を変える

ダイアログのエディットボックスやスタティックテキストの色を変えたいとき、HTMLならCSSで一行ですが、MFCではWM_CTLCOLORメッセージを処理する必要があります。OnCtlColorを使うと、背景色と文字色をコントロールごとに切り替えられます。

検証環境:Visual Studio 2026 / MFC / x64


目次

OnCtlColorの仕組み

コントロールが描画される直前に、親ウィンドウ(ダイアログ)にWM_CTLCOLORメッセージが送られます。このハンドラでテキスト色・背景色・背景ブラシを指定できます。

次の画面では、入力エラーのエディット、対応状況のスタティック、確認メモのリストボックスにOnCtlColorを適用しています。確認が必要な欄だけが色で目立ちます。

OnCtlColorで色を変えた入力エラー欄、状態表示、確認メモ一覧の表示例
HBRUSH CMyDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
    HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor);

    // 特定のコントロールの色を変更
    if (pWnd->GetDlgCtrlID() == IDC_EDIT_WARNING)
    {
        pDC->SetTextColor(RGB(255, 0, 0));     // 文字色:赤
        pDC->SetBkColor(RGB(255, 255, 200));   // 文字背景色:薄黄
        return m_brYellow;  // コントロール背景のブラシ
    }

    return hbr;
}

ブラシの準備と破棄

返したブラシは、コントロールを描画するたびに使われます。OnCtlColorの中でローカル変数として作ると、関数を抜けた時点でブラシが破棄されてしまうので、ブラシはメンバ変数として持たせます。ダイアログが破棄されるときに解放されます。

class CMyDlg : public CDialogEx
{
    CBrush m_brYellow;  // メンバ変数として保持
    CBrush m_brRed;
};

BOOL CMyDlg::OnInitDialog()
{
    CDialogEx::OnInitDialog();

    m_brYellow.CreateSolidBrush(RGB(255, 255, 200));
    m_brRed.CreateSolidBrush(RGB(255, 200, 200));

    return TRUE;
}
// CBrush はデストラクタで自動解放される

nCtlColorで種類を判定する

nCtlColorには、コントロールの種類が渡されます。次の定数で判定できます。

定数対象
CTLCOLOR_EDITエディットボックス
CTLCOLOR_STATICスタティックテキスト、グループボックス、読み取り専用/無効のエディット
CTLCOLOR_BTNボタン(効果は限定的)
CTLCOLOR_DLGダイアログ自体の背景
CTLCOLOR_LISTBOXリストボックス
HBRUSH CMyDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
    HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor);

    // すべてのスタティックテキストの色を変更
    if (nCtlColor == CTLCOLOR_STATIC)
    {
        pDC->SetTextColor(RGB(0, 0, 128));
        return hbr;
    }

    return hbr;
}

動的に色を切り替える

エラー時に赤くするなど、条件で色を変えるには、フラグ変数を用意し、変えたいコントロールにInvalidateで再描画を要求します。

// エラー発生時
m_bError = TRUE;
GetDlgItem(IDC_EDIT_VALUE)->Invalidate();  // 再描画を要求

// OnCtlColor 内
if (pWnd->GetDlgCtrlID() == IDC_EDIT_VALUE && m_bError)
{
    pDC->SetTextColor(RGB(255, 0, 0));
    pDC->SetBkColor(RGB(255, 220, 220));
    return m_brRed;
}

まとめ

  • OnCtlColorでコントロールの文字色・背景色・背景ブラシを変更できます
  • 返すブラシはメンバ変数として保持し、毎回作成しないでください
  • nCtlColorでコントロール種類を、GetDlgCtrlID() で個別コントロールを判定します
  • 動的に色を変えるには、フラグを設定してInvalidateで再描画を要求します

コントロールの位置や大きさを調べて描画に使うときは、スクリーン座標とクライアント座標の違いに注意が要ります。違いは「【MFC】GetWindowRect vs GetClientRect:スクリーン座標とクライアント座標」で確かめられます。

目次