質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
86.02%
MFC

MFC (Microsoft Fouondation Class)とは、MicrosoftがVC++用に開発したWindows用アプリケーションのフレームワークです。

Visual C++

Microsoft Visual C++はWindowsのCとC++の統合開発環境(IDE)であり、コンパイラやデバッガを含んでいます。

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

Win32 API

Win32 APIはMicrosoft Windowsの32bitプロセッサのOSで動作するAPIです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

画面の背景色を動的に変更できない。

KotS
KotS

総合スコア6

MFC

MFC (Microsoft Fouondation Class)とは、MicrosoftがVC++用に開発したWindows用アプリケーションのフレームワークです。

Visual C++

Microsoft Visual C++はWindowsのCとC++の統合開発環境(IDE)であり、コンパイラやデバッガを含んでいます。

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

Win32 API

Win32 APIはMicrosoft Windowsの32bitプロセッサのOSで動作するAPIです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

1回答

0グッド

1クリップ

4255閲覧

投稿2021/02/22 02:13

編集2021/02/22 07:08

前提・実現したいこと

チェックボックスのチェックイベントにより、ダイアログ画面とチェックボックスの背景色を切り替えるプログラムを作りたいと思っています。

発生している問題・エラーメッセージ

チェックボックスをチェックしてもチェックボックスの背景色は変わるのですが、
画面の背景色は変わりませんでした。

該当のソースコード

ObjColorChangeという名前のMFCプロジェクトをダイアログ型で作成。 ウィザードでだいたい作っていますが、追加行は //追加: 追加ブロックは //以下追加 と記述しています。 [ObjColorChangeDlg.h] // #pragma once // CObjColorChangeDlg ダイアログ class CObjColorChangeDlg : public CDialogEx { // コンストラクション public: CBrush m_brGreen; //追加:グリーンの背景色ブラシ CBrush m_brPink; //追加:ピンクの背景色ブラシ CBrush *m_brUse; //追加:使用背景色ブラシ CObjColorChangeDlg(CWnd* pParent = nullptr); // 標準コンストラクター // ダイアログ データ #ifdef AFX_DESIGN_TIME enum { IDD = IDD_OBJCOLORCHANGE_DIALOG }; #endif protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV サポート // 実装 protected: HICON m_hIcon; // 生成された、メッセージ割り当て関数 virtual BOOL OnInitDialog(); afx_msg void OnPaint(); afx_msg HCURSOR OnQueryDragIcon(); DECLARE_MESSAGE_MAP() public: afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);//追加:コントロールへの描画メッセージハンドラ afx_msg void OnBnClickedCheck1();//追加:チェックボックスクリック時イベントハンドラ BOOL m_bCheck1;//追加:チェックボックスのValueの変数 public: CButton m_cCheck1;//追加:チェックボックス変数 }; [ObjColorChangeDlg.cpp] // #include "pch.h" #include "framework.h" #include "ObjColorChange.h" #include "ObjColorChangeDlg.h" #include "afxdialogex.h" #ifdef _DEBUG #define new DEBUG_NEW #endif // CObjColorChangeDlg ダイアログ CObjColorChangeDlg::CObjColorChangeDlg(CWnd* pParent /*=nullptr*/) : CDialogEx(IDD_OBJCOLORCHANGE_DIALOG, pParent) , m_bCheck1(FALSE) { m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); } void CObjColorChangeDlg::DoDataExchange(CDataExchange* pDX) { CDialogEx::DoDataExchange(pDX); DDX_Check(pDX, IDC_CHECK1, m_bCheck1); DDX_Control(pDX, IDC_CHECK1, m_cCheck1); } BEGIN_MESSAGE_MAP(CObjColorChangeDlg, CDialogEx) ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_WM_CTLCOLOR() ON_BN_CLICKED(IDC_CHECK1, &CObjColorChangeDlg::OnBnClickedCheck1) END_MESSAGE_MAP() // CObjColorChangeDlg メッセージ ハンドラー BOOL CObjColorChangeDlg::OnInitDialog() { CDialogEx::OnInitDialog(); // このダイアログのアイコンを設定します。アプリケーションのメイン ウィンドウがダイアログでない場合、 // Framework は、この設定を自動的に行います。 SetIcon(m_hIcon, TRUE); // 大きいアイコンの設定 SetIcon(m_hIcon, FALSE); // 小さいアイコンの設定 // TODO: 初期化をここに追加します。 //以下追加 //起動時とみチェック時用に緑色のブラシ、チェック時用にピンクのブラシを作成する. m_brGreen.CreateSolidBrush(RGB(0, 255, 0));//緑色のブラシ m_brPink.CreateSolidBrush(RGB(234, 145, 152));// ピンクのブラシ m_brUse=&m_brGreen;//起動時は緑色のブラシを使用 return TRUE; // フォーカスをコントロールに設定した場合を除き、TRUE を返します。 } // ダイアログに最小化ボタンを追加する場合、アイコンを描画するための // 下のコードが必要です。ドキュメント/ビュー モデルを使う MFC アプリケーションの場合、 // これは、Framework によって自動的に設定されます。 void CObjColorChangeDlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); // 描画のデバイス コンテキスト SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0); // クライアントの四角形領域内の中央 int cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect); int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2; // アイコンの描画 dc.DrawIcon(x, y, m_hIcon); } else { CDialogEx::OnPaint(); } } // ユーザーが最小化したウィンドウをドラッグしているときに表示するカーソルを取得するために、 // システムがこの関数を呼び出します。 HCURSOR CObjColorChangeDlg::OnQueryDragIcon() { return static_cast<HCURSOR>(m_hIcon); } HBRUSH CObjColorChangeDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) { //以下コメントアウト //HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor); //// TODO: ここで DC の属性を変更してください。 //// TODO: 既定値を使用したくない場合は別のブラシを返します。 //return hbr; //以下追加 switch (nCtlColor) { case CTLCOLOR_DLG: return (HBRUSH)*m_brUse;//使用背景ブラシを返す case CTLCOLOR_STATIC://CheckBoxはCTLCOLOR_STATIC型 return (HBRUSH)*m_brUse;//使用背景ブラシを返す default: break; } return CDialog::OnCtlColor(pDC, pWnd, nCtlColor);//該当コントロール以外は既定のブラシ } void CObjColorChangeDlg::OnBnClickedCheck1() { // TODO: ここにコントロール通知ハンドラー コードを追加します。 //以下追加 UpdateData(TRUE); if (m_bCheck1) { m_brUse = &m_brPink;//チェック時はピンクを使用背景ブラシとする。 } else { m_brUse = &m_brGreen;//未チェック時は緑を使用背景ブラシとする。 } }

