如何从后台线程更新PictureBox

本文关键字:更新 PictureBox 线程 后台 | 更新日期: 2023-09-27 18:15:03

我在后台线程中进行所有昂贵的计算,需要能够分配pictureBox1。每个周期计算后的图像。我曾经使用委托来做这件事,但这是很长一段时间,事情似乎不再这样工作了。

我试着把分配在一个WorkerCompleted事件处理程序,但后来我不知道如何重新启动backgroundWorker1。我一整天都在做这个,感到非常沮丧,这以前是很容易做到的。

这是代码中最相关的部分:

using System;
using System.Globalization;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using KnownColorsPalette;
namespace Color_Visualizer
{
    public partial class Form1 : Form
    {
        static CultureInfo m_culture = CultureInfo.CurrentCulture;
        double[,][] distances = new double[3000, 3000][];
        FastPixel m_fp;
        public Form1()
        {
            InitializeComponent();
            WindowState = FormWindowState.Maximized;
            this.pictureBox1.LoadCompleted += new System.ComponentModel.AsyncCompletedEventHandler(PictureBox1_LoadCompleted);
            CoordinateSystem.AssignMe(this);
        }
        private void Form1_Load(object sender, EventArgs e)
        {
            ReadColors(); // Reads text file alternating name and RGB hex of
                          // Wikipedia's 1200+ named colors.
            Point3D p = new Point3D(127.5, 127.5, 127.5);
            foreach (FoundColors fc in m_lColors.Values)
                fc.pt = fc.color - p;
            Coord = new CoordinateSystem(new Plane(new Point3D(-127.5, -127.5, -127.5), new Point3D(-1, 0, 0)));
            backgroundWorker1.RunWorkerAsync();
        }

        double fSpeed = 5;
        Point3D m_pNormal = new Point3D();
        private void backgroundWorker1_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
        {
            double fAngle, fRadius, d;
            Point3D vU, vV;
            Point pLocation = new Point();
            m_pNormal = Coord.Plane.Normal;
            fAngle = Math.Atan2(m_pNormal.y, m_pNormal.x);
            fRadius = Math.Sqrt(m_pNormal.x * m_pNormal.x + m_pNormal.y * m_pNormal.y);
            fAngle += fSpeed * 180 / Math.PI;
            m_pNormal.x = Math.Cos(fAngle) * fRadius;
            m_pNormal.y = Math.Sin(fAngle) * fRadius;
            m_fp.Lock();
            m_fp.Clear(Color.Black);
            foreach (FoundColors fc in m_lColors.Values)
            {
                vU = new Point3D(Coord.U);
                d = dist(fc.pt, ref vU);
                vV = Coord.V;
                vV.mult(d);
                pLocation.X = (int)(m_midHoriz + vU.norm());
                pLocation.Y = (int)(m_midVert + vV.norm());
                m_fp.SetPixel(pLocation, fc.color);
            }
            m_fp.Unlock();
        }

        double m_fDist, m_fDot;
        public double dist(Point3D pt, ref Point3D vU)
        {
            double c1 = pt.dot(vU);
            double c2 = vU.dot(vU);
            double b = c1 / c2;
            vU.mult(b);
            m_fDot = pt.dot(Coord.Normal);
            m_fDist = pt.norm(pt - vU);
            return m_fDist;
        }
        double m_midHoriz, m_midVert;
        private void backgroundWorker1_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
        {
            pictureBox1.Image = m_fp.Bitmap;
        }
        private void Form1_Resize(object sender, EventArgs e)
        {
            m_midHoriz = pictureBox1.Width / 2;
            m_midVert = pictureBox1.Height / 2;
            m_fp = new FastPixel(new Bitmap(pictureBox1.Width, pictureBox1.Height));
        }
    }
}

这是我的支持代码的一部分:

