右クリックメニューを閉じた後の背景処理


焼蛤  2007-11-25 08:24:38  No: 66968

vc6++ SDKです。 

TrackPopupMenuで表示した所謂右クリックメニューって、メニューが消えたときのクライアント領域の背景の復興処理って自分でやらなきゃいけないんでしょうか?
デスクトップで右クリックメニューを閉じたあと、特に画面全体が再描画されてるようにも見えない。
メニューが表示された矩形領域の座標もわからないので、BitBltっていう手段も無理っぽいし、いちいち全体を描きなおすっていうのも無理な場合もあるし、ウィンドウスタイルかクラススタイルでのなんらかの指定になるんでしょうか?


maru  2007-11-26 00:51:05  No: 66969

メニューが消えたからといって自分で描画を行う必要はありません。
描画が必要ならばOSからWM_PAINTメッセージが来るので、そのパラメータ
に応じて描画すればいいだけ。

というか、やってみれば一発でわかると思うけど。


焼蛤  2007-11-26 07:14:53  No: 66970

右クリックメニュー表示前に、どういうものが表示されていたか記憶させてない場合です。


wclrp ( 'o')  2007-11-26 08:08:30  No: 66971

何でだろうね。
一時的な表示なら背後を覚えてくれるような話を聞いたことがある。
でも、背後の内容を確実に覚えてくれるのではないよ。

ということでどういうものが表示されていたか覚えておいたほうがいいんじゃない。


maru  2007-11-26 18:17:59  No: 66972

なぜこんなことを気にしているのか分からないし、今イチ話のつながりが
分からない。

> 右クリックメニュー表示前に、どういうものが表示されていたか記憶させてない場合です。
「記憶させていない」の主語と目的語(何に)が書かれていないのでよく分か
らないけど、...
WM_PAINTで少なくとも一回は描画は行なわれたんでしょ。
だったら、アプリケーション側でどういうものが表示されていたかは関係なく
画面上に描画データは残っているはず。従ってWindowsが右クリックメニュー
表示前にその領域を待避し、消えた後にそれを復旧することは可能なはず。

Windowsアプリケーションの描画は前にも書いたように、WM_PAINTメッセージ
でそのパラメータに応じて描画すればいいだけです。そのパラメータには右ク
リックメニューを表示した後だから描画しなければいけない、とか、他のアプ
リケーションが前にきて一部が消えたから描画しなければいけない、などの理
由は分かりません。そもそもそんな理由を考えなくていいシステムなんです。

wclrp ( 'o')さん
> どういうものが表示されていたか覚えておいたほうがいいんじゃない。
と言うのは当たり前では?何が描画されるか分からなければそもそもWM_PAINT
でどういう処理をすればいか分からない。


シャノン  2007-11-26 18:52:58  No: 66973

> デスクトップで右クリックメニューを閉じたあと、特に画面全体が再描画されてるようにも見えない。

未検証ですが、そのメニューがあった場所だけ再描画される(システムからアプリに再描画指示が来る)んじゃないかなーと。

> 右クリックメニュー表示前に、どういうものが表示されていたか記憶させてない場合です。

その場合は再描画されないでしょう。

再描画は勝手にされるものではありません。
メニューが消えた後であれ、ウィンドウのサイズを変えたときであれ、いかなる場合でも、システムから描画指示が来て、アプリが描画するのです。
そういう意味では、メニューが消えた後に限らず、描画処理が必要な場合は常にアプリがしなければいけません。

で、あなたは、メニューが消えた後が描画されなかったからこういう質問をしているわけですか?
なんとなく疑問に思っただけであれば、試してみたほうが早いのでは?


シャノン  2007-11-26 18:54:32  No: 66974

言い忘れた。

> 右クリックメニュー表示前に、どういうものが表示されていたか記憶させてない場合です。

maruさんもおっしゃっていますが、記憶しておくのが Windows プログラミングのセオリーです。
記憶させていないのなら、なぜ記憶していないのか、その理由が必要です。


maru  2007-11-26 21:01:04  No: 66975

一部修正

> 描画が必要ならばOSからWM_PAINTメッセージが来るので、そのパラメータ
> に応じて描画すればいいだけ。
WM_PAINTメッセージのパラメータで分かるのはウィンドウハンドルだけでした。
描画領域はBeginPaint関数で取得する必要があります。
# 最近は描画処理なんて書いていなかったのですっかり忘れている!

アプリ側は理由が何であれ、WM_PAINTで指定された領域を再描画すればよいの
です。理由なんか気にしちゃいけません。


焼蛤  2007-11-28 02:48:16  No: 66976

レスどうもです。
うーん、たしかカーソルやメニューの表示でできた穴?はシステムが再描画を受け持ってくれてたような記憶があるんですが、右クリックメニューで実際に再描画されるかというと、されなかったんです。
WM_PAINTで、再描画の要求がきた時に、アプリケーションで面倒をみる
多分これはGUIプログラムの基礎なんだと思います。

