BMPを表示するには – プログラミング – Home

通知
すべてクリア

[解決済] BMPを表示するには


ミミ
 ミミ
(@ミミ)
ゲスト
結合: 24年前
投稿: 63
Topic starter  

こんにちは、いつもお世話になっています。
ミミです。

ダイアログにビットマップを表示し、さらに線画や文字列を描画させるため、
掲示板や参考書等を参考にし、以下の様なコードを作成しました。

目的とすることは得られたのですが、
ダイアログ表示(DoModal())、非表示(EndDialog())を繰り返していくと、
アプリ起動直後のメモリ使用量よりも、増えていきます。

どこかでリソースリークしている箇所があるのかと思い調査しているのですが、
特に★1、★2の箇所が自分でもよく分かっていないため、
今の私の知識では、最後の ReleaseDC()、DeleteDC()位しか検討がつきません。

どこか不正な箇所や、足りないところがありましたら、
どうかアドバイス願えませんでしょうか?
それと、★1、★2についてもアドバイスしていただけたら幸いです。

環境は、Windows2000、VC6 SP6 です。
よろしくお願いいたします。

<<hに定義したメンバ変数>>
CBitmap m_myBMP; //
HBITMAP m_hBitmap; //
bool m_bDspBMP; // 既にBMP表示済みか否か

<<cpp>>
//---------------------------------------
BOOL CDispBmpDlg::OnInitDialog()
{
CDialog::OnInitDialog();

m_hBitmap = false; // ビットマップハンドルはまだ無効
m_bDspBMP = false; // OnPaintでの BMP 表示フラグ
SelectFile(); // 必ず選択することを前提

return TRUE;
}
//---------------------------------------
void CDispBmpDlg::OnPaint()
{
CPaintDC dc(this); // 描画用のデバイス コンテキスト

if (!m_bDspBMP){ return; } // ファイル未選択状態時は戻る
PaintRtn(); // ペイント処理本線
}
//---------------------------------------
bool CDispBmpDlg::SelectFile()
{
CString sWkName = c:\\Test.bmp;

m_hBitmap = (HBITMAP)LoadImage(NULL, sWkName, IMAGE_BITMAP,
0, 0, LR_DEFAULTCOLOR |
LR_LOADFROMFILE);
if(m_hBitmap){
if(m_myBMP.DeleteObject()){ // 1つ昔のビットマップオブジェクト
削除
m_myBMP.Detach();
}
if(m_myBMP.Attach(m_hBitmap)){
m_bDspBMP = true;
}
}
return true;
}
//---------------------------------------
bool CDispBmpDlg::PaintRtn()
{
BITMAP myBmp;
CRect lRect;

// (1)デバイスコンテキスト生成
CDC* pDC; // デバイスコンテキストへ
のポインタ取得
pDC = GetDC(); // ここにビットマップを描
画して、文字を描く

// (2)ビットマップの表示
CDC myDC;
myDC.CreateCompatibleDC(pDC); // 作業用のデバイスコンテ
キストを作成
CBitmap* pOldBMP;
pOldBMP= myDC.SelectObject(&m_myBMP); // 古いものに関連付け(後で
戻す為)★1

m_myBMP.GetBitmap(&myBmp);
GetClientRect(lRect);
lRect.NormalizeRect();

pDC->StretchBlt(0, 0,
lRect.Width(), lRect.Height(), // ダイアログいっ
ぱいに BMPを表示 &myDC,

// 転送するデバイスコンテキスト
0, 0, myBmp.bmWidth, myBmp.bmHeight,
SRCCOPY);
myDC.SelectObject(pOldBMP); // ★2

// (3)テキストの描画
pDC->SetTextColor(RGB(0,0,0));
pDC->SetBkMode(TRANSPARENT); // テキストの背景色は透明

CRect lTextRect;
lTextRect.top = 10;
lTextRect.bottom = lRect.Height();
lTextRect.left = 0;
lTextRect.right = lRect.Width();
pDC->DrawText(あいうえお, -1, &lTextRect, DT_RIGHT);

