お世話になります、fujicafeです。
現在、MFCにてダイアログベースのアプリケーションを作成中なのですが、ダイアログにビットマップを貼り付けてOnPaint()で表示するようにプログラムを作成したのですが、何度かダイアログの表示を繰り返すとOnPaintでのビットマップの読み込みが途中まででフリーズしてしまう現象が起きてしまいました。
プログラムは以下のように作成しています
void C****Dlg::OnPaint()
{
 CDC* pDC = this->GetDC();
CDC myDC;
CBitmap newbitmap;
CBitmap* oldbitmap;
CRect rc;
GetClientRect(rc);
newbitmap.LoadBitmap(IDB_BITMAP);
myDC.CreateCompatibleDC( pDC );
oldbitmap=myDC.SelectObject( &newbitmap );
pDC->BitBlt( 0, 0, rc.Width(), rc.Height(), &myDC, 0, 0, SRCCOPY );
myDC.SelectObject(oldbitmap);
}
としています。
初めにこのダイアログを表示時は、ちゃんとビットマップが表示されるのですが、他のダイアログでこのダイアログを表示させた時にビットマップが上半分まで表示されて、動作がフリーズしてしまう現状です。

なにかよい打開策がありましたら、教えていただけたらと思っています。宜しくお願いいたします。

このQ&Aに関連する最新のQ&A

A 回答 (5件)

 こんにちは。

補足頂きました。
 よく考えたら、CBitmapのデストラクタでビットマップが消去されているので、リークではなかったかもしれません。
 http://msdn.microsoft.com/ja-jp/library/wc99t364(VS.80).aspx

・なにかまだ考えられることがありましたら宜しくお願い致します。
 取りあえず、当方もフリーズの経験があるのですが、確りとCPaintDCの方を使用していますでしょうか。
 OnPaint()(WM_PAINTメッセージ相当)の中では、GetDC()/ReleaseDC()を使用して描いてはならず、BeginPaint()/EndPaint()相当(CPaintDC)に描かせます。
 http://msdn.microsoft.com/ja-jp/library/a48eab8d(VS.80).aspx
 http://orangeknowledge.jpn.org/report060325.html

 後、提示したコードが良くなかったかもしれません。以下の様にして見て下さい。

void C****Dlg::OnPaint()
{
CPaintDC paintDC(this);//此れじゃないと問題を起こす事がある
CDC myDC;

CBitmap* oldbitmap;
CRect rc;
GetClientRect(rc);

myDC.CreateCompatibleDC(&paintDC);

oldbitmap=myDC.SelectObject( &m_newbitmap );
paintDC.BitBlt( 0, 0, rc.Width(), rc.Height(), &myDC, 0, 0, SRCCOPY );
myDC.SelectObject(oldbitmap);

//不安なら以下をコメントアウト
//myDC.DeleteDC();
}
    • good
    • 0
この回答へのお礼

詳細な情報ありがとうございます。
早速、ご提示頂いたコードで動作させてみました。
結果としては
前回と同様にフリーズしてしまいました。
コードを提示して頂いて、ただ出来ない出来ないと文句を言っているようで本当に大変申し訳ございません。
私なりにもしらべて見たのですが、4つの各ダイアログを呼び出すメインダイアログ1,2にはピクチャーコントロールがあり、それぞれがビットマップを表示するようにしています。このピクチャーコントロールへのビットマップの貼り付け方法なのですが、ピクチャーコントロールのプロパティでイメージにビットマップのIDを選択させてビットマップを表示させるようにしているのですが、この方法ですと何か問題はありますでしょうか?

背景のビットマップと同様に、各ピクチャーコントロールに対するビットマップもOnInitialDialog()内で貼り付けて、OnPaintでBitBltで表示するようにしたらよいのでしょうか。
質問するくらいなら実際にやればいいのでしょうが、なぜかうまくその方法ですとピクチャーコントロールに画像が描画されないため悩んでいるところです。
たびたびの質問で申し訳ございません。

お礼日時:2009/05/20 13:39

