プロが教えるわが家の防犯対策術!

はじめまして。
VC.net winXPでプログラムの勉強をしてるんですが、
裏画面(メモリDC?)の処理がうまくできません。

ピクチャのプロパティをビットマップにしてOnInitDialogで
HBITMAPにLoadimageで読み込み
関連しているCstaticにsetbitmapをしてビットマップの表示をしています。

さらにその上にMoveToやらLineToやらで線を引いているんですが、
ウィンドウが隠れた後等の再描画時に引いた線が消えてしまいます。
それを回避する為に裏画面のHBITMAPに描画し、
それをBitBlt等を使ってピクチャに転送すれば良いような事はわかったのですが、
うまくそれを実現する事ができません。

ソースの一部は以下の通りです。

void CtestpictDlg::OnBnClickedDraw()//コマンドボタンを押した時に処理
{
//m_StaticPictureにはOnInitDialogでSetBitmap(m_hBmp)として
//ビットマップのセットがしてあり、ダイアログを見るとちゃんと表示されている。
CDC dc;
CString str;
CWnd *h = GetDlgItem(IDC_STATICPICTURE);
CDC *hdc = h->GetDC();//ピクチャのDCを取得

dc.CreateCompatibleDC(hdc);
HBITMAP test=CreateCompatibleBitmap(hdc->m_hDC,256,256);
//ピクチャからビットマップを初期化

HBITMAP* oldbmp = (HBITMAP*)dc.SelectObject(&test);
//dcにビットマップを割り当て

CPen p(PS_SOLID,1,RGB(0,255,0));
CPen* oldp = (CPen*)dc.SelectObject(&p);
dc.MoveTo(10,10);
dc.LineTo(100,100);//とりあえず斜めに線を引けるように。

//m_StaticPicture.SetBitmap(test);//ここでtestを見てみると真っ黒な256*256の画像
BitBlt(hdc->m_hDC,0,0,256,256,dc.m_hDC,0,0,SRCCOPY);
//UpdateData(FALSE);必要かどうかわからない…

//以下に開放処理等
}

まだ勉強し始めて日が浅いので、
ちぐはぐな事をしているかもしれませんがよろしくお願いします。

A 回答 (3件)

> CDCを使ってHBITMAPに描画する、


> というソース部分は合っていますでしょうか?
とりあえず動きそうにも見えますが、CDC/HDC と CBitmap/HBITMAPなど、MFCとWin32APIが混在していて、提示範囲だけではなんとも…。
MFCを使うのであれば、HBITMAPなどを直接使うのはお勧めできません。
(リソース解放などがわかりにくい<気づきにくいバグの温床)
ラッパーがMFCにいるのでそちらで統一してください。
また、BitBlt等もメンバ変数がいるのでそれを使ってください。m_hDC などを直接使うのも美しくありません。
# 一応、m_hDC や HBITMAP を使わなくても書ける様にできてます>MFC

>//UpdateData(FALSE);必要かどうかわからない…
これはDDX用なので描画には直接関係ないです。

> ピクチャからメモリDCへのBitBlt
> メモリDCからピクチャへのBitBlt

簡単な検証コードも書いてみましたが、これらはいずれも可能。
描画されないのは、どこかコードがおかしいのでしょう。

> //m_StaticPicture.SetBitmap(test);//ここでtestを見てみると真っ黒な256*256の画像

このコメントアウト部で確認できると考えているのなら、SetBitmapの役割にも誤解がありそうな気が。大丈夫ですか。
CStaticのSetBitmapは、呼んだ瞬間に画像を転送するものではなく、CStaticとビットマップを関連付けるもので、以後必要に応じて渡したビットマップを表示しようとしますから、設定以後はそのビットマップが常に有効でなければなりません。
「以下に開放処理等」でtestを破棄したりしてると、まともに表示されないと思います。

その上で、仮にコードが直ったとして、単純に OnPaint で線を引こうとしても、おそらくうまくいきません。
これは、ダイアログとピクチャは別のウィンドウであり、ダイアログのOnPaintで描画しても、ピクチャの描画で塗りつぶされるためと思われます。

対策:
1.ピクチャ用のサブクラスを作り、そちらのOnPaintで描画。
2.ピクチャを使わず、ダイアログに直接描画
なにか、ピクチャを使わなければならない理由がありますか?

ピクチャコントロールは、ダイアログが描画内容をコントロール任せにするためにあると思うので、それを外から弄る用途には向いてないような。
少なくともOOの観点からすれば、ピクチャを使うなら、その描画はピクチャでやるのが好ましいです。

