C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[5]: Regionで領域を指定したInvaldate


(過去ログ 65 を表示中)

[トピック内 9 記事 (1 - 9 表示)]  << 0 >>

■37345 / inTopicNo.1)  Regionで領域を指定したInvaldate
  
□投稿者/ Ins (1回)-(2009/06/17(Wed) 15:52:51)

分類:[C#] 

2009/06/17(Wed) 17:12:57 編集(投稿者)
2009/06/17(Wed) 16:41:25 編集(投稿者)

<pre><pre>環境
Microsoft Visual C# 2008 Express Edition
フォームアプリケーション

http://www1.axfc.net/uploader/Img/so/49332.jpg

RPGのマップエディタを作るためにマウスドラックで
中抜きされた矩形の選択領域を表示しようとしています。
PictureBox.Invalidate()をそのまま使うと重いのでRegionで更新領域を指定した上でInvalidateを
使おうとしているのですが、以下のソースコードにおいてマウスを素早く動かすなどすると(右上から左下に移動する際に多発)
選択領域の右下の一部分が欠けてしまいます。
画面を隠すなどすると描画されるので更新領域の指定が上手くいっていないのだと思いますが、原因が見つけられません。
欠けをなくすにはどうしたらいいでしょうか。

public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();

pictureTileListOn.Image = new Bitmap(256, 1024);
lastRg = new Region();
Rectangle rect = new Rectangle();
}

//選択矩形の描画始点
private int xLeft;
private int yTop;
//選択数
private int xSelectNum;
private int ySelectNum;
//最初に選択したタイル
private int xSelect;
private int ySelect;
//マウスカーソルの座標
private int xNow;
private int yNow;

private Region newRg;
private Region lastRg;
private Rectangle rect;

private void pictureTileListOn_MouseDown(object sender, MouseEventArgs e)
{
xSelect = e.X / 32;
ySelect = e.Y / 32;
SelectRectDraw((PictureBox)sender, e);
}
private void pictureTileListOn_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Right || e.Button == MouseButtons.Left)
{
SelectRectDraw((PictureBox)sender, e);
}
}
private void SelectRectDraw(PictureBox pBox, MouseEventArgs e)
{
if (xNow == e.X / 32 && yNow == e.Y / 32) { return; }
if (e.X >= pBox.Width || e.X < 0 || e.Y >= pBox.Height || e.Y < 0) { return; }

xNow = e.X / 32;
yNow = e.Y / 32;

Pen selectPen = new Pen(Color.White, 2);
Pen edgePen = new Pen(Color.Black, 4);

Graphics g = Graphics.FromImage(pBox.Image);
g.Clear(Color.Transparent);

//位置確定
if (xNow <= xSelect) { xLeft = xNow; }
else { xLeft = xSelect; }
xSelectNum = (xNow <= xSelect ? xSelect - xNow : xNow - xSelect) + 1;

if (yNow <= ySelect) { yTop = yNow; }
else { yTop = ySelect; }
ySelectNum = (yNow <= ySelect ? ySelect - yNow : yNow - ySelect) + 1;

//描画位置設定
rect.X = xLeft * 32 + (int)edgePen.Width / 2;
rect.Y = yTop * 32 + (int)edgePen.Width / 2;
rect.Width = xSelectNum * 32 - (int)edgePen.Width;
rect.Height = ySelectNum * 32 - (int)edgePen.Width;

g.DrawRectangle(edgePen, rect);


//------------------------
//ペン幅の半分だけ拡張したrgionオブジェクトを作る
rect.X -= 2;
rect.Y -= 2;
rect.Width += 4;
rect.Height += 4;
newRg = new Region(rect);
//縮小
rect.X += 4;
rect.Y += 4;
rect.Width -= 8;
rect.Height -= 8;
//中抜き
newRg.Xor(rect);

lastRg.Union(newRg);

pBox.Invalidate(lastRg);
pBox.Update();
lastRg = newRg;
//------------------------

}

}</pre></pre>
引用返信 編集キー/
■37346 / inTopicNo.2)  Re[1]: Regionで領域を指定したInvaldate
□投稿者/ .SHO (890回)-(2009/06/17(Wed) 16:18:45)
マウスをゆっくり動かせば大丈夫なんですか?

引用返信 編集キー/
■37347 / inTopicNo.3)  Re[1]: Regionで領域を指定したInvaldate
□投稿者/ gtk2k (2回)-(2009/06/17(Wed) 16:25:55)
画像サイズを256,1024にしているのが原因かと。
引用返信 編集キー/
■37348 / inTopicNo.4)  Re[2]: Regionで領域を指定したInvaldate
□投稿者/ Ins (2回)-(2009/06/17(Wed) 16:36:14)
No37346 (.SHO さん) に返信
> マウスをゆっくり動かせば大丈夫なんですか?

発生する条件ははっきりしないのですがゆっくりと動かした際にも発生します
発生頻度は早く動かした際の方が多いようです
なお左右や上下だけの移動では発生せず
右上から左下またはは左下から右上の斜め移動の際にのみ発生します

No37347 (gtk2k さん) に返信
> 画像サイズを256,1024にしているのが原因かと。

画像サイズを変更しても発生するのですが256,1024と言う数字の何処がいけないのでしょうか
引用返信 編集キー/
■37349 / inTopicNo.5)  Re[3]: Regionで領域を指定したInvaldate
□投稿者/ gtk2k (3回)-(2009/06/17(Wed) 16:49:44)
いや、こっちで試してみたがそんな症状出なかったから。
引用返信 編集キー/
■37350 / inTopicNo.6)  Re[2]: Regionで領域を指定したInvaldate
□投稿者/ Ins (4回)-(2009/06/17(Wed) 17:14:03)
すみません、説明がどうにも下手なので最初の投稿に画像を追加してみました。
引用返信 編集キー/
■37351 / inTopicNo.7)  Re[3]: Regionで領域を指定したInvaldate
□投稿者/ .SHO (891回)-(2009/06/17(Wed) 17:27:08)
単に処理が間に合っていないだけのような気もするんですが
まずは、無駄な処理を全部、とっぱらって必要な物だけにしてはどうでしょう?

