質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

Windows

Windowsは、マイクロソフト社が開発したオペレーティングシステムです。当初は、MS-DOSに変わるOSとして開発されました。 GUIを採用し、主にインテル系のCPUを搭載したコンピューターで動作します。Windows系OSのシェアは、90%を超えるといわれています。 パソコン用以外に、POSシステムやスマートフォンなどの携帯端末用、サーバ用のOSもあります。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

2回答

3597閲覧

タイマー作動途中で描画した図形の色や線が消える(白くなる)

TRON1216

総合スコア18

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

Windows

Windowsは、マイクロソフト社が開発したオペレーティングシステムです。当初は、MS-DOSに変わるOSとして開発されました。 GUIを採用し、主にインテル系のCPUを搭載したコンピューターで動作します。Windows系OSのシェアは、90%を超えるといわれています。 パソコン用以外に、POSシステムやスマートフォンなどの携帯端末用、サーバ用のOSもあります。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2017/06/23 10:00

編集2017/06/26 06:17

ある物体の円運動をタイマーを使って描画させるプログラムを作っています。xーy平面での運動を描画するウィンドウ、xーz平面での描画のウィンドウ、yーz平面での描画のウィンドウ計3つ出して、座標データのファイルを選択すると、3つのウィンドウに円運動が描画される流れにしました。実行できたのですが、なぜか運動の途中(全座標データがプロットされる前)に物体塗られている色が白色になったりするバグといいますかエラーが起きます。ウィンドウを一つだけ出して、実行した時は全座標データがプロットされるまで問題なく描画されました。ですが3つウィンドウを出すとこのような謎の現象が起きます。何が原因なのか検討もつかず、どなたかアドバイスいただけないでしょうか、、? 開発環境は、Visual studio C++です。下は正常な描画の時の写真と、エラー(白くなる)時の写真です。状況がイメージしやすいかなと思い添付します。
イメージ説明
イメージ説明
ソースコードに関しては、三つのウィンドウプロシージャのうち、xy平面についてのもの(WndProc3.cpp)、メモリ軸を描画する関数(disp_axes2.cpp)、xy座標を描画する関数(disp_xy.cpp)を添付しておきます。xz、yz、についても、これとコードはほぼ同じです。残り二つのウィンドウプロシージャと、xz、yz座標を描画する関数のコードも載せたかったのですが、最大文字数に達してしまい、全てを添付できませんでした。ご了承ください。

