ページ 11

Invalidate

Posted: 2009年8月05日(水) 19:33
by 研修生
MFCのVC++6.0で開発しています。
ダイアログ内をリサイズしてコントロールなど再配置するというプログラムを作っています。
コントロールを移動させInvalidateで再描画する。

普段ならこれでいいのですがダイアログ内の一部コントロールにおいて再描画したくないものもあるので
全体を再描画するのはまずいです。部分的に排除した画面全体を再描画する方法か
1つのコントロールだけにおいて再描画する方法を教えて下さい。

Re:Invalidate

Posted: 2009年8月05日(水) 20:35
by バグ
逆に質問で申し訳ないのですが、やりたい事は『再描画したくない』のですか?『表示したくない』のですか?
質問を読んでも、いまいち、やりたい事が伝わってこないものでして…ピンとこないんですよね。

Re:Invalidate

Posted: 2009年8月05日(水) 22:18
by 研修生
ダイアログ上にリストビュー1個とボタン2個があってサイズに合わせてコントロール配置するのですが
画面全体を再描画してしまうとリストビューのところがちかちかするんですよね。
必要なのはボタン2個の再描画なんです。ダイアログ内のリストビュー以外の箇所の再描画か
もしくはボタンの移動した箇所の再描画がしたいです。

質問の答えとしてはリストビューの所の再描画をしたくない でしょうか

Re:Invalidate

Posted: 2009年8月05日(水) 23:11
by バグ
そういうことでしたか。
それでしたら、InvalidateRect関数を使って、再描画したいエリアだけを指定して再描画してやればいいと思います。

Re:Invalidate

Posted: 2009年8月06日(木) 09:24
by 研修生
それもやったんですが私の考え方がおかしいのかもしれません。例えばOKボタンのメンバ変数をm_OKとします。
OnSize関数内で
SetWindowPosで移動させ
CRect rect;
m_OK.GetClientRect(&rect);//領域確保
InvalidateRect(&rect, TRUE);

としても全く変化がなくリサイズするとコマ送りようにOKボタンの残像が・・
どこがおかしいのでしょうか

Re:Invalidate

Posted: 2009年8月06日(木) 10:08
by バグ
それでは…

CRect rect;
m_OK.GetClientRect(&rect);

/* この位置でrectの中身を書き換えて座標を移動させる*/

m_OK.MoveWindow(&rect, TRUE);


これではどうでしょうか?
CButtonクラスのMoveWindow関数を使用して移動させ、第2引数をTRUEにする事で、m_OKを再描画させています。

Re:Invalidate

Posted: 2009年8月06日(木) 10:15
by 研修生
書き忘れてしまいました・・
MoveWindowは使わないように言われています。
MoveWindowでのやり方はできているんですが用意している関数の方を使うよういわれています

Re:Invalidate

Posted: 2009年8月06日(木) 10:29
by バグ
あ、それから追記ですが…

残像が残るのは移動させた後の領域を再描画しているからでしょう。
「移動させる前」と「移動させた後」の領域で重なっていない部分が再描画されずに残っているのが原因です。
ですから、研修生さんの方法でやりたいのならば、「移動させる前」と「移動させた後」の両方の領域を再描画させる必要があります。


>>m_OK.GetClientRect(&rect);//領域確保
>>InvalidateRect(&rect, TRUE);

それから、この書き方では、m_OKのクライアント領域を取得しているのに、そのまま親オブジェクト(今回の場合はダイアログクラスでしょうか?)のInvalidateRect関数の引数へ使用しています。これはマズイのではないでしょうか?

この方法でやりたいのならば…


CRect rect;
m_OK.GetClientRect(&rect); // OKボタンのクライアント座標を取得
m_OK.ClientToScreen(&rect); // クライアント座標をスクリーン座標に変換
this->ScreenToClient(&rect); // OKボタンのスクリーン座標をダイアログのクライアント座標へ変換
this->InvalidateRect(&rect); // 指定領域を再描画


こんな感じでしょうか?

Re:Invalidate

Posted: 2009年8月06日(木) 10:31
by バグ
>>MoveWindowでのやり方はできているんですが用意している関数の方を使うよういわれています

用意している関数というのは、何のことでしょうか?

Re:Invalidate

Posted: 2009年8月06日(木) 10:40
by 研修生
社員みんなで1つの製品を作ってますがその中で社員が使いやすいようにと独自に用意した
関数です。その関数内にSetWindowPosがありました。

Re:Invalidate

Posted: 2009年8月06日(木) 10:42
by バグ
これまでの話を総括すると、その関数は単純に座標を移動させるだけで再描画はしてくれないという解釈でよろしいですか?

Re:Invalidate

Posted: 2009年8月06日(木) 10:53
by バグ
MoveWindowが使えれば楽なんですが、事情があるなら仕方ないですね。
ちょっと、汚いソースになってしまいましたが…こんな感じかな?
同じ様な処理をいている個所を関数化すればスッキリするかもしれませんね。

// 移動前の座標を保持する
CRect rect1;
m_OK.GetWindowRect(&rect1); // OKボタンのスクリーン座標を取得
this->ScreenToClient(&rect1); // OKボタンのスクリーン座標をダイアログのクライアント座標へ変換

// 移動後の座標を保持する
CRect rect2;

/* ここで移動処理を行う */

m_OK.GetWindowRect(&rect2); // OKボタンのスクリーン座標を取得
this->ScreenToClient(&rect2); // OKボタンのスクリーン座標をダイアログのクライアント座標へ変換

// 再描画を行う
this->InvalidateRect(&rect1); // 移動前の領域を再描画する
this->InvalidateRect(&rect2); // 移動後の領域を再描画する

Re:Invalidate

Posted: 2009年8月06日(木) 11:15
by 研修生
なるほど、原因はわかりました。まだ曖昧な理解ですがここからは自分で考える所だと思いますので
頑張ってみます。ありがとうございました。