今回の場合は、大量のデータと画像をダーっと描画している途中で、右クリックメニューを表示し、処理を選択できるようにしていたので。。

ウィンドウ作成時か、若しくはクラス登録時か、なにかオプションでもあったかなぁと


maru  2007-11-28 04:27:36  No: 66977

> 大量のデータと画像をダーっと描画している途中

> 右クリックメニューを表示し
って、どういうことか理解できない。ペイント中で普通は他の操作できないよね。
ペイント処理を別スレッドでやっているってこと?

描画の途中に処理を選択するようなUIって想像できない。


焼蛤  2007-11-28 16:16:09  No: 66978

描画処理は副スレッドが受け持っています。
それをメインスレッドで、右クリックメニューやキーボードアクセラレータから操作する、そういう感じです。


maru  2007-11-28 19:18:06  No: 66979

描画処理を別スレッドにして、描画処理中にメニュー操作を行なう実験をしたら、WM_PAINTメッセージがきた。
# 描画が完了したあとの操作はまだやっていない。

で、肝心の
> ウィンドウ作成時か、若しくはクラス登録時か、なにかオプションでもあったかなぁと
は、不幸にして知りません。
あったとして、システムが画面を待避/復旧する間(メニューを表示してから消
す間)に別スレッドが描画した部分はメニューを表示した時点の画面に戻るよう
な気がします。
# あくまで私見です。

描画中に操作できるという仕様を変更したほうがよいのでは、というのが私の意見です(どんなプログラムか知りませんが)。
少なくとも、時間がかかる大量のデータ処理と、描画処理は分離した方が良いのではないでしょうか。

やっぱり描画処理を別スレッドにするのって分からない。
だって描画処理中に他の操作が出来るってことは、描画処理途中に対象領域が
変わることがあるってことだよね。その時は現在の処理をやめて、また最初か
らやり直すの?


シャノン  2007-11-28 20:51:34  No: 66980

大量のデータの描画中ということは、描画内容は刻々と変化しているのですか?
そんな状況では、描画すべき内容を把握しているのはアプリだけでしょう。

一応、CS_SAVEBITSというクラススタイルがありますが…


シャノン  2007-11-28 20:55:27  No: 66981

maruさん>

推測ですが、データ処理はアプリが動いている間はずっと継続するような形態なのでは?
例えば、WindowsのタスクマネージャにあるCPU使用率グラフみたいな。


maru  2007-11-28 21:29:34  No: 66982

シャノンさん>
そうだとしても、データ処理と描画処理は分離したほうが良いことは賛成してくれますよね。
タスクマネージャのCPU使用率だって、ウィンドウサイズを変更した後にそれ以前の
データのグラフは再表示されますし。

焼蛤さん>
要は描画処理の中に、時間のかかる処理は入れるな!ってこと。
描画処理が短時間に終われば、一番最初の疑問である「メニューが消えたときのクライアント領域の背景の復興処理」なんて気にしなくても済む。
そういう構造にしておくことが重要。


シャノン  2007-11-28 23:08:05  No: 66983

描画スレッドを使うっていう作りはそんなに変なものですかね?
ま、俺は使ったことありませんけども。


maru  2007-11-29 02:42:03  No: 66984

結構長いことWindowsのプログラムをやってきましたが、幸いなことに描画
スレッドなんて物を作成せずに済んでいます。

ある処理(描画)を専用のスレッドで行なう。と言う観点で見ると
> 描画スレッドを使うっていう作り
はそれほど変とは言えないかも知れません。

でも、描画の対象は画面であり、その画面はユーザの操作によって種々な更
新が起こり得るんです。その結果、描画を行なう必要が出てくる。まさに今
回のケースです。そうするとUI側で描画スレッドを管理する必要やら描画領
域を管理する必要が出てきてプログラムが複雑化する。そういう意味で私の
目から見ると「描画スレッド」は非常に奇異に感じます。
わざわざ複雑な作りにしているようにしか見えない。

大量のデータを処理しながら描画するって、考えられるのは自前で動画処理
をやるくらいかな?


焼蛤  2007-11-29 04:19:23  No: 66985

焼蛤です。
こんなにいろいろと付き合ってくれて感謝です。

シャノンさんが教えてくれたCS_SAVEBITSを実験してみましたが、右クリックメニュー表示前に、別スレッドの描画を一旦停止して、
メニュー表示→何も選択せずに閉じる(メニュー矩形の外をクリック)
これでは、システムが自動的にもとに戻してくれました。
これはCS_SAVEBITSが指定されているかの如何に関わらずです。
白い矩形が残るということもありません。(背景は白ブラシ)

