none
リストビューの表示が崩れる RRS feed

  • 質問

  • MFCのダイアログ上に、リストビューとボタンを配置し、リストビューをダブルクリックした時とボタンを押下した時に、別のダイアログを開く関数を呼び出しています。
    ボタンを押下してダイアログを開いた場合は何も問題ないのですが、リストビューをダブルクリックしてダイアログを表示すると、そのダイアログを閉じたときにリストビューの表示が変になります。
    それまで表示されていた項目が消えて、リストビューの下に別のコントロールがあった場合はそれが透けて見えます。

    原因と対処方法をご存知の方がいれば教えて頂けないでしょうか。

    環境: Windows XP SP2、VS2005 Pro(VC++)、MFCダイアログベース


    コード ブロック

    void CListCtrlTestDlg::OnBnClickedButton1()
    {
        func();
    }

    void CListCtrlTestDlg::OnNMDblclkList1(NMHDR *pNMHDR, LRESULT *pResult)
    {
        func();
        *pResult = 0;
    }


    void CListCtrlTestDlg::func()
    {
        CDialog1 dlg;
        dlg.DoModal();

        // etc...

        UpdateData( FALSE );
    }



    2007年11月20日 5:04

回答


  • GonGonさん、度々ありがとうございます。

    WM_ERASEBKGNDで塗りつぶすというのは、MFCですとOnEraseBkgnd( CDC* pDC )を追加して、そこで何らかの描画をするか、デフォルトの処理をキャンセルするということかと思いまして、やってみましたがダメでした。。。


      > ちなみにこの構成だとCPropertySheetとCPropertyPageを使うほうが早いような気がするのですが、それではだめなのでしょうか?

    例示したものはメインダイアログにタブとボタンしかないのでプロパティシートでも大丈夫だとは思うのですが、実際にはタブの外にも幾つかコントロールを配置しているので、タブコントロールを使っています。
    (間違っていなければ、プロパティシートの制限だったと認識していますので。)


    **********************************


    少し諦めかけていたのですが、GonGonさんのアドバイスを試した後で、もうちょっといろいろ試しているうちに、リストビューコントロールにWS_EX_TRANSPARENTを設定(リソースエディタのTransparentプロパティ:TRUE)したところ、なぜか直りました。

    感覚的には、WS_EX_TRANSPARENTが設定されていると背景が透けて今回のような現象になる気がして、反対に直ったのが不思議ですが、一応解決ということにしたいと思います。

    何度もアドバイスを頂きまして大変勉強になりました。
    ありがとうございました。
    2007年11月27日 9:13

