人に聞けない痔の悩み、これでスッキリ >>

ボールが右下に動いていくだけのプログラムです。
はじめはInvalidateRect(hWnd,NULL,.TRUE)を使っていたのですが画面がちらつくので
InvalidateRgnを使ってみました。そこで円の部分をリージョンで指定して背面消去したら
図1のようになってしまったので、
ペンの太さを考慮してなかったのが問題だと思って円の周辺に余裕を持ってリージョンを
設定して以下のようなプログラムになったのですが(スレッドの中身です)
図2のように進行方向の部分が欠けてしまいます。
その後余白の3の部分を7以上にしたら元の円のまま動きました。
ペンの太さは3なので十分だと思ったのですが6以下でなぜ欠けてしまうんでしょうか?

while(1){
hRgn = CreateEllipticRgn(x - hankei - 3, y - hankei - 3, x + hankei + 3, y + hankei + 3);
x = x + 4;
y = y + 2;
InvalidateRgn(hWnd,hRgn,TRUE);
Sleep(100);
}

「InvalidateRgn()について」の質問画像

A 回答 (2件)

InvalidateRgnで無効にした領域だけを再描画するため 右下が欠けたようになるのだと思います



CreateEllipticRgnでリュージョンを生成するのを 描画側でやります
描画には FillRgnとFrameRgnで行い

描画位置更新イベント側では GetRgnBoxでリュージョンの矩形範囲を取得し
進行方向へ膨らませて InvalidateRectを実行して見ましょう


// 描画側
hRgn = CreateEllipticRgn(x - hankei, y - hankei, x + hankei, y + hankei);
HBRUSH hBrFrame = CreateSolidBrush(RGB(255,0,0));
// hBr: 塗りつぶしようのブラシは生成済みと仮定
FillRgn(hWnd, hRgn, hBr);
FrameRgn(hWnd, hRgn, hBrFrame, 3, 3);
DeleteObject(hBrFrame);

// 消去側
RECT r = {0};
if (hRgn) {
  // 矩形範囲を取得
  GetRgnBox(hRgn, &r);
  // 再描画の増分を考慮
  r.right += 4;
  r.bottom += 2;
  /*
    左上に動かすなら left, topを更新
    右上なら right,top
    左下なら left,bottom
  */
  InvalidateRect(hWnd, &r, TRUE);
  // 使用済みなので リュージョンを破棄
  if (DeleteObject(hRgn)) {
    hRgn = NULL;
  }
}
x += 4;
y += 2;

この回答への補足

回答ありがとうございます。
InvalidateRgnを使ったとき背面消去だけリージョンの範囲で行われて
描画は全範囲で行われるものと勘違いしていました。
消去も描画もリージョンの部分のみ行われていたから進行方向のはみだした
部分について描画されなかったんですね。

描画はペンとブラシでEllipse()を使っていたんですが、
FillRgnとFrameRgnでやるんですね。
これを使えばペンの太さとか気にせずに
描画した部分に対してぴったり無効化の範囲を指定できるって事でしょうか?

また更新部分のリージョンの指定で以下のようなものを考えてみたのですが
矩形の方が処理が早いとか何かメリットがあるんでしょうか?
それとも今回の質問の問題箇所がそれで解決されるので簡単にして書いただけですかね?
またいくつか質問になってしまいましたが、よろしくお願い致します。

hRgn1 = CreateEllipticRgn(x - hankei, y - hankei, x + hankei, y + hankei);
ボールの位置を変化させる(x,yを変化させる)
hRgn2 = CreateEllipticRgn(x - hankei, y - hankei, x + hankei, y + hankei);
CombineRgn(hRgn1, hRgn1, hRgn2, RGN_OR);
InvalidateRgn(hWnd, hRgn1, TRUE);
Sleep(50);

補足日時:2014/12/08 01:22
    • good
    • 0

Ellipseでの描画は 指定された矩形範囲に内接する楕円を描画するのですが


内接するのはペンの中心です

// Pen,Brushは選択済みとします
Ellipse(hdc, 50, 50, 100, 100);
hRgn = CreateEllipseRgn(50,50,100,100);
InvalidateRgn(hWnd, hRgn, TRUE);

といったコード実行すると
Ellipseで描画した縁が消去されないと思います

FillRgn/FrameRgnを使えば 生成したリュージョン内での描画になるので上記のような問題は解決されるでしょう

再描画に関してですが WM_PAINTイベントの実装により変わってきますよ
BeginPaintを呼び出した際に 返される PAINTSTRUCT構造体psのrcPaintが無効にされた領域です
rcPaintだけを BitBltなどで転送する実装だと GetRgnBoxで取得できる領域と等価だとおもいます
無関係にクライアント領域を書き直す実装だと 無駄が多いようにおもいます
    • good
    • 0
この回答へのお礼

試してみて、リージョンによる描画の違いなど理解しました。
ありがとうございました。

お礼日時:2014/12/08 23:48

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!


人気Q&Aランキング