mcrblog

vcpp-ml

2003年04月

28

[vcpp 00060613] RE: コントロールのサイズ変更での不具合

神戸です.

皆様からのアドバイスを頂き、お世話になります.

恥ずかしながら、原因が違い個所にありました.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#あくまでも、これまでメモリDCを多数枚使った経験がなかったこと
#メモリDCの描画作成方法を少し修正したことで改善が見られたことで
#[重い]という感じがメモリDCの使用方法に問題があると思い違いをして
#ました.

メモリDCの描画を中止して動作確認を行っても,
やはり、ドラッグ中にマウスの動作に画面サイズ変更がついてこない
動作(重さ)を感じました.

おやっ?と感じ、新規にプロジェクトを作成してサイズ変更可ダイアログを
つくってこちらは快適にサイズ変更してました.

2つを比較して違いは別な個所にありました, ご迷惑をおかけいたしました.

[vcpp 00060576] にある
>WM_GETMINMAXINFOのメッセージ処理(CWnd::OnGetMinMaxInfo())で,

>RECT rc;
>GetClientRect(&rc);
>RECT rect= rc;     //現在のクライアント幅を指定
>DefWindowProc(WM_NCCALCSIZE,0,(LONG)&rect);
>lpMMI->ptMinTrackSize.y =   rect.bottom; //NC領域の高さ
>としたらできるようになりました.

のWM_NCCALCSIZE メッセージの処理を無効にすると、快適に動作
するようになりました.
(なんでだろう~~?)
#この処理は、ダイアログにメニューを追加してサイズ変更に対して、
#メニューが隠蔽される動作を禁止するためのものです.

ドラッグ中はWM_SIZE,WM_SIZE,WM_SIZE,WM_PAINTとメッセージ処理がされて
おり、上記WM_NCCALCSIZ処理Eを無効にすればリアルタイムにクライアント
(コントロール表示)が、サイズ変更表示しました.
これも1つのWM_PAINTでサイズが序々に変更する表示はされないはずですが
そうなってないのは疑問符です. この件は、もう少し調べてみたいと思います.

以上、ありがとうございました.
27

[vcpp 00060612] RE: コントロールのサイズ変更での不具合

 渋木です。

> WM_PAINTは "paint a portion of an application's window" とMSDNに書いて
> あるので、WM_PAINTは画面への描画だと限定しても特に差し支えないと、僕は考
> えます。

 のはずですね。

> > 一般に描画やその前準備は WM_PAINT で行われるものです。だから、デバイ
> > スコンテキストは WM_PAINT にしか渡されません。WM_PAINT がくるまで、
> > 描画対象がモニタ画面か、印刷か、画面での印刷プレビューか、
> > あるいは EMF(メタファイル)への出力か、特定できないからです。

 は、MFC の OnDraw() とゴッチャになったのかもしれませんね。

# MFC の OnDraw() は、WM_PAINT だけでなく印字処理も担当します。


--
// 渋木宏明 (Hiroaki SHIBUKI)
// mailto:h...@mbi.nifty.com
// http://www.hidori.jp/
// Microsoft MVP 2002-2003 of Windows Technology
27

[vcpp 00060611] Re: コントロールのサイズ変更での不具合

安達です。

あれ? 前のメール送れてないのかな
送れていないという前提で、

サイズ変更中のWM_PAINT具合は、WindowClassStyleのCS_HREDRAW/CS_VREDRAWに
よっても変わります。

また、WM_PAINTはウィンドウの再描画用だとMSDNに書いてあるので、ウィンドウ
の再描画に限定してしまってよいのでは無いでしょうか。
それ以外の用途にはWM_PRINTとかを使えと書いてあります。

/****************************************
 Shin Adachi
   s...@adachin.com
   http://www.adachin.com
****************************************/
27

[vcpp 00060610] Re: コントロールのサイズ変更での不具合

安達です。 初めての投稿かな?
暇だったので、Windows2000の上でテストしてみました。

