C#当计时器调用绘制函数时,为什么我的图片框不移动?

时间:2018-11-16 10:46:41

标签: c# forms animation graphics drawing

我正在创建一个简单的应用程序,该应用程序会抓取一些XML,这些XML与正在输出实时传感器数据的某些机床的状态有关,并使用设备的X / Y坐标在屏幕上跳动一下。 第一次对机器进行轮询时,老鼠就被放置在正确的位置,但是每次随后的计时器驱动的事件调用draw函数时,老鼠不会移动。

我认为这是由于机器处于待机状态,并且唯一的坐标变化是伺服系统的微小抖动,但为了检查,我创建了一个随机数生成器,并让系统使用了随机生成的坐标,而不是缩放的X / Y数据进入。

然后我发现老鼠没有动! 这是我绘制老鼠的函数(有2个系统,但现在我们只担心'bakugo')。我们特别关注if(dekuWake == false)和(bauwake == true); 在这里,我已将值打印到控制台(由计时器驱动),并且显示了“ system.drawing.point(s)”有效(在范围内和在变化中)。

计时器由form1中的按钮启动。 计时器事件调用轮询功能,该功能从站点抓取XY变量(有关此功能,请参见我的问题-What is wrong with my use of XPath in C#?) 此时,它确定状态是否为“可用”(是)并将“老鼠”的“清醒”布尔值设置为true(确定绘制的图像,如果机器处于脱机状态,则“老鼠”停留在其框内) 然后将坐标缩放到程序窗口的分辨率 (通常,现在它正在逐步执行轮询第一次开始时生成的2个整数数组。更新坐标函数设置ImageRat.Bakugo的X,Y坐标)并调用drawRats()。

为什么更改图像的位置实际上并不能重新放置图片框?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Reflection;
using System.Drawing;
using System.Windows.Forms;
namespace XMLRats3
{
    public class Drawing 
    {
        private PictureBox HouseImage;
        private PictureBox DekuImage;
        private PictureBox BakuImage;

        public Drawing(PictureBox house, PictureBox deku, PictureBox baku)
        {
            HouseImage  = house;
            DekuImage   = deku;
            BakuImage   = baku;
        }
        public void ClearRats()
        {
            HouseImage.Hide();
            DekuImage.Hide();
            BakuImage.Hide();
        }

        public void DrawRats(bool DekuWake, bool BakuWake) // Call this function using active status of 2 machines
        {
            ClearRats();

            /*// This shows that the generated coordinates are reaching this point successfully
            Console.WriteLine("BAKU X: " + ImageRat.Bakugo.PosX);
            Console.WriteLine("BAKU Y: " + ImageRat.Bakugo.PosY);
            */

            System.Drawing.Point DekuCoord = new System.Drawing.Point(ImageRat.Deku.PosX, ImageRat.Deku.PosY);      // Create a 'System Point' for Deku
            System.Drawing.Point BakuCoord = new System.Drawing.Point(ImageRat.Bakugo.PosX, ImageRat.Bakugo.PosY);  // Create a 'System Point' for Bakugo


            if (DekuWake == false)
            {
                DekuImage.Hide();
                if (BakuWake == false)
                {
                    BakuImage.Hide();
                    HouseImage.Image = DesktopApp1.Properties.Resources.bothsleep;// set HouseImage to both sleep
                }
                else
                {
                    BakuImage.Location = BakuCoord;
                    Console.WriteLine("Point:" + BakuCoord);
                    //Console.WriteLine("Reaching Relocation condition"); // Ensure we are getting here as animation not working
                    BakuImage.Show();
                    //BakuImage.
                    HouseImage.Image = DesktopApp1.Properties.Resources.dekuSleep; //Set HouseImage to DekuSleep 
                }
            }
            else //DekuWake == true
            {
                DekuImage.Show();
                if (BakuWake == true)
                {
                    HouseImage.Image = DesktopApp1.Properties.Resources.nosleep;//Set House image to nosleep
                    BakuImage.Location = DekuCoord;
                    DekuImage.Show();
                    BakuImage.Location = BakuCoord;
                    BakuImage.Show();
                }    
                else
                {
                    BakuImage.Hide();
                    HouseImage.Image = DesktopApp1.Properties.Resources.bakusleep;// Set house image to bakusleep
                    DekuImage.Location = DekuCoord;
                    DekuImage.Show();
                }
            }

            HouseImage.Show(); // Out here as it should always happen
        }
    }
 }

2 个答案:

答案 0 :(得分:0)

好吧,对于如何解决这个问题,我没有确切的答案,但是我可以告诉您它为什么会发生,并向您指出一些可以帮助您的知识。

在编写此代码时,我(现在仍然)对C#和多线程应用程序的概念非常陌生。

这是一个糟糕的软件架构问题。 这里的问题是只能从c#中的单个线程更新UI,并且由于计时器在另一个线程中运行,因此不允许从计时器调用的任何内容更新UI。 我认为有可能使用委托来浸入UI线程,尽管我还没有足够深入地了解如何做到这一点。

希望这将有助于对我的问题加注星标的人! How do I update the GUI from another thread?

答案 1 :(得分:0)

假定您使用的计时器与主类使用不同的类,且该类占用的线程与主线程不同,则要使计时器使用对象,应将对象添加为“同步对象”之一。因此,假设您的计时器称为timer1,则在设置计时器属性的方法中,应编写以下代码行

timer1.SynchronizingObject = yourPictureBox;

我希望能解决您的问题