C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Invalidateを遅らせる方法

[トピック内 9 記事 (1 - 9 表示)]  << 0 >>

■100434 / inTopicNo.1)  Invalidateを遅らせる方法
  
□投稿者/ ちょき (1回)-(2022/08/11(Thu) 08:29:47)

分類:[.NET 全般] 

VB.NETを使った画像処理プログラムを書いています。

いま、フォーム上にPictureBox1とChart1が配置してあるとします。

このPictureBox1にラインが描画されており、
これをマウスで操作すると、そのライン位置の画像データが抽出され、
あるフィルター処理がかけられた後に
そのデータがChart1に表示されるというプログラムを書いています。

普通に書くと

Sub PictureBox1_MouseMove
 
 ライン位置の設定
 PictureBox1.Invalidate
 Chart1の描画処理

End Sub


Sub PictureBox1_Paint

 ラインの描画

End Sub



となります。
これでも動作はするのですが、
Chart1の描画処理が非常に重いため、
カーソルの動きがカクカクしてしまいます。

そのため、

Sub PictureBox1_MouseMove
 
 ライン位置の設定
 PictureBox1.Invalidate

End Sub


Sub PictureBox1_Paint

 ラインの描画
 Chart1の描画処理

End Sub


のように改良しました。

こうすることで、ある程度レイテンシーを持たせて
Chart1の描画処理を行うため、Paint処理が軽くなります。

ただし、これでもやはりフィルター処理によっては重くなってしまいます。

ラインの描画はリアルタイムで表示してほしいですが、
Chart1の表示は多少は遅れがあっても良いと考えています。

そのため、Chart1のInvalidateだけを少し間隔をおくとかっていう設定はないでしょうか?


引用返信 編集キー/
■100435 / inTopicNo.2)  Re[1]: Invalidateを遅らせる方法
□投稿者/ KOZ (307回)-(2022/08/11(Thu) 09:10:16)
No100434 (ちょき さん) に返信
> 普通に書くと
> Sub PictureBox1_MouseMove
>  ライン位置の設定
> PictureBox1.Invalidate
> Chart1の描画処理
> End Sub
> Chart1の描画処理が非常に重いため、
> カーソルの動きがカクカクしてしまいます。

Chart1の描画処理を BeginInvoke で呼び出したらどうでしょう?

引用返信 編集キー/
■100436 / inTopicNo.3)  Re[2]: Invalidateを遅らせる方法
□投稿者/ ちょき (2回)-(2022/08/11(Thu) 12:39:53)
ありがとうございます。

試してみましたが。

BeginInvoke をSub PictureBox1_MouseMove内で実行すると
Paint内で実行するものと比べて遅くなってしまいました。

Paint内でもBeginInvokeを試してみたのですが、
特に大きな違いは見られませんでした。

他に方法はないでしょうか?

引用返信 編集キー/
■100437 / inTopicNo.4)  Re[3]: Invalidateを遅らせる方法
□投稿者/ KOZ (308回)-(2022/08/11(Thu) 14:42:52)
No100436 (ちょき さん) に返信
> 試してみましたが。
> BeginInvoke をSub PictureBox1_MouseMove内で実行すると
> Paint内で実行するものと比べて遅くなってしまいました。

変ですね?タイミングが違うだけで処理は同じはずですが・・・

Sub PictureBox1_MouseMove
 ライン位置の設定
 PictureBox1.Invalidate
 BeginInvoke Chart1の描画処理
End Sub

Sub PictureBox1_Paint
 ラインの描画
End Sub

こうなってますよね?

引用返信 編集キー/
■100438 / inTopicNo.5)  Re[1]: Invalidateを遅らせる方法
□投稿者/ Azulean (1249回)-(2022/08/11(Thu) 17:56:03)
2022/08/11(Thu) 17:57:33 編集(投稿者)

No100434 (ちょき さん) に返信
> ただし、これでもやはりフィルター処理によっては重くなってしまいます。
>
> ラインの描画はリアルタイムで表示してほしいですが、
> Chart1の表示は多少は遅れがあっても良いと考えています。
>
> そのため、Chart1のInvalidateだけを少し間隔をおくとかっていう設定はないでしょうか?


「MouseMove に対するライン表示の追従性の追求」に対して、「Chart1 の表示処理の処理にかかる時間(コスト)」が間に合わないってことですよね。
まずは「Chart 1 の表示処理にかかる時間」を Stopwatch クラスなどで測ってみてください。

