C# - 如何擦除屏幕上的绘制矩形?
C# - How to erase draw rectangle on screen?
我正在使用此代码绘制一个矩形,该矩形将在 500 毫秒后在鼠标位置重新绘制。
一切都很好,矩形绘制工作完美,但使用此代码,已经在屏幕上绘制的旧矩形将永远保留在屏幕上,它们不会被擦除。
我需要在制作新矩形后擦除旧矩形。新矩形是用 while 循环制作的。
int i = 0;
while (i != 1)
{
int x = Cursor.Position.X;
int y = Cursor.Position.Y;
Graphics g = Graphics.FromHwnd(IntPtr.Zero);
Rectangle mouseNewRect = new Rectangle(new Point(x, y), new Size(30, 30));
g.DrawRectangle(new Pen(Brushes.Chocolate), mouseNewRect);
Wait(500);
}
编辑:我需要擦除表格内外的矩形。想法?
您需要使要绘制的 window 在迭代之间重新绘制自身。另一种解决方案是将 window 捕获到内存中的图像;在该图像的副本上绘制矩形,然后将图像绘制到 window。每次都重复这个过程,这样目标 window 就没有之前迭代的痕迹。
您可以调用 Invalidate()
方法,该方法将通过再次调用 paint 方法请求重新绘制区域。
请参阅 MSDNControl.Invalidate()
在你的场景中,是这样的吗?
int i = 0;
while (i != 1)
{
int x = Cursor.Position.X;
int y = Cursor.Position.Y;
Graphics g = Graphics.FromHwnd(IntPtr.Zero);
Rectangle mouseNewRect = new Rectangle(new Point(x, y), new Size(30, 30));
g.DrawRectangle(new Pen(Brushes.Chocolate), mouseNewRect);
Wait(500);
Invalidate();
}
至于刷新整个屏幕,你可以用这个p/invoke。
https://www.pinvoke.net/default.aspx/user32.invalidaterect
[DllImport("user32.dll")]
static extern bool InvalidateRect(IntPtr hWnd, RECT lpRect, bool bErase);
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int Left, Top, Right, Bottom;
public RECT(int left, int top, int right, int bottom)
{
Left = left;
Top = top;
Right = right;
Bottom = bottom;
}
public RECT(System.Drawing.Rectangle r) : this(r.Left, r.Top, r.Right, r.Bottom) { }
public int X
{
get { return Left; }
set { Right -= (Left - value); Left = value; }
}
public int Y
{
get { return Top; }
set { Bottom -= (Top - value); Top = value; }
}
public int Height
{
get { return Bottom - Top; }
set { Bottom = value + Top; }
}
public int Width
{
get { return Right - Left; }
set { Right = value + Left; }
}
public System.Drawing.Point Location
{
get { return new System.Drawing.Point(Left, Top); }
set { X = value.X; Y = value.Y; }
}
public System.Drawing.Size Size
{
get { return new System.Drawing.Size(Width, Height); }
set { Width = value.Width; Height = value.Height; }
}
public static implicit operator System.Drawing.Rectangle(RECT r)
{
return new System.Drawing.Rectangle(r.Left, r.Top, r.Width, r.Height);
}
public static implicit operator RECT(System.Drawing.Rectangle r)
{
return new RECT(r);
}
public static bool operator ==(RECT r1, RECT r2)
{
return r1.Equals(r2);
}
public static bool operator !=(RECT r1, RECT r2)
{
return !r1.Equals(r2);
}
public bool Equals(RECT r)
{
return r.Left == Left && r.Top == Top && r.Right == Right && r.Bottom == Bottom;
}
public override bool Equals(object obj)
{
if (obj is RECT)
return Equals((RECT)obj);
else if (obj is System.Drawing.Rectangle)
return Equals(new RECT((System.Drawing.Rectangle)obj));
return false;
}
public override int GetHashCode()
{
return ((System.Drawing.Rectangle)this).GetHashCode();
}
public override string ToString()
{
return string.Format(System.Globalization.CultureInfo.CurrentCulture, "{{Left={0},Top={1},Right={2},Bottom={3}}}", Left, Top, Right, Bottom);
}
}
然后通过调用
来使用它
InvalidateRect(IntPtr.Zero, null, true);
将 null 和 true 作为第二个和第三个参数传递应该会导致重绘整个屏幕。
@Emcrank 发布的解决方案有效。
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
Load += async delegate
{
var g = Graphics.FromHwnd(IntPtr.Zero);
var mouseNewRect = new Rectangle(Point.Empty, new Size(30, 30));
var pen = new Pen(Brushes.Chocolate);
while (true)
{
mouseNewRect.Location = Cursor.Position;
g.DrawRectangle(pen, mouseNewRect);
await Task.Delay(500);
InvalidateRect(IntPtr.Zero, IntPtr.Zero, true);
}
};
}
[DllImport("user32.dll")]
static extern bool InvalidateRect(IntPtr hWnd, IntPtr lpRect, bool bErase);
}
无论如何,如果你想在窗体内部绘制鼠标位置,还有更好的解决方案。
public partial class Form1 : Form
{
private Rectangle _rect = new Rectangle(0, 0, 30, 30);
private readonly Pen _pen = new Pen(Brushes.Chocolate);
public Form1()
{
InitializeComponent();
SetStyle(ControlStyles.UserPaint | ControlStyles.OptimizedDoubleBuffer, true);
}
protected override void OnMouseMove(MouseEventArgs e)
{
_rect.Location = e.Location;
Invalidate(ClientRectangle);
base.OnMouseMove(e);
}
protected override void OnPaint(PaintEventArgs e)
{
//--improve graphics quality
var g = e.Graphics;
g.CompositingQuality = CompositingQuality.HighQuality;
g.SmoothingMode = SmoothingMode.AntiAlias;
_rect.Offset(-15, -15); //--center rect
e.Graphics.DrawRectangle(_pen, _rect);
base.OnPaint(e);
}
}
希望对您有所帮助。
我正在使用此代码绘制一个矩形,该矩形将在 500 毫秒后在鼠标位置重新绘制。
一切都很好,矩形绘制工作完美,但使用此代码,已经在屏幕上绘制的旧矩形将永远保留在屏幕上,它们不会被擦除。
我需要在制作新矩形后擦除旧矩形。新矩形是用 while 循环制作的。
int i = 0;
while (i != 1)
{
int x = Cursor.Position.X;
int y = Cursor.Position.Y;
Graphics g = Graphics.FromHwnd(IntPtr.Zero);
Rectangle mouseNewRect = new Rectangle(new Point(x, y), new Size(30, 30));
g.DrawRectangle(new Pen(Brushes.Chocolate), mouseNewRect);
Wait(500);
}
编辑:我需要擦除表格内外的矩形。想法?
您需要使要绘制的 window 在迭代之间重新绘制自身。另一种解决方案是将 window 捕获到内存中的图像;在该图像的副本上绘制矩形,然后将图像绘制到 window。每次都重复这个过程,这样目标 window 就没有之前迭代的痕迹。
您可以调用 Invalidate()
方法,该方法将通过再次调用 paint 方法请求重新绘制区域。
请参阅 MSDNControl.Invalidate()
在你的场景中,是这样的吗?
int i = 0;
while (i != 1)
{
int x = Cursor.Position.X;
int y = Cursor.Position.Y;
Graphics g = Graphics.FromHwnd(IntPtr.Zero);
Rectangle mouseNewRect = new Rectangle(new Point(x, y), new Size(30, 30));
g.DrawRectangle(new Pen(Brushes.Chocolate), mouseNewRect);
Wait(500);
Invalidate();
}
至于刷新整个屏幕,你可以用这个p/invoke。 https://www.pinvoke.net/default.aspx/user32.invalidaterect
[DllImport("user32.dll")]
static extern bool InvalidateRect(IntPtr hWnd, RECT lpRect, bool bErase);
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int Left, Top, Right, Bottom;
public RECT(int left, int top, int right, int bottom)
{
Left = left;
Top = top;
Right = right;
Bottom = bottom;
}
public RECT(System.Drawing.Rectangle r) : this(r.Left, r.Top, r.Right, r.Bottom) { }
public int X
{
get { return Left; }
set { Right -= (Left - value); Left = value; }
}
public int Y
{
get { return Top; }
set { Bottom -= (Top - value); Top = value; }
}
public int Height
{
get { return Bottom - Top; }
set { Bottom = value + Top; }
}
public int Width
{
get { return Right - Left; }
set { Right = value + Left; }
}
public System.Drawing.Point Location
{
get { return new System.Drawing.Point(Left, Top); }
set { X = value.X; Y = value.Y; }
}
public System.Drawing.Size Size
{
get { return new System.Drawing.Size(Width, Height); }
set { Width = value.Width; Height = value.Height; }
}
public static implicit operator System.Drawing.Rectangle(RECT r)
{
return new System.Drawing.Rectangle(r.Left, r.Top, r.Width, r.Height);
}
public static implicit operator RECT(System.Drawing.Rectangle r)
{
return new RECT(r);
}
public static bool operator ==(RECT r1, RECT r2)
{
return r1.Equals(r2);
}
public static bool operator !=(RECT r1, RECT r2)
{
return !r1.Equals(r2);
}
public bool Equals(RECT r)
{
return r.Left == Left && r.Top == Top && r.Right == Right && r.Bottom == Bottom;
}
public override bool Equals(object obj)
{
if (obj is RECT)
return Equals((RECT)obj);
else if (obj is System.Drawing.Rectangle)
return Equals(new RECT((System.Drawing.Rectangle)obj));
return false;
}
public override int GetHashCode()
{
return ((System.Drawing.Rectangle)this).GetHashCode();
}
public override string ToString()
{
return string.Format(System.Globalization.CultureInfo.CurrentCulture, "{{Left={0},Top={1},Right={2},Bottom={3}}}", Left, Top, Right, Bottom);
}
}
然后通过调用
来使用它InvalidateRect(IntPtr.Zero, null, true);
将 null 和 true 作为第二个和第三个参数传递应该会导致重绘整个屏幕。
@Emcrank 发布的解决方案有效。
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
Load += async delegate
{
var g = Graphics.FromHwnd(IntPtr.Zero);
var mouseNewRect = new Rectangle(Point.Empty, new Size(30, 30));
var pen = new Pen(Brushes.Chocolate);
while (true)
{
mouseNewRect.Location = Cursor.Position;
g.DrawRectangle(pen, mouseNewRect);
await Task.Delay(500);
InvalidateRect(IntPtr.Zero, IntPtr.Zero, true);
}
};
}
[DllImport("user32.dll")]
static extern bool InvalidateRect(IntPtr hWnd, IntPtr lpRect, bool bErase);
}
无论如何,如果你想在窗体内部绘制鼠标位置,还有更好的解决方案。
public partial class Form1 : Form
{
private Rectangle _rect = new Rectangle(0, 0, 30, 30);
private readonly Pen _pen = new Pen(Brushes.Chocolate);
public Form1()
{
InitializeComponent();
SetStyle(ControlStyles.UserPaint | ControlStyles.OptimizedDoubleBuffer, true);
}
protected override void OnMouseMove(MouseEventArgs e)
{
_rect.Location = e.Location;
Invalidate(ClientRectangle);
base.OnMouseMove(e);
}
protected override void OnPaint(PaintEventArgs e)
{
//--improve graphics quality
var g = e.Graphics;
g.CompositingQuality = CompositingQuality.HighQuality;
g.SmoothingMode = SmoothingMode.AntiAlias;
_rect.Offset(-15, -15); //--center rect
e.Graphics.DrawRectangle(_pen, _rect);
base.OnPaint(e);
}
}
希望对您有所帮助。