Visual Studioのタイマ処理を使って描画を行うプログラムの異常終了について

このQ&Aのポイント
  • Visual Studioのタイマ処理を使って描画を行うプログラムを作成したが、計測時間が100秒を超えると異常終了してしまう。
  • センサからのデータを50Hzでサンプリングし、描画を行う予定だが、異常終了してしまうため、解決策を教えてほしい。
  • プログラムの開発環境はWindows XP SP2でVC++6.0を使用している。
回答を見る
  • ベストアンサー

Visual Studioのタイマ処理を使って描画を行うプログラムを

Visual Studioのタイマ処理を使って描画を行うプログラムを 作成したのですがうまくいきません. プログラムの開発環境はWindows XP SP2でVC++6.0 外部に接続したセンサからのデータを50Hzで サンプリングして そのデータを元に描画を行う予定なのですが計測時間が100秒を超えると 異常終了してしまいます. 原因がよく分かりません. どうしたらよいのでしょうか? void CMyDlg::OnSamplingStart() { i=0; // サンプリング用タイマ開始 //なぜか12にするとちょうど50Hzでサンプリングする SetTimer(1,12,NULL); // 0.02秒毎タイマ割り込み,50Hz } void CMyDlg::OnTimer(UINT nIDEvent) { /* ここで,センサからのデータをサンプリングし,いろいろな計算をする. */ CDC* pDC=m_pict.GetDC(); CRect myRECT; m_pict.GetClientRect(myRECT); pDC->FillSolidRect(myRECT, RGB(255,255,255)); CPen BlueBoldPen,*OldBlueBoldPen; BlueBoldPen.CreatePen(PS_SOLID,5,RGB(0,0,255)); OldBlueBoldPen=pDC->SelectObject(&BlueBoldPen); pDC->MoveTo((int)(X0/10),(int)(Y0/10)); pDC->LineTo((int)(L3_x[i]/10),(int)(L3_y[i]/10)); pDC->LineTo((int)(C7_x[i]/10),(int)(C7_y[i]/10)); // ペンを元に戻す pDC->SelectObject(OldBlueBoldPen); BlueBoldPen.DeleteObject(); m_time=(double)i/50; UpdateData(FALSE); i=i+1; CDialog::OnTimer(nIDEvent); } 計測終了はボタンを押して終了します. どうが具体的な解決策を教えてください.

質問者が選んだベストアンサー

  • ベストアンサー
回答No.3

> CDC* pDC=m_pict.GetDC(); これに対する ReleaseDC() が見当たりませんが、きちんと解放していますか? デバイスコンテキストは不要になった時点で必ず解放してください。  m_pict.ReleaseDC(pDC);

f_22_8492
質問者

お礼

プログラムを修正して試したところ成功しました. 本当に困っていたので助かりました. ありがとうございました.

その他の回答 (2)

回答No.2

SetTimerのタイムアウト値が12msなので、 100秒経てば変数 i の値は 8333 になり、 配列のサイズ8000を超えてしまいます。 //なぜか12にするとちょうど50Hzでサンプリングする とありますが、この50Hzというのは果たして タイムアウト処理が起動された回数でしょうか? 試しにタイムアウト処理の中に if (i == 7999) { i = 0; // ブレークポイント設定場所(処理はダミー) } とか書き加えて、Debugモードでブレークポイントに止まるかどうか 確認してみてください。

f_22_8492
質問者

補足

回答ありがとうございます >試しにタイムアウト処理の中に if (i == 7999) { i = 0; // ブレークポイント設定場所(処理はダミー) } とか書き加えて、Debugモードでブレークポイントに止まるかどうか 確認してみてください。 確認してみたところブレークポイントには止まりませんでした. 実際に90秒計測してみたところ,iの値は4500とります. タイマが遅れているのか,SetTimerのタイムアウト値を12にすると ちょうど実時間と同じように時間を刻みます. 計測時間は m_time=(double)i/50; UpdateData(FALSE); で確認しています. 実際の計測は計測時間を90秒としています. 一回目の計測では問題なく計測できるのですが,二回目の計測では5秒ぐらい計測した あたりで異常終了しています. 描画をコメントアウトすると二回目,三回目と問題なく計測できます. コメントアウトした場合,一回目の計測ではメモリの使用量は増加しますが, 二回目,三回目では増加しません.これは一回目に使用した変数や配列を使用したためだと思います. しかし,描画した場合では二回目でもメモリの使用量は増加します. これが何かの原因の一部ではないのでしょうか? 何か解決策があれば願いします.

回答No.1

変数 i の宣言と 配列 L3_x、L3_y、O7_x、O7_y の宣言を見直してください。 i の値が配列より大きくなるとバッファがあふれます。

f_22_8492
質問者

補足

回答ありがとうございます. 変数iと配列L3_x,L3_y,C7_x,C7_yの宣言は int i=0; double C7_x[8000]; double C7_y[8000]; double L3_x[8000]; double L3_y[8000]; と,宣言しています. 描画するところをコメントアウトすると問題はありませんでした. 描画するとメモリの使用量がやけに多いのでそれが原因でしょうか?

関連するQ&A

  • VC++2010 で線形の描画についてですが・・

    VC++2010 で線形の描画についてまた質問なんですが、以下のように記述すると線ができなく、 点だけが動くプログラムになりました。解決方法がわからないのでよろしくお願いします。 今回のプロジェクトの目的はある機器からデータを取ってきて(1msごとに)それを1msごとに 直線として出力するプロジェクトです 電圧                    ↑          ________ ↑         |          |________→→ ーーーーーーーー  →→時間 ↑↑↑ このような線を出力しなければならないです。 以下がソースになっています。 使用環境VC++2010 MFC test10000Dlg.cpp ちなみにm_lineXとm_lineYはメンバー変数です(double型) ボタンがクリックされたときのイベント SetTimer(0, 1, NULL); void Ctest10000Dlg::OnTimer(UINT_PTR nIDEvent) { UpdateData(); after_datay = sam_data; m_xvEditX = m_lineX; m_xvEditSamd = m_lineY; m_xvEditSami = sam_i++; if(sam_i%200==0) { m_lineY -= 5; sam_i = 0; } m_lineX++; UpdateWindow(); Invalidate(FALSE); } void Ctest10000Dlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); // 描画のデバイス コンテキスト SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0); // クライアントの四角形領域内の中央 int cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect); int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2; // アイコンの描画 dc.DrawIcon(x, y, m_hIcon); } else { //****************************************************************************************************** CRect rect_dlg; GetClientRect(&rect_dlg); CBrush br_black(RGB(0,0,0)); //各色ペン CPen pen_black(PS_SOLID,1,RGB(0,0,0)); CPen pen_gray(PS_DOT,1,RGB(128,128,128)); CPen pen_blue(PS_SOLID,1,RGB(0,0,255)); CPen pen_white(PS_SOLID,1,RGB(255,255,255)); int max_y=1; if(int(m_sin+m_cos+1.0)>max_y) max_y=int(m_sin+m_cos)+1; CDC* pDC=m_pict.GetDC(); //PictureControlの大きさ取得 CRect rect; m_pict.GetClientRect(&rect); //元のブラシをoldbrに保持 CBrush* oldbr=pDC->SelectObject(&br_black); //元のペンをoldpenに保持 CPen* oldpen=pDC->SelectObject(&pen_black); //(1)背景描画(ブラシ白、ペン黒) pDC->Rectangle(&rect); //(2)中心線(黒、実線) pDC->SelectObject(&pen_blue); pDC->MoveTo(10,rect.Height()-10); pDC->LineTo(10,10); pDC->MoveTo(10,rect.Height()-10); pDC->LineTo(rect.Width()-10,rect.Height()-10); pDC->SelectObject(&pen_white); pDC->MoveTo(m_lineX,m_lineY_after); pDC->LineTo(m_lineX+1,m_lineY); pDC->SelectObject(oldbr); pDC->SelectObject(oldpen); m_lineY_after = m_lineY; UpdateData(FALSE); CDialog::OnPaint(); } } ではよろしくお願いします

  • ビットマップに描画をしてピクチャーコントロールに貼り付けるためには?

    ビットマップに描画をしてピクチャーコントロールに貼り付けるためには どうすればよいでしょうか? ネットで検索しましたそして、 下のようなコードを書きましたがうまくゆきません。 void CXXXView::OnButton() { CStatic m_ctlImage; // ピクチャーボックスに関連付けした変数 CBitmap m_bmpImage; // ピクチャーボックスに貼り付けるイメージ CDC m_dcImage; // Bitmap描画用のDC CDC* pDC = m_ctlImage.GetDC(); m_dcImage.CreateCompatibleDC(pDC); CRect Cltsz; picture1.GetClientRect(&Cltsz); m_bmpImage.CreateCompatibleBitmap(pDC,Cltsz.Width(),Cltsz.Height()); CBitmap* pOld=m_dcImage.SelectObject(&m_bmpImage); CPen myPEN(PS_SOLID,5,RGB(0,0,255)); CPen* oldPEN=m_dcImage.SelectObject(&myPEN); m_dcImage.MoveTo(10,10); m_dcImage.LineTo(100,100); m_dcImage.SelectObject(oldPEN); m_dcImage.SelectObject(pOld); m_ctlImage.SetBitmap(m_bmpImage); } この様にしましたが、ピクチャーコントロールには 何も描画されません、 何故でしょうか? VS2005で、ボタンをクリックした イベントで描画する場合です、 直線とかは、問題なく描画できました。 ビットマップに描画して貼り付けたいのです、 よろしくお願いします

  • CDCオブジェクトの作成について

    // あまり意味はないのですが、 //CDCのオブジェクトを宣言して、 //そこへ図形を描画して、 //クライエント領域にBitBltするときは、 //どうすればいいですか? //CreateCompatibleDCが関係していると思っています。 //ですが、上手く描画できません。 //教えてください、 //お願いします。 void CProject1View::OnDraw(CDC* pDC) { CProject1Doc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if (!pDoc) return; ////////////////////////////////////////////////////// CDC imageDC; CPen pen,*oldpen; pen.CreatePen(PS_SOLID,3,RGB(255,0,0)); imageDC.CreateCompatibleDC(pDC); for(int i=0;i<100;i++) { for(int j=0;j<100;j++) { imageDC.SetPixel(i,j,RGB(128,0,0)); } } oldpen=imageDC.SelectObject(&pen); imageDC.Rectangle(50,50,400,300); pDC->BitBlt(0,0,600,600,&imageDC,0,0,SRCCOPY); imageDC.SelectObject(oldpen); ////////////////////////////////////////////////////// }

  • MFCでボタンを押して図形を操作するには

    Visual studio 2008のMFCで、とあるプログラムを作っております。 ボタンをクリックすると円が出てきて、さらにクリックするとその下に円が表示されるというプログラムまで作りました。 void C***Dlg::OnBnClickedButton1(){ CDC* pDC=m_pict.GetDC(); CRect rect; m_pict.GetClientRect(&rect); pDC->Rectangle(&rect); CPen pen_red(PS_SOLID,1,RGB(255,0,0)); CBrush br_yellow(RGB(255,255,0)); CPen* oldpen=pDC->SelectObject(&pen_red); CBrush* oldbr=pDC->SelectObject(&br_yellow); pDC->Ellipse(-252,i-43,-212,i-3); i=i+48; UpdateWindow(); pDC->SelectObject(oldpen); pDC->SelectObject(oldbr); // TODO: ここにコントロール通知ハンドラ コードを追加します。 } とりあえずOnBnClickedButton1関数はこんな感じです。 ここから、 (1)クリックすると円が自動で動き、途中で止まり、しばし経ってから動き出してやがて上へ消えてゆく。 (2)2つ目の円も同じように動くが、1つ目の円が止まっていて重なりそうになったらその手前で止まる。 (3)1つ目の円が上に消えたら、2つ目の円が動き出し、以降は(1)と同じ動きをする。 このようなプログラムを作りたいのですが、初心者のためどのようなツールをどのように使えば良いのかわかりません。 どなたがヒントだけでもご教授頂けませんでしょうか?

  • LineTo,MoveToについて

    MFCのダイアログベースで 変化を表すグラフを作成したのですが 線を描くときに原点復帰してしまいます。 左上のエディットに数値をいれ 実行を押すと座標(200,200)から横にエディットで入力した数値分線を引いていくというものです。 Timerを使い1秒ごとに書かせています。 void CsinDlg::OnTimer(UINT_PTR nIDEvent) { // TODO: ここにメッセージ ハンドラー コードを追加するか、既定の処理を呼び出します。 static int count=0; static double i,x=0; char buf[100]; CString str; /*------描写設定----*/ CWnd* h = GetDlgItem(IDC_BB); CDC* pDC=h->GetDC(); //-----------------------------------// CEdit *edit = (CEdit*)GetDlgItem(IDC_EDIT1); edit->GetWindowText(str); i = atof((const char*)str); x=x+i; sprintf(buf,"%lf",x); siki_edit.SetWindowText(buf); /*---------------------------------------*/ if(count==0) pDC->MoveTo(200,200); // 座標(200,200) に移動 pDC->LineTo(200+x,200); // 座標(200+x,200) まで線を引く count++; h->ReleaseDC(pDC); CDialogEx::OnTimer(nIDEvent); } 実行結果は添付した画像のようになります。 イメージではcountが0の時だけMoveToで動かし、それ以降は座標(200,200)から横に線を引いていきたいのですが。 どのように直せばよいのでしょうか? LineToからLineToの指令ができないということでしょうか?

  • MFCプログラミング

    MFCのダブルバッファリングを用いて画面を切り替えるプログラムを作ったのですが 画面がちらついてしまいます、どう修正すればよいか教えてください // CgraphView 描画 void CgraphView::OnDraw(CDC* pDC) { CgraphDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if (!pDoc) return; // TODO: この場所にネイティブ データ用の描画コードを追加します。 CRect myRect; GetClientRect(myRect); if(background_color == 0) pDC->FillSolidRect(myRect, RGB(255, 255, 255)); else if(background_color == 1) pDC->FillSolidRect(myRect, RGB(153, 204, 255)); else pDC->FillSolidRect(myRect, RGB(255, 153, 204)); //ダブルバッファに関するコード CRect rc; GetClientRect(&rc); bkDC.CreateCompatibleDC(pDC); bkBMP.CreateCompatibleBitmap(pDC, rc.right, rc.bottom); CBitmap Bitmap, *pOldBitmap; pOldBitmap = bkDC.SelectObject(&bkBMP); //これから、すべての描画は、裏画面bkDCにおいて行う bkDC.FillSolidRect(rc, RGB(255, 255, 255)); int x, y, sx, sy; if(draw_state == 0) { bkDC.SetTextColor(RGB(0, 0, 0)); bkDC.TextOut(400, 500, _T("Start")); sx = 128;//表示するビットマップの横の大きさ sy = 128;//表示するビットマップの縦の大きさ y = 300;//表示するビットマップの左上の頂点のy座標 x = 50; draw_school(x, y, sx, sy); x = 200; draw_health(x, y, sx, sy); x = 350; draw_environment(x, y, sx, sy); } else if(draw_state == 1) { CRect myRect; GetClientRect(myRect); pDC->FillSolidRect(myRect, RGB(255, 255, 255)); } //裏画面bkDCにおいて、すべての描画を行った後 //裏画面を表画面に送る pDC->BitBlt(0, 0, rc.right, rc.bottom, &bkDC, 0, 0, SRCCOPY); bkDC.SelectObject(pOldBitmap); //裏画面を消去 bkBMP.DeleteObject(); bkDC.DeleteDC(); void CgraphView::OnInitialUpdate() { CView::OnInitialUpdate(); // TODO: ここに特定なコードを追加するか、もしくは基本クラスを呼び出してください。 bitmap[0].LoadBitmap(IDB_BITMAP1); bitmap[1].LoadBitmap(IDB_BITMAP2); bitmap[2].LoadBitmap(IDB_BITMAP3); bitmap[3].LoadBitmap(IDB_BITMAP4); bitmap[4].LoadBitmap(IDB_BITMAP5); bitmap[5].LoadBitmap(IDB_BITMAP6); Bmp_ID = 0; //タイマーをスタート SetTimer(ID_BITMAP, TIMER_MS_BITMAP, NULL); //画面再描画のタイマーをスタートする SetTimer(ID_REDRAW, TIMER_MS_FPS, NULL); Bmp_ID = 0; } void CgraphView::OnTimer(UINT_PTR nIDEvent) { // TODO: ここにメッセージ ハンドラ コードを追加するか、既定の処理を呼び出します。 if(nIDEvent == ID_BITMAP) Bmp_ID = (Bmp_ID+1) % 2; if(nIDEvent == ID_REDRAW) InvalidateRect(NULL, FALSE); CView::OnTimer(nIDEvent); } void CgraphView::OnDestroy() { CView::OnDestroy(); // TODO: ここにメッセージ ハンドラ コードを追加します。 KillTimer(ID_BITMAP); KillTimer(ID_REDRAW); } void CgraphView::OnLButtonDown(UINT nFlags, CPoint point) { // TODO: ここにメッセージ ハンドラ コードを追加するか、既定の処理を呼び出します。 mouse_x = point.x; mouse_y = point.y; if(draw_state == 0) { if(mouse_x > 400 && mouse_y > 500) { draw_state = 1; } } CView::OnLButtonDown(nFlags, point); } BOOL CgraphView::OnEraseBkgnd(CDC* pDC) { // TODO: ここにメッセージ ハンドラ コードを追加するか、既定の処理を呼び出します。 return TRUE; //return CView::OnEraseBkgnd(pDC); }

  • 【WinAPI】 四角形の色を選択して描画

    環境:VisualStudio2005、WinXP 目的:閉じた図形の内部の色を指定の色で塗りつぶしたい 現在 // 四角形を描画(Polygonバージョン) int x1 = 0, y1 = 0, x2 = 100, y2 = 100; POINT p[ 4 ]; p[ 0 ].x = x1, p[ 0 ].y = y1; p[ 1 ].x = x2, p[ 1 ].y = y1; p[ 2 ].x = x2, p[ 2 ].y = y2; p[ 3 ].x = x1, p[ 3 ].y = y2; Polygon( hdc, p, 4 ); や // 四角形を描画(Rectangleバージョン) Rectangle( x1, y1, x2, y2 ); などで四角形を描画するプログラムを作っています。 そしてこれに色を指定したいのですが、枠の部分に関しては HPEN hPen = CreatePen( PS_SOLID, 1/*線の厚さ*/, RGB(255,0,0) ); SelectObject( hdc , hPen ); // この後に四角形を描画 を指定することで色が変わりました。 しかし四角形の内側の部分の色に関しての色の指定方法が分かりません。 SelectObject(hdc , GetStockObject( GRAY_BRUSH ) ); でGRAY_BRUSH、BLACK_BLUSHなど数種類の指定ができるというのを調べましたが、 これだと好きな色を指定できません。 閉じた図形の内部の色を好きな色で塗りつぶす方法は無いのでしょうか・・?

  • CDC(LineTo)で描画した線を透過したい

    タイトルのままで恐縮です。 ソースは、以下のような感じです。 描画の所で線を描いているのですが、例えば、SetBkModeなどで、背景を透過(TRANSPARENT)等は、やった事があるのですが、文字そのものの透過がわかりません。透過率は適当で構いません。ご存知の方、ご教授願います。 宜しくお願い致します。 (中略) // 描画した線自体を透過させたいです。 CDC* dc; // 実際は、関数のパラメータです // ペンの作成 CPen Pen; CPen* pOldPen = NULL; if ( Pen.CreatePen( PS_SOLID, 2, color ) == FALSE ) { return false; } pOldPen = dc->SelectObject( &Pen ); // 描画(線を描く) // widht, height は関数パラメータ dc->MoveTo( x, y ); // この線を透過したい dc->LineTo( x + width, x + height ) ); dc->MoveTo( x + width, y ); // この線を透過したい dc->LineTo( x, y + height ); // ペンを元に戻す dc->SelectObject( pOldPen );

  • Windowsプログラミング 画面描画 ちらつき

    SetDIBitsToDevice関数を使って画面に描画をした後、LineTo関数やEllipse関数を使って その画面上に線や丸を表示させる処理をしているのですが、描画処理を一度にできていないためか ちらつきが発生してしまいます。 調べてみるとビットマップのマルチバッファリングなどが解決策にあるのですが、 私は一次元配列で画素値を格納していてビットマップに情報は保持していないため よく解決策で使われているBITBLTが使えない状態です。 裏画面に描画しておいて、最終的に描画は一度だけにするという考えは分かるんですが、 これをSetDIBitsToDevice関数を用いてちらつきが発生しないようにできるんでしょうか? プログラムとしては画像の上に線と円をひたすら描画していくようなイメージをしています。 アドバイスお願いします! case WM_PAINT: hDC=BeginPaint(hParent,&ps); SetDIBitsToDevice( ps.hdc, 0, 0,// コピー先x,y座標 pimg -> bih.biWidth,// DIBの幅 pimg -> bih.biHeight,// DIBの高さ 0, 0,// DIBの座標 0,// 走査線 pimg -> bih.biHeight,/ 走査線数 pimg -> lpBmpData, (BITMAPINFO *)&( pimg -> bih),// BITMAPINFOにキャスト DIB_RGB_COLORS ); for(int i=0; i<number-1; i++){ if(i==0){  hPen1 = CreatePen(PS_SOLID, 1, RGB(255,0,0));  electObject(hDC,hPen1);  MoveToEx(hDC,Xs,Ys,NULL);  Ellipse(hDC,Xs-2,Ys-2,Xs+2,Ys+2); }else{  LineTo(hDC,Xe,Ye);  Ellipse(hDC,Xs-2,Ys-2,Xs+2,Ys+2); } }

  • mfcの画像表示で、bmp表示がよくわかりません

    mfcの画像表示で、bmp表示がよくわかりません。 特に、SelectObject()でBitmapを戻す等が特によくわかりません。 今までは、そういうもんだとしてきたのですが、放っておけない事態になりまして、 相談させて下さい。 (1)下記のbmpDC.SelectObject(oldbmp)等について、その仕組みを詳細に紹介しているHPを ご存じでしたらお教えください。 (2)下記プログラムの画像の扱いで、まずい部分を、おかしいなと思われた部分をお教えください。  動作は、問題なく動作しています。BITMAPを敷き詰めるプログラムです。 CArray<HBITMAP> hBitAry; (HBITMAPを配列にしているまずさは今回は除外して下さい。) … int topX=-100-5; int topY=0; int hLen=100; int wLen=100; int yoko=0; CDC *pDC=mPict.GetDC(); for(int i=0; i<hBitAry.GetCount(); i++) { CDC bmpDC; bmpDC.CreateCompatibleDC(pDC); CBitmap *pBitmap=CBitmap::FromHandle(hBitAry.GetAt(i)); BITMAP BMP; pBitmap->GetBitmap(&BMP); CBitmap *oldbmp=bmpDC.SelectObject(pBitmap); if(yoko<3) { topX+=100+5; yoko++; } else { topX=0; topY+=100+5; yoko=0; } pDC->SetStretchBltMode(COLORONCOLOR); pDC->StretchBlt(topX,topY,100,100,&bmpDC,0,0,BMP.bmWidth,BMP.bmHeight,SRCCOPY); bmpDC.SelectObject(oldbmp); ::DeleteObject(CBitmap::FromHandle(hBitAry.GetAt(i))); } ReleaseDC(pDC); どうぞよろしくお願い致します。

専門家に質問してみよう