>何度かダイアログの表示を繰り返すとOnPaintでのビットマップの読み込みが途中まででフリーズしてしまう現象が起きてしまいました。



デバイスコンテキストを「使いっぱなし」にしてはいけません。使った物はちゃんと片付けましょう。

GetDCした場合、そのデバイスコンテキストを使い終わったらReleaseDCしなければなりません。

ReleaseDCをせずにGetDCを何度も繰り返すと、デバイスコンテキストのロックリソースが尽き、デバイスコンテキストへのアクセスが出来なくなったり(つまり、画面の描画が出来なくなったり)、スレッドが応答しなくなったりします。

また、CreateCompatibleDCで作成したデバイスコンテキストも、使い終わったらDeleteObjectで削除しなければなりません。

DeleteObjectをせずにCreateCompatibleDCを何度も繰り返すと、デバイスコンテキストのリソースが尽き、デバイスコンテキストへのアクセスが出来なくなったり(つまり、画面の描画が出来なくなったり)、スレッドが応答しなくなったりします。

以下の2点にご注意下さい。

・GetDCでデバイスコンテキストを占有した場合は、必ずReleaseDCで不要になったデバイスコンテキストのロックを解除して開放すること。

・CreateCompatibleDCでデバイスコンテキストを作成した場合は、必ずDeleteObjectで不要になったデバイスコンテキストを削除すること。

因みに、デバイスコンテキストは「各スレッドで同時に使えるのは16個くらい」なので、ダイアログの表示を5~8回も行えば、デバイスコンテキストのリソースが尽き、プロセスがフリーズするでしょう。

なお、あくまでも「同時に使えるのは」です。

なので「占有→使用→開放を16回以上」はOKです。これは「同時に使っているのは1個だけ」なので、何の問題もありません。

ですが「占有→使用→放置を16回以上」はNGです。これは「同時に使っているのは16個以上」なので、リソース不足でダウンします(質問者さんのプログラムが、この状態になっている)
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。
早速、CreateCompatibleDCを仕様したデバイスコンテキストをDeleteObjectしてみたのですが、やはりフリーズします。
そこで、CpaintDCを使用してBitBltしている箇所をあえて、
CDC* pDC = this->GetDC();
でデバイスコンテキストを取得し、最後にReleaseDCで解除するように変更したのですが、やはりフリーズしてしまいました。

呼び出す側のピクチャーコントロールへのビットマップの貼り付けをはずすか、呼ばれるダイアログの背景のビットマップの貼り付けをはずすとフリーズせずに動作するようなのですが、これは使用しているマシンの性能の問題なのでしょうか?
開発で使用しているマシンがPCではなく、組み込みのマシンのためそういう問題もあるのかなと思っています。

お礼日時:2009/05/20 15:39

CBitmap が、どう振舞うのか?


メモリデバイスコンテキストはどう使うのか?
このあたりの基本を勉強したほうがいいです。

newbitmap もメンバにしないといけないはずです。
    • good
    • 0
この回答へのお礼

ご指示ありがとうございます。
確かに、本やネットをみて、このコードでならビットマップ
が貼り付けれるとしか考えていなかったです。
しっかりとメモリデバイスコンテキストの振る舞いやCBitmap
について勉強し直さなければならないみたいです。

CBitmapをメンバ変数にしてみましたが、結果は変わらずでした。
もしかしたら
ダイアログ内のピクチャーボックスにビットマップを貼り付けている
のですが、その貼り付け方法がプロパティのイメージでビットマップの
IDを選択している
ということも影響の要因なのかなと思っています。
これも関係ありますでしょうか?

お礼日時:2009/05/20 12:48

myDCはメンバ変数にして、


OnPaintでは、BitBltだけするようにしたほうがいいですよ。
    • good
    • 0
この回答へのお礼

早速の返信ありがとうございます。
myDCをメンバ変数とすると、ダイアログ上のコントロールをクリック
するとエラーがでてストップしてしまうみたいです。
myDCを元のOnPaint()上に戻すと、コントロールは動作しますがやはりビットマップ呼び出し時にフリーズしてしまいます。

