リストビューのダブルバッファリング – プログラミング – Home

リストビューのダブルバッファリング
 
通知
すべてクリア

リストビューのダブルバッファリング


くろ
 くろ
(@くろ)
ゲスト
結合: 24年前
投稿: 14
Topic starter  

VC++6のMFCでダイアログベースの画面を作成しています。

リストビューを更新する際のチラつきを抑えるためにダブルバッファリングが有効だと聞
き、サンプルを調べていますがビットマップのものしか見つけられず困っています。
ビットマップの場合、バッファへ一旦画像を書き出してから実際の画面にコピーするとい
うのは理解出来たのですが、
リストビューの場合はバッファへどのようにリストビューを書き込む?作成する?のかが
わわかりません。

以下サイトを参考にしました。
http://www.t-recipe.com/vc/flicker.html


引用解決済
トピックタグ
ホウジョウウサギ
 ホウジョウウサギ
(@ホウジョウウサギ)
ゲスト
結合: 18年前
投稿: 73
 

ちょっと想像がつきませんが
CListCtrl(?)の項目を
SetRedrawぐらいではダメなほどに頻繁に更新するのでしょうか?

>リストビューの場合は
同じ場所にコントロールを2つ重ねて置いて
交互に表示非表示してやる…とか??


返信引用
ryo
 ryo
(@ryo)
ゲスト
結合: 23年前
投稿: 252
 

>リストビューを更新する際のチラつきを抑えるためにダブルバッファリングが有効だと

そもそも、これはどこの情報?


返信引用
仲澤@失業者
(@uncle_kei)
Prominent Member
結合: 5年前
投稿: 828
 

リストビューのチラつきを抑えるのにビットマップを使用するタイプの
ダブルバッファリングはほとんど効果がありません。というか、スクロールに
うまく対応できないため、大変な労力がかかるため、コスト的にまったくあいません。
即座に検討をとりやめにしましょう。

気になるチラつきの発生する原因やタイミングによりますが、概ね次の
部分を修正すると良くなることがほとんどです。

1.リストビューを保持している親(MDIフレームやDLG)のクラススタイルに
 CS_VREDRAWとCS_HREDRAWが設定してあれば、これを取り外す

レポートスタイルの場合で、アイテム行数が1000程度を超える場合は
2.LVS_OWNERDRAWFIXEDを指定して、全て自分で描画する。

自分は上記対策を行っていますが、50行×10カラムを秒間20回以上の
再描画更新中に、リストコントロールのサイズを変更してもまったく
チラつきませんです。
PCはcorei3 + NVIDIA Quadro FX580という平凡よりややへぼいものを
使ってます(笑)。


返信引用
AR2
 AR2
(@ar2)
Estimable Member
結合: 5年前
投稿: 110
 

 リストビューのブルバッファリングはOSによって難易度が異なります。
 VC6じゃちょっと厳しい気はしますが、シェルバージョンが6以降であれば、拡張スタ
イルのLVS_EX_DOUBLEBUFFERを指定するだけで、そこそこ高速かつ自動的に処理してくれ
ます。
 それ以前のものでダブルバッファリングを行いたいのであれば、オーナードローにし
て自前でビットマップと同じように描画するしかないです。

 ただ、ちらつきを抑えるには、ダブルバッファリング以前にすべきことがたくさんあ
るので、まずはそちらを把握すべきだと思います。
 ぐぐったら仲澤@失業者さんの適切な回答が他にも出てきましたので、こちらも参考
にしてはいかがでしょうか?
http://social.msdn.microsoft.com/forums/ja-JP/vcgeneralja/thread/4dfab71d-6eb2-
482f-8dfe-06b97d838262/


返信引用
くろ
 くろ
(@くろ)
ゲスト
結合: 24年前
投稿: 14
Topic starter  

みなさん回答ありがとうございます。
ダブルバッファは難しそうなのでやめときます。

質問の意図がわかりにくく大変申し訳ありませんでした。
やりたいことは、30行*10カラム程のアイテムを表示するリストビューを用意し、
各アイテムの値を100msec周期に更新します。
画面やコントロールのリサイズはしません。

SetRedrawを使用してもちらつきます。(一瞬コントロール内が白くなるような感じです)
そもそも更新の仕方が悪いのでしょうか?
現在仮想リストビューを使用し、100msec周期にInvalidateRectを使用し再描画しています。
仮想リストビューは以下を参考にしました。
http://homepage1.nifty.com/takuhiro/technique/programming/virtuallistctrl/index.htm

また、リストボックスの場合も同様に100msec周期に文字列を追加したいのですがちらつ
きます。


