我对我正在为练习编写的程序有疑问,该程序在当前状态下允许用户使用箭头键在表单周围移动标签。
我想开始在我的程序中添加一些图形矩形,并且我正在练习当计时器达到100时尝试绘制一个简单的矩形。
这里是奇怪的部分,矩形只在标签经过部分区域后绘制,并且只绘制标签经过的部分。发生这种情况的图片:label passing over rectangle。理想情况下,我想了解为什么会这样,但如果有人能提供解决方案,我也会非常高兴!
我会发布我的整个代码,因为我甚至不确定问题可能来自哪个部分。非常抱歉,如果它不整洁,希望有人会从图像中得到一个想法:
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)
{
}
}
}
提前致谢!
答案 0 :(得分:0)
发生的事情是OnPaint()
函数未被调用,因此您不会重新绘制所有表单。当Windows认为表单上的内容发生了变化时,它会向您的应用程序发出重绘命令,要求它重新绘制表单区域的全部或部分,该区域在代码中显示为Form.OnPaint()
方法被解雇了。
您需要做的是告诉Windows您的表单已更改。最简单的方法是致电:
this.Invalidate();
一旦某些内容发生了变化,可能会在ApplyMovement()
的循环结束时发生。
(您也可以调用this.Refresh()
,Invalidate
整个表单,然后对其进行同步重绘。感谢@Bradley )
这样,你告诉Windows该表单是&#34;无效&#34;并且需要完全重新绘制,因此Windows将(间接)调用OnPaint()
方法。
修改强>
重新水化您的应用后,我对ApplyMovement()
方法应用了以下更改:
if (label2.Text == "100") myRock = new Rectangle(position, size);
......改为......
if (label2.Text == "100")
{
myRock = new Rectangle(position, size);
this.Invalidate();
}
现在,当递增标签字段的值达到&#34; 100&#34;时,myRock
矩形会立即显示在我的测试中。
了解您的代码永远不会直接调用OnPaint()
非常重要。您使用Invalidate()
方法告诉Windows自己表单的一部分(或全部)已更改并需要在屏幕上更新。 Windows然后会打电话给#34; OnPaint()
方法。
如果你正在使用这样的OnPaint()
方法将程序中的信息绘制到屏幕上,例如myRock
矩形或某些自定义绘制文本,那么任何时候该信息更改时,您需要致电Invalidate()
以触发OnPaint()
。
所有常用控件(如文本框和按钮)自动更新到屏幕的方式。只要您更改其中一个属性,他们就会在内部调用Invalidate()
。
快速思考问题的方法是,只要您想要OnPaint()
被调用,就可以致电Invalidate()
。
希望这有帮助