こんにちは
まず環境です
VC++6.0、MFC、SDI、WindowsXP
現在ラジオボタンの背景部分に画像を使用したいと思い、いじっているところです
目的は、ラジオボタンを設置するウインドウの背景に画像を使用しているため、
そのまま普通にラジオボタンを付けるとそこだけ灰色(通常で)でくりぬかれてしまう
ためです
近い色をCtrlColorで設定して多少ごまかし気味にすることもできますが、
できるならばさらに綺麗に見せるために同じ画像を背景にしようかと思ったわけです
おおまかなソースを示します
class CMyRadioButton : public CButton
{
・・・
CBrush m_BrushBg;
};
// コンストラクタ
CMyRadioButton::CMyRadioButton ()
{
m_BrushBg.CreateStockObject(NULL_BRUSH);
}
// ON_WM_CTLCOLOR_REFLECT
HBRUSH CMyRadioButton::CtlColor(CDC* pDC, UINT nCtlColor)
{
// SetBkMode(TRANSPARENT); // 効果なし
return m_BrushBg;
}
// ON_WM_ERASEBKGND
BOOL CMyRadioButton::OnEraseBkgnd(CDC* pDC)
{
/* 画像描画処理 */
return FALSE;
}
予想ではこれで背景に画像が表示されるかと思っていたのですが、
実際は画像が描画されたあとに、さらにその上が黒で塗りつぶされ、
結局見えなくなってしまいます
ちなみにm_BrushBgをCreateSolidBrushで作成してCtlColorでreturnすれば、
その黒で塗りつぶされた部分がそのブラシの色で描画されるようです
これをNULL_BRUSHにしても黒で塗られてしまうのはなぜなのでしょう?
何か知っている方がいましたら助言いただけるとありがたいです
描画処理以外については問題なさそうに見えますが・・
念のため、描画処理の部分も公開された方が良いかと思います。
背景画像によっては特殊な注意が必要なようです。
http://home.att.ne.jp/yellow/hide_n/programming/tips09.html
回答になっておらず、すみませんm(_ _)m
レスありがとうございます
実際の描画処理は独自クラスを使用しているため説明すると長くなるなと思って
省略してしまったのがいけませんでした
簡単なテスト用コードを作ってみたのでそれを示します
BOOL CMyRadioButton::OnEraseBkgnd(CDC* pDC)
{
// TODO: この位置にメッセージ ハンドラ用のコードを追加するかまたはデフォルト
の処理を呼び出してください
CRect Rect;
CBrush Brush(RGB(255, 0, 0));
CBrush* pBrush;
GetClientRect(Rect);
pBrush = pDC->SelectObject(&Brush);
pDC->Rectangle(Rect);
pDC->SelectObject(pBrush);
Sleep(1000);
return FALSE;
}
このようにただRectangleで矩形を描画するだけでも結果は同じになります
Sleepは、描画の途中経過を目視できるように入れてあります
これを実行すると、一度クライアント領域が赤で塗りつぶされたあと、
再び黒で塗りつぶされる様子が見て取れます
いろいろ検索していると、以下の記事を見つけました
http://forums.belution.com/ja/vc/000/209/78s.shtml
別のVCフォーラムの記事ですが、これによるとほぼ希望通りの処理を実現できているよう
です
ということは不可能ではないはず
それでふと思ったのですが、もしかしたらビジュアルスタイルが悪さしてるのかなと
それでビジュアルスタイルを切ってみると、希望通りの動作になりました
そこでさらに実験してみると、どうやらビジュアルスタイルを適用すると、
CtlColor内でpDC->SetTextColor()をしても適用されなかったりもしました
クラシックスタイルなら適用され、文字色はちゃんと変わります
しかし現在作成しているアプリケーションはマニフェストファイルによって
ビジュアルスタイルを適用させているのでできればそのままでいきたいのです
もしくは特定のコントロールのみ、ビジュアルスタイルを適用外にするなどということは
可能なのでしょうか?
何かヒントがあればお願いします
同様のことをやってみましたが、特に問題なく(黒塗りにならず、下の画像が表示され
て)表示されてましたよ。
透明ブラシを使っているので、OnEraseBkgndに特に記述する必要は無いと思いますよ。
記述しても問題ないとは思いますが。
/////////////////////////////////////////////////////////////////////////////
// CRadio メッセージ ハンドラ // CRadio : CButtonの派生クラス
void CRadio::PreSubclassWindow()
{
// TODO: この位置に固有の処理を追加するか、または基本クラスを呼び出し
てください
ModifyStyle(0, BS_AUTORADIOBUTTON);
CButton::PreSubclassWindow();
}
HBRUSH CRadio::CtlColor(CDC* pDC, UINT nCtlColor) // ON_WM_CTLCOLOR_REFLECT()
// TODO: この位置で DC のアトリビュートを変更してください
CBrush nullb;
nullb.CreateStockObject(NULL_BRUSH);
pDC->SetBkMode(TRANSPARENT);
return nullb;
// TODO: 親ハンドラを呼び出したくない場合はここでブラシのハンドルとし
て NULL 以外を返すようにしてください
// return NULL;
}
ダイアログに貼り付けての確認ですので、貼り付ける場所が別の場所だとうまくいかな
いかも知れませんが。
レスありがとうございます
提示していただいたソースを元にこちらでもダイアログでテストプログラムを作ってみ
ました
試しにダイアログの背景をハッチブラシで塗りつぶし、
その上にサブクラス化したラジオボタンを配置してみました
これをマニフェストファイルなしの状態で起動すると
背景がうまく透明になって希望通りの動作をしました
マニフェストファイルを適用した場合は、ダイアログでのテストでは
少し背景がずれて表示されるものの、一応それっぽくはなりました
しかしこれを現在作成しているプログラムに持って行くとダメなようです
現在作成しているプログラムではCViewから派生させた独自クラスに
ラジオボタンを配置しているのですが、ダイアログではなくビューだというのがいけな
いのでしょうか・・・
またはビジュアルスタイルの仕様と考えて割り切るしかないのでしょうか・・・
CViewでも確認してみましたが、特に問題ないみたいですよ。
・・・
void CXXXView::OnInitialUpdate()
{
CView::OnInitialUpdate();
// TODO: この位置に固有の処理を追加するか、または基本クラスを呼び出し
てください
// m_Radoi:先の CRadio型の変数
// IDC_RADIO:IDシンボルブラウザで作成済みのID
m_Radio.Create(test, WS_VISIBLE, CRect(0, 0, 50, 20), this,
IDC_RADIO);
m_Radio.SetWindowPos(NULL, 50, 50, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
// 位置と大きさは適当です
}
・・・
CViewに直接貼り付けるとやや強引な感じがしますので、ダイアログバーなどに乗せたほ
うがいいかもしれません。
マニフェストファイルってヘッダーファイルのことですか?ごめんなさいよくわからな
かったので。
お手数おかけします
アプリケーションの構造上、どうしてもViewに貼り付ける必要があるもので、
そこだけはしょうがないのです・・・
またマニフェストファイルというのは、詳細な部分はわからないのですが、
アプリケーション内のコントロールにWindowsXPのビジュアルスタイルを適用させるため
のファイルのようで、それをリソースに含めてコンパイルします
そうすると、ユーザーがWindowsXPを使用していて、かつビジュアルスタイルで表示する
ように設定している場合、
そのアプリケーション内のコントロールにビジュアルスタイルが使用されるようになり
ます
通常の状態ではビジュアルスタイルを使用している環境でも、それが適用されるのはア
プリケーションのタイトルバーやフレーム部分、メニューといった領域だけで、
ボタンなどのコントロールには適用されないようです
詳しくはこのページに書かれているので参考にしてください
http://www.microsoft.com/japan/msdn/windows/windowsxp/xptheming.asp
こちらでもあれからいろいろ実験してみましたが、やはりクラシック、ビジュアル両ス
タイルで共通して正常に描画できる処理を見つけ出すことができませんでした
そこで半分妥協して、背景が画像ではなく単色塗りつぶしの場所にラジオボタンを移動
そしてラジオボタンの背景部分はViewの背景色と同じ色で塗りつぶすようにCtlColor()
を処理するようにしています
理想的な状態に持っていけなかったことが悔やまれますが、あまりこれひとつに固執す
るわけにもいかないので、ひとまず作業を進めることにします
回答いただいたみなさん、どうもありがとうございました