お礼日時:2009/05/20 09:19

 こんばんは。


 OnPaint()が呼ばれる度に、ビットマップをリソースからロードしているので、リークを起こしているのではないでしょうか。
 newbitmapをメンバ変数にして、OnInitDialog()で作成して置くのが無難です。
 後、OnPaint()でダイアログに描写する際は、CDCではなくて、PaintDCの方ではないでしょうか。
 以下では駄目でしょうか。

class C****Dlg
{
private:
CBitmap m_newbitmap;//ヘッダに移動
};

BOOL C****Dlg::OnInitDialog()
{
// TODO: 特別な初期化を行う時はこの場所に追加してください。

//此処で作成しておく
m_newbitmap.LoadBitmap(IDB_BITMAP);

return TRUE; // TRUE を返すとコントロールに設定したフォーカスは失われません。
}

void C****Dlg::OnPaint()
{
//再描画で使用するDC
CPaintDC paintDC(this);
CDC myDC;

CBitmap* oldbitmap;
CRect rc;
GetClientRect(rc);

//互換メモリデバイスコンテキストの作成
CDC* pDC = this->GetDC();
myDC.CreateCompatibleDC(pDC);
ReleaseDC(pDC);

//選択して書く
oldbitmap=myDC.SelectObject( &m_newbitmap );
paintDC.BitBlt( 0, 0, rc.Width(), rc.Height(), &myDC, 0, 0, SRCCOPY );
myDC.SelectObject(oldbitmap);
}

この回答への補足

もう一つ付け加えなのですが、メインダイアログ1で4つのダイアログ
を各コントロールから呼び出す際には今回のような症状が出ていません。
メインダイアログ1からメインダイアログ2を呼び出して、さらにそこから4つのダイアログを呼び出していった時の4番目のダイアログの呼び出し時に必ずこの現象が生じるようです。

補足日時:2009/05/20 09:28
    • good
    • 0
この回答へのお礼

丁寧な説明ありがとうございます。
早速、教えて頂いた通りにビットマップの呼び出しをOnInitDialog()
に移動させ、OnPaint()内ではBitBltのみを処理するようにして観ました。
結果としては、以前と同様にビットマップの呼び出しで動作がフリーズしてしまいます。でも、確かにメモリリークを起こしているような気がします。
現在のプログラムの詳細な状況を説明させていただきますと、
メインのダイアログが2つありまして、それをメインダイアログ1,メインダイアログ2とします。
メインダイアログ1からメインダイアログ2を呼び出すにはF1キーで呼び出します。メインダイアログ1,メインダイアログ2にはそれぞれ同じボタンが4つありまして、4つのボタンで4つのダイアログを表示させます。ダイアログは全て背景をビットマップとしています。
現在の症状としては、フリーズするときにはダイアログ上の背景ビットマップが約上半分表示され、ダイアログ上のコントロールは全て空白となり、呼び出したメインダイアログの背景が透けて見えるといった状況です。
開発環境がWindows CE6.0でVisualStudio2005なのが不安ではあるのですが、なにかまだ考えられることがありましたら宜しくお願い致します。

お礼日時:2009/05/20 09:27

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

このQ&Aを見た人が検索しているワード

このQ&Aと関連する良く見られている質問

Q画面の設定以外で文字の大きさを変更したい場合

こんばんは。WinXPを使っています。
画面のプロパティーから解像度を変更しても、文字の大きさが大きく感じます。WinXPの画面の設定から文字の大きさを変更する場合は解像度を変更しればいいと思うのですが、それでも小さくならない場合はどのようにして文字を小さくする事ができるでしょうか?

Aベストアンサー

解像度以外の手段では
画面のプロパティ→「デザイン」タブ→詳細設定
で、アクティブタイトルバー、パレットタイトル、ヒント、メッセージボックス、メニュー、選択項目、非アクティブタイトルバーの文字の大きさをポイント単位で変更できます。

