再描画時のちらつきを直したい – プログラミング – Home

再描画時のちらつきを直したい
 
通知
すべてクリア

[解決済] 再描画時のちらつきを直したい

固定ページ 1 / 2

たまお
 たまお
(@たまお)
ゲスト
結合: 17年前
投稿: 20
Topic starter  

グラフや四角形などを描画しているのですが、
この画面のスクロール時にグラフを再描画(OnDraw())をするために
Invalidate() をコールしています。
これだと、再描画時にグラフや四角形などの表示がちらつくため、
なんとか、ちらつかないようにできないものでしょうか?
よろしくお願い致します。


引用未解決
トピックタグ
bun
 bun
(@bun)
ゲスト
結合: 24年前
投稿: 761
 

Invalidate() が呼ばれると、
まず WM_ERASEBKGND というメッセージが飛んできて、画面全体を背景色で塗りつぶしま
す。その後、WM_PAINT というメッセージが飛んできて、画面を再描画することになりま
す(WM_PAINTのメッセージハンドラOnPaint()から OnDraw()が呼ばれます)。

一度、画面全体を背景色で塗りつぶすために、ちらつくのです。
なので、WM_ERASEBKGNDのメッセージハンドラ OnEraseBkgnd() を実装し、ベースクラス
のOnEraseBkgnd()を呼ばないようにすると背景色での塗りつぶしが無くなるためちらつ
かなくなります。
ただし、その場合は、背景に当たる部分も OnDraw() 内で描画しなければならないこと
に注意してください。


返信引用
maru
 maru
(@maru)
ゲスト
結合: 17年前
投稿: 358
 

> 一度、画面全体を背景色で塗りつぶすために、ちらつくのです。
であるならば、Invalidate()の呼び出しをInvalidate(FALSE)に変えることで、
背景を消去を行なわないようにすることが出来るので、OnEraseBkgnd()を実装す
るより、より簡単かと思います。


返信引用
maru
 maru
(@maru)
ゲスト
結合: 17年前
投稿: 358
 

あれ? 何か勘違いしてるのかな。
http://msdn.microsoft.com/library/ja/default.asp?
url=/library/ja/vclib/html/_mfc_cwnd.3a3a.invalidate.asp
によれば、bErase = TRUE により、背景が消去されるのはBeginPaint()が呼び出された時って
書いてある。
BeginPaint()って普通はOnPaint()から呼び出すと思うけど、違ったかな?

本題に戻って...
スクロール処理をするのならば、CScrollViewを使った方が簡単だと思うけど如何でしょうか。
すでに使っているのであれば悪しからず。


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

参考までに
Invalidate()する方法をやめて

::ScrollWindowEx( hwnd, 0, scrl_y, NULL, NULL, NULL, NULL, ( SW_INVALIDATE |
SW_ERASE));

を使用するという方法もあります(上の例はY方向だけにスクロールします)。

スクロールされた結果無効になった部分だけが再描画の対象リージョンになり、
OnPaintで全てを描画しなおしても、このリージョンだけが表示上の
更新対象となります。結果としてチラツキが抑えられます。


返信引用
たまお
 たまお
(@たまお)
ゲスト
結合: 17年前
投稿: 20
Topic starter  

ご返答ありがとうございます。
Invalidate(FALSE); は、行ってみたのですが・・・
それでも、まだ、ちらつきは直らなかったのです。
よろしくお願い致します。


返信引用
玲音 (st.lain)
 玲音 (st.lain)
(@玲音 (st.lain))
ゲスト
結合: 17年前
投稿: 89
 

毎度、チラツキ→これしか案内しないパターンです。

>> Flicker Free Drawing In MFC
> www.codeproject.com/gdi/flickerfree.asp?target=CMemDC

CMemDCを使ったほうが早いと思います。WM_ERASEBKGNDやスクロールも
含めて全て記載されているので。
(ダウンロードにはメンバ登録が必要ですが。フリーメールもOKです)

# かといって、チラツキが直らない原因を知らなくてもよい、とは言いませんが。


返信引用
たまお
 たまお
(@たまお)
ゲスト
結合: 17年前
投稿: 20
Topic starter  

ご返答ありがとうございます。
Invalidate()を ScrollWindowEx()に変更すると、
残念ながら・・・
そもそも描画処理自体が何も行われないようです。


返信引用
たまお
 たまお
(@たまお)
ゲスト
結合: 17年前
投稿: 20
Topic starter  

ご返答ありがとうございます。
よくわからないのですが・・・
Invalidate()を ScrollWindowEx()に変更する方法では、
OnDraw() が呼ばれないようですが、これは再描画(OnDraw)する必要がなく
ScrollWindowEx()内で、再描画まで行われるという理解で
よろしいのでしょうか?


返信引用
ソイレントグリーン
 ソイレントグリーン
