none
ダイアログの残像が下に残るのを解消したい RRS feed

  • 質問

  • 毎回大変お世話になっております、鏑木と申します。
    連日の質問で申し訳ございません。
    この現象はもしかしたらCE特有のものかもしれませんが、もし参考となるご意見を頂ければと思い、質問
    させて頂きました。
    現在、Visual Studio 2005にてC++のダイアログベースのアプリケーションを開発しているのですが、
    メインダイアログからサブダイアログを表示させ、そのサブダイアログを閉じた際に、メインダイアログの
    後ろ側にサブダイアログの残像が残ってしまう現象にあっています。
    通常のPCのダイアログベースのプログラムであれば、OnPaint()を自動的に何度も呼びだすのですが、
    CEの場合はなぜかそれをせず、OnPaint()は最初に呼び出された際に実行されるだけで、自動的に
    呼び出されません。それが原因なのかなと思い、

    ***dlg.DoModal();     //サブダイアログの表示
    Invalidate();             //OnPaint()呼び出し

    としたのですが、何も現象は変わりませんでした。ちなみにOnPaint()内ではダイアログベース上のスタティックテキスト
    の再表示のみのコードを記述しています。

    参考となるご意見がもしありましたら、よろしくお願いいたします。
    尚、開発環境は
    Windows CE 6.0
    Visual Studio 2005
    です。
    ご回答をお待ちしております。


    2009年9月11日 2:13

回答

  • メインダイアログのOnEraseBkgnd()をオーバーライドして背景塗りつぶしをつぶして
    OnPaint側で処理しているとかですかねぇ。
    それもしていないとなると通常の処理でも背景が更新されないことになりますけれど。

    ボタンクラスの中で処理する件に関しては私的にはあんまりお勧めできない感じです。
    たとえば、カラー選択ダイアログを出す専用ボタンを作成して、これを使えばどのダイアログでも
    簡単にカラー選択ダイアログを出すボタンを付けられますという目的であればわかる気がするのですが、
    そうでないならダイアログ側で処理して結果をボタンに渡すでもよいと思うからです。
    実際の話、私自身はそういうケースではそういう実装をしています。
    この辺は各個人の考え方もあるのでそれはいけないというのは言いすぎだと思いますけれど、
    基本的な画面処理の流れが比較的、浅い層で確認できた方が全体の構成を把握しやすくなる
    というのが私の考え方です。

    普通に考えると他のウインドウが被った時点で他のウインドウの下になっている部分は
    無効化されていると思うので単純な再描画で描画できると思うんですけれどねぇ。
    InvalidateRectに関しても無効になった領域を無効対象のリージョンに追加するという
    動きみたいですし。
    ただ、CEの場合、HWの非力さをカバーするために特殊な実装を行っているケースがあると
    思うので、一般的な処理方法で確認してみる事も必要なのではないかと思っていたりします。
    一般的な実装ではうまくいってもちょっとひねるとうまくいかないというケースもありそうな気が
    しているので。
    わからない部分に関しては確実に潰していった方が次のステップで迷うことが少なくなりますし。


    解決した時は、参考になったレスポンスの所にある[回答としてマーク]ボタンをクリックしてスレッドを締めましょう。
    • 回答としてマーク 鏑木肆星 2009年10月23日 2:39
    2009年9月13日 1:08
  • としたのですが、何も現象は変わりませんでした。ちなみにOnPaint()内ではダイアログベース上のスタティックテキスト
    の再表示のみのコードを記述しています。
    読み返してみると、ここに問題があるような気がしてきました。

    OnPaint()のデフォルトの実装(Windowプロシージャ)では、
    BeginPaint(), EndPaint()を呼び出すのみのコードとなっています。

    BeginPaint()を呼び出すと、システムは無効領域がある場合に
    WM_ERASEBKGNDをウィンドウに送って背景を初期化させ、
    無効となった領域を無効領域から削除して有効とします。

    したがって、OnPaint()をオーバーライドしておきながら、Default()を呼び出すなど、
    とにもかくにも::BeginPaint()が呼び出されるような何らかの手立てを打っていなければ、
    WM_ERASEBKGNDが送られることはなく、
    結局背景塗りつぶしは行われないということになるのだと思います。
    • 編集済み Atsushi777 2009年9月15日 9:33 少し日本語がおかしいので
    • 回答としてマーク 鏑木肆星 2009年10月23日 2:39
    2009年9月15日 9:15
  • CEでは通常のPCの動作と違い、OnPaint()が常に呼び出されるわけではなく、こちらからInvalidate()
    なりを呼び出さないと処理されません。そのためあまり負荷はかからないだろうと思い、OnPaint()内に
    ダイアログ上のさまざまなコントロールの文字列指定を入れて、Invalidate()の呼び出しで一気に
    コントロールの指定をしようと思い、今回のような処理をしています。
    誤解しているようですが通常のPCでも(わざとそう仕向けない限り)OnPaint()が常に呼び出されることはありません。
    描画サイクルに関してはPCでもCEと基本は同じで、Window内にInvalidな領域がなければOnPaintは呼び出され(=WM_PAINTは届き)ません。
    またInvalidな領域は上に重なったウィンドウが移動したり、CWnd::Invalidate()やInvalidateRect() API呼び出し等で発生します。

    別スレッドで他の方も書いていますがWindows(CE含む)ではこういったお約束を理解せずにコーディングすると収拾がつかなくなります。まずはこういった点をしっかり学習すべきかと思います。
    一連の質問を見ているとあせりのあまり、表面的な理解のみでプログラムを進めようとして、かえって混乱しているように見えます。
    • 回答としてマーク 鏑木肆星 2009年10月23日 2:40
    2009年10月7日 13:56

