アナログデータを取り込んでオシロスコープの様に波形を描画する処理を作成しようとしております。
1.X軸、Y軸の罫線を引いた背景用のビットマップを読み込む。
2.背景を裏画面用にコピーし、グラフを描画する。
3.表示画面領域にグラフを描画した裏画面をBitBltで表示する。
の手順ですれば良いと考えております。
そこで最初にアプリケーション起動時にまず背景を読み込んで
表示しようと思い、OnInitDialog()内に
CDC* pDC = this->GetDC(); //現在のデバイスコンテキストpDC
CDC myDC; //ビットマップ表示用デバイスコンテキスト
myDC.CreateCompatibleDC(pDC); //pDCと互換のデバイスコンテキストを生成
CBitmap myBMP; //ビットマップ処理用オブジェクト
myBMP.LoadBitmap(IDB_WAVE_SCREEN); //画像読み込み
pDC->BitBlt(10,10,500,300,&myDC,0,0,SRCCOPY); //ビットマップを転送
と書き込んだのですがビットマップが表示されません。
どのようにすればよいのかアドバイスいただけないでしょうか。
OnInitDialogは,ダイアログが表示されるよりも前に呼ばれます。
OnPaint内で描画してやらないことには意味がありません。
当初は下記の様に記述し、ダイアログが表示される度に
処理が走っていることは確認したのですが、何も表示されなかった為に
OnInitDialog()に記述していました。
どうやら最初のものであっていたようですので下記の記述に戻しましたが
やはりビットマップが表示されませんでした。
IDB_WAVE_SCREENには縦300×横500で作成したビットマップを設定しています。
void CANALOGDlg::OnPaint()
{
// ---------------------------------
// グラフ領域の表示
// ---------------------------------
CDC* pDC = this->GetDC(); //現在のデバイスコンテキストpDC
CDC myDC; //ビットマップ表示用デバイスコンテキスト
myDC.CreateCompatibleDC(pDC); //pDCと互換のデバイスコンテキストを生成
CBitmap myBMP; //ビットマップ処理用オブジェクト
myBMP.LoadBitmap(IDB_WAVE_SCREEN); //画像読み込み
pDC->BitBlt(10,10,500,300,&myDC,0,0,SRCCOPY); //ビットマップを転送
CDialog::OnPaint();
}
myDCからっぽですね
myDC.SelectObject(&myBMP);
とかひつようなのではないでしょうか?
あと、CPaintDC使ったほうがらくだと思うけど
たくさんのご指摘されたことを考慮に入れて、
下記の様にすればダイアログ表示時にうまく背景が描画できました。
************************************
OnInitDialog()
{
// ---------------------------------
// グラフ領域の背景設定
// ---------------------------------
CDC* pDC = this->GetDC(); // 現在のデバイスコンテキストpDC
m_DrawDC.CreateCompatibleDC(pDC); // pDCと互換のデバイスコンテキストを生成
m_BackScreenBMP.LoadBitmap(IDB_WAVE_SCREEN); // 背景ビットマップの作成
m_DrawDC.SelectObject(&m_BackScreenBMP); // マージ領域にコピー
}
void CANALOGDlg::OnPaint()
{
CPaintDC dc(this) ;
dc.BitBlt(384,38,500,300,&m_DrawDC,0,0,SRCCOPY); //背景画面を表画面に転送。
}
************************************
これで最初の質問の1をクリアすることが出来たので
2番の処理を行おうと下記のような処理を行いましたが
うまく波形が表示されませんでした。
************************************
OnInitDialog()
{
// ---------------------------------
// グラフ領域の背景設定
// ---------------------------------
CDC* pDC = this->GetDC(); // 現在のデバイスコンテキストpDC
m_DrawDC.CreateCompatibleDC(pDC); // pDCと互換のデバイスコンテキストを生成
m_MargeDrawDC.CreateCompatibleDC(pDC); // pDCと互換のデバイスコンテキストを生成
m_BackScreenBMP.LoadBitmap(IDB_WAVE_SCREEN); // 背景ビットマップの作成
m_DrawDC.SelectObject(&m_BackScreenBMP); // マージ領域にコピー
flag = 1;
}
//-------------------------------------------------------------------
// 波形描画
//-------------------------------------------------------------------
void CANALOGDlg::WriteWave()
{
int i;
double nYten;
m_MargeDrawDC.SelectObject(&m_BackScreenBMP); // マージ領域に背景をコピー
// グラフ波形 ライン設定
CPen GraphPEN(PS_SOLID, 1, RGB(255,255,0));
m_MargeDrawDC.SelectObject(&GraphPEN);
m_MargeDrawDC.MoveTo(0, (int)(wave_zero - ((dDataV_ch[0][0] / volt_scale) * wave_zero)));
for(i = 1; i <= draw_point; i += skip_data)
{
nYten = (dDataV_ch[0][i] / volt_scale) * wave_zero;
m_MargeDrawDC.LineTo((int)(skip_draw * i),(int)(wave_zero - nYten));
}
flag = 0;
Invalidate();
}
void CANALOGDlg::OnPaint()
{
CPaintDC dc(this);
if(flag == 1)
dc.BitBlt(384,38,500,300,&m_DrawDC,0,0,SRCCOPY); //背景画面を表画面に転送。
else
dc.BitBlt(384,38,500,300,&m_MargeDrawDC,0,0,SRCCOPY); //背景画面を表画面に転送。
}
************************************
と言うように、裏画面としてm_MargeDrawDCを作成し、WriteWaveでそこに背景をコピーした後、
背景を描画してBitBltで背景及び波形を描画したm_MargeDrawDCを表示したつもりなのですが
何も表示されなくなってしまいました。
MSDNのSelectObjectの説明で
「ビットマップはメモリ デバイス コンテキストのみに選択でき、同時に複数のメモリ デバイス コンテキストに対しては選択できません」
とあります。
m_DrawDC、m_MargeDrawDCの両方で、m_BackScreenBMPをSelectObjectしてますね^^;
// マージ領域に背景をコピー
というコメントが怪しげです^^;
あと、SelectObjectは対にしておいたほうがあとで戻すときに楽ですよ。
色々と間違った使い方をしていたようで、自分なりに調べて
新しく処理を作りかえました。
************************************
1.メンバー変数に2変数を追加
CDC m_memDC;
CBitmap m_memBmp;
2.OnInitDialog() でこの2つの変数を初期化
CRect rct;
GetDlgItem(IDC_WAVE_DRAW_WINDOW) -> GetWindowRect(&rct);
CDC *pDC = GetDlgItem(IDC_WAVE_DRAW_WINDOW) -> GetDC();
m_memBmp.CreateCompatibleBitmap(pDC, rct.Width(), rct.Height());
m_memDC.CreateCompatibleDC(pDC);
m_memDC.SelectObject(&m_memBmp);
GetDlgItem(IDC_WAVE_DRAW_WINDOW) -> ReleaseDC(pDC);
// メモリ上のビットマップイメージを初期化しています。
CDC dc;
CBitmap bitmap;
bitmap.LoadBitmap(IDB_WAVE_SCREEN_1); // 初期画面のビットマップ
dc.CreateCompatibleDC(&m_memDC);
CBitmap *pOldBmp = dc.SelectObject(&bitmap);
m_memDC.BitBlt(0, 0, rct.Width(), rct.Height(), &dc, 0, 0, SRCCOPY);
dc.SelectObject(pOldBmp);
dc.DeleteDC();
bitmap.DeleteObject();
3.OnPaint() に以下のコードを記述
// ---------------------------------
// グラフ領域の表示
// ---------------------------------
CDC *pDC = GetDlgItem(IDC_WAVE_DRAW_WINDOW) -> GetDC();
CRect rct;
GetDlgItem(IDC_WAVE_DRAW_WINDOW) -> GetClientRect(&rct);
pDC -> BitBlt(0, 0, rct.Width(), rct.Height(), &m_memDC, 0, 0, SRCCOPY);
GetDlgItem(IDC_WAVE_DRAW_WINDOW) -> ReleaseDC(pDC);
4.波形を描画するための処理
void CANALOGDlg::WriteWave()
{
int i;
double nYten;
CDC dc;
CBitmap bitmap;
CDC *pDC = GetDlgItem(IDC_WAVE_DRAW_WINDOW) -> GetDC();
bitmap.LoadBitmap(IDB_WAVE_SCREEN_2);
dc.CreateCompatibleDC(pDC);
CBitmap *pOldBmp = dc.SelectObject(&bitmap);
CRect rct;
GetDlgItem(IDC_WAVE_DRAW_WINDOW) -> GetClientRect(&rct);
// グラフ波形 ライン設定
CPen GraphPEN(PS_SOLID, 1, RGB(255, 255, 255));
dc.SelectObject(&GraphPEN);
dc.MoveTo(0, (int)(wave_zero - ((dDataV_ch[0][0] / volt_scale) * wave_zero)));
for(i = 1; i <= draw_point; i += skip_data)
{
nYten = (dDataV_ch[0][i] / volt_scale) * wave_zero;
dc.LineTo((int)(skip_draw * i),(int)(wave_zero - nYten));
}
m_memDC.BitBlt(0, 0, rct.Width(), rct.Height(), &dc, 0, 0, SRCCOPY);
dc.SelectObject(pOldBmp);
dc.DeleteDC();
bitmap.DeleteObject();
OnPaint();
}
5.DestroyWindow() に下記のコードを記述
void CANALOGDlg::OnDestroy()
{
m_memDC.DeleteDC();
m_memBmp.DeleteObject();
}
***********************************
IDC_WAVE_DRAW_WINDOWはグラフを表示する為のピクチャーコントロール
IDB_WAVE_SCREEN_1は背景を黒く塗り、白線で縦、横を10等分にした罫線を引いたビットマップ
IDB_WAVE_SCREEN_2はIDB_WAVE_SCREEN_1と同じビットマップを設定
これにより、起動時にはIDB_WAVE_SCREEN_1が表示され、グラフ表示の処理が走るとWriteWave()でIDB_WAVE_SCREEN_2に波形を描画したものが表示されるようになりました。
今のところしたかった動作をしているのですが
もし、改善点があればご指摘いただけますようお願いします。
> 今のところしたかった動作をしているのですが
わたしは、「動けばいいじゃん」という駄目プログラマなので^^;
ただ、OnPaintを直接コールすることはしないですね。
GetDlgItem(IDC_WAVE_DRAW_WINDOW) -> Invalidate()
といった感じになるのでしょうか
最初はInvalidate()を呼び出して処理を行ったのですが、
タイマー処理の関係上、画像の描画より先にタイマー処理が
走ってしまうので、仕方なくOnPaint()を直接呼び出す形にしました。
今のところは不都合がないのでこのままで行こうと思います。
また何か質問があれば書き込みさせていただきますのでよろしくお願いします。
ツイート | ![]() |