Windowをぐりぐり動かすだけで、すべてのWindowMessageはDefWindowProc()で処
理しています。
ログはWM_SIZE, WM_SIZING, WM_PAINT, WM_NCPAINT, WM_ERASEBKGNDを取りまし
た。

「ドラッグ中に云々」 off
ドラッグ中はWM_SIZINGがモリモリ
終了後に WM_NCPAINT -> WM_ERASEBKGND -> WM_SIZE -> WM_PAINT

「ドラッグ中に云々」 on
ドラッグ中は WM_SIZING+ -> WM_NCPAINT -> WM_ERASEBKGND -> WM_SIZE ->
WM_PAINT
終了後になぜかWM_SIZING

小さく変更する時も、大きく変更する時も挙動は変わらないように見えました。

大方予想通りですね。
WM_ERASEBKGNDがWM_SIZEの前に来るのは知りませんでした。
以上に間違いがありましたら、是非教えてください。


僕としても、現状で明らかに「遅い」ならば、WM_SIZEでフラグを立てて、
WM_PAINTで作り直す案を推薦します。
富豪的プグラミングは「ユーザーフレンドリな事を最優先しろ」って話だと思う
ので、軽い方が使いやすいならばそちらを採用すべきです。
#1 「ドラッグ中に云々」も富豪的UIだよね
#2 上記案で作り直しても、見た目は変わらない「はず」

> 一般に描画やその前準備は WM_PAINT で行われるものです。だから、デバイス
> コンテキストは WM_PAINT にしか渡されません。WM_PAINT がくるまで、
> 描画対象がモニタ画面か、印刷か、画面での印刷プレビューか、
> あるいは EMF(メタファイル)への出力か、特定できないからです。
WM_PAINTは "paint a portion of an application's window" とMSDNに書いてあ
るので、WM_PAINTは画面への描画だと限定しても特に差し支えないと、僕は考え
ます。

んで、その他のデバイスコンテキストに出力する場合はWM_PRINTとかを使え、と
書いてありますね。僕はこのメッセージ処理したことが無いんであまり大きな事
言えませんが。



余計なお世話かもしれませんが、議論するのは結構ですが、本質に関係の無い所
で熱くならないようにしてください。
# 送信する前にいっぱいコーヒーでも飲むとか
VCPPは参加者数も多いですし、それに前にも似たような事があって後味の悪い結
果になったような気がするので

以上、乱文失礼しました。

/****************************************
 Shin Adachi
   s...@adachin.com
   http://www.adachin.com
****************************************/
26

[vcpp 00060609] Re: コントロールのサイズ変更での不具合


馬渕@最後のレスです。
ちょっとした息抜きのつもりで何年ぶりにレスしたら
この有様ですか。

Yasuhiro.Kambe wrote in [vcpp 00060607] Re: コントロールのサイズ変更での不具合:

>3.他
>  一応、私の実装は
>  WM_SIZE でサイズに応じてメモリDC(仮想メモリ2枚,マスク用3枚)のサイズ変更
>  をしてInvalidate()させてます.☆ここが重いです.

これがいけないんです。サイズ変更のドラッグ中、内部では
WM_SIZE,WM_SIZE,WM_SIZE,WM_SIZE,WM_SIZE,WM_PAINT,
M_SIZE,WM_SIZE,WM_SIZE,WM_SIZE,WM_SIZE,WM_SIZE,WM_SIZE,WM_PAINT,
.....

のように、複数回のWM_SIZE ごとに WM_PAINT が来ます。
いくら WM_SIZE で メモリDCを更新したところで、 WM_PAINT で
描画されなければ、WM_PAINT 直前の WM_SIZE 処理以外は
無駄処理になります。それが重くなる原因です。

>  WM_PAINTにてメモリDCをコントロールのクライアントにBitBltしてます.
>
>  一応、サイズ変更と再描画を分けて考えているつもりですが、何かいけない
> でしょうか?