using System;
using System.Drawing;
using System.Diagnostics;
using System.Windows.Forms;
namespace Color_Visualizer
{
    public partial class Form1 : Form
    {
        class CoordinateSystem
        {
            const int MAX = 256;
            const double PlaneWidth = 600;
            static Form1 Me;
            static Point3D axisZ = new Point3D(0, 0, 1);
            static Point3D axisY = new Point3D(0, 1, 0);
            private Plane m_plane = new Plane(new Point3D(128, 128, 128), new Point3D(-128, 0, 0));
            private Point3D m_pV = new Point3D(0, 0, 0);
            private Point3D m_pU = new Point3D(0, 0, 0);
            private double m_fInc;
            public CoordinateSystem(Plane axAxis)
            {
                m_fInc = PlaneWidth / Me.ClientSize.Height;
                Plane = axAxis;
            }
            public static void AssignMe(Form1 form) { Me = form; }
            public Point3D U { get { return m_pU; } protected set { m_pU = value; } }
            public Point3D V { get { return m_pV; } protected set { m_pV = value; } }
            public Point3D Normal { get { return m_plane.Normal; } set { m_plane.Normal = value; } }
            static double COSerror = 0.99619469809174553229501040247389;
            public Plane Plane
            { 
                get { return m_plane; }
                set {
                    m_plane = value;
                    if (m_plane.dot(axisZ) > COSerror)
                        U = U.cross(m_plane, axisY);
                    else
                        U = U.cross(m_plane, axisZ);
                    U.div(U.norm());
                    V = U.cross(U, m_plane);
                    V.div(V.norm());
                }
            }
        }
        [DebuggerDisplayAttribute("x = {x}, y = {y}, z = {z}")]
        public class Point3D
        {
            public double x, y, z;
            public Point3D(double _x, double _y, double _z) { x = _x; y = _y; z = _z; }
            public Point3D(Point3D p) { x = p.x; y = p.y; z = p.z; }
            public Point3D() { x = 0; y = 0; z = 0; }
            public bool Equals(Point3D p) { return x == p.x & y == p.y & z == p.z; }
            public override bool Equals(object obj) { return Equals((Point3D)obj); }
            public static bool operator ==(Point3D p1, Point3D p2) { return p1.Equals(p2); }
            public static bool operator !=(Point3D p1, Point3D p2) { return !p1.Equals(p2); }
            public static Point3D operator -(Point3D e, Point3D s) { return new Point3D(e.x - s.x, e.y - s.y, e.z - s.z); }
            public static Point3D operator +(Point3D e, Point3D s) { return new Point3D(e.x + s.x, e.y + s.y, e.z + s.z); }
            public static Point3D operator *(double m, Point3D v) { return new Point3D(m * v.x, m * v.y, m * v.z); }
            public static Point3D operator *(Point3D v, double m) { return new Point3D(v.x / m, v.y / m, v.z / m); }
            public static Point3D operator /(double m, Point3D v) { return new Point3D(m * v.x, m * v.y, m * v.z); }
            public static Point3D operator /(Point3D v, double m) { return new Point3D(v.x / m, v.y / m, v.z / m); }
            public static implicit operator Color(Point3D p) { return Color.FromArgb((int)p.x, (int)p.y, (int)p.z); }
            public static implicit operator Point3D(Color c) { return new Point3D(c.R, c.G, c.B); }
            //public override int GetHashCode()
            //{
            //    unchecked
            //    {
            //        var hash = new SpookyHash();
            //        hash.Update(x);
            //        hash.Update(y);
            //        hash.Update(z);
            //        return hash.Final().GetHashCode();
            //    }
            //}
            // dot product (3D) which allows vector operations in arguments
            public double dot(Point3D u, Point3D v) { return u.x * v.x + u.y * v.y + u.z * v.z; }
            public double dot(Point3D u) { return u.x * x + u.y * y + u.z * z; }
            public double norm(Point3D v) { return Math.Sqrt(dot(v, v)); }     // norm = length of  vector
            public double norm() { return Math.Sqrt(dot(this, this)); }     // norm = length of  vector
            public double dist(Point3D u, Point3D v) { return norm(u - v); }         // distance = norm of difference
            public double dist(Point3D u) { return norm(this - u); }
            public Point3D cross(Point3D u, Point3D v) { return new Point3D(u.y * v.z - u.z * v.y, u.z * v.x - u.x * v.z, u.x * v.y - u.y * v.x); }
            public Point3D cross(Point3D u) { return new Point3D(u.y * z - u.z * y, u.z * x - u.x * z, u.x * y - u.y * x); }
            public void add(Point3D p) { x += p.x; y += p.y; z += p.z; }
            public void mult(double m) { x *= m; y *= m; z *= m; }
            public void div(double m) { x /= m; y /= m; z /= m; }
        }

        class Plane : Point3D
        {
            Point3D m_pNormal;
            public Plane(Point3D pOrigin, Point3D pNormal) : base(pOrigin) { m_pNormal = pNormal; }
            public Plane(Point3D p) : base(p) { }
            public Plane(double x, double y, double z) : base(x, y, z) { }
            public Point3D Normal { get { return m_pNormal; } set { m_pNormal = value; } }
            public double PointToPlane(Point3D p) { return p.dot(Normal); }
        }

        private CoordinateSystem m_coordSys;
        private CoordinateSystem Coord
        {
            get { return m_coordSys; }
            set { m_coordSys = value; }
        }
    }
}

和更多的支持代码:

    [DebuggerDisplayAttribute("{name}, R={color.R}, G={color.G}, B={color.B}")]
    class FoundColors
    {
        public Color color = Color.Empty;
        public string name = "";
        public CIELab_Color cLab;
        public Point3D pt;
        public List<int> lClosest = new List<int>();
        public int nFarthest;
        public FoundColors(FoundColors fc)
        {
            color = fc.color;
            name = fc.name;
            cLab = new CIELab_Color(fc.cLab.CIE_L, fc.cLab.CIE_a, fc.cLab.CIE_b);
            lClosest.AddRange(fc.lClosest);
            nFarthest = fc.nFarthest;
        }
        public FoundColors() { }
    }

如何从后台线程更新PictureBox

如果我立即Thread.Sleep() 200ms,那么Invoke方法确实有效。

            m_fp.Unlock();
            this.Invoke((MethodInvoker)delegate () { pictureBox1.Image = m_fp.Bitmap; });
            Thread.Sleep(200);
        } while (true);

还没有测试过下限,但它在不同的机器上不一致,所以报告它不会提供信息。

打开一个新线程并创建一个while in函数

Worker workerObject = new Worker();
Thread workerThread = new Thread(workerObject.DoWork);
workerThread.Start();
public void DoWork()
{
    while (!_shouldStop)
    {
        //REFRESH YOUR IMAGE
    }
}