すべての返信

  • ダイヤログ内のコントロールが重なっているということでしょうか?

     

    それなら重なり合っているコントロールに対してWS_CLIPSIBLINGSスタイルを追加すると重なり部分の描画が制限され上位のコントロールが常に描画されます。

    コントロールの上下関係はタブの順番に依存します。

    2007年11月21日 2:00
  • GonGonさん、ご返答ありがとうございます。

    実際に作成しているアプリでコントロールが重なっているわけではないのですが、質問用に簡単に作ったダイアログで最初に書かれている「TODO: ダイアログのコントロールをここに配置」の文字が透けて見えたので、参考になるかと思い書いたまでです。
    これについてはあまり気にしないでください。

    質問の意図としましては、リストビューをダブルクリックした時とボタンを押した時にしている処理は同じなのに、その後の描画結果がなぜ違うのかということと、それを解決する方法を知りたいのです。

    それぞれのOnXX関数を抜けた後にOSなどがやっていることが違っているんでしょうか?
    もし違っていれば解決方法はあるんでしょうか?
    ということです。

    ダブルクリックしてダイアログを開いて閉じると、リストビューの部分がグレーになってしまうのですが、ボタンをクリックしての場合はちゃんと再描画されるのです。
    2007年11月21日 2:28
  • >OnNMDblclkList1

    の関数が終わっていないのがまずいのかもしれません。

     

    OnBnClickedButton1でfuncを呼んでいるなら、OnBnClickedButton1を実行するPostMessageを呼べばよさそう。

     

    this->PostMessage(WM_COMMAND, MAKEWPARAM(IDC_BUTTON1, BN_CLICKED));

     

    みたいな感じで。

    2007年11月21日 2:57
  • 蒼い洞窟さん、ご返答ありがとうございます。

    やってみましたがダメでした。。。
    症状は変わらずです。

    ちなみに、ある特定のマシンでだけの症状ではなく、少なくともかなりHWが異なる開発用マシンとテストマシンの両方でなるので、グラボなどに起因することではないと思っています。

    2007年11月21日 5:08
  • 描画結果が違うのはWS_CLIPSIBLINGSが指定されていないためです。

     

    OS内部の仕様まではよくわかりませんが、ダイヤログ内のコントロールが描画される順序は一定ではないようです。

    基本的にDCの描画は後から描かれたものが上書きされます。このためWS_CLIPSIBLINGSが指定されていないコントロールでは、どちらの表示(当たり判定は別です)が上に来るかは操作によって変化し一定ではありません。

     

    一定の結果を得るためにはWS_CLIPSIBLINGSスタイルを設定して、兄弟ウィンドウの重なり合う部分に描画されるのを防ぐことが必要です。

    もしくは、ダイヤログのコントロールが重ならないようにレイアウトすることです。

    なので今回の件に関しては無視するのがよいかと・・・

     

     

    ちなみにWS_CLIPSIBLINGSのヘルプ内での説明は次の通りです

     

    WS_CLIPSIBLINGS   関連する子ウィンドウをクリップします。つまり、1 つの子ウィンドウが描画メッセージを受け取ると、WS_CLIPSIBLINGS スタイルが適用されている場合、更新する子ウィンドウの領域から、そのウィンドウと重複しているほかの子ウィンドウをすべてクリップします。WS_CLIPSIBLINGS が指定されていない場合に、子ウィンドウが重複していると、1 つの子ウィンドウのクライアント領域で描画するときに、隣接する子ウィンドウのクライアント領域に描画してしまう可能性があります。必ず WS_CHILD スタイルと一緒に使います。

    2007年11月21日 7:41
  • GonGonさん、再びありがとうございます。

    リストビューを配置しているダイアログは普通のダイアログですので、WS_POPUPが設定されており、WS_CLIPSIBLINGSと一緒に使うWS_CHILDとは一緒に使えないようですが、一応指定してみました。
    しかし、結果は変わりませんでした。。。

    その後、WS_CLIPSIBLINGS、リストビューそのものにModifyStyle( 0, WS_CLIPSIBLINGS )にて追加指定してみたところ、このトピック用に作ったサンプルアプリでは改善されました。
    ありがとうございます。

    しかしながら、実際に作っているアプリではダメでした。。。
    特別変なことをしているつもりはないのですが、改善されたサンプルアプリと比較して、もう少しいろいろ試してみます。
    2007年11月21日 10:30
  • ダイヤログにWS_CLIPSIBLINGSスタイルを追加しても意味がないと思います。

     

    リストコントロールだけでなく重なり合うコントロールすべてにWS_CLIPSIBLINGSスタイルを追加して、ダイヤログエディタでコントロールのタブの順番を変更すれば上位のコントロールが必ず手前に表示されるようになると思います。

    むしろ手前に表示されるものよりも、奥に表示されるものに対してWS_CLIPSIBLINGSは必要だと思います。

     

    ちなみにリストビューとありますが、CListViewを使っているということでしょうか?

    2007年11月22日 1:24
  • GonGonさん、度々ありがとうございます。

    CListView(リストコントロール)ではなく、CListCtrl(リストビューコントロール)を使っています。
    説明不足ですみません。

    このリストビューを配置しているダイアログ内ではリストビューと重なり合うコントロールはなく、一応タブオーダーも1です。

    昨日改善できたのは、リストビューを配置しているダイアログが普通のダイアログだったのですが、これを実際のアプリに近づける為にタブコントロール内で使用する子ダイアログにすると、最初の状況に戻ってしまい、ダブルクリックで別のダイアログを開き閉じるとリストビューの表示が変になってしまいます。。。
    2007年11月22日 3:24
  • それならそのタブコントロールにWS_CLIPCHILDRENスタイルを追加すればよいのでは?

     

    一般的なウィンドウにはこのスタイルが最初から設定されていますが、コントロールは基本的に子ウィンドウを持たないので設定されていません。

    2007年11月22日 4:23
  • > それならそのタブコントロールにWS_CLIPCHILDRENスタイルを追加すればよいのでは?

    私もそう思ってやってみましたが、ダメでした。
    2007年11月22日 5:05
  • 外部の掲示板にどのような状態になるか画像を貼り付けてみました。
    参考になるかわかりませんが。
    http://www.gazoru.com/b-5474513e725d29.html
    2007年11月22日 5:35
  • 以前、ドッキングコントロール内にリストコントロールを配置して表示していた際に起こった現象に似ているのですが、このときはドッキングコントロール内部をWM_PAINT内で塗りつぶしていました。これをWM_ERASEBKGNDで塗りつぶすようにすることでこのような現象が直りましたが参考になるでしょうか?

     

    ちなみにこの構成だとCPropertySheetとCPropertyPageを使うほうが早いような気がするのですが、それではだめなのでしょうか?

     

    2007年11月27日 7:13

  • GonGonさん、度々ありがとうございます。

    WM_ERASEBKGNDで塗りつぶすというのは、MFCですとOnEraseBkgnd( CDC* pDC )を追加して、そこで何らかの描画をするか、デフォルトの処理をキャンセルするということかと思いまして、やってみましたがダメでした。。。


      > ちなみにこの構成だとCPropertySheetとCPropertyPageを使うほうが早いような気がするのですが、それではだめなのでしょうか?

    例示したものはメインダイアログにタブとボタンしかないのでプロパティシートでも大丈夫だとは思うのですが、実際にはタブの外にも幾つかコントロールを配置しているので、タブコントロールを使っています。
    (間違っていなければ、プロパティシートの制限だったと認識していますので。)


    **********************************


    少し諦めかけていたのですが、GonGonさんのアドバイスを試した後で、もうちょっといろいろ試しているうちに、リストビューコントロールにWS_EX_TRANSPARENTを設定(リソースエディタのTransparentプロパティ:TRUE)したところ、なぜか直りました。

    感覚的には、WS_EX_TRANSPARENTが設定されていると背景が透けて今回のような現象になる気がして、反対に直ったのが不思議ですが、一応解決ということにしたいと思います。

    何度もアドバイスを頂きまして大変勉強になりました。
    ありがとうございました。
    2007年11月27日 9:13
  •  ぼーず さんからの引用

    感覚的には、WS_EX_TRANSPARENTが設定されていると背景が透けて今回のような現象になる気がして、反対に直ったのが不思議ですが、一応解決ということにしたいと思います。

     

    WS_EX_TRANSPARENT はZ-Orderが下の兄弟ウィンドウすべてが更新されてから

    WM_PAINTを受け取るというフラグですので、要するに最後に描画することになるわけですから、

    これによって直っても不思議ではないです。

     

    ところで、タブコントロールの子としてリストビューを作成されていませんか?

    おそらく想像ですが、タブコントロールは自身の子ウィンドウを配置されることを

    想定していないのではないかと思っています。

    プロパティシートをSpy++で見ても、タブコントロールと他のコントロールは

    兄弟関係であって、親子関係ではないことが確認できます。

     

    タブコントロールをリストコントロールの(最下層の)兄弟としてみたら、

    WS_EX_TRANSPARENTなしでもうまくいくのではないかと思います。

    2008年3月13日 4:37