ブラウザの文字の大きさなら、ブラウズの最中にマウスのスクロールボタンをCtrlボタンを押しながらグリグリすると5段階に変更できます。

ExcelやWordでしたら、ツール→オプション→全般タブから標準の文字の大きさをポイント単位で変更できます。

Qダイアログのボタンが押された時に、その「ボタン」のあるダイアログと、すでに表示されている他のダイアログを消したいです

Win2000/MFC/ダイアログベース
で作業しています。初心者です(^^;)

Aというダイアログで「あるボタンa」を押してDoModalでBというダイアログを表示させ、Bダイアログで「あるボタンb」を押してDoModalでCというダイアログを表示させ、Cダイアログで「あるボタンc」を押した時にBダイアログとCダイアログを閉じたい(消したい)のですが
EndDialogで消せません
DoModalの戻り値をret_b,ret_cとした場合
EndDialog(ret_c);
EndDialog(ret_b);
としたのですが。。。

やり方がおかしいのか、よくわかりません・・
初心者でもわかりやすいお返事お待ちしています(^^;)

Aベストアンサー

各ダイアログボックスを CDialog の派生クラスとして次のように定義したとします。

CDlgA --- A というダイアログボックス
CDlgB --- B というダイアログボックス
CDlgC --- C というダイアログボックス

CDlgA のあるメンバ関数から CDlgB::DoModal() でダイアログボックス B を表示させます。 CDlgB のあるメンバ関数で EndDialog() を実行すればダイアログボックス B を閉じることができます。ここで、 CDialog::EndDialog() は引数として INT 型の値をひとつ渡すことができますが、その値が先の CDlgB::DoModal() の戻り値となります。
戻り値がある特定の値だったとき、つまり、質問の例ではダイアログボックス B で EndDialog(ret_b) が実行されたことが特定できたときに CDlgA も EndDialog() を実行すれば連鎖してダイアログボックスを閉じることができます。
ダイアログボックス C についても同様です。

実際のコーディングでは次のようになると思います。
ただし、ダイアログボックス A もモードレスで表示されていると仮定しています。



#define ret_b (-1) // 特定の値
#define ret_c (-1) // ID_OK や ID_CANCEL と重ならないように注意

...

(CDlgA の実装)

void CDlgA::OnButtonA() // あるボタン a が押されたときの処理
{
CDlgB dlg; // ダイアログボックス B

if (dlg.DoModal() == ret_b) // モードレスで表示して、戻り値をチェック
EndDialog(-1); // ダイアログボックス A を閉じる
}

...

(CDlgB の実装)

void CDlgB::OnButtonB() // あるボタン b が押されたときの処理
{
CDlgC dlg; // ダイアログボックス C

if (dlg.DoModal() == ret_c) // モードレスで表示して、戻り値をチェック
EndDialog(ret_b); // ダイアログボックス B を閉じる
}

...

(CDlgC の実装)

void CDlgC::OnButtonC() // あるボタン c が押されたときの処理
{
EndDialog(ret_c); // ダイアログボックス C を閉じる
}

各ダイアログボックスを CDialog の派生クラスとして次のように定義したとします。

CDlgA --- A というダイアログボックス
CDlgB --- B というダイアログボックス
CDlgC --- C というダイアログボックス

CDlgA のあるメンバ関数から CDlgB::DoModal() でダイアログボックス B を表示させます。 CDlgB のあるメンバ関数で EndDialog() を実行すればダイアログボックス B を閉じることができます。ここで、 CDialog::EndDialog() は引数として INT 型の値をひとつ渡すことができますが、その値...続きを読む

Q「新しいウィンドウで開く」で開く画面の大きさの変更の仕方を教えて下さい。

 恐れ入ります。初歩的な質問で済みません。
検索結果などがたくさん出て、それら一つ一つを右クリックで「新しいウィンドウで開く」をクリックし表示される画面の大きさを変更するにはどうしたら良いのでしょうか?
 ちなみに今は画面の中央に小さく表示されるのですが、目一杯の大きさに変更したいのです。