右クリックで描画を止め、メニューが閉じた後描画を再開、という形なら
白い矩形は残りませんでした。

でも、たしかにみなさんのご指摘のように、複雑な処理は避けたほうがいいですね。
今回はメルセンヌ・ツイスターというランダム関数の日本版みたいなものを実験していたので、再描画をシステムに受け持ってもらえたら楽になるなぁと・・
ただどういうときに、システム側で面倒をみてくれるのか、がいまいちよく分かりません。ぺゾル度本には、カーソルとメニューはOSで云々というくだりがあったような記憶がありますが。


焼蛤  2007-11-29 04:42:11  No: 66986

今PSDKを読み返してみたんだけど、CS_SAVEBITSについて
「Saves, as a bitmap, the portion of the screen image obscured by a window of this class. When the window is removed, the system uses the saved bitmap to restore the screen image, including other windows that were obscured.」
ってある。
これって、自分のウィンドウのイメージじゃなくて、自ウィンドウが隠した背後のウィンドウたちの再描画をシステムで面倒みますよ、ってことなんじゃないかと思うんですが。。


rin  2007-11-29 05:18:03  No: 66987

焼蛤さん
副スレッドで行っている描画処理というのは、
どんな手法で、どこに対して描画処理をしてるのでしょうか?

また、再描画されないというのは
A「メニューを表示する前に表示されていたものが、メニューを閉じたあとに消えている」
B「メニューを表示中にも描画作業は続けていて、
  メニューの下に描画することもある。その下に描画したはずのものが
  メニューを閉じても更新されていなかった。」
どっちでしょうか?

別スレッドから、表示ウィンドウのDCに直接書くという実験してみたんですが、
前者Aは起こらず、後者Bは起きました。
さらに、Bの場合は、メニュー閉じたあとにWM_PAINTが通知されました。
どうやら、メニューが表示されてる間は、メニューの下には描画できず
メニューを閉じた後にやってね・・とWM_PAINTが発生してるようです。
#メニュー表示中に、別の場所に描画成功してる場合は、メニューを閉じてもWM_PAINTは起きない

対策としては、何度もいわれてる通り「描画内容を記憶しておく」しかないかと。

「裏画面」「ダブルバッファ」とかって言われる手法がお勧め。

概略
1:最初に表示画面とは別に、メモリ上に別の描画領域を作成しておく
2:副スレッドはコッチに描画する。
3:描画したら、表示ウィンドウに対し、再描画するように通知。
4:表示ウィンドウは、再描画通知がきたら別領域から表示領域に必要分コピーする。必要分がわからなければ全部
5:メニューにしろなんにしろ、表示領域が再描画通知うけたら4番の処理する

こうすれば、メニュー表示からは影響うけない描画領域に
描画したものをまるまる記憶しておくことができますし、
描画処理のための座標とかそんなこまっちくれぇことも記憶させなくてすみます。
当然、再計算もいりません。
#ちらつきを抑える方法として有名な手段です。
#イマドキのPCなら、毎回、画面全体をコピーするとしても、
#そのことで遅延表示されることはまずない。

>maruさんへ
ゲームなんかは、描画スレッドが別なこと多いですよ。
とくにオンラインゲームやアクションゲーム
ユーザの行動とはまったく別に時間でどんどん描画しつづけますし
かといってユーザの行動の結果もどんどん受け入れる必要ありますから


ゲーム屋  2007-11-29 08:47:46  No: 66988

>ゲームなんかは、描画スレッドが別なこと多いですよ。
>とくにオンラインゲームやアクションゲーム
うーん、これはほぼ「間違い」ですよ。特に市販ゲームを指しているのならそうです。ごく最近までゲームはむしろシングルスレッドを代表するアプリでしたから。ようやく最近になって物理やAIの面でマルチスレッドになり始めたばかりで、それですらごく少数の話です。
本題とは関係の無い話ですみませんが。


maru  2007-11-30 02:33:14  No: 66989

> ゲームなんかは、描画スレッドが別なこと多いですよ。
そうですか...。ゲームを作る人や環境からは遠いところにいるもので...

「描画スレッド」という単語を単独で考えるとおかしな話になります。
元々は、私が
> やっぱり描画処理を別スレッドにするのって分からない。
って書いたのを、シャノンさんが
> 描画スレッドを使うっていう作りはそんなに変なものですかね?
と「描画スレッド」と呼んだんですけど、今回私が「描画処理」と呼んでい
るものは、WM_PAINTに対する画面更新処理にあたります。
前にも書いたように、画面更新処理の為にスレッドを立てるというのは、や
はり奇異に感じます。
それとは別に、画面用のデータを生成するという意味での描画に対するスレ
ッドで「描画スレッド」という使い方であれば、それほどおかしくは感じま
せん。

# それで、rinさんが使った「描画スレッド」はどっち?


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加