これが、数ミリ秒で終わらず、数十ミリ超えてくるなら「シングルスレッドでは望みを実現することは不可能であろう」ということになります。
Task を使ったマルチスレッドを勉強してみてください。
ただ、バックグラウンドスレッドでの処理完了前に次の MouseMove による処理のリクエストが走るなど、作るのはそれなりに難しくなります。


なお、「Chart 1 の表示処理」が自前のコードではなく、Chart1 にお任せの処理である場合、スレッドを分けること自体が無理なので、「データ量を減らすなど、何かを諦めてください」となるかもしれません。


No100437 (KOZ さん) に返信
> ■No100436 (ちょき さん) に返信
>>試してみましたが。
>>BeginInvoke をSub PictureBox1_MouseMove内で実行すると
>>Paint内で実行するものと比べて遅くなってしまいました。
>
> 変ですね?タイミングが違うだけで処理は同じはずですが・・・


いやいや、処理の「回数」は増えているでしょう。

MouseMove や Paint はメインスレッドの埋まり具合によって間引かれますが、BeginInvoke での呼び出しは間引かれませんので、結果的に増えます。(メインスレッドが埋まる)
引用返信 編集キー/
■100439 / inTopicNo.6)  Re[1]: Invalidateを遅らせる方法
□投稿者/ radian (92回)-(2022/08/12(Fri) 11:08:08)
2022/08/12(Fri) 23:02:51 編集(投稿者)

No100434 (ちょき さん) に返信
> ラインの描画はリアルタイムで表示してほしいですが、
> Chart1の表示は多少は遅れがあっても良いと考えています。
>
> そのため、Chart1のInvalidateだけを少し間隔をおくとかっていう設定はないでしょうか?

Invalidateを遅らせたところで、Chart1の更新自体に時間がかかるなら、
どう足掻いても更新が発生したタイミングはカクつくのではないでしょうか。
(コントロールの更新自体はUIスレッドになるでしょうし)
単純に描画回数を減らすなら、Timerオブジェクト起動してそちらで更新するとか?
前回の更新時間を記憶しておけば、更新しすぎるという事はないでしょうし。

別スレッド、あるいは別プロセスでChart用のフォーム作れば影響は避けれそうですけど、
データのやり取りなど色々考える事多くて面倒そうではあります。
引用返信 編集キー/
■100451 / inTopicNo.7)  Re[2]: Invalidateを遅らせる方法
□投稿者/ KOZ (310回)-(2022/08/12(Fri) 17:33:59)
No100438 (Azulean さん) に返信
> いやいや、処理の「回数」は増えているでしょう。
> MouseMove や Paint はメインスレッドの埋まり具合によって間引かれますが、BeginInvoke での呼び出しは間引かれませんので、結果的に増えます。(メインスレッドが埋まる)

うーん、これで追従できないほど長い処理だとどうしようもない気がします。

ラインの操作はおそらく、MouseDown で開始して MouseUp で終了するのでしょうから、
MouseUp イベントで走らせるとか、Application.Idle イベントを使うとか。
引用返信 編集キー/
■100456 / inTopicNo.8)  Re[1]: Invalidateを遅らせる方法
□投稿者/ HattariB (30回)-(2022/08/16(Tue) 10:00:15)
No100434 (ちょき さん) に返信
> 普通に書くと
> PictureBox1.Invalidate
>
引数無しで呼び出してる。

ま、これはおいといて、

マウスムーブハンドラでは、直接重い処理は呼ばない方が良いと思います。
必要な情報をエンキュ&#12316;して、タイマーかけた別スレッドで、デキューしなから更新させるのが、
良いと思います。

引用返信 編集キー/
■100457 / inTopicNo.9)  Re[2]: Invalidateを遅らせる方法
□投稿者/ ちょき (3回)-(2022/08/16(Tue) 11:14:02)
皆さんありがとうございます。

タイマーかけた別スレッドで走らせるのは一度考えたのですが
コードが見づらくなるので
デフォルトでタイミングをずらすコマンドがないかと思って質問しました。
やはりそのような方法はなさそうですね。


解決済み
引用返信 編集キー/

このトピックをツリーで一括表示


トピック内ページ移動 / << 0 >>

このトピックに書きこむ