// static とあるものは、メンバ等
// エラー処理や解放系をだいぶ省略、やっつけ処理

// 初期化

static CImageimage;
HRESULTresult= image.Load(TEXT("c:/work/cg4.jpg"));
ASSERT(SUCCEEDED(result));
pict.SetBitmap(image);
pict.GetClientRect(backRct);
CDC*dc= GetDC();
ASSERT_VALID(dc);
VERIFY(backDc.CreateCompatibleDC(dc));
VERIFY(backBmp.CreateCompatibleBitmap(dc, backRct.Width(), backRct.Height()));
oldBmp= backDc.SelectObject(&backBmp);
VERIFY(ReleaseDC(dc));

// 描画

CPaintDCdc(this);
CDC*frontDc= pict.GetDC();
VERIFY(backDc.BitBlt(backRct.left,backRct.top,backRct.right,backRct.bottom,frontDc,0,0,SRCCOPY));
CPenpen;
VERIFY(pen.CreateStockObject(WHITE_PEN));
CPen*oldPen= backDc.SelectObject(&pen);
backDc.MoveTo(10,10);
backDc.LineTo(100,100);
backDc.SelectObject(oldPen);
VERIFY(frontDc->BitBlt(backRct.left,backRct.top,backRct.right,backRct.bottom,&backDc,0,0,SRCCOPY));
pict.ReleaseDC(frontDc);

//CDialog::OnPaint();

これで、ダイアログを無効化せずにピクチャだけ無効化するとcg4の上に線が引かれます。ダイアログの無効化ではcg4が表示されるのみで、線は引かれません。
    • good
    • 0

> ピクチャからビットマップを取得しtestに入れて、



ぱっと見、この処理が見当たりません。

> HBITMAP test=CreateCompatibleBitmap(hdc->m_hDC,256,256);

このAPIは、互換ビットマップを作るだけで、画像自体はコピーしてくれません。

この回答への補足

MrBanさん回答ありがとうございます。
CreateCompatibleBitmapを調べたところ
仰るとおり互換のビットマップだけでした。
なのでBitbltを用いtestにコピーをとりそこに描画し、
ピクチャにBitbltで戻す。という事をやってみました。

ソースの変更点は以下の通りです
-------------------------------------------------------------
HBITMAP test=CreateCompatibleBitmap(hdc->m_hDC,256,256);
//ピクチャからビットマップを初期化
dc.BitBlt(0,0,256,256,hdc,0,0,SRCCOPY);//ピクチャのDCからビットマップtestへBitblt
~~~
dc.MoveTo(10,10);
dc.LineTo(100,100);//とりあえず斜めに線を引けるように。
hdc->BitBlt(0,0,256,256,&dc,0,0,SRCCOPY);//ビットマップtestからピクチャのDCへBitblt
--------------------------------------------------------------
以上の事を行ってもhdcへ描画されませんでした。
m_StaticPicture.SetBitmap(test);
UpdateData(FALSE);
を最後のBitbltの代わりに行うと、testの中身は相変わらず真っ黒な画像でした。


ここから考察して、
ピクチャからメモリDCへのBitBlt
メモリDCからピクチャへのBitBlt
が行えていない(行えない)、と考えているんですが実際のところどうなんでしょうか?

補足日時:2006/05/02 14:21
    • good
    • 0

>ウィンドウが隠れた後等の再描画時に引いた線が消えてしまいます。


それは
>void CtestpictDlg::OnBnClickedDraw()//コマンドボタンを押した時に処理
で線の描画をしているからです。
普通、これらの描画処理はOnPaintで行います。

この回答への補足

FAYさん回答ありがとうございます。
DialogのOnPaint時にOnBnClickedDraw();を呼んでみましたが、
>//m_StaticPicture.SetBitmap(test);
>//ここでtestを見てみると真っ黒な256*256の画像
と同じく真っ黒な画像になってしまいました。

やりたい事としては裏画面(HBITMAP)に
マウスで線や円の描画を行ってそれを
ピクチャに表示したいのですが…。

上のプログラムは
ピクチャからビットマップを取得しtestに入れて、
testをdcに結びつけdcで描画、
それをBitBltでピクチャに転送。
というような事ができると思っていました。

しかしtestの中は真っ黒で線さえ引けていませんでした。

CDCを使ってHBITMAPに描画する、
というソース部分は合っていますでしょうか?

補足日時:2006/05/01 13:14
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!