入門書などを読むと、以下の方法で行っています。
void CXXView::OnPaint()
{
CPaintDC dc(this); // 描画用のデバイス コンテキスト
CRect rect ;
GetClientRect(&rect) ;
CBrush brush ;
brush.CreateSolidBrush(RGB(255,255,200)) ;
dc.FillRect(rect,&brush) ;
// 以降bmpを表示
}
でもこれだと再描画する度にちらちらします。
Invalidate(FALSE)だと、bmpを縮小させたりする時に残像が残ってしまいます。
BOOL CXXView::PreCreateWindow(CREATESTRUCT& cs)
{
if (!CWnd::PreCreateWindow(cs))
return FALSE;
CBrush brush ;
brush.CreateSolidBrush( RGB(255,255,200) );
cs.dwExStyle |= WS_EX_CLIENTEDGE;
cs.style &= ~WS_BORDER;
cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS,
::LoadCursor(NULL, IDC_ARROW), (HBRUSH)brush.Detach(), NULL);
return TRUE;
}
ここで使っているHBRUSHを変更すればいいと思うのですが、
取得する方法も変更する方法も見つかりません。ご存知の方いらっしゃいますか。
背景ブラシは関係なく、
OnPaintで、ブラシで全体を塗った後、ビットマップを描画しているために
ちらついているものと思われます。
ちなみにOnEraseBkgndで背景の塗り潰しを無効にしていますか?
無効にしていないと二回背景を塗り潰すのでちらつきがひどいと思います。
あと考えられるのは、背景の塗り潰しを全面に対してやるのではなくて、
ビットマップが載る予定の領域を避けて塗ると言う手もあると思います。
拡縮するにしてもそのサイズと位置はわかっているはずなので
その部分をクリッピングするとか、
その部分を抜いたリージョンを作成してそれで塗り潰すとか
してみてはどうでしょうか?
あとは、バックバッファ上で拡縮と背景の描画までしてから
画面に転送するとかですかねぇ。
>取得する方法も変更する方法も見つかりません
これは好きな時に背景色を変えたいということですか?
だとすると、好きな時に例えば次のようにするといいと思います。
void CXXView::OnXXX()
{
static HBRUSH hbrush = ::CreateSolidBrush( 好きな色 );
::SetClassLong( m_hWnd, GCL_HBRBACKGROUND, ( LONG )hbrush );
Invalidate();
}
皆様レスありがとうございます。
>背景ブラシは関係なく、
>OnPaintで、ブラシで全体を塗った後、ビットマップを描画しているために
>ちらついているものと思われます
ええ、ですからOnPaintのFillRectをやらないで背景色を変える方法を考えています。
>ちなみにOnEraseBkgndで背景の塗り潰しを無効にしていますか?
>無効にしていないと二回背景を塗り潰すのでちらつきがひどいと思います。
これをすると、FillRectしてもちらつきが少ないと言うことでしょうか?
後で試してみます。
>void CXXView::OnXXX()
>{
> static HBRUSH hbrush = ::CreateSolidBrush( 好きな色 );
> ::SetClassLong( m_hWnd, GCL_HBRBACKGROUND, ( LONG )hbrush );
> Invalidate();
>}
これで変更することが出来ました。ありがとうございます。
SetClassLongというAPIがあるのですね。
でも1回しか変更できなかったので以下の様にしました。
一応成功したのですが、何かおかしな事してますでしょうか。
元のハンドル破棄したほうがいいのかなと思ったのですが...
void CXXView::OnXX()
{
// TODO: この位置にコマンド ハンドラ用のコードを追加してください
CColorDialog cd ;
if(cd.DoModal() == IDOK )
{
m_back_color = cd.GetColor() ;
HBRUSH brush =(HBRUSH)::GetClassLong(m_hWnd,GCL_HBRBACKGROUND) ;
if(brush)
::DeleteObject(brush) ;
brush = ::CreateSolidBrush( m_back_color );
::SetClassLong( m_hWnd, GCL_HBRBACKGROUND, ( LONG )brush );
Invalidate();
}
}
ウィンドウクラス登録時に新しいブラシを作っているので、ブラシを替える時は
以前のものを破棄、でいいと思います。
(もし(HBRUSH)(COLOR_WINDOW+1)とか::GetStockObject(WHITE_BRUSH)とかのブラシ
を登録時に使っていたら、これを破棄するとマズいかもしれません…)
結局、::SetClassLong( m_hWnd, GCL_HBRBACKGROUND, ( LONG )brush );をやっていると
言う事は、OnEraseBkgndが生きていると言うことですね。
設定された色で背景を消す時に絡む処理なので。
OnEraseBkgndの方を生かしてOnPaint内の処理を消すのであればいいのですが、
OnPaint側の処理も消してOnEraseBkgndも殺してしまうと背景の塗り潰しが
なくなってしまうので注意した方が良いです。
最終的にちらつきを最小限にするという話になるとバックバッファを使った方法を
取る事になると思います。背景を全面塗り潰して、ビットマップを貼り付けると
ビットマップが張り付く直前に背景が全面塗り潰された状態が一瞬見えてしまう為に
ちらつきになっていると思うので、背景とビットマップがいっぺんに表示されれば、
ちらつきはほとんどなくなるのではと思います。
ご意見ありがとうございます。
>ウィンドウクラス登録時に新しいブラシを作っているので、ブラシを替える時は
>以前のものを破棄、でいいと思います。
>(もし(HBRUSH)(COLOR_WINDOW+1)とか::GetStockObject(WHITE_BRUSH)とかのブラシ
> を登録時に使っていたら、これを破棄するとマズいかもしれません…)
やはりそういう事なんでしょうね。
でもそうすると最後にHBRUSH破棄してないのは大丈夫なのかな。(? ?);
デバッガは何も言ってこないけど...
>最終的にちらつきを最小限にするという話になるとバックバッファを使った方法を
>取る事になると思います。背景を全面塗り潰して、ビットマップを貼り付けると
>ビットマップが張り付く直前に背景が全面塗り潰された状態が一瞬見えてしまう為に
>ちらつきになっていると思うので、背景とビットマップがいっぺんに表示されれば、
>ちらつきはほとんどなくなるのではと思います
memDCを2つ用意して1つ目にbmpを選択させて、2つめを塗りつぶした後bmpを転送、
そして表DCに転送と言うやり方でしょうか。
今後の参考にさせていただきます。ありがとうございました。
>最後にHBRUSH破棄してない
アプリケーションが取得したメモリやリソースはアプリケーションの終了時に全て
元に戻される、的なことがどこかに書いてあったので大丈夫だと思います。