どうか宜しくお願い致します。

Aベストアンサー

>検索結果などがたくさん出て

タブブラウザを使った方がいいかな~と思います。

IEだと仰る様に一つ一つを右クリックで「新しいウィンドウで開く」をクリック
するのも面倒ですし、下におろすのも面倒です。

タブブラウザなら、画面がウインドウだらけになるうっとうしさも無いですし、
ポップアップも制御できます。

画面の切り替えもタブをクリックするだけですし、たくさんひらいた
ページをまとめて閉じることもできます。

ご存知でしたら失礼しました。

QSendMessage(hW,WM_CREATE,0,0);を

SendMessage(hW,WM_CREATE,0,0);
を実行するとシステムがWM_DOWNやWM_CHARを発行しなくなるみたいです
というのはそれ以降キー入力を無視するようになるのです
いったんアプリをアイコン化してウィンドウ化するとWM_DOWNやWM_CHARを発行するようになります
WM_CREATEを送ってもWM_DOWNやWM_CHARを発行しなくなるのを阻止するために何か方法はないでしょうか?

Aベストアンサー

>プログラムのイニシャライズのために送ったのですが送らないで住むプログラムに変更しました

普通はそんな方法はとりません。
システムが何をするか分からないからです。

自分でメッセージを定義して、初期化処理を行うようするためのメッセージを送るほうが無難です。
WM_CREATEと同じ処理を初期化処理として行わせたいのであれば、初期化処理を関数化して自分で定義したメッセージでも呼び出せばいいのですし。


>作ったプッシュボタンを押してシステムがWM_COMMANDを送ってきた後キー関係のメッセージを送ってくれなくなります

プッシュボタンがキーボードフォーカスを持ってのるでは?

ボタンがキーボードフォーカスを持っていてもキー関連のメッセージを親ウィンドウが受け取りたいのであれば、サブクラス化をするしかないでしょう。

QOutlookメールで、画面の文字の大きさを変更するには、どうしたらよ

Outlookメールで、画面の文字の大きさを変更するには、どうしたらよいのですか。

Aベストアンサー

画面の文字の大きさは、
[表示] メニュー → [現在のビュー] → [現在のビューの編集] →
[その他の設定] と [自動書式] の項目でそれぞれフォントの大きさが変更できます。
また、送信メールとテキスト形式の受信メールのフォントの大きさは、
[ツール] メニュー → [メール形式] タブ → [ひな形およびフォント] → [ひな形] タブでそれぞれ変更できます。

Qdc.TextOut(0 ,0 , *str) ;について

環境 WIN98 VC++6.0 MFC にて

パターンBはOKですが、パターンAだと不正な処理で落ちてしまいます。

どうしてなのかお教えください。

void CFffView::OnPaint()
{
CPaintDC dc(this);
//パターンA
CString* str ;
str = (CString*)("999");
dc.TextOut(0 ,0 , *str) ;

//パターンB
CString aaa ;
aaa = (CString)("999");
dc.TextOut(0 ,0 , aaa) ;
}

Aベストアンサー

両方ダメ。
Aのパターンで動くのは、たまたま。

CString aaa ;
aaa = "999";
dc.TextOut(0 ,0 , aaa) ;

これで十分。

あえてキャストするんだったら、
CString aaa ;
aaa = (LPCSTR)"999";
dc.TextOut(0 ,0 , aaa) ;


aaa=のところでは、ただの代入が行われているわけではありません。
オーバーロードされたオペレータが呼ばれています。


>str = (CString*)m_array.GetAt(i) ;

これは、m_arrayの要素にCString*を入れていて、初めて成り立つ式です。
値をいれているところと、m_arrayの宣言を確認してください。

str = (CString*)("999");
も、
aaa = (CString)("999");
も、リテラル文字列をつっこもうとしています。
リテラル文字列とCStringはまったく別物です。

Q最初に表示されるIEの画面の大きさは、変更可能?

こんにちは、みなさん。

