矩形仅绘制标签在 c# 窗体上经过的部分



我有一个关于我正在编写的练习程序的问题,该程序在当前状态下允许用户使用箭头键在表单周围移动标签。

我想开始向我的程序添加一些图形矩形,目前正在练习在计时器达到 100 时尝试绘制一个简单的矩形。

这是奇怪的部分,矩形仅在标签经过部分矩形后绘制,并且只会绘制标签经过的部分。发生这种情况的图片:标签经过矩形。理想情况下,我想了解为什么会发生这种情况,但如果有人可以提供解决方案,我也会非常高兴!

我将发布我的整个代码,因为我什至不确定问题可能来自哪一部分。如果它不整洁,非常抱歉,希望有人会从图像中有一个想法:

namespace WindowsFormsApplication1

{

public partial class Form1 : Form
{
int direction;
int X = 200;
int Y = 200;
Rectangle myRock;
public System.Windows.Forms.Timer aTimer = new System.Windows.Forms.Timer();

public Form1()
{
InitializeComponent();
this.Load += new System.EventHandler(this.Form1_Load);
this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.Form1_KeyDown);
this.Click += new System.EventHandler(this.Form1_Click);

}
void worker()
{
for (int i = 0; i < 100000; i++) {
if (label2.InvokeRequired)
{
label2.Invoke((MethodInvoker)delegate
{
label2.Text = i.ToString(); // this is a timer acting as a score keeper
});
Thread.Sleep(100);
}
}
}



public void DrawRectangleRectangle(PaintEventArgs e, Rectangle rect)
{
// Create pen.
Pen blackPen = new Pen(Color.White, 3);
SolidBrush whiteBrush = new SolidBrush(Color.White);
// Create rectangle.

// Draw rectangle to screen.
e.Graphics.DrawRectangle(blackPen, rect);
e.Graphics.FillRectangle(whiteBrush, rect);
}
private void Form1_Load(object sender, EventArgs e)
{
}


private void Form1_Click(object sender, EventArgs e)
{
Thread newThread = new Thread(worker);
direction = 2;
newThread.Start();  

}
private void SetDirection(KeyEventArgs e)
{
if (e.KeyCode == Keys.Down) direction = 4;
else if (e.KeyCode == Keys.Up) direction = 2;
else if (e.KeyCode == Keys.Right) direction = 3;
else if (e.KeyCode == Keys.Left) direction = 1;
}
private void ApplyMovement()
{
Size size = new Size(100,100);
Point position = new Point(100, 100);
while (direction != 0)
{
Application.DoEvents();
if (direction == 1) X--;
else if (direction == 2) Y--;
else if (direction == 3) X++;
else if (direction == 4) Y++;
if (label2.Text == "100") myRock = new Rectangle(position, size);
Thread.Sleep(10);
label1.Location = new Point(X, Y);
}
}
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
SetDirection(e);
ApplyMovement();
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
int label2Variable = Convert.ToInt32(label2.Text);
if (label2Variable > 100)
{
DrawRectangleRectangle(e, myRock);
}
}
private void label1_Click(object sender, EventArgs e)
{
}
}      

}

提前感谢!

正在发生的事情是没有调用OnPaint()函数,因此您不会重新绘制所有窗体。 当 Windows 认为窗体上的某些内容已更改时,它将向应用程序发出"重绘"命令,要求它重绘窗体区域的全部或部分,该区域在代码中显示为正在触发的Form.OnPaint()方法。

您需要在此处做的是告诉 Windows 您的窗体已更改。 最简单的方法是调用:

this.Invalidate();

一旦发生了变化,那么可能在ApplyMovement()循环的末尾.

(您也可以调用this.Refresh(),这将Invalidate整个窗体,然后导致它的同步重绘。谢谢@Bradley)

这样,您就会告诉 Windows 窗体"无效"并且需要完全重新绘制,然后 Windows 将(间接)调用OnPaint()方法。

编辑

解除冻结您的应用程序后,我对ApplyMovement()方法应用了以下更改:

if (label2.Text == "100") myRock = new Rectangle(position, size);

。改为...

if (label2.Text == "100")
{
myRock = new Rectangle(position, size);
this.Invalidate();
}

现在,当递增标签字段的值达到"100"时,myRock矩形会立即出现在我的测试中。

请务必了解,您的代码从不直接调用OnPaint()。 使用Invalidate()方法告诉 Windows 本身窗体的一部分(或全部)已更改,需要在屏幕上更新。 然后,Windows 将"调用"OnPaint()方法。

如果您使用这样的OnPaint()方法将信息从程序绘制到屏幕,例如myRock矩形或一些自定义绘制的文本,则每当信息更改时,您都需要调用Invalidate()来触发OnPaint()

这是所有常见控件(如文本框和按钮)自行更新到屏幕的方式。 每当更改其属性之一时,它们都会在内部调用Invalidate()

一个快速的思考方法是,任何时候你想叫OnPaint(),你打电话给Invalidate()

希望这有帮助

最新更新