VC++6.0 XP
ピクチャボックスに作図した図を表示させたいので、
メモリDC上にビットマップ形式で作図し、それをCStatic::SetBitmap()
で表示させようとしています。(この方法自体、自信がないです)
結果、作図処理は、省いていますが、以下のソースになっています。
CStatic::SetBitmap()の引数は、ビットマップハンドルなので、
メモリDCのビットマップハンドルを入手できる?
入手できたら、いいとおもうのですが、よくわかりません。
詳しい方、よろしくおねがいします。
void CSDisp::OnPaint()
{
CPaintDC dc(this); // 描画用のデバイス コンテキスト
// TODO: この位置にメッセージ ハンドラ用のコードを追加してください
if (m_FirstFlag) {
m_FirstFlag = FALSE ;
m_pDC.CreateCompatibleDC(&dc) ;
m_pDC.SelectObject(&m_Bitmap);
m_pDC.FillSolidRect(0,0,128,64,RGB(0,0,255));
}
//m_PictはCStatic (ピクチャーボックス)のメモリDC上の絵を表示させたい
m_Pict.SetBitmap(m_Bitmap) ; <--ここで落ちる。
}
CWnd *wnd = GetDlgItem( 対象のコントロールID);
CDC *dc = wnd->GetDC();
で、対象にしたいコントロールのデバイスコンテキストを利用できるようになる
これに対し、メモリDCをBltすればいける
・・・はず
>詳しい方、よろしくおねがいします。
詳しくない方は返事書いちゃいけないということですか?
ソースからして MFC をお使いのようだと判断しましたが、
(環境については文面から推し量らなくてもいいように書いてくださいね)
何故 OnDraw ではなく OnPaint を使うのかが分らないなど幾つか
不明な点がありますが、一番分らないのは、ここで落ちると説明が
ある点です。そこで落ちることはどうやって確かめたのでしょうか?
もしデバッガーでシングルステップして落ちたことを確かめたのであれば
そのときの m_Pict や m_Bitmap やの値について何も気にしていなかった
のでしょうか?
更に、
>m_pDC.SelectObject(&m_Bitmap);
は成功しているのですか?
また、m_Bitmap 名前からしてメンバー変数なのでしょうが
実際にはいつ、どこでどのようにして内容(実体)を作っているのか
知りたいと思います
ryoさん、レスありがとうございます。
CStatic のヘルプを見ると、描画関連のメソッドがないように思えたので、
一度ビットマップ形式のメモリに書かなくてはならないのかな?
と思いまして、そうしましたが、
こういうものが使えるなら、わざわざビットマップへ書き込む必要はない?のではと思
えてきました。
しかし、以下のようにコーディングすると一瞬描画するのですが、すぐきえてしまいま
す。
void CSDisp::OnPaint()
{
CPaintDC dc(this); // 描画用のデバイス コンテキスト
// TODO: この位置にメッセージ ハンドラ用のコードを追加してください
CWnd *wnd = GetDlgItem(IDC_PICT);
CDC *PBoxDC = wnd->GetDC();
PBoxDC->LineTo(300,300) ;
}
*IDC_PICTは、対象のコントロールIDです。
しまさん、レスありがとうございます。
不明瞭な点がありまして、申し訳ございませんでした。
おっしゃるとおりMFCをつかっています。
アプリケーションウィザードを使って、ダイアログベースを指定して、
そのダイアログにピクチャーボックスをリソースエディタで貼り付けて、
そのピクチャーボックスに作図したグラフを書きたいのですが、
CStaticのヘルプを見ると、描画メソッドが無いように思えたので、
一度、ビットマップに作図する必要があるのかな?と思いまして、
このような、質問をさせていただきました。
> 詳しくない方は返事書いちゃいけないということですか?
そんなことはありません。
気をわるくされたのならもうしわけありませんでした。
> OnDraw ではなく OnPaint を使うのか
ダイアログベースなのでOnDraw()はないです。(と思っています)
クラスウィザードでWM_PAINTのメッセージに対し関数を作成すると、OnPaint()がでてき
たので、これでいいのでは?と考えています。
>一番分らないのは、ここで落ちると説明がある点です。
落ちたのは、ステップ実行して確かめました。
SetBitmap()の引数は、ビットマップハンドルなので、メンバ変数のアドレスを渡して
も、落ちるのはしかたがないと思えるのですが、もともと、ただ、ピクチャーボックス
へ絵を表示するぐらいで、ここまでまわりくどいことをしなければならないのかわから
ないので、そのあたりのことも含めて質問しました。
文章を簡潔にしたいあまり、書き足りないことがたくさんありましたことをおわびいた
します。レスポンスありがとうございました。
あるビットマップを、同時に複数のDCに選択させることはできません。
提示の例だと、
CBitMap * BmpOld = m_pDC.SelectObject(&m_Bitmap);
m_pDC.FillSolidRect(0,0,128,64,RGB(0,0,255));
m_pDC.SelectObject( BmpOld); //選択を外す
の様に、選択を外さないと、当該のビットマップ=m_Bitmapを
他のオブジェクトに渡しても、そのオブジェクトは、
そのビットマップに対して何もできません。
仲澤@失業者さん、レスありがとうございます。
ビットマップを使わなくてもいいのでは、という考え方になってきています。
void CSDisp::OnPaint()
{
CPaintDC dc(this); // 描画用のデバイス コンテキスト
// TODO: この位置にメッセージ ハンドラ用のコードを追加してください
CWnd *wnd = GetDlgItem(IDC_PICT);
CDC *PBoxDC = wnd->GetDC();
PBoxDC->LineTo(300,300) ;
}
とすると一瞬書きますが、すぐ消えてしまいます。
わたしの推測ですが、ダイアログ全体の描画、ラインの描画、コントロールの描画とい
う順になっていて、OnPaint()で記述する事がだめ?なのではないでしょうか?
CPaintDC の宣言をはずせば、1度目はうまくいきます。
もちろん、再描画が必要になったとき、だめです。
void CSGrafView::OnPaint()
{
// CPaintDC dc(this); // 描画用のデバイス コンテキスト
// TODO: この位置にメッセージ ハンドラ用のコードを追加してください
CDC *PictDC = m_GrafPict.GetDC() ;
PictDC->LineTo(300,300) ;
// Sleep(1000) ;
// 描画用メッセージとして CDialog::OnPaint() を呼び出してはいけません
}
オーナードローで描画するのではまずいのでしょうか?
void CDlgTestDlg::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct)
{
// TODO: ここにメッセージ ハンドラ コードを追加するか、既定の処理を呼び出しま
す。
if( lpDrawItemStruct->CtlID==IDC_PICBOX && (lpDrawItemStruct->itemAction &
ODA_DRAWENTIRE) )
{
::FillRect( lpDrawItemStruct->hDC, &(lpDrawItemStruct->rcItem), (HBRUSH)
GetStockObject( WHITE_BRUSH ) );
::MoveToEx( lpDrawItemStruct->hDC, 0,0, NULL );
::LineTo( lpDrawItemStruct->hDC, lpDrawItemStruct->rcItem.right,
lpDrawItemStruct->rcItem.bottom );
}
else{ CDialog::OnDrawItem(nIDCtl, lpDrawItemStruct); }
}
思うんですが、ViewのOnPaintでStaticコントロールのDCに
描画しようとしているのがそもそも間違いなんじゃないかという気がします。
Staticコントロールもウインドウなわけですから、コントロール自身の
OnPaintもあると思います。コントロール自身のOnPaintよりも前の段階で
無理やりCStaticのDCに描画しても自身のOnPaintで上書きされるのではないでしょうか。
CStaticのDCに描きたいのか、CStaticの位置に描画出来れば良いのかで
話が違ってくるような気がします。CStaticのDCに描画したいのであれば、
CStatic自身のOnPaintで描画するか、オーナードローで描画すると言う事に
なるのではないでしょうか。
位置をあわせたいだけならCStaticの枠にしておいて描画その物は
ViewのDCに対して行なうという方法もありますよね。
ホウジョウウサギさん、PATIOさん、レスありがとうございます。
>Staticコントロールもウインドウなわけですから、コントロール自身の
OnPaintもあると思います。コントロール自身のOnPaintよりも前の段階で
無理やりCStaticのDCに描画しても自身のOnPaintで上書きされるのではないでしょう
か。
理解を深める上で、すごく重要なコメントです。ありがとうございます。
>CStatic自身のOnPaintで描画するか、オーナードローで描画すると言う事に
なるのではないでしょうか。
CStatic自身のOnPaintということですと、CStaticをオーバロードする必要があるとおも
いますので、リソースエディタでどの位置にピクチャーボックスを貼り付けるとか作業
はできない?のではないのでしょうか?
ということは、ホウジョウウサギさんもいっていただいている通り、オーナドロー?
オーナドローについてあまり知りませんので、いまから調べてみます。
SS_BITMAPじゃないの?
作図ごのBitmapでピクチャボックスならWM_PAINTじゃなくてもいいんじゃない
詳しくないけどゴメンネ
最初に色々と状況をきいておくべきだったかな
とりあえず、MFC・ダイアログベースで話すすめます。
ダイアログベースであるならば、描画すべきタイミングはベースになるダイアログの
OnPaintで行います
この、OnPaintはダイアログベースで作成したのなら
最初からで追加されているはず(VC6もたぶん・・・)
なので、クラスウィザードで追加する必要はないと思います。
さらに、ダイアログのOnPaintは
void CxxxDlg::OnPaint()
{
if( IsIconic() ){
//略 今回は使わないので無視
}
else
{
CDialog::OnPaint();
//使うのはこの領域 (*1)
}
}
となってるはずで
CPaintDC dc(this);
は、通常かかわってこない。
*1のところに
CWnd *wnd = GetDlgItem(IDC_PICT);
CDC *PBoxDC = wnd->GetDC();
PBoxDC->LineTo(300,300) ;
これを置いてみて試してください
ってなわけで
>クラスウィザードでWM_PAINTのメッセージに対し関数を作成すると、OnPaint()がでてき
>たので、これでいいのでは?と考えています。
ここで追加した対象の”クラス”や
>void CSDisp::OnPaint()
>void CSGrafView::OnPaint()
これらのクラスは何ものでしょうか?
追記
ダイアログベースではなく、実はフォームビューとかだったりするなら
CWnd *wnd = GetDlgItem(IDC_PICT);
をしたあと、GetWindowRectとScreenToClientを使って、
対象のコントロールの位置を取得
CPaintDC dc(this);にたいし、取得した位置に合わせてかけばいいはず
>ビットマップを使わなくてもいいのでは、という考え方になってきています。
では、ピクチャボックス(static)を使う意味はなんでしょう。
自分のWM_PAINTで、自分のクライアント領域の好きな部分に、
好きに描画すれば良いだけですよねぇ(笑)。この場合でもビットマップを
使用したほうが、ややクレバーだと考えられますけど(vv;)。
さて、いったい何の問題があるのかさっぱりわからなくなってきましたが、
本当は何がしたいのか、「したいこ」とを具体的に述べると、もっと
ましな回答が付くかもしれません。