// (4)デバイスコンテキスト解放
ReleaseDC(pDC);
DeleteDC(myDC);

return true;
}


引用未解決
トピックタグ
ミミ
 ミミ
(@ミミ)
ゲスト
結合: 24年前
投稿: 63
Topic starter  

すみません、PaintRtn()のところ、注釈がかなり見にくくなってしまいました。


返信引用
島
 島
(@島)
ゲスト
結合: 23年前
投稿: 238
 

CDialog::DoModal() によって、CDialog::OnInitDialog() が動きますから
DoModal() と EndDialog() とを繰り返すということは CDspBmpDlg::SelectFile()
を繰り返しているということはお分かりでしょうか?

> m_hBitmap = (HBITMAP)LoadImage(NULL, sWkName, IMAGE_BITMAP,
> 0, 0, LR_DEFAULTCOLOR |
>LR_LOADFROMFILE);

が CDispBmpDlg::SelectFile() での処理ですが、これから分かることは、
m_hBitmap が示すビットマップにどんどん読み込んでいるということです
LoadImage() は読み込んだ画像のハンドルを返すので、画像が溜まることになります
 勿論(もちろん)DoModal() を抜けたら Windows でのダイアログはもう存在しません
 が、CDispBmpDlg のインスタンスはまだ存在します。インスタンスが消滅しても
 読み込んだ画像はあなたが削除しない限り残るのですから
(msdn ライブラリーの LoadImage をよくお読み下さい/MSのサイトも調べましょう)
CDispBmpDlg のデストラクターで m_hBitmap を削除(DeleteObject())するといい
でしょう

OnPaint() でせっかく作っている CPaintDC dc; を PaintRtn() で使っていないのは
勿体ないと思います。
void CDispBmpDlg::PaintRtn(DC & dc) {
CDC myDC;

myDC.CreateComaptibleDC(&dc);
/
後(あと)、省略
/
}


返信引用
ミミ
 ミミ
(@ミミ)
ゲスト
結合: 24年前
投稿: 63
Topic starter  

ミミです。

島さん、いつもご親切にアドバイスありがとうございます。

>勿論(もちろん)DoModal() を抜けたら Windows でのダイアログはもう存在しませんが、
>CDispBmpDlg のインスタンスはまだ存在します。

LoadImageで得られたハンドルに対し、DeleteObject()しなくてはならないことは、
完全に見落としていました。勉強になります。
デストラクタにて、DeleteObject(m_hBitmap);を実行したところ、
メモリの上昇はなくなりました。

それと、よくよく考えてみますと、OnPaint()でローカル変数として定義しているdc、
使われていませんね。仰る通りです。

大変厚かましいとは思うのですが、
自分の中では、★印の箇所に自分で記述した注釈である「古いものに関連付け(後で戻す為)」
の必要性がいまいちピンときません。
DCを使用した描画に際しては、何故この様に古いものに戻したりする作業が必要になるのです
か?
差し支えがなければ、ご教授頂きたく思います。


返信引用
bbb
 bbb
(@bbb)
ゲスト
結合: 20年前
投稿: 4
 

>DCを使用した描画に際しては、何故この様に古いものに戻したりする作業が必要になるのです
か?

MSDNのSelectObjectの説明に

An application should always replace a new object with the original, default
object after it has finished drawing with the new object.

と書いてあるからです。
実際、選択したままのオブジェクトをDeleteObjectしても削除されずリークすると思います。


返信引用
ミミ
 ミミ
(@ミミ)
ゲスト
結合: 24年前
投稿: 63
Topic starter  

ミミです。

> 選択したままのオブジェクトをDeleteObjectしても削除されず
なるほど、理解ができました。
選択されたままだと、削除そのものが失敗するため、いくらDeleteObject()と
記述していても、実際は削除されていないという事ですね。

島さん、bbbさん、ありがとうございました。
今後もよろしくお願いいたします。


返信引用

返信する

投稿者名

投稿者メールアドレス

タイトル *

プレビュー 0リビジョン 保存しました
共有:
タイトルとURLをコピーしました