すべての返信

  • どーも、PATIOです。

    状況が良く分かりません。
    私のイメージではデスクトップを覆い隠すようなメインダイアログをイメージしていたので
    メインダイアログの後ろ側にサブダイアログの残像が残ってしまうというのがイメージできません。

    昔の話なので現在もそうかはわかりませんが、CEは基本的にPCより性能が低いので
    できる限り負荷を下げる方向でOSが設計されていたと思います。
    ですから、画面更新のようにCPUパワーを食ってしまう処理はなるべく避ける方向で
    実装されていると思います。
    あと、Invalidateはそのウインドウの領域内を無効化するだけですから
    ウインドウの外に関しては関係無いと思います。
    ダイアログの外の部分に関してはInvalidateを呼び出しても更新されないと思います。

    解決した時は、参考になったレスポンスの所にある[回答としてマーク]ボタンをクリックしてスレッドを締めましょう。
    2009年9月11日 8:45
  • 私の頭の中では、メインダイアログのスタティックテキストのみが更新され、サブダイアログがほとんどそのまま表示されているイメージなのですが、これであっていますか?

    あっているとして、ですが、

    サブダイアログの PreCreateWindow で CS_SAVEBITS フラグを付けてみる。

    ( 相当な負荷がかかりそうですが ) サブダイアログが閉じた時にデスクトップウィンドウに対して Invalidate、UpdateWindow、または RedrawWindow を呼び出す。

    という方法ぐらいしか思い付きませんでした。

     # 機種にもよるんでしょうが、WinCE、手強いですねぇ。
    2009年9月11日 8:58
  • PATIO様、いつもご意見本当に感謝しております。

    PATIO様のご想像通り、メインダイアログ・サブダイアログともに
    ShowWindow(SW_SHOWMAXIMIZED);
    で最大化しているため、デスクトップを全て覆っています。
    しかし、ダイアログ上に配置させたコントロールとコントロールの隙間、
    たとえば、ピクチャーコントロールとボタンとの間に、若干ながら隙間が
    でき、その隙間から一度表示させて、閉じたサブダイアログの残像が見えると
    いった状況です。
    要は、ダイアログ上でのコントロールの配置や、コントロール上に配置させる
    ビットマップの大きさをぴったりに出来ればいいのですが、なかなかそれが出来ず
    もし、ダイアログの再描画などの更新処理によって、その隙間から見える残像が
    消せたらなと思い、今回ご質問させていただきました。

    ちなみに、最初に提示しましたコード

    ***dlg.DoModal();     //サブダイアログの表示
    Invalidate();             //OnPaint()呼び出し

    は、メインダイアログ上のボタンコントロールの派生クラス内でのコードで、このままだと
    ボタンクラス内でのInvalidate()となるため

    C***Button::OnBnClicked()
    {
      ****dlg.DoModal();
      ::SendMessage(AfxGetMainWnd()->GetSafeHwnd(),WM_PAINT,0,0);//メインダイアログへWM_PAINT送信
    }
    という風に変更してみたのですが、変化がありませんでした。
    2009年9月11日 9:36
  • ミッヒー様、いつもご意見をいただき大変ありがとうございます。

    >私の頭の中では、メインダイアログのスタティックテキストのみが更新され、サブダイアログがほとんどそのまま表示されているイメージなのですが、これであっていますか?
    いえ、そんなに最悪な状況ではありません。言葉の言い回しが下手で、誤解をさせてしまい申し訳ございません。
    状況はPATIO様の返答にも書かせて頂いたように、ダイアログ上のコントロール間の隙間に、残像が残ってしまうといった状況です。

    WindowsCE、本当に強敵です。。
    2009年9月11日 9:44
  • えーと、WM_PAINTを送るのはやめた方が良いと思います。
    本来、システムが送るメッセージなので。
    あと、ウインドウの領域が無効化されていないとWM_PAINTが来ても画面は更新されません。
    なので、うーんと言う感じです。

    で、気になったのが、ボタンの派生からウインドウを出しているのが気になりました。
    一般的には、ダイアログの方でボタンのクリックイベントを拾って処理すると思いますので
    なぜ、このようになっているのかなと。
    ダイアログの方でイベントを拾って、そこでInvalidateするのが本当だと思います。
    もしくはボタンの親ウインドウがダイアログになっていると思うので
    親ウインドウにユーザー定義メッセージを送って、
    受けた親側でInvalidateするとかですかねぇ。

    ボタンクラスの中でダイアログを出しに行くと言うのは私的には違和感があります。
    もしかしたらこれが原因で親のダイアログのクライアント領域が更新されていないのではないかと
    言う気がします。

    追伸:
    Win32APIのInvalidateRectをつかえば、ウインドウハンドルを指定して無効化できますから
    親のダイアログのウインドウハンドルが分かっていれば、無効化できるはずです。
    もっとも、ボタンクラスの中でクリックイベントの処理をするのはちょっと賛成できないのは変わりませんけれど。
    ボタンクラスの中でクリックイベントに対応してしまうとオペレーションに対する画面の流れが分かりづらく
    なりますから、私だったらお勧めしません。
    解決した時は、参考になったレスポンスの所にある[回答としてマーク]ボタンをクリックしてスレッドを締めましょう。
    2009年9月11日 9:50
  • あー。凄まじい勘違いをしていたようで、申し訳ありません。

    ただ、PATIO さんが指摘されている部分

    ボタンクラスの中でダイアログを出しに行くと言うのは私的には違和感があります。
    もしかしたらこれが原因で親のダイアログのクライアント領域が更新されていないのではないかと
    言う気がします。
    私も同感です。C***Buton::OnBnClicked() のタイミングでは画面上でボタンが押下された表示になっているように思います。

    そこからモーダルダイアログが表示される場合、C***Button は押下された状態なのか、通常の状態なのか、システム側では判断出来ないのではないでしょうか? その為、ボタンのエッジ部分がとりあえず ( システムも余分な作業はしないように設計されているでしょうし ) 未ダーティー領域とされ、モーダルダイアログが閉じた後も、再描画領域に含まれていないのではないか、と思います。
    2009年9月11日 11:50
  • 単にメッセージディスパッチが行われてないだけじゃ?
    何らかの処理で、ループさせてるような場合、InvalidateRectで無効化しても描画処理が行えないのでは?

    たとえばOnInitDialogの中でループで初期化処理をしているような場合

    for (int i = 0; i < 100000; i++) {
    //なんか処理
    }
    としているなら、
    for (int i = 0; i < 100000; i++) {
     //なんか処理
     MSG msg;
     if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
      TranslateMessage(&msg);
      DispatchMessage(&msg);
     }
    }

    の様にメッセージディスパッチしたらどうなりますか?
    2009年9月11日 12:42
  • メインダイアログのOnEraseBkgnd()をオーバーライドしてDefault()を呼び出していないとか、
    もしかしてそういうことをしていませんか?

    ---
    今回のボタンクリックの処理をボタンクラスで行うのには私も違和感がありますし、
    処理内容からすると問題だとは思いますが、今回の描画の件はそれとは関係ないと思います。
    単にBN_CLICKEDの処理をダイアログクラスで行うか、
    そのメッセージをボタンに返送(REFLECT)して行うかの違いだけですから。

    たとえば、ボタンを押すと色選択ダイアログを出して選択した色をボタンフェイスに表示し、
    COLORREFを返すボタンクラスを作成するとなると、
    この場合はボタンクラスのOnBnClicked()で色選択ダイアログを表示するのが適切だと
    いう話にもなったりするわけです。
    2009年9月12日 11:19
  • メインダイアログのOnEraseBkgnd()をオーバーライドして背景塗りつぶしをつぶして
    OnPaint側で処理しているとかですかねぇ。
    それもしていないとなると通常の処理でも背景が更新されないことになりますけれど。

    ボタンクラスの中で処理する件に関しては私的にはあんまりお勧めできない感じです。
    たとえば、カラー選択ダイアログを出す専用ボタンを作成して、これを使えばどのダイアログでも
    簡単にカラー選択ダイアログを出すボタンを付けられますという目的であればわかる気がするのですが、
    そうでないならダイアログ側で処理して結果をボタンに渡すでもよいと思うからです。
    実際の話、私自身はそういうケースではそういう実装をしています。
    この辺は各個人の考え方もあるのでそれはいけないというのは言いすぎだと思いますけれど、
    基本的な画面処理の流れが比較的、浅い層で確認できた方が全体の構成を把握しやすくなる
    というのが私の考え方です。

    普通に考えると他のウインドウが被った時点で他のウインドウの下になっている部分は
    無効化されていると思うので単純な再描画で描画できると思うんですけれどねぇ。
    InvalidateRectに関しても無効になった領域を無効対象のリージョンに追加するという
    動きみたいですし。
    ただ、CEの場合、HWの非力さをカバーするために特殊な実装を行っているケースがあると
    思うので、一般的な処理方法で確認してみる事も必要なのではないかと思っていたりします。
    一般的な実装ではうまくいってもちょっとひねるとうまくいかないというケースもありそうな気が
    しているので。
    わからない部分に関しては確実に潰していった方が次のステップで迷うことが少なくなりますし。


    解決した時は、参考になったレスポンスの所にある[回答としてマーク]ボタンをクリックしてスレッドを締めましょう。
    • 回答としてマーク 鏑木肆星 2009年10月23日 2:39
    2009年9月13日 1:08
  • PATIO様、いつもご回答ありがとうございます。

    >本来、システムが送るメッセージなので。
    >あと、ウインドウの領域が無効化されていないとWM_PAINTが来ても画面は更新されません。
    やっぱりそうですか、なんかごり押しな気がしていたのでよろしくないだろなぁと思っていました。。

    >一般的には、ダイアログの方でボタンのクリックイベントを拾って処理すると思いますので
    >なぜ、このようになっているのかなと。
    >ダイアログの方でイベントを拾って、そこでInvalidateするのが本当だと思います。
    確かに言われてみるとそうですね。プログラムが見づらくなるし、よくないですね。
    早速、ボタンクリック時にメインダイアログへメッセージを送って、メインダイアログから呼び出します。



    2009年9月14日 1:30
  • ミッヒー様いつもご回答ありがとうございます。

    >私も同感です。C***Buton::OnBnClicked() のタイミングでは画面上でボタンが押下された表示になっているように思います。
    サブダイアログの下では、そのサブダイアログを呼び出したボタンが押されたままの状態になってる可能性は高いですね。。
    とりあえず、ボタン選択時にメッセージを送信して、サブダイアログの呼び出し部分はメインダイアログ内にします。

    >ボタンのエッジ部分がとりあえず ( システムも余分な作業はしないように設計されているでしょうし ) 未ダーティー領域とされ、モーダルダイアログが閉じた後も、再描画領域に含まれていないのではないか、と思います。
    再描画領域に含まれていない、といった再描画の仕方でもないんです。それだと、そのサブダイアログを呼び出したボタンがまったく描画されずに、そのボタンがあるはずの部分に閉じたはずのサブダイアログの
    残像が残っているということになるので。そうではなく、ダイアログ上の各コントロールは再描画されているのですが、肝心のダイアログ本体が再描画されていないような気がします。
    2009年9月14日 1:37
  • らーめん食べたいなぁさん、いつもご回答ありがとうございます。

    >何らかの処理で、ループさせてるような場合、InvalidateRectで無効化しても描画処理が行えないのでは?
    ダイアログ上ではつねに波形の描画をしているため、その可能性もありますね。
    そこで、らーめん食べたいなぁさんがおっしゃるように、波形の描画処理部分内にメッセージディスパッチの処理を
    いれてみましたが、再描画時の状態に変化はありませんでした。
    やはり再描画のメッセージ処理というより、ダイアログ自体の再描画時の処理の問題のような気がします。
    2009年9月14日 2:13
  • どーも、PATIOです。

    処理が終わるまで描画がされなくて、処理が終わったとたん描画されるならそういう事もあるかなと
    思いますけれど、ループさせている処理の処理時間が十分に短く、一回の処理毎にメッセージループに処理を
    返すような構造になっていれば、問題無いと思いますよ。
    問題があるのは何分も掛かるような処理をループで回し続けているようなケースだと思います。
    一回に描画処理する時間が十分に短いならそのイベントハンドラから抜けた時点でメッセージループに
    制御が返りますから、ループ内にメッセージディスパッチを入れる必要は有りませんし、
    逆にループ内にメッセージディスパッチを入れないといけないようなら処理の流れに問題があるような
    気がします。イベントドリブン型のシステムではこの辺はお約束だと思いますし。

    なので、もしループ内にメッセージディスパッチを入れたままにしているのであれば、
    はずした方が良いかなと思います。
    あちこちにメッセージループがあるとメッセージ処理が思わぬタイミングで動いてしまい、
    想定しない結果になる事が有りますので。

    解決した時は、参考になったレスポンスの所にある[回答としてマーク]ボタンをクリックしてスレッドを締めましょう。
    2009年9月14日 2:25
  • Atsushi777様、いつもご回答ありがとうございます。

    >メインダイアログのOnEraseBkgnd()をオーバーライドしてDefault()を呼び出していないとか、
    >もしかしてそういうことをしていませんか?

    メインダイアログ側ではOnEraseBkgnd()はオーバーライドしていないので、それはないです。
    背景処理はデフォルトの処理となっています。
    2009年9月14日 5:18
  • PATIO様、いつもご回答ありがとうございます。

    >メインダイアログのOnEraseBkgnd()をオーバーライドして背景塗りつぶしをつぶして
    >OnPaint側で処理しているとかですかねぇ。
    >それもしていないとなると通常の処理でも背景が更新されないことになりますけれど。
    Atsushi777様へもご返答したのですが、メインダイアログではOnEraseBkgnd()をオーバーライドせずに
    背景処理はデフォルトとしています。

    ボタンとサブダイアログの動作については、変更できしだい改めてご連絡致します。
    現在、OSのWindows CE6.0でプログラム実行用メモリが何もせずに使われていくというわけのわからない
    現象が起きていることに気づき、その対処法を考えていますので(--;)
    OSとアプリの開発を一人でさせるのはどうかしてます。。。すいません、ぐちってしまいました。。
    2009年9月14日 5:22
  • 残像とは関係ないところですけど、
    >ダイアログの方でイベントを拾って、そこでInvalidateするのが本当だと思います。
    確かに言われてみるとそうですね。プログラムが見づらくなるし、よくないですね。
    早速、ボタンクリック時にメインダイアログへメッセージを送って、メインダイアログから呼び出します。
    ボタンクリック時に自分でメッセージを送出しようという話ですか?
    ボタンクリック時には、WM_COMMAND(BN_CLICKED)がメインダイアログに送られるのですから、
    自分でメッセージを送る必要はないと思います。

    ボタンのON_CONTROL_REFLECT(BN_CLICKED, OnBnClicked)を削除してやる必要がありますが。
    2009年9月15日 9:02
  • としたのですが、何も現象は変わりませんでした。ちなみにOnPaint()内ではダイアログベース上のスタティックテキスト
    の再表示のみのコードを記述しています。
    読み返してみると、ここに問題があるような気がしてきました。

    OnPaint()のデフォルトの実装(Windowプロシージャ)では、
    BeginPaint(), EndPaint()を呼び出すのみのコードとなっています。

    BeginPaint()を呼び出すと、システムは無効領域がある場合に
    WM_ERASEBKGNDをウィンドウに送って背景を初期化させ、
    無効となった領域を無効領域から削除して有効とします。

    したがって、OnPaint()をオーバーライドしておきながら、Default()を呼び出すなど、
    とにもかくにも::BeginPaint()が呼び出されるような何らかの手立てを打っていなければ、
    WM_ERASEBKGNDが送られることはなく、
    結局背景塗りつぶしは行われないということになるのだと思います。
    • 編集済み Atsushi777 2009年9月15日 9:33 少し日本語がおかしいので
    • 回答としてマーク 鏑木肆星 2009年10月23日 2:39
    2009年9月15日 9:15
  • どーも、PATIOです。

    ボタンクリックに関してはAtsushi777さんが書かれている通り、ボタン側のREFLECTを止めて
    ダイアログ側で普通に受け取るという方法で良いと思います。
    多分、そういう意味で書かれたのだろうと思いますが、念の為。

    OSのイメージ作成とアプリケーションを同時進行でされているのですね。
    一人でやるとなるとかなり大変だと思いますが、頑張ってください。
    まあ、愚痴くらいならみんな聞き流してくれると思うので、たまに愚痴るくらいなら許されるでしょう。(^^;

    私自身はOSの方までは手を出さずに済んだので良かったんですが、
    OSの方までとなるとHWとの絡みも出てくるでしょうから大変そうですね。
    気持ちはお察しします。

    解決した時は、参考になったレスポンスの所にある[回答としてマーク]ボタンをクリックしてスレッドを締めましょう。
    2009年9月15日 9:17
  • 鏑木肆星さんのOnPaintの実装が具体的にコードで提示されていなかったので
    気が付きませんでしたが、Atsushi777さんが書かれているようにOnPaintに関しては、
    実装上のお約束と言うのが有りますのでそれにそって実装されていないとうまく行きません。

    で、通常OnPaintを実装する場合は、内部でGDIの呼び出しを行って描画をしますから
    CDialog::OnPaint();の呼び出しは削除しますよね。
    これはCDialog::OnPaint();の中でせっかく設定されたウインドウの無効領域が解除されて
    しまうからで、GDIで描画を行う時にやるCPaintDC    dc(this);を呼び出すことで描画準備が
    行なわれ、dcの開放で無効領域の解除が行なわれます。
    なので、CDialog::OnPaint();を行なっていないのであれば、CPaintDC    dc(this);を
    行なわないとうまく動作しないと思います。

    あと気になったのが、ダイアログ上のスタティックテキストの再表示のコードがなぜOnPaint内に
    あるのかも気になりました。GDIで描画しているのであればわかるのですが、
    スタティックテキストならコントロールに対して文字列の指定をしていれば、再表示はかかると
    思います。上にウインドウが被れば、無効化されて再描画されるはずですし、
    OnPaint内で再描画の為のコードを書く事は無いような気がするのです。
    一般的にコントロールの再描画はそのコントロールに任せるのが普通です。
    OnPant内で行う必要があるのはコントロールに任せていない自前でGDIを使って
    描画している部分になります。スタティックコントロール内のテキストを変更したいので
    あれば、そのテキストが分かった段階でスタティックコントロールにSetWindowTextを
    行なえば、それ以降の描画はスタティックコントロールが行ってくれるはずです。

    解決した時は、参考になったレスポンスの所にある[回答としてマーク]ボタンをクリックしてスレッドを締めましょう。
    2009年9月15日 9:33
  • PATIO様、ご返答が遅くなり大変申し訳ございません。

    >通常OnPaintを実装する場合は、内部でGDIの呼び出しを行って描画をしますから
    >CDialog::OnPaint();の呼び出しは削除しますよね。
    >これはCDialog::OnPaint();の中でせっかく設定されたウインドウの無効領域が解除されて
    >しまうからで、GDIで描画を行う時にやるCPaintDC    dc(this);を呼び出すことで描画準備が
    >行なわれ、dcの開放で無効領域の解除が行なわれます。
    >なので、CDialog::OnPaint();を行なっていないのであれば、CPaintDC    dc(this);を
    >行なわないとうまく動作しないと思います。
    ということは、描画処理に独自の処理が必要ない場合には無意味にOnPaint()の呼び出しは止めた
    ほうがよいということですね。

    >あと気になったのが、ダイアログ上のスタティックテキストの再表示のコードがなぜOnPaint内に
    >あるのかも気になりました。GDIで描画しているのであればわかるのですが、
    >スタティックテキストならコントロールに対して文字列の指定をしていれば、再表示はかかると
    >思います。上にウインドウが被れば、無効化されて再描画されるはずですし、
    >OnPaint内で再描画の為のコードを書く事は無いような気がするのです。
    確かにそうですね、コントロール変数に文字列に指定すればその場で再表示処理をしてくれますね。。
    CEでは通常のPCの動作と違い、OnPaint()が常に呼び出されるわけではなく、こちらからInvalidate()
    なりを呼び出さないと処理されません。そのためあまり負荷はかからないだろうと思い、OnPaint()内に
    ダイアログ上のさまざまなコントロールの文字列指定を入れて、Invalidate()の呼び出しで一気に
    コントロールの指定をしようと思い、今回のような処理をしています。

    鏑木
    2009年10月7日 2:15
  • CEでは通常のPCの動作と違い、OnPaint()が常に呼び出されるわけではなく、こちらからInvalidate()
    なりを呼び出さないと処理されません。そのためあまり負荷はかからないだろうと思い、OnPaint()内に
    ダイアログ上のさまざまなコントロールの文字列指定を入れて、Invalidate()の呼び出しで一気に
    コントロールの指定をしようと思い、今回のような処理をしています。
    負荷を気にするのであれば、アイドルタイムを使うなりタイマーを使うなり、他に適切な方法があります。

    本来の目的と異なる使い方をされることそのものは個人の自由ですが、
    本来と正しい目的での利用では発生しない問題を避ける責任はご自分にあります。

    ところで、ダイアログの派生クラスの OnPaint() 内に、以下の一行は記述されているのでしょうか?
    CPaintDC  dc(this);
    されていないのだとしたら、これを記述したら今回の問題は解決するのでしょうか? しないのでしょうか?
    2009年10月7日 5:03
  • CEでは通常のPCの動作と違い、OnPaint()が常に呼び出されるわけではなく、こちらからInvalidate()
    なりを呼び出さないと処理されません。そのためあまり負荷はかからないだろうと思い、OnPaint()内に
    ダイアログ上のさまざまなコントロールの文字列指定を入れて、Invalidate()の呼び出しで一気に
    コントロールの指定をしようと思い、今回のような処理をしています。
    誤解しているようですが通常のPCでも(わざとそう仕向けない限り)OnPaint()が常に呼び出されることはありません。
    描画サイクルに関してはPCでもCEと基本は同じで、Window内にInvalidな領域がなければOnPaintは呼び出され(=WM_PAINTは届き)ません。
    またInvalidな領域は上に重なったウィンドウが移動したり、CWnd::Invalidate()やInvalidateRect() API呼び出し等で発生します。

    別スレッドで他の方も書いていますがWindows(CE含む)ではこういったお約束を理解せずにコーディングすると収拾がつかなくなります。まずはこういった点をしっかり学習すべきかと思います。
    一連の質問を見ているとあせりのあまり、表面的な理解のみでプログラムを進めようとして、かえって混乱しているように見えます。
    • 回答としてマーク 鏑木肆星 2009年10月23日 2:40
    2009年10月7日 13:56
  • Atsushi777様、ご回答ありがとうございます。

    >本来の目的と異なる使い方をされることそのものは個人の自由ですが、
    >本来と正しい目的での利用では発生しない問題を避ける責任はご自分にあります。
    全くその通りですね。。メッセージには元々目的とする処理があることを、無視していました。
    現在、皆様がたの意見をふまえ、OnPaint内にコントロールの文字列処理部分を含むことを
    止めました。

    >ところで、ダイアログの派生クラスの OnPaint() 内に、以下の一行は記述されているのでしょうか?
    >CPaintDC  dc(this
    );
    >されていないのだとしたら、これを記述したら今回の問題は解決するのでしょうか? しないのでしょうか?
    このコードはOnPaintを呼びだした際にデフォルトで記述されていました。

    鏑木
    2009年10月8日 0:40
  • ホーミン様、いつもご回答ありがとうございます。

    >誤解しているようですが通常のPCでも(わざとそう仕向けない限り)OnPaint()が常に呼び出されることはありません。
    >描画サイクルに関してはPCでもCEと基本は同じで、Window内にInvalidな領域がなければOnPaintは呼び出され(=WM_PAINTは届き)ません。
    >またInvalidな領域は上に重なったウィンドウが移動したり、CWnd::Invalidate()やInvalidateRect() API呼び出し等で発生します。
    そうなのですか。。私はOnPaintは常に定期的に呼び出される関数かと思っていました。全く違った理解だったのですね。

    >別スレッドで他の方も書いていますがWindows(CE含む)ではこういったお約束を理解せずにコーディングすると収拾がつかなくなります。まずはこういった点をしっかり学習すべきかと思います。
    >一連の質問を見ているとあせりのあまり、表面的な理解のみでプログラムを進めようとして、かえって混乱しているように見えます。
    ホーミン様のおっしゃる通りです。Windowsプログラムの基本を深く理解せずに、触りだけ理解して実際のプログラム作成に挑んでいるため、度々こちらにて質問させて頂かせております。
    私の方でも表面的な理解ではなく、納得のいくまで理解はしたいのですが、時間の関係で現在は出来ずに後回し後回しにしてしまっている現状です。
    ご迷惑をおかけします。

    鏑木
    2009年10月8日 0:48