リージョンきってInvalidateするだけでいいんですよね?
Penを作ったり(しかもselectPenは作っただけで使用していない)
Rectangleの描画したりっていらないですよね?

引用返信 編集キー/
■37353 / inTopicNo.8)  Re[4]: Regionで領域を指定したInvaldate
□投稿者/ Ins (6回)-(2009/06/17(Wed) 18:00:48)
No37351 (.SHO さん) に返信
> 単に処理が間に合っていないだけのような気もするんですが
> まずは、無駄な処理を全部、とっぱらって必要な物だけにしてはどうでしょう?

このソースはもともとプロジェクトの一部を切り出して単体で動作するようにしたものなので
無駄な部分を取り切れていなかったようです。
CPU使用率は50%を切っているので処理が間に合っていないと言うことはないと思います

> リージョンきってInvalidateするだけでいいんですよね?
> Penを作ったり(しかもselectPenは作っただけで使用していない)
> Rectangleの描画したりっていらないですよね?

いえ、むしろRectangleで選択領域を明示することがメインです。
処理を向上させるためRectangleで描画した範囲のみを更新領域に指定してInvalidateをしようとしています
引用返信 編集キー/
■37359 / inTopicNo.9)  Re[5]: Regionで領域を指定したInvaldate
□投稿者/ gtk2k (4回)-(2009/06/17(Wed) 22:55:59)
ごめん、ノートでやったら現象起きた。
検証してみるとUnion後のlastRgは、
2つの矩形をあわせたものが期待されるが、
欠けたり残像したりするときのUnion後のlastRgが
その部分が欠けたものなっているな。
なんでなんだろ。原因はわからない。

あとGraphicsオブジェクトはDisposeするように。


// 検証コード
public Form1()
{
InitializeComponent();

pictureTileListOn.Image = new Bitmap(1280, 1024);
lastRg = new Region();
Rectangle rect = new Rectangle();
}

//選択矩形の描画始点
private int xLeft;
private int yTop;
//選択数
private int xSelectNum;
private int ySelectNum;
//最初に選択したタイル
private int xSelect;
private int ySelect;
//マウスカーソルの座標
private int xNow;
private int yNow;

private Region newRg;
private Region lastRg;
private Rectangle rect;
private List<Region> rgs = new List<Region>();
private int rgsIdx;

private void pictureTileListOn_MouseDown(object sender, MouseEventArgs e)
{
xSelect = e.X / 32;
ySelect = e.Y / 32;
SelectRectDraw((PictureBox)sender, e);
}
private void pictureTileListOn_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Right || e.Button == MouseButtons.Left)
{
SelectRectDraw((PictureBox)sender, e);
}
}
private void SelectRectDraw(PictureBox pBox, MouseEventArgs e)
{
if (xNow == e.X / 32 && yNow == e.Y / 32) { return; }
//if (e.X >= pBox.Width || e.X < 0 || e.Y >= pBox.Height || e.Y < 0) { return; }
System.Diagnostics.Debug.WriteLine("A");
xNow = e.X / 32;
yNow = e.Y / 32;

Pen selectPen = new Pen(Color.White, 2);
Pen edgePen = new Pen(Color.Black, 4);

Graphics g = Graphics.FromImage(pBox.Image);
g.Clear(Color.Transparent);

//位置確定
if (xNow <= xSelect) { xLeft = xNow; }
else { xLeft = xSelect; }
xSelectNum = (xNow <= xSelect ? xSelect - xNow : xNow - xSelect) + 1;

if (yNow <= ySelect) { yTop = yNow; }
else { yTop = ySelect; }
ySelectNum = (yNow <= ySelect ? ySelect - yNow : yNow - ySelect) + 1;

//描画位置設定
rect.X = xLeft * 32 + (int)edgePen.Width / 2;
rect.Y = yTop * 32 + (int)edgePen.Width / 2;
rect.Width = xSelectNum * 32 - (int)edgePen.Width;
rect.Height = ySelectNum * 32 - (int)edgePen.Width;

//g.DrawRectangle(edgePen, rect);


//------------------------
//ペン幅の半分だけ拡張したrgionオブジェクトを作る
rect.X -= 2;
rect.Y -= 2;
rect.Width += 4;
rect.Height += 4;
newRg = new Region(rect);
//縮小
rect.X += 4;
rect.Y += 4;
rect.Width -= 8;
rect.Height -= 8;
//中抜き
newRg.Xor(rect);
g.FillRegion(Brushes.Black, newRg);
lastRg.Union(newRg.Clone());

// 領域の履歴をとる
rgs.Add(lastRg.Clone());

pBox.Invalidate(lastRg);
pBox.Update();
g.Dispose();
lastRg = newRg;
//------------------------
System.Diagnostics.Debug.WriteLine("B");
}

// 過去10の履歴を見る
private void Form1_KeyPress(object sender, KeyPressEventArgs e)
{
if (rgsIdx > 10) rgsIdx = 0;
this.Text = rgsIdx.ToString();
Graphics g = Graphics.FromImage(this.pictureTileListOn.Image);
g.Clear(Color.White);
g.FillRegion(Brushes.Black, rgs[rgs.Count - 11 + rgsIdx]);
g.Dispose();
pictureTileListOn.Invalidate();
rgsIdx += 1;
}
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -