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

Rectangle only paints sections which a label has passed over on c# form

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

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

这是奇怪的部分,矩形只有在标签经过它的一部分时才会绘制,并且只会绘制标签经过的部分。这件事的照片:label passing over rectangle。理想情况下,我想了解为什么会这样,但如果有人能提供解决方案,我也会很高兴!

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

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 表单是 "invalid" 并且需要完全重新绘制,因此 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 将 "call" OnPaint() 方法。

如果您使用这样的 OnPaint() 方法将信息从您的程序绘制到屏幕上,例如 myRock 矩形或一些自定义绘制的文本,那么任何时候该信息更改,您需要调用 Invalidate() 来触发 OnPaint().

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

一个快速的思考方式是,任何时候你想要调用 OnPaint(),你调用 Invalidate()

希望这对您有所帮助