WndProc3.cpp #include "kobayashi.h" #define ID_MYTIMER 1 LRESULT CALLBACK WndProc3( HWND hWnd3, UINT msg, WPARAM wp, LPARAM lp ) { HDC hdc; PAINTSTRUCT ps; HPEN hPen3,h01dPen3; HBRUSH hBrush3, h01dBrush3; RECT rect;// ウィンドウの描画領域を格納する構造体 switch (msg) { case WM_CREATE: SetTimer(hWnd3, 1, 50, NULL); break; case WM_TIMER: if (wp != 1) return (DefWindowProc(hWnd3, msg, wp, lp)); k +=1; InvalidateRect(hWnd3, NULL, TRUE); break; case WM_PAINT: hdc = BeginPaint( hWnd3, &ps );// 画面のデバイスコンテキストを得て描画 GetClientRect( hWnd3, &rect );// ウィンドウの描画領域を得る PatBlt( hdc, 0, 0, rect.right, rect.bottom, BLACKNESS );// 最初に黒く塗りつぶす hPen3 = CreatePen(PS_SOLID, 10, RGB(0,160,233)); h01dPen3 = (HPEN)SelectObject(hdc, hPen3); hBrush3 = CreateSolidBrush(RGB(0,160,233)); h01dBrush3 = (HBRUSH)SelectObject(hdc, hBrush3); Ellipse( hdc, 293.5-7.479, 281-7.479, 293.5+7.479, 281+7.479); //ウィンドウの中心にシアンの色の円(地球)を描画 DeleteObject(hPen3); if ( IsDlgButtonChecked( hDlg, IDC_CHECK_DISPLAY1 ) == BST_CHECKED ) disp_xy( hdc, rect, hDlg, 1 );// データを表示する if ( IsDlgButtonChecked( hDlg, IDC_CHECK_DISPLAY2 ) == BST_CHECKED ) disp_xy( hdc, rect, hDlg, 2 );// データを表示する if ( IsDlgButtonChecked( hDlg, IDC_CHECK_DISPLAY3 ) == BST_CHECKED ) disp_xy( hdc, rect, hDlg, 3 );// データを表示する if ( IsDlgButtonChecked( hDlg, IDC_CHECK_DISPLAY4 ) == BST_CHECKED ) disp_xy( hdc, rect, hDlg, 4 );// データを表示する disp_axes2( hdc, rect ); EndPaint( hWnd3, &ps );// 描画終り ReleaseDC( hWnd3, hdc );// 画面のデバイスコンテキストhdcを破棄する break; case WM_LBUTTONDOWN: KillTimer(hWnd5, 1); KillTimer(hWnd4, 1); KillTimer(hWnd3, 1); KillTimer(hWnd2, 1); sprintf_s(szBuf, 256, "月面高度%12.2ekm %d番目のデータ",EQL_MOON[k]-1737,k); MessageBox(NULL, szBuf, "位置情報", MB_OK); break; case WM_RBUTTONDOWN: SendMessage(hWnd5, WM_CREATE, 0,0); SendMessage(hWnd4, WM_CREATE, 0,0); SendMessage(hWnd3, WM_CREATE, 0,0); SendMessage(hWnd2, WM_CREATE, 0,0); break; case WM_DESTROY: KillTimer(hWnd3, 1); PostQuitMessage(0); break; default: return (DefWindowProc(hWnd3, msg, wp, lp)); } return 0; }
disp_xy.cpp #include "kobayashi.h" #define _USE_MATH_DEFINES #include <math.h> // xy平面にデータを表示する関数 BOOL disp_xy( HDC hdc, RECT rect, HWND hDlg, int channel ) { COLORREF color; if ( (channel < 1) || (channel > 4) ) return FALSE;// チャンネル指定が間違っていた場合 // プロット色を決める if ( channel == 1 ) color = RGB(255,153,0);// チャンネル1はYellow if ( channel == 2 ) color = RGB(228,0,127);// チャンネル2はMagenta if ( channel == 3 ) color = RGB(0,160,233);// チャンネル3はCyan if ( channel == 4 ) color = RGB(51,153,102);// チャンネル4は緑 HPEN hPen_xy = CreatePen( PS_SOLID, 9, color); SelectObject( hdc, hPen_xy );// hdcで上記のペンを使うために選ぶ HBRUSH hBrush_xy, h01dBrush_xy; hBrush_xy = CreateSolidBrush(color); h01dBrush_xy = (HBRUSH)SelectObject(hdc, hBrush_xy); int nop= rect.right - rect.left + 1; double ppd= (rect.bottom - rect.top)/10.0;// 縦方向1div当たり何ピクセルか if ( channel == 4 ) j[k] = (int)( ((double)rect.right/2.0) + ((double)XEQL[k]/100000*(nop/10.0)+ 0.5) ); if ( channel == 1 ) j[k] = (int)( ((double)rect.right/2.0) + ((double)XMOON[k]/100000*(nop/10.0)+ 0.5) ); if ( channel == 2 ){ j[k] = (int)( 293.5/*((double)rect.right/2.0)*/ + 275*cos(a3[k]) ); if(XSUN[k]<0) j[k] = 293.5-(j[k]-293.5); } if ( channel == 4 ) y[k] = (int)( ((double)rect.bottom/2.0) - ((double)YEQL[k]/100000)*ppd + 0.5 ); if ( channel == 1 ) y[k] = (int)( ((double)rect.bottom/2.0) - ((double)YMOON[k]/100000)*ppd + 0.5 ); if ( channel == 2 ){ y[k] = (int)( 281-275*sin(a3[k]) ); if(XSUN[k]<0) y[k] = 281+(281-y[k]); if ( channel== 1 ) Ellipse(hdc, j[k]-2.039, y[k]-2.039, j[k]+2.039, y[k]+2.039); //黄色の円(月)を描画 if ( channel== 4 ) Ellipse(hdc, j[k]-0.1, y[k]-0.1, j[k]+0.1, y[k]+0.1); //緑の円(探査機)を描画 if ( channel== 2 ) { HPEN hPen_SUN = CreatePen( PS_SOLID, 0, RGB(228,0,127)); SelectObject( hdc, hPen_SUN ); HBRUSH hBrush_SUN, h01dBrush_SUN; hBrush_SUN = CreateSolidBrush( RGB(228,0,127)); h01dBrush_SUN = (HBRUSH)SelectObject(hdc, hBrush_SUN); if(XSUN[k]>0 && YSUN[k]>0){ POINT pt[3]={{j[k],y[k]}, {j[k]-15*cos(a3[k]-M_PI/12),y[k]+15*sin(a3[k]-M_PI/12)}, {j[k]-15*sin(5*M_PI/12-a3[k]),y[k]+15*cos(5*M_PI/12-a3[k])}}; Polygon(hdc, pt, 3); } if(XSUN[k]<0 && YSUN[k]>0){ POINT pt[3]={{j[k],y[k]}, {j[k]+15*sin(a3[k]+5*M_PI/12),y[k]+15*cos(a3[k]+5*M_PI/12)}, {j[k]+15*cos(-M_PI/12-a3[k]),y[k]+15*sin(-M_PI/12-a3[k])}}; Polygon(hdc, pt, 3); } if(XSUN[k]<0 && YSUN[k]<0){ POINT pt[3]={{j[k],y[k]}, {j[k]+15*cos(a3[k]-M_PI/12),y[k]-15*sin(a3[k]-M_PI/12)}, {j[k]+15*sin(5*M_PI/12-a3[k]),y[k]-15*cos(5*M_PI/12-a3[k])}}; Polygon(hdc, pt, 3); DeleteObject( hPen_SUN ); } //太陽の方向を三角形(矢印)で描画 } DeleteObject( hPen_xy );// ペンを破棄する return TRUE;// 戻り値TRUEを返す }
#include "kobayashi.h" // ウィンドウ中に目盛軸を描く関数 BOOL disp_axes2( HDC hdc, RECT rect ) { int i, x, y;// forで使う変数iと、縦横のグリッド線を引くときのx座標とy座標 HPEN hPen_a = CreatePen( PS_DOT, 0, RGB(0,0,0));// 黒色、破線のペンを作る(注:白と黒の破線になる) SelectObject( hdc, hPen_a );// hdcで上記のペンを使うために選ぶ double hdiv = (double)(rect.right - rect.left)/10.0; double vdiv = (double)(rect.bottom - rect.top)/10.0; for ( i=0; i<=10; i++ ) {// 縦線を描く x = (int)( hdiv * (double)i + 0.5 ); MoveToEx(hdc, x, rect.top, NULL);//ペンを移動する LineTo(hdc, x, rect.bottom);//線を引く if ( i == 0 ) TextOut(hdc, x, rect.bottom-20, "-5*10^5",7); if ( i == 5 ) TextOut(hdc, x, rect.bottom-20, "0",1); if ( i == 9 ) TextOut(hdc, x, rect.bottom-20, "5*10^5",6); } for ( i=0; i<=10; i++ ) {// 横線を描く y = (int)( vdiv * (double)i + 0.5 ); MoveToEx(hdc, rect.left, y, NULL); LineTo(hdc, rect.right, y); if ( i == 0 ){ TextOut(hdc, rect.left, y, "5*10^5",6); } if ( i == 5 ){ TextOut(hdc, rect.left, y, "0",1); } } DeleteObject( hPen_a );// ペンを破棄する return TRUE; }

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Bongo

2017/06/23 10:28

コードが長すぎるようであれば、描画フローの概略や使っている機能(Windowsの描画APIであるとか、DirectXやOpenGLだとか)の記載がありますとより良いかと思います。そこから疑わしい部分に近づけるかもしれません。
TRON1216

2017/06/23 10:31

ありがとうございます。WindowsAPIを使っています。フローチャートは後で載せます汗
guest

回答2

0

ベストアンサー

こんにちは。

皆目検討もつかない時は、1つ1つ状況を確認していくのが妥当です。

色が白になると言うことは、その色を決定している部分に何か問題があることは間違いないです。先ずはできるだけ描画直前の色をOutputDebugString()等で出力してみるとよいと思います。・・・①
それが意図する色だったら、それと実際に描画する時の色が異なるのですから、CreateSolidBrush、SelectObject、Ellipseの処理過程の間で何か想定外のことが起きている筈です。
私なら、Ellipseの直前で連続して、上記3つを呼び出して色がCreateSolidBrushで設定した通りになることを確認します。
これが確認できれば、必ず何か途中のどこかで何か起きてます。
それを1つ1つ追いかけていくのです。例えば隅っこの決まった場所に設定している筈のブラシで円を描いてみる等です。どこかで白になる筈です。

逆に①が既に白だったら、その値を設定する変数を間違って破壊しています。破壊されるタイミングがどこなかの1つ1つ追いかけることです。恐らくメモリ管理をとちっています。(3つのウィンドウの色設定変数が別々に確保する必要があるのに1つしか確保できていないなどなど)