WM_SIZE 内でのメモリDCに対する操作も厳密には描画の一部(前準備)です。
でも、WM_SIZE で描画の準備をするのは本来推奨されていません。
だから、WM_SIZE にはデバイスコンテキストが渡されていません。

一般に描画やその前準備は WM_PAINT で行われるものです。だから、デバイス
コンテキストは WM_PAINT にしか渡されません。WM_PAINT がくるまで、
描画対象がモニタ画面か、印刷か、画面での印刷プレビューか、
あるいは EMF(メタファイル)への出力か、特定できないからです。
OnSize() で処理してしまうと、描画対象が特定されていないのに、勝手に
決めつけて描画素材(MemoryDCのこと)を用意することになります。

>4.最後に
> 検討した結果、サイズ変更時、コントロールのリアルタイムの再描画は
> したいので、マスクDCのサイズ変更を軽くするしか手はなさそうです.
> 違う方法で、検討してみます.

勘違いがあるようですが、

Invalidate() を呼んでも、実際に画面領域への書き込みは WM_PAINT() が
来なければ、行われません。ほかのタスクが重たければ、Invalidate() を
10回呼んだところで、WM_PAINT は一回しか来ないかもしれません。

WM_SIZE --> サイズ変わった。 (描画とは論理的に関係ありません)
Invalidate() -->  画面上にある特定の描画済み領域は最新状態ではない
                  ことをカーネルに知らせる。この時点でも、
                  描画とはなんら直接関係はありません。
                 (自分のウィンドウが隠れていれば、いくら
                  Invalidate() しても無視されます)
WM_PAINT --> ここではじめて画面への書き込みが許可されます。
             
だから、WM_SIZE でいくら Invalidate したところで、画面へのリアルタイム
再描画にはつながりません。 WM_PAINT を受け取った時点で最新の情報に
基づいて描画できるかどうか、それがリアルタイムの画面更新です。

Windows のメッセージ処理は非同期です。WM_SIZE が来たから、WM_PAINT
がくるとは限りませんし、WM_PAINT が来たのは、WM_SIZE 以外にも理由は
たくさんあります。

私からのレスは以上です。
知ったかぶりの人間と無意味なやりとりをするヒマはありませんし、
同じことを繰り返し書くのも疲れますので。

馬渕 茂
KOAH INTERACTIVE

P.S.
 .NET の完成度の低さに絶句して、かつての VC のマスターズたちがとうとう
 MS を見放して Builder に鞍替えしたのかもね。

 最後に、

Tietew wrote in [vcpp 00060606] Re: コントロールのサイズ変更での不具合:
>違います。ウィンドウサイズが変更された結果,無効領域ができるので 
>WM_PAINT が来るだけです。サイズを縮小方向に変更するのなら,
>WM_PAINT は(自動的には)来ません。しかも,UpdateWindow() しない
>と,次のアイドル時間まで WM_PAINT は遅延されます。

 ひぇぇぇ・・・。サイズが小さくなるから、WM_PAINT が来ません?
UpdateWindow() しないと WM_PAINT が来ません?
 思いっきりシングルタスクじゃん。
  UpdateWindow() しても WM_PAINT が来るとは限りませんし、
UpdateWindow() しなくたってWM_PAINT は来ます。タスクバーにある
「すべて最小化」でもクリックして SPY でもしてごらん。

 画面への描画はカーネルが「描け」と言われたときに「描く」ものです。
描きたいときに描くものだったら、画面グチャグチャですよ。

 だから、
> Windows API って読めるんですか :-p

 この程度の揚げ足取りしか反論できないんですね。
Windows Application Programming Interface を読みなさいってどこが
いけないのでしょうかね。昔じゃ、Windows プログラマにとっては
これが聖書みたいなもんだけどね。いまじゃ MSDN の隅っこに追いやられて
ほとんど英語版しか存在しないから、読んでいても それが Windows API 
だってことに気づかないんでしょうね。(^^)
記事検索
Amazon.co.jp
  • ライブドアブログ