Invalidateによる再描画について

[戻る]
モーモー 2003/02/22(土) 18:03:43
度々、お世話になっております。

さっそく質問ですが、
Invalidateの再描写の動きを知りたいのです。。。
例えば、マウスクリックのときに再描写したいと思い、
void CXXXXXView::OnLButtonDown(UINT nFlgs,CPoint point)
{
    Invalidate(FALSE);
}
とやると、このOnButtonDown関数を抜けてから、OnDraw関数にいくのでしょうか?


実は今、2つの絵を同時に処理したくて、
2回再描写しようと、以下のようにプログラムを組んでいるのですが、、、
void CXXXXXView::OnLButtonDown(UINT nFlgs,CPoint point)
{
   ・・・・・・
    //On_Drawにある絵を描く関数に渡す引数(位置とBITMAPID)の設定//
    Invalidate(FALSE);

    //On_Drawにある絵を描く関数に渡す引数(位置とBITMAPID)の設定//
    Invalidate(FALSE);
   ・・・・・・
}

2回目の再描写しか機能していないのか・・・よくわからないんですけど、
2つ目しか絵がかけません。
それで、1つ目と2つ目の間に、MessageBoxなどで適当な処理を加えると、
何かしらのワンクッションが置かれるらしく、2つとも絵が出てきます。

どういう動きでこうなってしまうのかわからないので、教えてください。


それと、再描写のInvalidateの引数について、もう1つ質問があります。
今、FALSEにして前に描いた絵を消さないようにしているのですが、
最小化して元に戻したりすると、前に描いていた絵が消えてしまいます。。。
どうすれば、前の絵を消さずに、再描写できるのでしょうか?
『ららら』の過去ログで、”Invaliate(FALSE)の使い道は?”みたいなやつで、
FALSEじゃなくてもいいっていうのを見たことがあったんですが、
詳しい書き方がなかったので、こちらも教えていただきたいです。

長くなりましたが、よろしくお願いします。

n [E-Mail] 2003/02/22(土) 18:28:25
Invalidate() はウィンドウズにメッセージを「ポスト(Post)」します。
ポストされたメッセージに対応するハンドラは、現在実行中のハンドラや
先にポストされていたメッセージに対応するハンドラの実行終了を待って、
実行されます。

OnLButtonDown() で Invalidate() を呼び出すと WM_PAINT がポストされ、
まだ他にポストされたメッセージが無ければ OnLButtonDown() の終了後、 
OnEraseBkgnd()、OnDraw() と連続して呼び出されます。

この「ポスト」して順番を待つ、で都合が悪いときには、
Invalidate() の直後に UpdateWindow() を呼ぶことで、即再描画されます。

2003/02/22(土) 19:05:19
モーモーさん、今晩は
>Invalidateの再描写の動きを知りたいのです。。。

msdn ライブラリーでお調べになればわかる事ですが

CWnd::Invalidate() は更新領域を(Windows に)通知するだけです
Windows は通知を受けた更新領域を記録し、適切な時期に WM_PAINT をそのウィンドーに
送ります。その結果 CWnd::OnDraw() が動きます

CWnd::Invlidate(BOOL bErase) の仮引数 bErase の件ですが、次回の WM_PAINT で
更新領域内の背景を背景色で塗るかどうかを指示するものです(TURE なら塗る)
TRUE にしていると一々全体を(Invalidate なので全体になる)背景色で塗りつぶしてから
CWnd::OnDraw() で描画を行うので、今まで在った絵が(背景色で塗るので)一瞬消えて再び
現れる事になってちらつくように感じる事があります

>最小化して元に戻したりすると、前に描いていた絵が消えてしまいます。。。
>どうすれば、前の絵を消さずに、再描写できるのでしょうか?

CXXXXXView::OnDraw() での処理に問題があるのではないでしょうか
CXXXXXView::OnLButtonDown() での処理を見ているとそう感じざるを得ません

モーモー 2003/02/23(日) 00:50:05
返事が遅くなって申し訳ありません。

nさん、島さん、レスありがとうございます。

nさんのおっしゃっているようにUpdateWindow()を追加することで、
2回続けて再描写することはできました。

しかし、最小化して元に戻したときは全てがクリアさています。。。
島さんのおっしゃるように、On_Drawの基本的な描き方がなってないのかもしれません。。。

すみませんが、ソースを書いてみましたので、
なにかおかしなところがあれば、ご指摘ください。
よろしくお願いします。


