ページ 11

ウィンドウの自動更新について

Posted: 2016年5月16日(月) 22:43
by クールくん

コード:

		case WM_CREATE:
			SetTimer(hwnd,ID_MYTIMER,500,NULL);
			break;

		case WM_TIMER:
			InvalidateRect(hwnd,NULL,TRUE);
			UpdateWindow(hwnd);
			break;

		case WM_PAINT:
			rc = sqlite3_open("./db/data.db",&db);

			if(rc != SQLITE_OK)
			{
				MessageBox(NULL,"Error","ERROR!!",MB_OK);
			}
			else
			{
				memset(query,0,sizeof(query));
				query = "select NAME,FLAG from TABLE";
				sqlite3_prepare(db,query,strlen(query),&stmt,NULL);

				sqlite3_reset(stmt);

				hdc = BeginPaint(hwnd,&paint);

				memset(str,0,sizeof(str));
				i = 0;
				while(SQLITE_ROW == (rc = sqlite3_step(stmt)))
				{
					name = sqlite3_column_text(stmt,0);
					flag = sqlite3_column_int(stmt,2);

					sprintf(str,"%s                 %d",name,flag);
					TextOut(hdc,10,i*20,(LPCSTR)str,strlen(str));
					i++;
				}


				sqlite3_finalize(stmt);
				sqlite3_close(db);
			}
			break;
ウィンドウにSQLiteで取得したデータを描画させるプログラムです。
データの追加、削除、変更をする外部プログラムがあるのですが、
この外部プログラムにて、何らかのアクションがあったとしても
常に最新のデータを描画させ続けたいのですが、
このような書き方に何か問題はありますか?

描画、再描画は一応できているのですが、
このプログラムは常に起動させておきたいです。
昨晩から試に起動させっぱなしにして仕事に行って、いま帰宅したのですが、
画面が真っ白になっていました。
再描画の無限ループになっているので、PCへの負担は大きいと思いますが、
通常このような場合、どのように対処するのでしょうか?

同一のプログラム内でデータ更新のアクションがあれば、その瞬間にだけ再描画させるプログラムを書くことができますが、
外部プログラムとなると、よくわかりません。

アドバイスよろしくお願いします。

Re: ウィンドウの自動更新について

Posted: 2016年5月16日(月) 22:52
by みけCAT
少なくとも、
BeginPaint 関数を呼び出したときには、必ず対応する EndPaint 関数を呼び出さなければなりません。
とされているBeginPaint 関数を呼び出しているのに、EndPaint 関数を呼び出していないので、まずいでしょう。

Re: ウィンドウの自動更新について

Posted: 2016年5月16日(月) 23:01
by クールくん
みけCAT さんが書きました:少なくとも、
BeginPaint 関数を呼び出したときには、必ず対応する EndPaint 関数を呼び出さなければなりません。
とされているBeginPaint 関数を呼び出しているのに、EndPaint 関数を呼び出していないので、まずいでしょう。
確かにEndPaintを使っていなかったのは、まずかったです。
ご指摘ありがとうございます。

他に問題点や、改善した方がいいところがあったらお願いします。

Re: ウィンドウの自動更新について

Posted: 2016年5月16日(月) 23:45
by YuO
思ったことをつらつらと。
  • SQLiteのデータが更新されていないなら,表示を更新する必要は無いですよね。
    表示するデータの量によりますが,前回のデータを保持した状態で,タイマー駆動でデータをとってきて,前回と比較,変化があれば再描画,という形にすると,描画の回数が減ります。
  • そもそもSQLiteはファイルベースなので,ファイルの変更を監視する,という方法でデータの変更をとってくることができるかもしれません。

Re: ウィンドウの自動更新について

Posted: 2016年5月17日(火) 00:10
by クールくん
YuO さんが書きました:思ったことをつらつらと。
  • SQLiteのデータが更新されていないなら,表示を更新する必要は無いですよね。
    表示するデータの量によりますが,前回のデータを保持した状態で,タイマー駆動でデータをとってきて,前回と比較,変化があれば再描画,という形にすると,描画の回数が減ります。
  • そもそもSQLiteはファイルベースなので,ファイルの変更を監視する,という方法でデータの変更をとってくることができるかもしれません。
ご指摘ありがとうございます。
確かにファイルの変更を監視するとう方法がいいかもしれませんね。
通常このような処理をする場合には何を監視すればいいのでしょうか?
バイト数ですか?
それともバイナリでしょうか?

Re: ウィンドウの自動更新について

Posted: 2016年5月17日(火) 00:16
by みけCAT
クールくん さんが書きました:通常このような処理をする場合には何を監視すればいいのでしょうか?
相手のプログラムの仕様にもよるかもしれませんが、タイムスタンプはどうでしょうか?

Re: ウィンドウの自動更新について

Posted: 2016年5月17日(火) 00:21
by みけCAT
他に気になったことは、
クールくん さんが書きました:

コード:

				memset(query,0,sizeof(query));
				query = "select NAME,FLAG from TABLE";
どうせすぐに代入をするのに、わざわざ0 (ちなみに仕様上NULLとは限らない) で初期化しているのはなぜでしょうか?
クールくん さんが書きました:

コード:

					name = sqlite3_column_text(stmt,0);
					flag = sqlite3_column_int(stmt,2);

					sprintf(str,"%s                 %d",name,flag);
nameに十分長い文字列(へのポインタ)が代入された場合、バッファオーバーランを起こすリスクがあります。
クールくん さんが書きました:

コード:

					TextOut(hdc,10,i*20,(LPCSTR)str,strlen(str));
strはsprintfに渡されているので、char*、もしくは式中でchar*に変換される配列であると予想できます。
従って、明示的にTextOutAを呼び出し、LPCSTRへのキャストも消したほうがいい気がします。

Re: ウィンドウの自動更新について

Posted: 2016年5月17日(火) 14:25
by YuO
クールくん さんが書きました:確かにファイルの変更を監視するとう方法がいいかもしれませんね。
通常このような処理をする場合には何を監視すればいいのでしょうか?
Windowsに関してならば,ReadDirectoryChangesWFindFirstChangeNotificationといった,ファイルシステムの変更を通知してくれるAPIがありますので,これを使います。
通知内容は,FILE_NOTIFY_CHANGE_LAST_WRITEだけでも十分だと思います。