座標軸っぽいメッシュはどうも色が黒に成っている様子ですから、原因は同じかもしれません。

まずはブラシかペンのどちらか追いかけやすそうな方から、原因追求することをお勧めします。両方一度にやろうとするとハマリますし、同じ原因だったら、もう片方への反映は簡単ですし。

投稿2017/06/23 12:54

Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

TRON1216

2017/06/24 12:06

返信が遅くなり大変申し訳ありません。ご丁寧なアドバイス、本当にありがとうございます!このアドバイスをもとに再度試行錯誤してみます。また何かあればよろしくお願い致します。
TRON1216

2017/06/26 02:46

OutputDebugStringの中に入れるものがよくわからず、ブレークポイントを置いたりメッセージボックスを置いたりしてデバッグしようとしたのですが、イマイチこのエラーの原因がわからないままです、、OutputDebugStringの中に入れるものは何を入れれば良いのでしょうか?もうひとつ、「色設定変数をウィンドウごとに別々に確保する」ということに関して、後少しでいいので詳しく教えていただきたいです。初心者なので理解に乏しくご迷惑をおかけしています。申し訳ありません汗
Chironian

2017/06/26 03:57

> OutputDebugStringの中に入れるものがよくわからず、ブレークポイントを置いたりメッセージボックスを置いたりしてデバッグ それでよいですよ。 OutputDebugStringはブレークしたりメッセージボックス表で停止したりしないでデバッグ・ウィンドウへ出力されるという程度の差だけです。 一時停止しても問題ないなら、ブレークで十分です。 (お勧めしといてなんですが、ブレークしてみている変数の値を文字列へ変換してOutputDebugStringで出力しますが、この変換作業は虚しい手間がかかります。) > イマイチこのエラーの原因がわからないままです 描画する色を決めている変数がある筈では? ブレークした時に、その変数の値を確認して下さい。あるべき値になってなくて「白」や「黒」になっているかもしれません。 あるべき値になっていたら、その処理~描画までにバグがあります。 あるべき値になっていなかったら、その処理の前にバグがあります。 前者なら、CreateSolidBrush、SelectObject、Ellipseのどこかで色が可笑しくなっているので、それを追跡します。 後者なら、「描画する色を決めている変数」が可笑しくなっている原因を追求します。 > 「色設定変数をウィンドウごとに別々に確保する」 上述の後者の場合、描画先のウィンドウは3つありますが、この「描画する色を決めている変数」をその3つ全体に対して1つしか確保していない可能性も疑われます。きちんとそれぞれのウィンドウに対して異なる変数を確保するようにしましょう。
TRON1216

