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

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

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

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

Win32 API

Win32 APIはMicrosoft Windowsの32bitプロセッサのOSで動作するAPIです。

Q&A

解決済

3回答

10767閲覧

WM_PAINT時の画面のちらつきを抑えたい

katayaam

総合スコア10

C

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

Win32 API

Win32 APIはMicrosoft Windowsの32bitプロセッサのOSで動作するAPIです。

0グッド

0クリップ

投稿2017/01/07 10:04

###前提・実現したいこと
C言語とWIN32APIを使用したシステム開発を行っています。
現在はマウスカーソルの速度に応じてマウスカーソルの色を変化させるプログラムを実装しようとしています。
カーソルの速度が大きく変化した場合にのみWM_PAINTを呼び出し、カーソル(ウィンドウ)の再描画を行う方針です。

###発生している問題・エラーメッセージ
問題なのですが、InvalidateRect()の後にUpdateWindow()すると画面がちらつき、プログラムが凍ってしまいます。
調べたところ、ちらつく原因としては
InvalidateRect()で背景を塗りつぶす→UpdateWindow()による再描画の繰り返しによるものであると考えられたため、InvalidateRect()の第三引数をNULLにしたりと試みましたがうまくいきませんでした。

###該当のソースコード

/*カーソルの速度変化の判定部分*/ //20161225追加 if(test_gazeposition_flag){ //20160103追加(視線カーソルの速度評価) //最初の一回目はbefore_gazepositionを持っていないのでスルーする方向で行く if(Before_GazePosition_Count) { cal_speed = check_speed(GazePosition_X,GazePosition_Y,Before_GazePosition_X,Before_GazePosition_Y); file2 = fopen("./experiment/cal_speed.txt", "a+"); fprintf(file2, "%d,%d,%d,%d,%d\n",cal_speed,GazePosition_X,GazePosition_Y,Before_GazePosition_X,Before_GazePosition_Y); fclose(file2); //cal_speedによって速度のクラスを決定する if(cal_speed >= 40) { //高速 class_speed = 1; } else if(cal_speed >=20) { //中速 class_speed = 2; } else if(cal_speed >=5) { //低速①(パスート運動) class_speed = 3; } else if(cal_speed >=2) { //低速②(注視) class_speed = 4; } //以前のclass_speedと差異があるかの判定 if(check_class(class_speed)) { //以前と同じ場合、ここでは何もしない else { //違う場合は色を変えるためのフラグをオンに //一回目はここに入るはず… change_speed++; change_color = TRUE; } //1つ前のクラスを保存 before_class = class_speed; } else { //インクリメントすることで以後上の分岐に入る Before_GazePosition_Count++; } //20170103追加(ひとつ前のカーソル位置の保存) Before_GazePosition_X = GazePosition_X; Before_GazePosition_Y = GazePosition_Y; if(change_color) { InvalidateRect(hwndGazeCursor_Ctl,NULL,FALSE); ←カーソルの色を変える必要のある場合は一旦InvalidateRect()しています UpdateWindow(hwndGazeCursor_Ctl); } else { //視線カーソルウィンドウの更新 UpdateWindow(hwndGazeCursor_Ctl); ←カーソルの色を変える必要のない場合はそのままUpdateWindow()しています } /////////////////// WM_PAINTによる描画部分////////////////////////////////////// case WM_PAINT: if(!test_gazeposition_flag){ // BeginPaintでマーカーの表示を始める hdc = BeginPaint(hwnd, &ps); hBrush = CreateSolidBrush(RGB(0,0,0)); // ブラシの決定 RGB(0,0,0) SelectObject(hdc, hBrush); Rectangle(hdc, 0, 0, 17, 30); //直方形の描画 hOldB = SelectObject(hdc, hBrush); DeleteObject(hBrush); EndPaint(hwnd,&ps); } else { /*カーソルのスピードによって使用するブラシが変わりますが、上記とほぼ同様の描画処理*/ } break;

###試したこと
InvalidateRect()の第二引数を再描画の対象部分に指定 ← 解決に至らず(ちらつきがおさまらない)
InvalidateRect()の第三引数をNULLへと変更 ← 解決に至らず(同上)

###補足情報(言語/FW/ツール等のバージョンなど)
より詳細な情報
以下、参考にしたサイトです。

(1)「InvalidateRect関数」
<URL>https://msdn.microsoft.com/ja-jp/library/cc410421.aspx/

(2)「ちらつきをおさえる」
<URL>http://www.eonet.ne.jp/~maeda/winc/direct.htm/

(3)「描画の一括処理」
<URL>http://eternalwindows.jp/graphics/repaint/repaint04.html/

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

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

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

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

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

guest

回答3

0

頂いたコード片からは原因はわかりませんが、hBrushがSelectされた状態のままDeleteObject()されています。
普通は最初のSelectObjectの戻り値で古い方を保持します。