返信引用
仲澤@失業者
(@uncle_kei)
Prominent Member
結合: 5年前
投稿: 828
 

仮想リストビュー(LVS_OWNERDATA)は、保持できる行数(アイテム数)を増やすのには
効果がありますが、すばやい描画を行うことには、たいした役には立ちません。

すばやく描画するにはLVS_OWNERDRAWFIXEDを指定して、DrawItem()時に、
自分でTextOut()するのが最も効率的です。

さらにチラ付きを抑制するにはグリッドラインの再描画を自分で行うか、
又は再描画させないようにします。

あとは、チラ付きを抑制の基本ですが、WM_ERASEBKGNDはFALSEを戻して、背景が
塗りつぶされないようにしたほうが良いでしょう。背景は必要ならば自分で
塗りつぶします。

リストコントロールはデータの描画スピードが(特に行数が増えると)とっても
カメなので、コントロールに描画をさせていてはらちがあきませんです(vv;)。


返信引用
hirocco
 hirocco
(@hirocco)
ゲスト
結合: 14年前
投稿: 138
 

じゃあ、こんなのはどうでしょう

リストビューで保持すべきデータを持っておく
これはリストでも配列でもベクタでもなんでもいいと思います
で,更新があるのかどうかをそのデータで判定する
更新がある場合のみ再描画する

更に実データのシャドーを持つサブクラスなんか作って
このデータを書き換えるだけのメソッドを用意しておく
で、再描画周りもこのクラスに持たせてしまってしまうとか

首題とそれましたねwww


返信引用
ロマ
 ロマ
(@ロマ)
ゲスト
結合: 18年前
投稿: 170
 

これでいかがでしょうか。

リソースファイルの IDD_MYDIALOG の STYLEに WS_CLIPCHILDRENを追加し、
Invalidate()の引数 bEraseをFALSEにする


返信引用
ロマ
 ロマ
(@ロマ)
ゲスト
結合: 18年前
投稿: 170
 

追加です。
LPSTR_TEXTCALLBACK
など、CALLBACKを使ってください


返信引用
ロマ
 ロマ
(@ロマ)
ゲスト
結合: 18年前
投稿: 170
 

たびだびすみません
> リソースファイルの IDD_MYDIALOG の STYLEに WS_CLIPCHILDRENを追加し、
これ不要なようです


返信引用
くろ
 くろ
(@くろ)
ゲスト
結合: 24年前
投稿: 14
Topic starter  

みなさんご親切にありがとうございます。
試してみたいと思います。
不明点があったり解決しましたらまた書き込みさせて頂きますね!


返信引用
ITO
 ITO
(@ITO)
ゲスト
結合: 22年前
投稿: 1235
 

> やりたいことは、30行*10カラム程のアイテムを表示するリストビューを用意し、
> 各アイテムの値を100msec周期に更新します。
100mS周期で更新しないとだめですか?
ちらつかないのが何msec周期か確かめてみましたか?
スクロール等の操作上もんだいがなければ表示のみ周期を
遅らせることも可能かと思いますが、如何でしょうか?


返信引用
ロマ
 ロマ
(@ロマ)
ゲスト
結合: 18年前
投稿: 170
 

ちらつきの原因は、LVM_SETITEMで文字列を更新した場合、
::InvalidateRect(hndListView, &rect, TRUE)と似たことが起こり、
WM_ERASEBKGNDが生じ、背景を塗りつぶした後に文字が書かれるからです。

対策としては
仲澤@失業者さんが示したような方法も一手ですし、
私が述べた方法でもできますが、
暇なので、LVM_SETITEMで文字列を更新する手も考えました。

方法1(強引なやり方)
LVM_SETITEMで文字列を更新した後(複数行なら全部更新した後)、
::ValidateRect(hwndListView, 0);
::InvalidateRect(hwndListView, 0, FALSE);
更新領域を GetUpdateRgnで取得して、ValidateRgn/InvalidateRgnするほうが
穏やかかもしれません。

別の方法(トリッキー)
LVM_SETITEMで全部更新する前に
GWL_STYLEからWS_VISIBLEをクリアし、
更新後にWS_VISIBLEをを元に戻し、
InvalidateRect(hwndListView, 0, FALSE)を呼ぶ。
# ShowWindowではなく、単にスタイルのフラグを操作するだけです。
この方法ならば、WM_SETREDRAWと違って、WM_ERASEBKGNDは生じません。


返信引用

返信する

投稿者名

投稿者メールアドレス

タイトル *

プレビュー 0リビジョン 保存しました
共有:
タイトルとURLをコピーしました