補足情報(FW/ツールのバージョンなど)

Visual C++ 2017, プロジェクト作成開始時にMFCアプリを選択。
チェック時にチェックボックスの背景のみピンクになっているが、ダイアログ画面の背景もピンクになって欲しい。

以下のような質問にはグッドを送りましょう

  • 質問内容が明確
  • 自分も答えを知りたい
  • 質問者以外のユーザにも役立つ

グッドが多くついた質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

気になる質問をクリップする

クリップした質問は、後からいつでもマイページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

下記のような質問は推奨されていません。

  • 間違っている
  • 質問になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

適切な質問に修正を依頼しましょう。

回答1

1

ベストアンサー

追記しました:

こちらが直接の回答です。改めてVisual Studio 2012/MFCで確認しました。

チェックボックスのチェックをON/OFFしたとき、チェックマークの変更によりチェックボックス自体は自ら再描画しますが、ダイアログボックスの方はそうではない為に再描画が行われず、その為に背景色が変わらないのが原因です。ですのでチェックボックスのイベントハンドラーでブラシを切り替えるとき、ダイアログボックスの描画領域をInvalidate()で無効化することで再描画されるようになります。

CObjColorChangeDlg::OnBnClickedCheck1()を以下のように修正して試してみてください。チェック状態に変化があればダイアログボックスの描画領域全体をCWnd::Invalidateで無効化し、再描画を促します。尚、チェックボックスのクリック時、つまり切替時にInvalidateRectを呼び出すと言う点で、私の先の回答と一致しています。

C++

