C#上位机系列(6)—波形滚动显示

承接上节,从本节开始持续更新后续代码功能,由于更新内容比较随机,详细介绍见代码备注

更新内容:

1. 绘图曲线函数

2.缓存数组与数据处理数组

3.画面刷新

4.外部输入接口

代码如下:

FormScope.cs:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WinForms_Start1
{


    public partial class FormScope : Form
    {
        const int dataCountMax = 10001;
        bool scopeRun;

        //缓存数据
        public static volatile Queue<int> quedata1 = new Queue<int>(dataCountMax);//通道1数据
        //public static volatile Queue<int> quedata2 = new Queue<int>(10001);
        //public static volatile Queue<int> quedata3 = new Queue<int>(10001);
        //public static volatile Queue<int> quedata4 = new Queue<int>(10001);


        //示波器显示数组
        int[] arrScope1 = new int[dataCountMax];
        //int[] arrScope2 = new int[10001];
        //int[] arrScope3 = new int[10001];
        //int[] arrScope4 = new int[10001];


        //显示数据个数
        int dataCount;



        //示波器参数
        PointF startPoint; //绘图原点
        PointF originPoint; //示波器框的原点
        float Slength_X, Slength_Y;
        private Pen TablePen = new Pen(Color.FromArgb(0x3c, 0x3c, 0x3c));//线条画笔,灰色
        private Pen RedPen = new Pen(Color.FromArgb(0xff, 0x00, 0x00), 1f);//波形1线条颜色,红色

        float DrawStepX;//x轴分辨率
        float DrawStepY;//y轴分辨率

        //屏幕刷新定时器
        Timer timRefresh = new Timer();


        public FormScope()
        {
            InitializeComponent();
            ScopeInit();

            for (int i = 0; i < dataCountMax; i++)  //必须提前填满,不然容易出BUG
            {
                quedata1.Enqueue(0);
                //ComDataDef.queCube2.Enqueue(0);
                //ComDataDef.queCube3.Enqueue(0);
                //ComDataDef.queCube4.Enqueue(0);
            }

        }
        /// <summary>
        /// 示波器初始化函数
        /// </summary>
        private void ScopeInit()
        {
            scopeRun = true;
            startPoint.X = 30;
            startPoint.Y = 500;
            originPoint = ConvertPoint(startPoint, 10, 50);//示波器原点坐标
            Slength_X = 600;
            Slength_Y = 400;
            dataCount = 100;//该值需要小于dataCountMax
            DrawStepX = Slength_X/ dataCount;//根据显示数据自适应
            DrawStepY = 1f;

            timRefresh.Tick += new EventHandler(this.timRefresh_Tick);
            timRefresh.Interval = 50;  //定时器刷新屏幕
            timRefresh.Start();
            SetStyle(ControlStyles.DoubleBuffer, true); // 设置双缓冲,防止图像抖动
            SetStyle(ControlStyles.AllPaintingInWmPaint, true); // 忽略系统消息,防止图像闪烁

            Invalidate();//刷新显示   
        }

        
        private void timRefresh_Tick(object sender, EventArgs e) //屏幕刷新定时器
        {

            //防止部分数据未及时更新出bug
            originPoint = ConvertPoint(startPoint, 10, 50);//示波器原点坐标
            DrawStepX = Slength_X / (float)dataCount;

            //数据处理
            if (scopeRun)
            {
                QueToArray(quedata1, arrScope1);
            }

            Invalidate();//刷新显示        
        }

        //private void QueToArray(Queue<int> que, int[] arr, ComboBox cmb) //把缓存通道数据放进数组
        private void QueToArray(Queue<int> que, int[] arr)
        {
            int i = 0;
            foreach (int num in que)
            {
                arr[i] = num;
                i++;
            }
        }

        private void Form_Paint(object sender, PaintEventArgs e)画图函数
        { 
            System.Drawing.Drawing2D.GraphicsPath gp = new System.Drawing.Drawing2D.GraphicsPath();
            e.Graphics.FillRectangle(Brushes.Black, e.Graphics.ClipBounds);  //默认黑色
            //画示波器框线  (颜色,起点坐标,终点坐标)
            //横轴
            e.Graphics.DrawLine(TablePen, originPoint, ConvertPoint(originPoint, Slength_X, 0));
            e.Graphics.DrawLine(TablePen, ConvertPoint(originPoint,0,Slength_Y), ConvertPoint(originPoint, Slength_X, Slength_Y));
            //纵轴
            e.Graphics.DrawLine(TablePen, originPoint, ConvertPoint(originPoint, 0, Slength_Y));
            e.Graphics.DrawLine(TablePen, ConvertPoint(originPoint, Slength_X, 0), ConvertPoint(originPoint, Slength_X, Slength_Y));

            //刻度轴

            //坐标参数

            //波形显示,(输入数组,显示个数,偏移量,初始点)
            ShowWaveLine(arrScope1, dataCount, 0 ,originPoint, DrawStepX, DrawStepY, e, RedPen);
            
        }
        private void ShowWaveLine(int[] arr,int datacount,int databackcount ,PointF p, float drawstepX, float drawstepY, PaintEventArgs e, Pen pen ) //数组,初始坐标,线条,触发事件
        {
            int count = dataCountMax - datacount - databackcount;
            if (count < 0)
            {
                count = 0;
            }
            float p1_x;
            float p1_y;
            float p2_x;
            float p2_y;
            for (int i = 0; i < dataCountMax - databackcount -count; i++)
            {
                //当前坐标
                p1_x = p.X + i * drawstepX;
                p1_y = p.Y - arr[i+count-1] * drawstepY;
                //计算下一个坐标
                p2_x = p.X + (i+1) * drawstepX;
                p2_y = p.Y - arr[(i+ count)] * drawstepY;

                //防止过界
                if (p1_y < originPoint.Y - Slength_Y)
                {
                    p1_y = originPoint.Y - Slength_Y;
                }
                else if(p1_y > originPoint.Y)
                {
                    p1_y = originPoint.Y;
                }
                if (p2_y < originPoint.Y - Slength_Y)
                {
                    p2_y = originPoint.Y - Slength_Y;
                }
                else if (p2_y > originPoint.Y)
                {
                    p2_y = originPoint.Y;
                }
                e.Graphics.DrawLine(pen, p1_x, p1_y, p2_x, p2_y);
            }
        }

        /// <summary>
        /// 坐标转换函数
        /// </summary>
        /// <param name="point"></param>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns>新坐标值</returns>
        /// 
        PointF ConvertPoint(PointF point, float x, float y)
        {
            PointF p = point;
            p.X += x;
            p.Y -= y;
            return p;
        }

        //参数输入接口
        public void DataInput(int data)
        {
            quedata1.Dequeue();
            quedata1.Enqueue(data);
        }
    }
}

设计文件

namespace WinForms_Start1
{
    partial class FormScope
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.SuspendLayout();
            // 
            // FormScope
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(12F, 24F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(1774, 1129);
            this.Name = "FormScope";
            this.Text = "示波器";
            this.Paint += new System.Windows.Forms.PaintEventHandler(this.Form_Paint);
            this.ResumeLayout(false);

        }

        #endregion
    }
}

最后在主窗口里持续添加数据

效果如下:

猜你喜欢

转载自blog.csdn.net/qq_49552487/article/details/128286975