On_Draw(CDC* pDC)
{
 ・・・・・
   if(click == on){         //click は、クリックしているかというフラグ 
      PicDraw(pDC,SITEN.x,SITEN.y,P_ID);
      click = OFF;
}

PicDraw(CDC *pDC,int px,int py,UINT pID)
{
  CDC myDC;
  CBitmap  myBMP;
  BITMAP   bmpInfo;
  myBMP.LoadBitmap(pID);
  myBMP.GetObject(sizeof(bmpInfo),&bmpInfo);
  int pH = bmpInfo.bmHeight;
  int pW = bmpInfo.bmWidth;
  myDC.CreateompatibleDC(pDC);
  CBitmap* oldBMP = myDC.SelectObject(&myBMP);
  pDC->BitBlt(px,py,pW,pH,&myDC,0,0,SRCCOPY);
  myDC.Select(&myBMP);
}

2003/02/23(日) 03:31:25
一瞬で判るようなコードの問題が何故お判りにならないのかが不思議です

OnDraw() では click が on でなければ描画しない上に、描画後には
click を OFF にするのですから、最小化から元の戻る場合や、他のウィンドーが上に
かさねっていたのがなくなって隠れていた部分を再描画する場合や、では当然 click は
on 以外の値ですから何も描画できません

モーモー 2003/02/23(日) 20:32:25
すみません。。。ありがとうございます。

実は、ソフト起動時にもOn_Drawで初期描写(?)するため、
そのときには、PicDrawの引数が何も設定されてないので、起動すると同時にエラーとなり
落ちてしまいます。
それを、回避しようとして、単純にクリックしたときにフラグを立てただけなのです。。。

すみませんが、どういうふうに実装すれば、オープン時の描写は、うまくいくでしょうか?
いろいろ調べて、OnEraseBkgnd()を使えばInvalidate(true)でも、
いけそうということがわかったのですが。。。。
どうしでも、On_Drawの書き出し(?)が、思いつきません。

もう少しお力をお借りしたく、すみませんが助言お願いします。

2003/02/23(日) 20:55:06
SITEN か P_ID かの初期値が有得ない値であれば十分判定可能なのではないでしょうか?

ところで On_Draw() はどのクラスにも属さない函数なのですか?
後、Invalidate() と 再描画との関連についてはお判りになったのでしょうか?
MSDN ライブラリーでお調べになりましたか?

モーモー 2003/02/23(日) 22:43:54
知識が無さ過ぎてすみません。
”函数”ってなんですか?
Invalidateについては、MSDNで調べて見ました。
まだ、なんとなく理解した。。。というところでしょうか。

ご迷惑かけてすみません。

sala 2003/02/23(日) 23:44:51
>”函数”ってなんですか?
関数でしょ。
前から気になってたんですが、初心者も見るこういうところでは
一般的な用語使った方がいいと思いますよ > 島さん

2003/02/23(日) 23:55:26
>初心者も見るこういうところでは一般的な用語使った方がいいと思いますよ

成る程、そういう意見もあるでしょう(でも函数の方が関数よりも由緒正しいのですよ)
今後は最低限一度は函数(関数)と併用表記するように心掛けます

nara 2003/02/24(月) 00:09:06
心掛けるだけ? 仕方ないから、"関数"とも書いてやるよって感じに取れる…
函数の方が由緒正しいんでしょうけど、"初心者も見る掲示板"という場において、しかも、
初心者かもしれない人を相手に、由緒正しいのを書くのと、一般的で初心者でも理解できるの
を書くのと、どちらが良いと考えているのでしょうか。
上のカキコからは、前者が良いと考えているんでしょうけども。

NEG(ねぐ) [E-Mail] [HomePage] 2003/02/24(月) 09:32:57
>”函数”ってなんですか?

 辞書を調べれば一発!

επιστημη 2003/02/24(月) 10:10:02
>> ”函数”ってなんですか?
> 辞書を調べれば一発!

まったくだ。訊くまでもないこと。
辞書まで誰かに引いてもらおうってか?

しんた 2003/02/24(月) 10:46:37
モーモーさんの質問には、答えないのですか??

επιστημη 2003/02/24(月) 10:51:20
> モーモーさんの質問には、答えないのですか??

島さんからの質問への、モーモーさんの応答を待っています。

モーモー 2003/02/24(月) 11:02:02
すみません。失礼しました。国語辞典で調べたらありました。
決して、そういうつもりで質問したわけではありませんので、お許しください。


>On_Draw() はどのクラスにも属さない函数なのですか?
On_Drawの中にある、PicDraw(pDC,SITEN.x,SITEN.y,P_ID) というのが、
CItemというクラスにあるものでして、それ以外のクラスには属していませんが、
これがなにか問題なのでしょうか?

それから、OnEraseBkgnd(pDC)を使って、最小化して元に戻した時に絵を消さないようにする
のは
できたのですが、なぜか直前の絵だけしかのこってないのです。
絵を3つ描いて最小化させ、元に戻すと真白の状態ではないにしろ、
最後の絵しか残らないのです。。。
OnEraseBkgnd()っていうのは、背面を塗りつぶすかどうかってことですよね?
この現象はなぜなんでしょうか?教えてください。

n [E-Mail] 2003/02/24(月) 11:39:19
> OnEraseBkgnd(pDC)を使って、最小化して元に戻した時に絵を消さないようにする

これはOnDraw()にコードを書くだけで充分なはず??

2003/02/24(月) 11:53:13
>決して、そういうつもりで質問したわけではありませんので、お許しください。
こちらこそあなたに不慣れな表記(函数(かんすう、関数))を使ってしまい御免なさい

>これがなにか問題なのでしょうか?

いえ、CView::OnDraw() と On_Draw() とがどういう関係なのか知りたかったのです

>最後の絵しか残らないのです。。。

現在絵を幾つ表示しなければならないのか誰かが知っていなければなりませんね
あなたの提示されたコードを読んで判る事は表示対象が幾つどのようなものがあるのか
について記録なさっていないようだという事です

std::vector か CArray か、上限があるなら排列((はいれつ、配列)でもいいでしょうが)
か、に記録するといいと思います
例えば、std::vector <CItem> Items; が CXXXXXDoc か CXXXXXView かのメンバーとして
あれば、幾つどのようなものがあるのかが判るので表示する事が出来るでしょう

モーモー 2003/02/24(月) 11:53:14
On_Draw()のなかに、
OnEraseBkgnd(pDC)と書いてからif(xxx){PicDraw()}するようにしてあるだけなんですけど、
上記のような現象がでてしまうのですが。。。。

n [E-Mail] 2003/02/24(月) 12:38:22
OnEraseBkgnd()は自分で直接呼び出す関数じゃないです。
Invalidate()等の呼び出しにより間接的に呼ばれる(呼ばせる)ものなので、
自分で呼び出すと混乱が増えますよ。

モーモー 2003/02/24(月) 13:43:56
そうでしたか。。。ありがとうございます。

では、クラスウィザードでBOOL CXXXView::OnEraseBkgnd(CDC* pDC) を作成し、
その中でriturn値をどうにかすればいいんでしょうかね?

n [E-Mail] 2003/02/24(月) 13:47:48
OnDraw()の内容はどうなっているんですか?

モーモー 2003/02/24(月) 14:05:00
大変失礼しました。
On_Drawと書いてあったのは、私の記述ミスでCXXXView::OnDraw()のつもりでした。
申し訳ありません。すっかり混乱させてしまってますね・・・ごめんなさい。

あと、島さんのレスを飛ばしてたので、それに対しての返事なんですけど、
絵の情報はButtonUpのときに配列として保持してあるのですが。
情報をもっていても、Invalidate()による再描画では最後の一つしか表示しないですよね?
どうすればよいでしょうか。

REE 2003/02/24(月) 14:36:53
おそらく、モーモーさんのプログラムでは、
OnDraw()の中では、絵を一つしか書いてないのではないでしょうか?

正しく表示させるためには、OnDraw()の中で、全ての絵を書くようにする必要があります。
下記のイメージでお考え下さい。


変更前

CXXXXXView::OnDraw(...) 
{
  描画処理
}

CXXXXXView::OnLButtonDown(...)
{
   ・・・・・・
    //On_Drawにある絵を描く関数に渡す引数(位置とBITMAPID)の設定//
    Invalidate(FALSE);

    //On_Drawにある絵を描く関数に渡す引数(位置とBITMAPID)の設定//
    Invalidate(FALSE);
   ・・・・・・
}

変更後

CXXXXXView::OnDraw(...) 
{
  for(i=0;i<絵の枚数;i++)
  {
    i番目の絵のパラメータ設定(配列などから取り込み)
    描画処理
  }
}

CXXXXXView::OnLButtonDown(...)
{
   ・・・・・・
    //On_Drawにある絵を描く関数に渡す引数(位置とBITMAPID)を配列に保存//
    //On_Drawにある絵を描く関数に渡す引数(位置とBITMAPID)を配列に保存//
    Invalidate(FALSE);
   ・・・・・・
}

モーモー 2003/02/25(火) 13:47:05
[[解決]]
返事遅くなってすみません。

REEさんのレス通りにやってみたらできました。

この掲示に関わっていただきました皆様には大変感謝しています。
超初心者の私を見捨てずに答えてくださり、ありがとうございましたm(__)m


また行き詰まったら顔(?)出すと思いますので、またよろしくお願いします。

古いスレッドには追加発言できません。