1void CObjColorChangeDlg::OnBnClickedCheck1() 2{ 3 // UpdateData()で更新する前に、保存 4 BOOL pre = m_bCheck1; 5 6 UpdateData(TRUE); 7 if (m_bCheck1) { 8 m_brUse = &m_brPink;//チェック時はピンクを使用背景ブラシとする。 9 } 10 else { 11 m_brUse = &m_brGreen;//未チェック時は緑を使用背景ブラシとする。 12 } 13 14 if (pre != m_bCheck1) { 15 // チェック状態に変更があれば、ダイアログボックス全体を無効化 16 Invalidate(); 17 } 18}

以下は当初の回答です:
(Windows 10/Visual Studio 2019で確認)

ダイアログボックスの持つコントロールの背景色の描画に使われるWM_CTLCOLORメッセージは過去のWindowsで送受されたメッセージで、現行のものではコントロールの種別ごと、WM_CTLCOLORBTNWM_CTLCOLORSTATICなどに細分化されています。MFCの場合は過去バージョンの互換性も考慮した結果、WM_CTLCOLORのメッセージハンドラーであるOnCtlColorが作成できているのだと思います。

加えてダイアログボックスの背景色用にもWM_CTLCOLORDLG メッセージと言うものがあり、これを利用することでダイアログボックスの背景色を変えることができます。以下はMFCではないWindows APIを直に使ったサンプルコードです。ダイアログボックスが持つチェックボックス(ID=IDC_CHECK1)のチェックをON/OFFするごとにチェックボックスとダイアログボックスの背景色を切り替えます。これを参考にMFCバージョンの質問者さんのコードに適用することで、ご要望の動きができると思います。

C++

1#include <windows.h> 2#include "resource.h" 3 4INT_PTR CALLBACK AboutDlg(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); 5 6int APIENTRY wWinMain(_In_ HINSTANCE hInstance, 7 _In_opt_ HINSTANCE /* hPrevInstance*/, 8 _In_ LPWSTR /* lpCmdLine*/, 9 _In_ int /* nCmdShow*/ ) 10{ 11 DialogBox(hInstance, MAKEINTRESOURCE(IDD_ABOUTBOX), NULL, AboutDlg); 12 return 0; 13} 14 15static HBRUSH g_brGreen = NULL; 16static HBRUSH g_brPink = NULL; 17 18INT_PTR OnCtlColor(HWND hDlg, WPARAM wParam, LPARAM lParam, HWND hTargetWnd) 19{ 20 OutputDebugStringA("CTLCOLOR\n"); 21 22 HBRUSH h = NULL; 23 LONG id = GetWindowLong((HWND)lParam, GWL_ID); 24 char s[256]; 25 wsprintfA(s, "control id=%ld\n", id); 26 OutputDebugStringA(s); 27 if (hTargetWnd == (HWND)lParam) { 28 BOOL checked = IsDlgButtonChecked(hDlg, IDC_CHECK1); 29 h = checked ? g_brPink : g_brGreen; 30 } 31 return (INT_PTR)h; 32} 33 34INT_PTR CALLBACK AboutDlg(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) 35{ 36 UNREFERENCED_PARAMETER(lParam); 37 INT_PTR ret = FALSE; 38 switch (message) 39 { 40 case WM_INITDIALOG: 41 g_brGreen = CreateSolidBrush(RGB(0, 255, 0)); 42 g_brPink = CreateSolidBrush(RGB(234, 145, 152)); 43 ret = TRUE; 44 break; 45 46 case WM_COMMAND: 47 switch (LOWORD(wParam)) { 48 case IDOK: 49 case IDCANCEL: 50 EndDialog(hDlg, LOWORD(wParam)); 51 ret = TRUE; 52 break; 53 54 case IDC_CHECK1: 55 if (HIWORD(wParam) == BN_CLICKED) { 56 const char* ps = IsDlgButtonChecked(hDlg, IDC_CHECK1) 57 ? "Checked\n" : "Unchecked\n"; 58 OutputDebugStringA(ps); 59 // どうせダイアログボックス全体を再描画する必要があるので、 60 // ダイアログボックス自体を無効化。 61 //HWND hWnd = GetDlgItem(hDlg, IDC_CHECK1); 62 //InvalidateRect(hWnd, NULL, TRUE); 63 //UpdateWindow(hWnd); 64 InvalidateRect(hDlg, NULL, TRUE); 65 //UpdateWindow(hDlg); 66 ret = TRUE; 67 } 68 break; 69 70 default: 71 break; 72 } 73 break; 74 75 case WM_CTLCOLORSTATIC: 76 // チェックボックス 77 ret = OnCtlColor(hDlg, wParam, lParam, GetDlgItem(hDlg, IDC_CHECK1)); 78 break; 79 80 case WM_CTLCOLORDLG: 81 // ダイアログボックス 82 ret = OnCtlColor(hDlg, wParam, lParam, hDlg); 83 break; 84 85 case WM_DESTROY: 86 if (g_brGreen != NULL) { 87 DeleteObject(g_brGreen); 88 } 89 if (g_brPink != NULL) { 90 DeleteObject(g_brPink); 91 } 92 break; 93 94 default: 95 break; 96 } 97 98 return ret; 99}

チェックボックスのON時:
イメージ説明
チェックボックスのOFF時:
イメージ説明

投稿2021/02/22 15:35

編集2021/02/23 06:20
dodox86

総合スコア9146

KotS👍を押しています

良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。

下記のような回答は推奨されていません。

  • 間違っている回答
  • 質問の回答になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

このような回答には修正を依頼しましょう。

回答へのコメント

dodox86

2021/02/22 15:57 編集

と、言いますか、改めて質問者さんのコードを見ると、OnCtlColorの case CTLCOLOR_DLG: ...の部分でちゃんとダイアログボックス用に背景色ブラシを返していますね。良さそうにも思います。失礼しました。 当方の環境でMFCが使えず、同じ状況を再現できなかったのでネイティブのコードで試しましたが、もし回答のサンプルコードを参考に直して尚うまく動かないようであればお知らせください。MFC特有の問題と言うこともあり得ます。
KotS

2021/02/24 02:48

dodox86様 ご連絡遅くなり申し訳ございません。 迅速なご回答、大変ありがとうございました。 こちらのMFC環境でも追記のご回答でうまく動作しました。 Object.Invalidate()メソッドで強制的な再描画ができるのですね。 勉強になりました。 またこの板に質問させていただくことはあるかもしれませんが、もし機会がありましたら、よろしくお願いいたします。
dodox86

2021/02/24 03:05

> Object.Invalidate()メソッドで強制的な再描画ができるのですね。 強制的と言うよりか、まず、Invalidate(InvalidateRect)でウィンドウ、ここではCDialogExのクライアント領域をまず無効化、すなわちInvalidateします。無効化とは今現在 クライアント領域に描画済みのものはもう無効なものとして、リフレッシュしなければならない状態です。するとWindowsからいずれWM_PAINTメッセージが送られ、OnPaintで描画処理が走る形になります。WM_PAINTはしばしば送られない場合もあるので、本当に強制的に再描画させる場合はInvalidate(InvalidateRect)してからUpdateWindowを実行させます。機会あればWindows APIのWM_PAINT、InvalidateRect, UpdateWindowあたりで検索し、理解を深めてみてください。(まぁ、現役とは言え古い技術なのでほどほどに)
dodox86

2021/02/24 03:10

この辺りのメカニズムはWindowsに限らずGUIプログラミングで共通で出てくる概念であったりするので、頭に留めておいて損は無いと思います。
KotS

2021/02/24 04:16

dodox86様 丁寧なご解説、大変ありがとうございました。 実は今までVB6や.NET開発が多かったもので、メッセージ的なことを意識したことがあまりありませんでした。 これからもう少し調べてみます。 ありがとうございました。

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
86.02%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問

同じタグがついた質問を見る

MFC

MFC (Microsoft Fouondation Class)とは、MicrosoftがVC++用に開発したWindows用アプリケーションのフレームワークです。

Visual C++

Microsoft Visual C++はWindowsのCとC++の統合開発環境(IDE)であり、コンパイラやデバッガを含んでいます。

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

Win32 API

Win32 APIはMicrosoft Windowsの32bitプロセッサのOSで動作するAPIです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。