(@ソイレントグリーン)
ゲスト
結合: 17年前
投稿: 65
 

環境がよく分かりませんが、下記はVS2005MFCです
以前私も、描画に関する質問を、この掲示板で質問させていただき
皆さんのお世話で、解決できました、あまり自信はありませんが、いかがでしょうか
多分察するに、Invalidate()する、インスタンスが取れていないように見受けられます。

【背景色再描画処理】
背景スタイル  四角
背景色     黒
ハッチング   有り

CDC m_MemDC;

void InitializationScreen::InvalidateCtrl()
{
CClientDC dc(this);
CRect rcClient;
GetClientRect(rcClient);

if (m_MemDC.GetSafeHdc() == NULL)
{
m_MemDC.CreateCompatibleDC(&dc);
m_Bitmap.CreateCompatibleBitmap(&dc,rcClient.Width(),rcClient.Height());
m_MemDC.SelectObject(m_Bitmap);

// draw scale
m_MemDC.SetBkColor(RGB(0,0,0));
CBrush bkBrush(HS_CROSS,RGB(0,128,0));
m_MemDC.FillRect(rcClient,&bkBrush); // ハッチング
}

InvalidateRect(rcClient, FALSE);
}


返信引用
FUKU
 FUKU
(@FUKU)
ゲスト
結合: 17年前
投稿: 73
 

個人的に良く使う手は、

1. ウィンドウのクラススタイルから CS_HREDRAWと、CS_VREDRAWを外す。
2. WM_ERASEBKGND をハンドリングする。(bunさんのレスと同じ)
3. ScrollWindowEx()で帰ってくるクリップ矩形のみを、'同期的に'再描画する。
(つまり、Invalidate系を使わない)

です。これだけやれば、描画のちらつきは、まず無くなります。
あと、描画図形が複雑で、且つ余り更新されない場合は
ダブルバッファによる描画も良いでしょう。


返信引用
たまお
 たまお
(@たまお)
ゲスト
結合: 17年前
投稿: 20
Topic starter  

皆様ご返答ありがとうございます。
以下の簡単なコード例は、教えて戴いた ScrollWindowEx() する方法で、
ちらつきは、無くなりスクロールできました。
・・・が、OnDraw() するたびに、赤、青のグラフを交互に描画したいのですが、
常に、赤しか描画されないのは、どういうわけでしょうか?
ちなみに、ScrollWindowEx() でなく、Invalidate() を呼ぶと、ちらつきは発生
しますが、グラフ描画は、赤、青 交互に描画されます。
よろしくお願い致します。

int gFlg = 1;

// CTestFormView メッセージ ハンドラ
void CTestFormView::OnDraw(CDC* pDC)
{

  if ( gFlg == 1 ) {
    // 赤グラフ描画
    pDC->FillSolidRect(10, 10, 100, 100, RGB(255, 0, 0));
    gFlg = 0;
  } else {
    // 青グラフ描画
    pDC->FillSolidRect(10, 100, 100, 200, RGB(0, 0, 255));
    gFlg = 1;
  }
}

// OK ボタンのクリックイベント
void CTestFormView::OK_Button1()
{
  //Invalidate(TRUE);

  // スクロール
  ScrollWindowEx( 5, 5, NULL, NULL, NULL, NULL, ( SW_INVALIDATE | SW_ERASE));
}


返信引用
Ban
 Ban
(@ban)
Prominent Member
結合: 5年前
投稿: 776
 

ScrollWindowExは、わざわざ再描画する(OnDrawを呼ぶ)とは限らないから、では。
必要がなければ、既に書いてあるデータを移動するだけですから、
gFlg = xxx を含むOnDraw自体が呼ばれないこともあるでしょう。

# クリックイベントの方で、gFlgを更新するべきだと思いますが、
# なぜにOnDraw?この例はシンプルに表現するためのサンプルですか?


返信引用
Ban
 Ban
(@ban)
Prominent Member
結合: 5年前
投稿: 776
 

# 蛇足の補足
#> クリックイベントの方で、gFlgを更新するべきだと思いますが、
# 単に所管であって、こうすれば直るという話ではないです。


返信引用
たまお
 たまお
(@たまお)
ゲスト
結合: 17年前
投稿: 20
Topic starter  

ご返答ありがとうございます。
ScrollWindowEx でも、再描画(OnDraw)は、常に呼ばれているようです。
呼ばれて・・・
pDC->FillSolidRect(10, 10, 100, 100, RGB(255, 0, 0));
または、

pDC->FillSolidRect(10, 100, 100, 200, RGB(0, 0, 255));
のいすれかが実行されているのですが、表示が変わらないのです。
よろしくお願い致します。


返信引用
固定ページ 1 / 2

返信する

投稿者名

投稿者メールアドレス

タイトル *

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