2017/06/26 04:25

丁寧なコメントありがとうございます。 色を決めている変数に関してですが、ペンやブラシにRGB()を書き込んでます。このRGBが色を決める変数になるということでしょうか?
TRON1216

2017/06/26 04:42

補足なのですが、実行中ウィンドウを二つ隠す(最小化する)状態にして置くと、残った一個のウィンドウは最後までエラーなく描画され続けています。しかし、画面上にウィンドウ2個以上設けて実行させると、途中から全ウィンドウの色が写真のように白黒になってしまっています。
Chironian

2017/06/26 05:43

> ペンやブラシにRGB()を書き込んでます。このRGBが色を決める変数になるということでしょうか? 描画されている円が複数ありますが、それぞれ異なる色になってます。 そのそれぞれ異なる色をどのように管理しているのか、私には分かりません。それがRGB()なのかそうでないのか、分かりません。 しかし、その色を決定するための変数が何かある筈です。 不具合があるときは全て白になっていますので、その変数の値が異常になっている可能性もあると思います。 > 実行中ウィンドウを二つ隠す(最小化する)状態にして置くと、残った一個のウィンドウは最後までエラーなく描画され続けています なるほど。最小化している時は恐らくWM_PAINTが届かない筈です。(要確認。) 本当に届かないことが確認できれば、WM_PAINT処理の中に不具合があることがほぼ確定します。 ブラシやペンの選択ミスや上記の変数の破壊等、いろいろ考えられますので1つ1つ絞り込む必要があると思います。
TRON1216

2017/06/26 06:10

毎回丁寧に、本当に感謝しています。今コードを一部ですが載せました。ざっとで構いませんので、見ていただけないでしょうか?
TRON1216

2017/06/26 07:36

ブラシを削除したところ、無事に白くなることなく最後まで作動しました汗ほんとに感謝しています!ご迷惑をおかけして申し訳ありませんでした。お忙しいところ、時間を割いていただき本当に感謝しています。助かりました、、
Chironian

2017/06/26 07:49

いいえ、どういたしまして。 頑張っている人のお手伝いってなかなか楽しいものなのですよ。
guest

0

だいたいこの手のバグはどこかでグローバル変数を誤って再初期化している類なので心当たりのあるグローバル変数を片っ端からウォッチ式に入れて描画周りにbreak pointを置いてdebugしましょう。

投稿2017/06/24 12:15

yumetodo

総合スコア5850

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

TRON1216

2017/06/26 02:47

コメントありがとうございます。ウォッチ式とはSetTimer関数のことですか?
ardin

2017/06/26 07:50

横ですが、 ウォッチ式とはデバッグモード時に変数の中を表示できる機能です。 brekpointにひかかった際に、breawkpointをかけた同クラスの変数を表示できます。 だいたい画面の下にウォッチという項目があるのでそこです。 名前の列に変数名を入れてください ウォッチのウィンドウが見つからない場合、 画面上部メニューから[デバッグ]-[ウィンドウ]-[ウォッチ]でウォッチウィンドウを開けます
TRON1216

2017/06/26 08:04

なるほど、、ありがとうございます!今後参考にさせていただきます。
yumetodo

2017/06/27 01:37

ardinさんがだいたい答えてくれているけれど補足。 C/C++のデバッガーとしては、VSに付属のものやgdb, lldbなどが有名。いずれもwatch式という変数の監視ができる(watchという英単語そのものに監視という意味もある)。
TRON1216

2017/06/27 05:09

丁寧なアドバイスありがとうございます!なるほど、知らなかったです。感謝します。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問