インターネットを見る時に、最初に表示される、インターネットエクスプローラーの
画面の大きさは変更できますか??

変更できるなら、どんなやり方ですか??

ご存知の方、いらっしゃいましたら、宜しくお願いします。

Aベストアンサー

IEを起動して始めに表示される画面(ホームページ)の状態で操作します。
マウスを使って表示させたい大きさにIEの全体のウィンドウを変更します。
任意の大きさと位置が決まったら「Shiftキー」を押しながら閉じるボタンをクリックしてIEを終了させます。

※Shiftキーでうまくいかない場合はShiftキーの替わりにCtrlキーを使って試してみてください
※大きさを決めるときは、いつも始めに開いたページでウィドウの大きさ・位置を決めるのがコツです
※IEにい限らず、エクスプローラも同じ要領で変更できます

QhPF=SelectObject(hD,hF);は何故エラーに

HFONT hF,hPF;
・・・・・・・・・・・・・・
hD=BeginPaint(hW,&ps);
hF=CreateFont(10,0,0,0,FW_NORMAL,FALSE,FALSE,FALSE,
 SHIFTJIS_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,
 DEFAULT_QUALITY,FIXED_PITCH|FF_MODERN,"System");
hPF=SelectObject(hD,hF);//ここがエラー
・・・・・・・・・・・・・・

において
hPF=SelectObject(hD,hF);//ここがエラー
を単に
SelectObject(hD,hF);//これでエラーでなくなる
とすればエラーでなくなります

エラー内容は
Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland
goo.cpp:
エラー E2034 goo.cpp 808: 'void *' 型は 'HFONT__ *' 型に変換できない(関数 __stdcall WinProcedure(HWND__ *,unsigned int,unsigned int,long) )
*** 1 errors in Compile ***

hPFを後で使いたいので困っています
どうしたらエラーがなくなるでしょうか?

HFONT hF,hPF;
・・・・・・・・・・・・・・
hD=BeginPaint(hW,&ps);
hF=CreateFont(10,0,0,0,FW_NORMAL,FALSE,FALSE,FALSE,
 SHIFTJIS_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,
 DEFAULT_QUALITY,FIXED_PITCH|FF_MODERN,"System");
hPF=SelectObject(hD,hF);//ここがエラー
・・・・・・・・・・・・・・

において
hPF=SelectObject(hD,hF);//ここがエラー
を単に
SelectObject(hD,hF);//これでエラーでなくなる
とすればエラーでなくなります

エラー内容は
Borland C++ 5.5.1 for...続きを読む

Aベストアンサー

キャストするだけのこと?

hPF = (HFONT)SelectObject(hD,hF);

Qようこそ画面アイコン大きさ変更

ようこそ画面でアイコンの大きさを変更したいのですが、どのようにしたらよいでしょうか、
ちなみに以下のレジストリー変更ではダメでした。
HKE_CURRENT_USER→desktoptop→logpixelsで数値の値を変える

Aベストアンサー

変えられないと思います。

Qint i,j; \n i=0,j=5;

int i,j;
i=0;
j=5:
と書いてあるソースは普通ですが、
int i,j;
i=0,j=5:
と書いてあるソースもあります。
後者はC++の正しい書式ですか?

カンマ演算子というのは後者のカンマのことですか?

Aベストアンサー

 正しい書式です。

i=0,j=5;
 における、「,」をカンマ演算子といいます。2項の演算子です。カンマで区切られた演算を「左から順番に」実行し、最後の演算を結果として返します。
 したがって、例の文であれば、i=0を実行し、次にj=5を実行。そして、j=5の結果の5を結果として返します。
 ・・・
 が、本来的には、あまり、例のような使い方はしませんね。よく見られるのは、次のような場合です。

 for (i=0,j=0 ; i < 50 ; ++i,++j) {

 のような形でよく見られます。for文の各式は、一つの式でなければならないので、こんな書き方をするわけです。初期化と更新部が一つにまとまり、ループが読みやすくなるのが利点かな。


人気Q&Aランキング

おすすめ情報