AboutDialogBoxの背景色

[戻る]
Beginner 2003/02/13(木) 21:00:47
何時もお世話になります。
ブロック崩しの色付けにAboutDialogBoxの背景色をセットしようとして、以下のコードを
CAboutDlgにOnEraseBkgndメッセージハンドラを付け加えて、以下のコードを書きました。

BOOL CAboutDlg::OnEraseBkgnd(CDC* pDC) 
{
    // TODO: この位置にメッセージ ハンドラ用のコードを追加するかまたはデフォル
トの処理を呼び出してください
    CBrush backBrush(RGB(200,20,200));
    CBrush *oldBrush = pDC->SelectObject(&backBrush);
    CRect rect;
    pDC->GetClipBox(&rect);
    pDC->PatBlt(rect.left, rect.top, rect.Width(), rect.Height(), 
PATCOPY);
    pDC->SelectObject(oldBrush);
    return CDialog::OnEraseBkgnd(pDC);
}

しかし、背景色はdefaultのままで変化ありません。ちなみにreturn文の前にAfxMessageBox()
を置けば背景色は思いどおりに変わりますが、無限ループに入ります。

どなたかご教示下さい。

Beginner 2003/02/13(木) 21:02:58
書き忘れました。申し訳ありません。
Win2K, VC++6.0, MFCです。

小悪魔恭子 2003/02/13(木) 22:02:00
>    return CDialog::OnEraseBkgnd(pDC);
return TRUE;
でよいのでは?

123 2003/02/13(木) 22:06:04
HBRUSH BOOL CAboutDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) 
{
    COLOREF backColor=RGB(200,20,200);
    CBrush  backBrush(backColor);

    if (nCtlColor == CTLCOLOR_DLG || nCtlColor == CTLCOLOR_STATIC)
    {
    pDC->SetBkColor(backColor);
    return (HBRUSH) backBrush.GetSafeHandle();
    }

    return CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
}

Beginner 2003/02/14(金) 05:58:45
小悪魔恭子様、

ありがとうございます。仰る通りreturn TRUE;に変更するとうまくいきました。ただ、Dialog
の中のstatic_textについては背景色は変わりません。


123様、
ご教授ありがとうございます。
試みましたが、WM_CTLCOLORのメッセージがAboutDlgに送られないのか、ダイアロクもテキス
トも背景色は変化しませんでした。どのようにすればWM_CTLCOLORのメッセージがAboutDlgを
開いた時に送られるようになるでしょうか?

Beginner 2003/02/14(金) 06:10:10
小悪魔恭子様、

今、発見しました。

要するにdefaultでメッセージハンドラの最後に付け加えられる
    return CDialog::OnEraseBkgnd(pDC);
を実行させずに
    return FALSE;でも
    return TRUE;でも
何でも良いから戻せば良いようです。
結果は同じになります。

何だか良く分かりません。
要するに
    return CDialog::OnEraseBkgnd(pDC);
を返せば、折角その前に行った背景描画処理が無駄になって、派生元クラスのdefaultの関数が
実行されてしまうからでしょうか?

sugar 2003/02/14(金) 09:14:49
CDialog::OnEraseBkgnd(pDC);
これを実行していることが、デフォルトの処理を実施させていることになります。

dairygoods 2003/02/14(金) 12:05:07
>    CBrush  backBrush(backColor);
>
>    if (nCtlColor == CTLCOLOR_DLG || nCtlColor == CTLCOLOR_STATIC)
>    {
>    pDC->SetBkColor(backColor);
>    return (HBRUSH) backBrush.GetSafeHandle();
>    }

これでは、関数から出た時にブラシが削除されてしまいます。
backBrushを関数より寿命の長いスコープに置いてみてください。
(メンバ変数、クラス変数、グローバル変数など)

Beginner 2003/02/14(金) 12:52:44
dairygoods様、

ご指導のようにbackBrushをAboutDlgのメンバー変数に持っていきましたが、ビルドすると

BlockHitGame.obj : error LNK2001: 外部シンボル ""protected: int __thiscall 
CAboutDlg::OnEraseBkgnd(class CDC *)" (?
OnEraseBkgnd@CAboutDlg@@IAEHPAVCDC@@@Z)" は未解決です

のようなエラーがでてしまいます。
何のことだかさっぱり分かりません。
また、123様のコードでもreturnでbackBrushへのハンドルを返すことになるので、backBrush
が関数を出たときに削除されるとは思えないのですが。
ご指導宜しくお願いします。

dairygoods 2003/02/14(金) 13:22:40
> のようなエラーがでてしまいます。

