はじめまして、しかごと言います。今回、どうしてもこれ以上進めなくなって、
質問させていただきます。
今私は、リストボックスに表示されているビットマップファイル名を選択すると、
ピクチャーコントロールにそのビットマップが表示されるようなものを作っています。
簡単に言えば、デスクトップの壁紙選択画面のようなものです。
全ての処理は、メインのダイアログのほかに、モードレスダイアログを作成し、そこで
処理を行っています。
一番最初は、ピクチャーコントロールにCStatic変数を割り当て、SetBitmapで選択した
ビットマップのハンドルを指定して表示しようとしました。
ソースは以下のよう感じです。
HBITMAP hbmp = (HBITMAP)::LoadImage(NULL, pathname[t_num], IMAGE_BITMAP, 0, 0,
LR_LOADFROMFILE);
m_pic.SetBitmap(hbmp);
>このコードは、リストボックスの選択変更時に呼び出されるOnSelChangeList関数内に
記述しています。
しかし、この場合ピクチャーコントロールがビットマップの大きさに変化し、ビットマ
ップが大きすぎると、リストボックスなどにかぶさってしまいます。
なので、ビットマップを読み込むCDIBクラスを作成し、そのクラスを呼び出してピクチ
ャーコントロールに合う大きさに変更させて、表示させようとしました。
CDIBクラスを作成し、ビットマップも一応表示されるような感じになったのですが、そ
れが一瞬しか表示されず、その後すぐに消えてしまいます。
なにをどうしたらいいか、さっぱりわかりません。
もし宜しければ、教えてください。
*開発環境
OS:WinXp(sp2) 開発環境:VisualStudio2005、MFC(ダイアログベース)
以下に、関係があるだろうと予想している部分のソースを書きます。
CDIB m_dib;
void C×××::OnChangeTexList()//LBN_SELCHANGEがきたら呼び出される。
{
// TODO: ここにコントロール通知ハンドラ コードを追加します。
m_dib.Open(pathname[t_num]);//ファイルオープン
Invalidate(FALSE);
UpdateData(TRUE);
m_row = m_dib.getWidth();
m_colum = m_dib.getHeight();
m_scale = (float)(m_dib.getPixbits());
UpdateData(FALSE);
}
>CDIBクラスのOpen関数内で、pathnameで指定されたファイルのビットマップ情報を読
み込んでいます。
void C×××::OnPaint()
{
CPaintDC dc(this); // device context for painting
// TODO: ここにメッセージ ハンドラ コードを追加します。
// 描画メッセージで CDialog::OnPaint() を呼び出さないでください。
CRect myRect;
CClientDC *pdc;
CWnd* myPICT=GetDlgItem(IDC_TEX_PICT);
pdc = new CClientDC(myPICT);
myPICT->GetClientRect(myRect);
if(m_dib.IsValid())
m_dib.Draw(pdc,0,0,(int)(myRect.Width()),(int)(myRect.Height()));
ReleaseDC(pdc);
delete pdc;
}
>CDIBクラスのDraw関数内で、DrawDibDraw関数を使い表示してます。
ピクチャボックスに描画した内容は一時的なもので、ピクチャボックス自身の描画
で上書きされたのではないかと思います。ピクチャボックスを非表示にしたり、枠の
みにすることで対処できるかも知れませんが、ピクチャボックスの意味が無いので
余りお勧めできません。
ピクチャボックスへのピットマップ設定は出来ているようですので、メモリ上に表示
用のビットマップをつくりそれをピクチャボックスに設定する方法はどうでしょう?
方法自体はオフスクリーン描画等といわれる方法とほぼ同じものです。
1、CreateDIBSectionやCreateDIBitmapやCreateCompatibleBitmapで描
画対象のクライアントサイズ分のビットマップを作りる。
2、作成したビットマップをピクチャボックスに関連付ける。
3、CreateCompatibleDCやCreateDCで作ったHDCに先ほどのHBITMAPを
SelectObjectで選択する。
4、作成したHDCに対して描画を行ってHBITMAPを更新して、さらに
InvalidateRectなどでピクチャボックスを再描画する。
5、描画内容変更のたび、4を繰り返しでいけると思います。
6、終了時に全ての変更を元に戻すなりして後始末をする。
MFCに依存しないAPIでの説明ですので、適宜読み替えてください。
DCとピクチャボックスに同時に一つのビットマップを関連付けることが許されるのか
どうか分かりませんので、同時が駄目ならば描画中はダミーを選択させるなどし
て下さい。
MSDNで探せば載っている気もするんですが、分かりませんでした。
う~ん、、、ぱっと見、ちゃんと動きそうですけどね。
「ここがおかしい」と言えれば良いんですけど私程度では思いつかないので
こちらで確認したコードを示しておきます。
CBitmap m_Bitmap;
CDC m_memDC;
void C×××::OnChangeTexList()//LBN_SELCHANGEがきたら呼び出される。
{
HBITMAP hbmp = (HBITMAP)::LoadImage(
NULL, d:\\aaa.bmp, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE |
LR_CREATEDIBSECTION );
m_Bitmap.Detach();
m_Bitmap.Attach(hbmp);
CClientDC clientDC(this);
m_memDC.DeleteDC();
m_memDC.CreateCompatibleDC(&clientDC);
m_memDC.SelectObject(&m_Bitmap);
Invalidate();
}
void C×××::OnPaint()
{
CPaintDC dc(this); // device context for painting
// TODO: ここにメッセージ ハンドラ コードを追加します。
// 描画メッセージで CDialog::OnPaint() を呼び出さないでください。
if (m_Bitmap.GetSafeHandle()) {
CRect myRect;
CWnd* myPICT = GetDlgItem(IDC_TEX_PICT);
CDC* pdc = myPICT->GetDC();
myPICT->GetClientRect(myRect);
pdc->BitBlt(0,0, myRect.Width(), myRect.Height(), &m_memDC, 0,0, SRCCOPY);
myPICT->ReleaseDC(pdc);
}
}
ビットマップファイル全体を表示するならBitBlt→StretchBlt
あ、もしかしたらCDIBクラスに問題があるかもですね
興味あって再現テストしたいのだが、不明点がいくつか・・・
>CDIBクラスを作成し、ビットマップも一応表示されるような感じになったのですが、
そ
>れが一瞬しか表示されず、その後すぐに消えてしまいます。
一瞬表示して、どのように消えるのかな?
①なにも表示されない。ウインドウ背景となる?
②m_pic.SetBitmap(hbmp)で結びつけた画像に戻る?
ピクチャコントロールのプロパティは?
①フレーム
②ビットマップ
③オナードロー
hbmpはどうしてる?
①初期表示終わったらDeleteObjectしてる?
②そのまま放置?
CDIBって何者?
麩さんありがとうございます。これから調べながら試して見たいと思います。
FUKUさん、ありがとうございます。せっかくビットマップの読み取りクラスを作っ
たので、少し粘ってみてダメだったらFUKUさんのやり方を参考にやってみたいと思いま
す。
一さん、ご指摘の点は以下のようになります。
>一瞬表示して、どのように消えるのかな?
ピクチャーコントロールのTypeを四角形にして白にしているので、一瞬表示された後、
その白色に戻ります。
>ピクチャコントロールのプロパティは?
先ほど書いたように、四角形にしています。
>hbmpはどうしてる?
hbmpを使用しているほうは、一応表示はされるのですが、ピクチャーコントロールがbmp
画像の大きさになり、他のコントロールにもかぶってくるので、そちらでの方法は今は
やっておりません。分りにくくて申し訳ありません。
ただ、hbmpはそのまま放置していました。
>CDIBって何者?
ビットマップデータを読み込み、表示するクラスです。
皆様、色々なご意見ありがとうございます。
これから、皆様に意見を参考に色々やってみます。作成するのが遅いので、時間がかか
るかもしれませんが、解決したらきちんと書かせていただきます。
色々と試して見た結果、麩さんのおっしゃっていた通りピクチャーコントロール自身の
描画で上書きされていたみたいです。
コントロールのTypeを四角形から、フレームに変更したらきちんと表示されました。
今は、その場しのぎ的な感じなのですが、Typeをフレームにして、一度コントロール内
を白で塗りつぶしてから、表示させるようにしています。
なんとなくそれっぽく見えるので、取りあえずはこれで様子をみてみます。
すいません、解決にチェックを入れるのを忘れていました。
皆さんありがとうございました。