c

1(1) 2hdc = BeginPaint(hwnd, &ps); 3hBrush = CreateSolidBrush(RGB(0,0,0)); 4hOld = SelectObject(hdc, hBrush); 5Rectangle(hdc, 0, 0, 17, 30); 6SelectObject(hdc, hOld); 7DeleteObject(hBrush); 8EndPaint(hwnd, &ps); 9// ... 10return 0;

WM_PAINT(に限らないが..)ではbreakせずにreturn 0したほうがよいと思います。breakした先がDefWindowProc()だと良からぬことが起こっても不思議ではありません。EndPaintされた時点で要更新リージョンは無くなったのでDefWindowProcはWM_PAINTがきても何もしないと期待するのもある意味自然ですが、ちらついているのはBeginPaint()しているのにDefWindowProc()が背景色で上書きしている、と推測することもできます。

----追記
あまり説明することはありません。元の(質問者さんの)コードはこれです。

c

1(2) 2hdc = BeginPaint(hwnd, &ps); 3hBrush = CreateSolidBrush(RGB(0,0,0)); 4SelectObject(hdc, hBrush); // hBrushをSelectしている 5Rectangle(hdc, 0, 0, 17, 30); 6hOldB = SelectObject(hdc, hBrush); // << hBrushをもう一回Selectしている 7DeleteObject(hBrush); // << Select中のhBrushがDeleteされている 8EndPaint(hwnd,&ps); 9... 10break;

SelectObject 関数より、

アプリケーションは新しいオブジェクトを使い終えたら、必ず元の(既定)オブジェクトに置き換えるべきです。

ので、Deleteしてしまうのもマズいですが、hBrushをSelectしたままのもマズいです。私のコード片(1)では、最初のSelectObjectの戻り値を保持し、最後にそれに戻しています。APIの仕様(ドキュメント)を読めばこうなるというだけで、それ以上説明のしようがありません。

投稿2017/01/08 06:37

編集2017/01/09 10:18
sharow

総合スコア1149

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

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

katayaam

2017/01/09 07:33

回答ありがとうございます。 返信遅くなりました。申し訳ございません。 >頂いたコード片からは原因はわかりませんが、hBrushがSelectされた状態のままDeleteObject()されています。 >普通は最初のSelectObjectの戻り値で古い方を保持します。 恥ずかしながら、この部分についてご教授お願いします。
sharow

2017/01/09 10:12

コメントではマークダウンが効かないので回答に追記しました。
guest

0

CreateWindowsExでWS_EX_COMPOSITEDを指定してみたらどうでしょう?

プログラムが凍ってしまうというのは示されているコードではちょっと判断つかないです。

投稿2017/01/08 03:57

toki_td

総合スコア2850

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

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

katayaam

2017/01/08 12:40

>CreateWindowsExでWS_EX_COMPOSITEDを指定してみたらどうでしょう? 一応調べてみたのですが、CreateWindowsEx関数の第一引数に「WS_EX_COMPOSITED」を指定するということでしょうか? 「WS_EX_COMPOSITED」というものが見かならないのですが… 以下、参照したサイトです。 <URL><https://msdn.microsoft.com/ja-jp/library/cc410714.aspx/>
toki_td

2017/01/09 07:41

ほんとだ。英語版のほうには書いてるんですけどね。 https://msdn.microsoft.com/en-us/library/windows/desktop/ff700543(v=vs.85).aspx see remarkといいながらremarkがなかったりしますが、、、 WM_EX_COMPOSITEDを指定すると子ウィンドウを含む自身の領域をダブルバッファリングするようになります。そのため背景の消去が見えなくなるかと。
guest

0

ベストアンサー

UpdateWindowを呼ぶ必要はありますか?

参考文献: http://rarara.cafe.coocan.jp/cgi-bin/lng/vc/vclng.cgi?print+200302/03020122.txt

投稿2017/01/07 13:42

majiponi

総合スコア1720

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

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

katayaam

2017/01/08 12:44

回答ありがとうございます。 確かにUpdateWindow()なしでInvalidateRect()をすれば、更新リージョンのメッセージが送信され、再描画されると思います。 しかしながら、InvalidateRect()のみでは意図したタイミングで再描画されると限らないとのことなのでUpdateWindow()しています。
katayaam

2017/01/09 02:28

>GetDCなどを使って描画しては 確かにそうですね。今日中に試してみます。
katayaam

2017/01/12 02:10

返信遅くなりました。 アイドル中の描画専用関数を用意することでなんとか解決することができました。 (どうやら描画の呼び出す場所が悪かったようです) 全ての回答者様に感謝しています、ありがとうございました。 全ての回答者様にBAをつけたいのですが、一番早く回答をくださったmajiponi様にBAをつけたいと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問