CBrushの件とは関係ないと思います。
OnEraseBkgnd()関数を削除したが、MESSAGE_MAPが
そのままとかではないですか。


> 関数を出たときに削除されるとは思えないのですが。

イメージだけで捉えずに、疑問に思った点は
テストプログラムを作って確かめてみると良いでしょう。

HBRUSH GetHandle() {
  CBrush brush(RGB(0,0,0));
  return (HBRUSH)brush.GetSafeHandle();
}

...

HBRUSH hbr = GetHandle();
LOGBRUSH lb;
int ret = ::GetObject(hbr, sizeof(lb), &lb);
if (ret == 0) {
  // hbrは削除されている
} else {
  // hbrは削除されていない
}

Beginner 2003/02/14(金) 16:42:23
dairygoods様、

仰る通り、小生が勝手にハンドラをコメントアウトして、MESSAGE_MAPに残ったままだからでし
た。そこの部分もコメントアウトするとOKでした。
しかし、未だ問題があります。
やはりAbouDlgの背景色は変化しません。残念ながらSPY++などの使い方も分からないのです
が、きっとWM_CTLCOLORメッセージがAboutDlgに届いていないのだと思います。

dairygoods 2003/02/14(金) 16:56:34
> 残念ながらSPY++などの使い方も分からないのです
> が、きっとWM_CTLCOLORメッセージがAboutDlgに届いていないのだと思います。

SPY++など使えなくても簡単に調べられます。
OnCtlColor()関数の中にブレークポイントを設置して
デバッガで実行するだけです。

で、本当に呼ばれていない場合ですが、
MESSAGE_MAPにON_WM_CTLCOLOR()はありますか?

Beginner 2003/02/14(金) 17:14:50
dairygoods様、

そうですね。馬鹿でした。ブレークポイントを

BRUSH CAboutDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) 
{
    HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
    
    // TODO: この位置で DC のアトリビュートを変更してください
    
    // TODO: デフォルトのブラシが望みのものでない場合には、違うブラシを返してく
ださい
     if (nCtlColor==CTLCOLOR_DLG||nCtlColor==CTLCOLOR_STATIC) {

        pDC->SetBkColor(backColor);
         return (HBRUSH) backBrush.GetSafeHandle();
     }
    return hbr;
}

の中のifの頭に設定しましたところ、ちゃんとAboutDlgを表示しようとするとそのブレークポ
イントで停止しました。ということはちゃんとこのハンドラが呼ばれているということですね。
では、どうして思いどおりに行かないのでしょうか?

akey 2003/02/14(金) 17:59:37
backBrushは、作っていますか?
(CBrush::CreateSolidBrushを呼んでいますか?)

Beginner 2003/02/14(金) 18:15:25
akey様、

ご指摘ありがとうございます。
CBrushのコンストラクタを調べたのですが、

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
    //{{AFX_DATA_INIT(CAboutDlg)
    //}}AFX_DATA_INIT
     backColor = RGB(200,100,100);
     CBrush backBrush(backColor);
}

でCreateSolidBrushが呼ばれているように思います。
ですから、backBrushはちゃんと作成されていると思いますが......

akey 2003/02/14(金) 18:19:53
以下のようにしないと駄目です

class CAboutDlg : public CDialog
{
public:
    CAboutDlg();
private:
    CBrush backBrush;
 :
 :

};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
    //{{AFX_DATA_INIT(CAboutDlg)
    //}}AFX_DATA_INIT
     backColor = RGB(200,100,100);
     backBrush.CreateSolidBrush(backColor);
}


オブジェクトの寿命を考えましょう

Beginner 2003/02/14(金) 20:03:22
[[解決]]
akey様、

ご指摘の通りでした。
自分なりに無い知恵を絞り考えたのですが、結局私はCAboutDlgのメンバー変数として
backBrushを宣言し、それが使われるものと思っていたのですが、

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
    //{{AFX_DATA_INIT(CAboutDlg)
    //}}AFX_DATA_INIT
     backColor = RGB(200,100,100);
     CBrush backBrush(backColor);  //ここで別のbackBrushが宣言されている
}

で、再びCAboutDlg():CDialog()内でローカルにbackBrushが宣言されていた、ということな
のですね。
本当に自分の馬鹿さ加減にあきれます。
でもお忙しい中、ご指摘本当にありがとうございました。
ちゃんとAboutDlgの背景もstatic textの背景も全て思いどおりの色に変化しました。

今後ともご指導宜しくお願いします。

古いスレッドには追加発言できません。