CBitmapButton上へ文字列表示

[戻る]
ebimayo 2006/03/17(金) 10:33:47
初めまして
タイトルに書いたCBitmapButton上に文字列表示する方法について
質問させて頂きます。

<<やろうとしている事>>
1.CBimapButtonの機能を用いて通常状態、押された状態、無効状態、
  フォーカスを得た状態のビットマップを設定する。
2.1で用意したビットマップボタンに任意の文字列を書く。
(1は問題なく出来ていて2の実現方法で悩んでいます)


<<実現のために試した方法と結果>>
 CBitmapButtonを派生させたクラスを自作して、そのクラス内で
 OnPaintのイベントをキャッチして文字列を描画する。
  実際の処理例を以下に記述しました。

// CBitmapButtonを基本クラスとして派生したCButtonTestクラスを自作し
class CButtonTest : public CBitmapButton

// CButtonTestクラスでOnPaintをキャッチするようにして
// 以下の文字列描画処理を書きました。
void CButtonTest::OnPaint()
{
    if (IsIconic()){
    }else{
        CBitmapButton::OnPaint();

        CDC          *hDC;
        PAINTSTRUCT  lpPaint;
        RECT         tRect;

        GetClientRect(&tRect);
        InvalidateRect( NULL, FALSE );
        hDC = BeginPaint(&lpPaint);
        hDC->SetBkMode(TRANSPARENT);
        hDC->DrawText( _T("表示したい文字"),-1, &tRect, 
                       DT_SINGLELINE|DT_CENTER );
        EndPaint(&lpPaint);
    }
}

上記のように書くとビットマップボタン上に文字列が表示されるのですが、
エクスプローラや別のアプリケーションなどのウィンドウで
ビットマップボタンに重なるように動かすと、ビットマップボタンの
ビットマップが灰色表示になってしまいます。(文字列は正常に表示し続けます)


<<知りたいこと>>
1.ビットマップボタンを用いてビットマップをボタンの背景のように使用し、
  その上に文字列を表示することは可能か?可能ならその実現方法
2.1の実現が不可能な場合の代わりになりそうな方法


何か少しでもわかることがあったら教えていただけたらと思い質問しました。

開発環境
Microsoft WindowsXP(SP2)
Microsoft Visual C++ 2005
  ダイアログベースアプリケーション(MFC)

subaru 2006/03/17(金) 14:24:17
DrawItemをオーバーライドするとできるのではないでしょうか。

ebimayo 2006/03/17(金) 16:57:01
[[解決]]
回答ありがとうございます。

教えていただいたDrawItemを使用して以下のようにしました。
(OnPaintでは処理しないように削除しました。)

// 以下のようにオーバーライドするようにしました
public:
    virtual void DrawItem( LPDRAWITEMSTRUCT lpDrawItemStruct );

// DrawItemの処理を以下のようにしました
void CButtonTest::DrawItem( LPDRAWITEMSTRUCT lpDrawItemStruct )
{
    CDC          *hDC;
    CFont        *pcFont;
    PAINTSTRUCT  lpPaint;
    RECT         tRect;
    WORD         wID;
    HANDLE       hBmp;
    BITMAP       tBmp;
    HDC          hBufdc;
    HGDIOBJ      hDef;

    wID = 0;
    if( (lpDrawItemStruct->itemState & ODS_DISABLED) != 0 ){
        wID = m_nBMPDisabled;
    }else
    if( (lpDrawItemStruct->itemState & ODS_SELECTED) != 0 ){
        wID = m_nBMPSel;
    }else
    if( (lpDrawItemStruct->itemState & ODS_FOCUS) != 0 ){
        wID = m_nBMPFocus;
    }
    if(wID == 0){
        wID = m_nBMP;
    }
    hDC = CDC::FromHandle(lpDrawItemStruct->hDC);
    hBmp = LoadImage( AfxGetInstanceHandle(), MAKEINTRESOURCE(wID), 
                      IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR );
    GetObject(hBmp, sizeof(BITMAP), &tBmp);
    hBufdc = CreateCompatibleDC(hDC->m_hDC);
    hDef = SelectObject(hBufdc, hBmp);
    BitBlt( hDC->m_hDC, 0, 0, tBmp.bmWidth, tBmp.bmHeight, 
            hBufdc, 0, 0, SRCCOPY);
    DeleteObject(hBmp);
    GetClientRect(&tRect);
    hDC->SetBkMode(TRANSPARENT);
    hDC->DrawText( _T("表示したい文字"),-1, &tRect, 
                   DT_SINGLELINE|DT_CENTER );
    if( hDef != NULL ){   SelectObject(hBufdc, hDef); }
    if( hBufdc != NULL ){ DeleteDC(hBufdc); }
}

上記で使っているm_nBMPDisabled、m_nBMPSel、m_nBMPFocus、m_nBMPは
元々このクラスはCBitmapButtonの派生クラスでLoadBitmapsに渡すために
派生クラスのコンストラクタで渡すようにしている各ボタン状態に応じた
ビットマップリソースIDです。

知りたかったことの1に書いたことが上記の方法で実現できました。
ありがとうございます。

ただ、これに関してひとつ疑問があるのですが、私のやり方だとCBitmapButtonを
派生して作っている意味がなく、CButtonの派生クラスで実現可能なのでは?
自分でCButtonから派生したCBitmapButtonのクラスの拡張(文字が書けるだけですが)
バージョンを作っているんじゃないかと思えてきたことです。

教えていただいたことを参考に出来たので解決チェック付けておきます。
これ以外にもいい方法があって私のやり方が回りくどいやり方だとしたら
教えてもらえたら幸いです。
#自分のやり方が最適だと思えなかったので・・・

subaru 2006/03/17(金) 20:26:43
動作確認してないんですけどこんな感じでどうでしょうか?

void CButtonTest::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
    CBitmapButton::DrawItem(lpDrawItemStruct);
    CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
    pDC->SetBkMode(TRANSPARENT);
    pDC->DrawText( _T("表示したい文字"),-1, &lpDrawItemStruct->rcItem, 
                   DT_SINGLELINE|DT_CENTER );
}

ebimayo 2006/03/20(月) 09:06:05
返信遅くなってすいません
subaruさんありがとうございます。

subaruさんの提示してくれたやり方で実現できました。
まだ理屈が理解できてませんが、CBitmapButton::DrawItemで
基本クラスが担当してくれる描画を行わせてからその上に自分の
描画したい文字列を書くってイメージでしょうか

OnPaintでやったときにCBitmapButton::OnPaint();を呼び出して
うまく描画出来なかったのでDrawItemでは基本クラスを呼ぶことを最初から
試していませんでした。

MSDNの対象クラスとそのメンバ関数のヘルプは良く見ますが
イベントの発生条件等詳しく理解出来ていませんでした。
OnPaintとDrawItemの違いがいまいち良くわかってないですが、
もっと理解出来るようにしたいと思います。

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