モードレスダイアログでもちらつきなく描画するには?

解決


Place  2010-07-08 09:38:56  No: 71799  IP: 192.*.*.*

質問させて頂きます。

------------
|       ___|___
|    A  |      |
|       |   B  |
--------|      |
        --------

上図のように、AのメインウィンドウとBのサブウィンドウを用意しています。
BはAと親子関係を持つと、Aの枠を超えて表示出来ないため、親子関係は持っておりません。

最近、モードレスダイアログにしてAの枠を超えて表示でき、親子関係にしました。

その結果、枠を超えての表示は行えましたが、Aを動かした時にBは追従するよう動きますが
その際にAとBが重なっている部分が瞬間的に消え、Bもダイアログもチラツキが発生します。

モードレスダイアログにする前はそのような現象はありませんでした。
描画する際も、一度裏画面に描画して、WM_PAINT時に裏画面の内容を表にだす(ダブルバッファリング)方法を利用していますので
それでチラツキは考えにくいです。

背景を初期化するWM_ERASEBKGNDが発行された時は、何もしないようにしていますので
何故ちらつくのかが疑問に思っています。

ダイアログと通常のウィンドウでは描画に何か違いがあるのでしょうか?
個人的には、モードレスダイアログ時に、Aと親子関係を結んだため
このような現象が起きているのでは無いのかと思っています。


なるべく、Bはモードレスダイアログで解決したいです。
どうぞ解決策など、お知恵をお貸しください。

編集 削除
仲澤@失業者  2010-07-08 12:50:12  No: 71800  IP: 192.*.*.*

>その結果、枠を超えての表示は行えましたが、Aを動かした時に
>Bは追従するよう動きますが

自分のコードで追従させているのでしょうか(質問)。
その場合で、SetWindowPos()を使っている場合、SWP_NOREDRAWを
指定してますでしょうか。

>その際にAとBが重なっている部分が瞬間的に消え、
>Bもダイアログもチラツキが発生します。

Aが消えるのは当たり前ですが、BにWM_PAINTが来るのは変ですね。

編集 削除
Place  2010-07-08 14:18:00  No: 71801  IP: 192.*.*.*

レス有難うございます。

>自分のコードで追従させているのでしょうか(質問)。
はい、自分のコードで追従させています。
具体的には、Aがクリックされたらマウスキャプチャーを行い
WM_MOUSEMOVE時にAが動いたら、一緒にBを動かしています。
Bを動かすときは、MoveWindowを使用しており、再描画フラグはFALSEにしています。


>Aが消えるのは当たり前ですが、BにWM_PAINTが来るのは変ですね。
Aが消えるのは親子関係を持っているからでしょうか?

また、私が書いた図が崩れて表示されています…
テキストエディタに貼り付けて頂けると、きちんと表示されます
ご迷惑をお掛けし申し訳ありません。

編集 削除
仲澤@失業者  2010-07-08 14:44:28  No: 71802  IP: 192.*.*.*

>Bを動かすときは、MoveWindowを使用しており、再描画フラグはFALSEにして>います。

経験的に言うと、再描画に関しては、MoveWindow()は信用できませんので、
SetWindowPos()に変更してみてください。

>Aが消えるのは親子関係を持っているからでしょうか?

親子関係とは(本来は)無関係です。AはBよりZオーダーが奥側です。
Aが移動を開始〜終了するとき

1.WM_MOVING
2.WM_WINDOWPOSCHANGING
3.WM_GETMINMAXINFO
4.WM_WINDOWPOSCHANGED // ここで移動が完了
5.WM_MOVE

の順でメッセージを処理しますが、4.で既に移動が完了してしまいます。
この段階ではBはまだ以前の位置のままです。
その後、5.の中でBの位置を変更しても、もう遅いのです。
WS_CHILDウインドウのように完全に追従させるには
上記のメッセージの流れを理解した上で、Bウインドウの位置を
そのメッセージ毎にコントロールしなければなりません。

しかし、Bに再描画が来るのは、多分別の原因ではないかと
疑っています。

編集 削除
Place  2010-07-08 21:57:50  No: 71803  IP: 192.*.*.*

レス有難うございます。

>SetWindowPos()に変更してみてください。
試してみたところ、やはり解決には至りませんでした。

モードレスから普通のウィンドウに変えるだけで、ちらつき等はやはり解決します。


また、詳しいメッセージの流れを記載して頂き有難うございます。
>上記のメッセージの流れを理解した上で、Bウインドウの位置を
>そのメッセージ毎にコントロールしなければなりません。
先にBを移動させて、後からAを移動させる方法が思い浮かびましたが
それ以外の方法としては、WM_MOVINGが来てからBウィンドウを操作になるんでしょうか?

編集 削除
ロマ  2010-07-09 03:56:11  No: 71804  IP: 192.*.*.*

> モードレスから普通のウィンドウに変えるだけで、ちらつき等はやはり解決します。

ひょっとして、ダイアログボックスプロシージャで
case WM_PAINT:
    (色々処理して)
    return 0;
に、なっていませんか。

編集 削除
ロマ  2010-07-09 05:22:48  No: 71805  IP: 192.*.*.*

上の書き込み取り消します。
寝ぼけてました、すみません。

編集 削除
gak  2010-07-09 12:57:36  No: 71806  IP: 192.*.*.*

このプログラムはMFC、SDKのどちらで開発してる?
レス内容見ているとSDKぽいけど、合ってる?

> モードレスダイアログにする前はそのような現象はありませんでした。
> 背景を初期化するWM_ERASEBKGNDが発行された時は、何もしないようにしていますので
仮にSDKの場合、同じメッセージでもWindowプロシージャ、Dialogプロシージャで別対応する必要があるけど、この辺りは大丈夫?

例えば WM_ERASEBKGND の場合、Windowプロシージャで背景の消去を行わない時は 0 を返す。
だが、Dialogプロシージャの場合は
> 通常、ダイアログボックスプロシージャはメッセージを処理した場合に 0 以外の値(TRUE)を、処理しなかった場合に 0(FALSE)を返すべきです。
> ダイアログボックスプロシージャが 0(FALSE)を返した場合、ダイアログマネージャはそのメッセージに応答して既定のダイアログ処理を実行します。
という仕様なので、Windowプロシージャ と同感覚で 0(FALSE)を返すと既定の背景の消去処理が行われる。

編集 削除
Place  2010-07-10 08:15:08  No: 71807  IP: 192.*.*.*

gakさん

有難うございます!
FALSEを返していましたので、TRUEを返すようした所
無事解決しました!
本当に有難うございました。

編集 削除
Place  2010-07-10 08:15:47  No: 71808  IP: 192.*.*.*

解決チェックを入れ忘れました。申し訳ありません。

編集 削除