Windows Forms图形界面开发

开发封装一个图形化界面的类,实现图片的缩放、平移、适配变化、显示文本、直线、圆、多边形等功能,主要利用PictureBox和Matrix来封装类,本文是自己学习后加入自己深入理解的总结记录,方便自己以后查看。

主要用来在界面上做图形显示和操作图片,解决工业视觉中上位机图形界面对Visoinpro、Halcon、VisionMaster的依赖,同时解决它们界面显示上的回调问题,可用于开源算法平台上位机界面的显示

一、PictrueBoxCtrl类的整体组成由构造函数、变量、属性、方法、控件事件、自定义事件构成、图形化显示参数类组成

二、界面演示

三、源码如下

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using System.ComponentModel;

namespace VisionProgram.UI
{
    //pictrueBox自定义类
    public class PictrueBoxCtrl : IDisposable//功能没添加全,时间有限,后面有谁优化的可联系我,xbb
    {
        /// <summary>
        /// 构造函数
        /// </summary>
        public PictrueBoxCtrl(Control parent, Point location, Size size)
        {
            _control = new PictureBox();
            _zoomMatrix = new Matrix();
            _rect = new Rectangle(0, 0, size.Width, size.Height);
            _control.Location = location;
            _control.Size = size;
            _control.Parent = parent;
            _control.Dock = DockStyle.Fill;
            RegisterEvent();
            ControlParamInit();
        }

        #region 变量

        /// <summary>
        /// 用于内部激活是否重绘
        /// </summary>
        private bool _mEnable = true;

        /// <summary>
        /// 显示的控件
        /// </summary>
        private PictureBox _control;

        /// <summary>
        /// 背景纹理画刷(设置图像后会将图像转换成纹理画刷,因为填充画刷的速度要比绘制图像的速度快得多)
        /// </summary>
        private TextureBrush _tBrush;

        /// <summary>
        /// 控件的矩形区域
        /// </summary>
        private Rectangle _rect = new Rectangle();

        /// <summary>
        /// 图像宽度
        /// </summary>
        private int _imgWidth = 1;

        /// <summary>
        /// 图像高度
        /// </summary>
        private int _imgHeight = 1;

        /// <summary>
        /// 按下平移键,鼠标在控件上的横坐标
        /// </summary>
        private float _mouseDownX = 0.0f;

        /// <summary>
        /// 按下平移键,鼠标在控件上的纵坐标
        /// </summary>
        private float _mouseDownY = 0.0f;

        /// <summary>
        /// 缩放系数
        /// </summary>
        private float _zoom = 1.0f;

        /// <summary>
        /// 图片左上角X轴的偏移量
        /// </summary>
        private float _imgX = 0.0f;
        /// <summary>
        /// 图片左上角Y轴的偏移量
        /// </summary>
        private float _imgY = 0.0f;

        /// <summary>
        /// 按下平移键,记录当前的_imgX
        /// </summary>
        private float _imgStartX = 0.0f;

        /// <summary>
        /// 按下平移键,记录当前的_imgY
        /// </summary>
        private float _imgStartY = 0.0f;

        /// <summary>
        /// 当前的缩放矩阵
        /// </summary>
        private Matrix _zoomMatrix;

        /// <summary>
        /// 最小缩放倍率
        /// </summary>
        private float _minZoom = 0.01f;

        /// <summary>
        /// 最大缩放倍率
        /// </summary>
        private float _maxZoom = 30.0f;

        /// <summary>
        /// 每次鼠标滚轮时,缩放系数的增量值
        /// </summary>
        private float _mouseZoomDV = 0.02f;

        /// <summary>
        /// 平移按键
        /// </summary>
        private MouseButtons _translateBtn = MouseButtons.Left;

        /// <summary>
        /// 指示是否正在执行平移操作
        /// </summary>
        private bool _inTranslate = false;

        /// <summary>
        /// 窗体文本显示
        /// </summary>
        private RecordTextData[] _recordTextDataArray = new RecordTextData[30];

        /// <summary>
        /// 当前文字显示行数
        /// </summary>
        private int _numRecordsText = 0;

        /// <summary>
        /// 窗体直线显示
        /// </summary>
        private RecordLineData[] _recordLineDataArray = new RecordLineData[10];

        /// <summary>
        /// 当前窗体显示直线数量
        /// </summary>
        private int _numRecordsLine = 0;
        
        /// <summary>
        /// 窗体圆显示
        /// </summary>
        private RecordCircleData[] _recordCircleDataArray = new RecordCircleData[10];
        /// <summary>
        /// 当前窗体显示圆数量
        /// </summary>
        private int _numRecordsCircle = 0;
        /// <summary>
        /// 窗体矩形显示
        /// </summary>
        private RecordRectangleData[] _recordRectangleDataArray = new RecordRectangleData[10];

        /// <summary>
        /// 当前窗体显示圆数量
        /// </summary>
        private int _numRecordsRectangle = 0;
        
        #endregion

        #region 属性

        /// <summary>
        /// 获取或设置背景颜色
        /// </summary>
        public Color BackColor
        {
            get { return _control.BackColor; }
            set { _control.BackColor = value; }
        }

        public PictureBoxSizeMode pbSizeMode
        {
            get { return _control.SizeMode; }
            set { _control.SizeMode = value; }
        }
        /// <summary>
        /// 获取是否正在执行平移操作
        /// </summary>
        public bool InTranslate
        {
            get { return _inTranslate; }
            protected set
            {
                if (value != _inTranslate)
                {
                    _inTranslate = value;
                    if (value)
                    {
                        OnStartTranslate();
                    }
                    else
                    {
                        OnStopTranslate();
                    }
                }
            }
        }
        #endregion

        #region 方法
        /// <summary>
        /// 注册事件
        /// </summary>
        public void RegisterEvent()
        {
            _control.MouseDown += new MouseEventHandler(_ctrl_MouseDown);
            //_control.MouseMove += new MouseEventHandler(_ctrl_MouseMove);//根据需求开
            _control.MouseUp += new MouseEventHandler(_ctrl_MouseUp);
            //_control.MouseEnter += new EventHandler(_ctrl_MouseEnter);//根据需求开
            _control.MouseWheel += new MouseEventHandler(_ctrl_MouseWheel);
            _control.Paint += new PaintEventHandler(_ctrl_Paint);
        }

        /// <summary>
        /// 释放背景纹理画刷
        /// </summary>
        protected virtual void tBrushDispose()
        {
            if (_tBrush != null)
            {
                _tBrush.Dispose();
                _tBrush = null;
            }
            _numRecordsText = 0;//清空计数
            _numRecordsLine = 0;
            _numRecordsCircle = 0;
            _numRecordsRectangle = 0;
        }

        /// <summary>
        /// 释放资源
        /// </summary>
        public void Dispose()
        {
            tBrushDispose();
            if (_zoomMatrix != null)
            {
                _zoomMatrix.Dispose();
                _zoomMatrix = null;
            }
            if (_control != null)
            {
                _control.Dispose();
                _control = null;
            }
        }

        /// <summary>
        /// 强制触发重绘事件
        /// </summary>
        public void Refresh()
        {
            _control.Refresh();
        }

        /// <summary>
        /// 设置背景图像
        /// </summary>
        /// <param name="img"></param>
        public void SetBackImage(Bitmap img)
        {
            _mEnable = false;
            tBrushDispose();        //释放当前纹理
            if (img != null)
            {
                _imgWidth = img.Width;
                _imgHeight = img.Height;
                if (((float)_control.Height / _imgHeight) < ((float)_control.Width / _imgWidth))//长度方向比例系数小
                {
                    _zoom = (float)_control.Height / _imgHeight;
                    _imgX = (float)(((float)_control.Width/ _zoom) - _imgWidth)/2;
                    _imgY = 0.0f;
                }
                else//宽度方向比例系数小
                {
                    _zoom = (float)_control.Width / _imgWidth;
                    _imgX = 0.0f;
                    _imgY = (float)(((float)_control.Height / _zoom) - _imgHeight) / 2;
                }
                //当图像的水平分辨率和垂直分辨率不为96时,将图像转换成纹理画刷之后会导致图像自动被裁剪掉一部分
                if (img.VerticalResolution != 96 || img.HorizontalResolution != 96)
                {
                    //重新实例化一张图片之后,新图片的水平分辨率和垂直分辨率会自动调整为96
                    using (Bitmap bmp = new Bitmap(img))
                    {
                        _tBrush = new TextureBrush(img, WrapMode.Clamp);
                    }
                }
                else
                {
                    _tBrush = new TextureBrush(img, WrapMode.Clamp);
                    
                }
            }
            else
            {
                _imgWidth = 1;
                _imgHeight = 1;

            }
            AdjustMatrix();
            //NormalMatrix();
            _mEnable = true;
         
        }

        /// <summary>
        /// 缩放图像
        /// </summary>
        /// <param name="x">缩放的中心点X</param>
        /// <param name="y">缩放的中心点Y</param>
        /// <param name="zoom">缩放系数</param>
        protected void ZoomImage(int x, int y, float zoom)
        {
            if (zoom > _maxZoom)
                zoom = _maxZoom;
            else if (zoom < _minZoom)
                zoom = _minZoom;
            float oldX = x / _zoom;
            float oldY = y / _zoom;
            _zoom = zoom;
            _imgX = x / zoom - oldX + _imgX;
            _imgY = y / zoom - oldY + _imgY;
            _zoomMatrix.Reset();
            _zoomMatrix.Scale(zoom, zoom);
            _zoomMatrix.Translate(_imgX, _imgY);
            _control.Refresh();
        }

        /// <summary>
        /// 归一化当前矩阵
        /// </summary>
        protected virtual void NormalMatrix()
        {
            _zoom = 1.0f;
            _imgX = 0.0f;
            _imgY = 0.0f;
            _zoomMatrix.Reset();
            _zoomMatrix.Scale(_zoom, _zoom);
            _zoomMatrix.Translate(_imgX, _imgY);
        }

        /// <summary>
        /// 适应pictrueBox大小的当前矩阵
        /// </summary>
        protected virtual void AdjustMatrix()
        {
            //_zoom = 1.0f;
            //_imgX = 0.0f;
            //_imgY = 0.0f;
            _zoomMatrix.Reset();
            _zoomMatrix.Scale(_zoom, _zoom);
            _zoomMatrix.Translate(_imgX, _imgY);
        }

        /// <summary>
        /// 增加窗体背景文本
        /// </summary>
        /// <param name="isok"></param>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="text"></param>
        /// <param name="fontSize"></param>
        public void SetBackText(bool isok, float x, float y, string text , float fontSize)
        {
            try
            {
                _recordTextDataArray[_numRecordsText].isok = isok;
                _recordTextDataArray[_numRecordsText].x = x;
                _recordTextDataArray[_numRecordsText].y = y;
                _recordTextDataArray[_numRecordsText].text = text;
                _recordTextDataArray[_numRecordsText].fontSize = fontSize;
                _numRecordsText += 1;
            }
            catch(Exception ex)
            {
                throw new Exception($"显示文本{text}出现异常:{ex.Message}");
            }
        }
        
        /// <summary>
        /// 增加窗体背景直线
        /// </summary>
        /// <param name="x0"></param>
        /// <param name="y0"></param>
        /// <param name="x1"></param>
        /// <param name="y1"></param>
        /// <param name="lineWidth"></param>
        public void SetBackLine(int x0, int y0, int x1, int y1, float line_width)
        {
            try
            {
                _recordLineDataArray[_numRecordsLine].x0 = x0;
                _recordLineDataArray[_numRecordsLine].y0 = y0;
                _recordLineDataArray[_numRecordsLine].x1 = x1;
                _recordLineDataArray[_numRecordsLine].y1 = y1;
                _recordLineDataArray[_numRecordsLine].line_width = line_width;
                _numRecordsLine += 1;
            }
            catch(Exception ex)
            {
                throw new Exception($"显示直线异常:{ex.Message}");
            }
        }
        
        /// <summary>
         /// 增加窗体背景圆
         /// </summary>
         /// <param name="center_x"></param>
         /// <param name="center_y"></param>
         /// <param name="radius"></param>
        public void SetBackCircle(float center_x, float center_y,float radius,float circle_width)
        {
            try
            {
                _recordCircleDataArray[_numRecordsCircle].center_x = center_x ;
                _recordCircleDataArray[_numRecordsCircle].center_y = center_y;
                _recordCircleDataArray[_numRecordsCircle].radius = radius;
                _recordCircleDataArray[_numRecordsCircle].circle_width = circle_width;
                _numRecordsCircle += 1;
            }
            catch(Exception ex)
            {
                throw new Exception($"显示圆异常:{ex.Message}");
            }
        }
        /// <summary>
        /// 增加窗体背景矩形
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="width"></param>
        /// <param name="height"></param>
        /// <param name="line_width"></param>
        /// <exception cref="Exception"></exception>
        public void SetBackRectangle(int x, int y, int width, int height, float line_width)
        {
            try
            {
                _recordRectangleDataArray[_numRecordsRectangle].x = x;
                _recordRectangleDataArray[_numRecordsRectangle].y = y;
                _recordRectangleDataArray[_numRecordsRectangle].height = height;
                _recordRectangleDataArray[_numRecordsRectangle].line_width = line_width;
                _recordRectangleDataArray[_numRecordsRectangle].width = width;
                _numRecordsRectangle += 1;
            }
            catch (Exception ex)
            {
                throw new Exception($"显示圆异常:{ex.Message}");
            }
        }
        /// <summary>
        /// 重置窗口
        /// </summary>
        public void Reset_PixtrueBox()
        {
            if (((float)_control.Height / _imgHeight) < ((float)_control.Width / _imgWidth))//长度方向比例系数小
            {
                _zoom = (float)_control.Height / _imgHeight;
                _imgX = (float)(((float)_control.Width / _zoom) - _imgWidth) / 2;
                _imgY = 0.0f;
            }
            else//宽度方向比例系数小
            {
                _zoom = (float)_control.Width / _imgWidth;
                _imgX = 0.0f;
                _imgY = (float)(((float)_control.Height / _zoom) - _imgHeight) / 2;
            }
            Bitmap bit = new Bitmap(_control.ClientRectangle.Width, _control.ClientRectangle.Height);
            _control.DrawToBitmap(bit, _control.ClientRectangle);
            //bit.Save("D:\\1.bmp");
            AdjustMatrix();
            _control.Refresh();

            //SaveFileDialog save = new SaveFileDialog();
            //save.FileName = "画图";
            //save.Filter = "(.jpg)|*.jpg";


    
           
       

            //_control.Image.Save("D:\\1.bmp");
            //_tBrush.Image.Save("D:\\1.bmp");
        }

        public void Save_PixtrueBox(string fileName, ImageFormat imageFormat )
        {
            Bitmap bit = new Bitmap(_control.ClientRectangle.Width, _control.ClientRectangle.Height);
            _control.DrawToBitmap(bit, _control.ClientRectangle);
            if(imageFormat == null)
                bit.Save(fileName);
            else
                bit.Save(fileName, imageFormat);
        }

        /// <summary>
        /// 控件变量初始化
        /// </summary>
        protected void ControlParamInit()
        {
            for (int i = 0; i < 30; i++)
            {
                int index = i;
                //文字显示数组
                _recordTextDataArray[index] = new RecordTextData();
            }
            for (int i = 0; i < 10; i++)
            {
                int index = i;      
                _recordLineDataArray[index] = new RecordLineData();
                _recordCircleDataArray[index] = new RecordCircleData();
                _recordRectangleDataArray[index] = new RecordRectangleData();
            }
        }
        #endregion

        #region 控件事件
        /// <summary>
        /// 在控件重绘时发生
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void _ctrl_Paint(object sender, PaintEventArgs e)
        {
            if (_mEnable)
            {
                Graphics g = e.Graphics;
                g.InterpolationMode = InterpolationMode.HighQualityBicubic;         //设置插值模式
                if (_tBrush != null)
                {
                    #region 显示背景图片
                    g.Transform = _zoomMatrix;                                      //设置变换矩阵
                    g.FillRectangle(_tBrush, 0, 0, _imgWidth, _imgHeight);
                    #endregion

                    #region 显示文本
                    for (int i = 0; i < _numRecordsText; i++)
                    {
                        if (_recordTextDataArray[i].isok)//ForestGreen/LimeGreen
                            g.DrawString(_recordTextDataArray[i].text, new Font("微软雅黑", _recordTextDataArray[i].fontSize, FontStyle.Bold), new SolidBrush(Color.LimeGreen), new PointF(_recordTextDataArray[i].x, _recordTextDataArray[i].y));
                        else
                            g.DrawString(_recordTextDataArray[i].text, new Font("微软雅黑", _recordTextDataArray[i].fontSize, FontStyle.Bold), new SolidBrush(Color.Red), new PointF(_recordTextDataArray[i].x, _recordTextDataArray[i].y));
                    }
                    #endregion
                    #region 显示线段
                    for (int i = 0; i < _numRecordsLine; i++)
                    {
                        g.DrawLine(new Pen(Brushes.Red, _recordLineDataArray[i].line_width), new Point(_recordLineDataArray[i].x0, _recordLineDataArray[i].y0)
                            , new Point(_recordLineDataArray[i].x1, _recordLineDataArray[i].y1));
                    }
                    #endregion
                    #region 显示圆
                    for (int i = 0; i < _numRecordsCircle; i++)
                    {
                        g.DrawEllipse(new Pen(Brushes.Red, _recordCircleDataArray[i].circle_width), new RectangleF(
                            _recordCircleDataArray[i].center_x - _recordCircleDataArray[i].radius, _recordCircleDataArray[i].center_y - _recordCircleDataArray[i].radius,
                           _recordCircleDataArray[i].radius*2, _recordCircleDataArray[i].radius*2));
                    }
                    #endregion
                    #region 显示矩形区域
                    for (int i = 0; i < _numRecordsRectangle; i++)
                    {
                        g.DrawRectangle(new Pen(Brushes.Red, _recordRectangleDataArray[i].line_width), new Rectangle(_recordRectangleDataArray[i].x, _recordRectangleDataArray[i].y,
                            _recordRectangleDataArray[i].width, _recordRectangleDataArray[i].height));
                    }
                    //g.DrawRectangle(new Pen(Brushes.Red, 100), new Rectangle(0, 0,
                    //        500, 500));
                    #endregion
                    //PointF[] P = new PointF[4];
                    //P[0] = new PointF(0, 0);
                    //P[1] = new PointF(500, 0);
                    //P[2] = new PointF(0, 500);
                    //P[3] = new PointF(500, 500);


                    //g.DrawLine(new Pen(Brushes.Red, 10), 1, 1, 500, 100);
                    //g.DrawEllipse(new Pen(Brushes.Red, 10), new RectangleF(100, 100, 500, 500));
                    //g.DrawLines(new Pen(Brushes.Red, 10), P);

                }
            }
        }
        /// <summary>
        /// 在滚轮滑动时发生
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void _ctrl_MouseWheel(object sender, MouseEventArgs e)
        {
            if (_mEnable)
            {
                if (e.Delta >= 0)

                    ZoomImage(e.X, e.Y, _zoom + _mouseZoomDV);
                else
                    ZoomImage(e.X, e.Y, _zoom - _mouseZoomDV);
            }
        }
        /// <summary>
        /// 在鼠标进入时发生
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void _ctrl_MouseEnter(object sender, EventArgs e)
        {
            //为控件设置焦点,因为只有控件有焦点才能为控件触发鼠标滚轮事件
            _control.Focus();
        }
        /// <summary>
        /// 在鼠标抬起时发生
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void _ctrl_MouseUp(object sender, MouseEventArgs e)
        {
            if (_mEnable)
            {

                if (e.Button == _translateBtn)
                {
                    if (_inTranslate)
                    {
                        float deltaX = e.X - _mouseDownX;
                        float deltaY = e.Y - _mouseDownY;
                        _imgX = _imgStartX + (deltaX / _zoom);
                        _imgY = _imgStartY + (deltaY / _zoom);
                        _zoomMatrix.Reset();
                        _zoomMatrix.Scale(_zoom, _zoom);
                        _zoomMatrix.Translate(_imgX, _imgY);
                        _control.Refresh();
                    }
                    InTranslate = false;
                }
            }
        }
        /// <summary>
        /// 在鼠标移动时发生 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void _ctrl_MouseMove(object sender, MouseEventArgs e)
        {
            if (_mEnable)
            {
                if (_inTranslate)
                {
                    float deltaX = e.X - _mouseDownX;
                    float deltaY = e.Y - _mouseDownY;
                    _imgX = _imgStartX + (deltaX / _zoom);
                    _imgY = _imgStartY + (deltaY / _zoom);
                    _zoomMatrix.Reset();
                    _zoomMatrix.Scale(_zoom, _zoom);
                    _zoomMatrix.Translate(_imgX, _imgY);
                    _control.Refresh();
                }
            }
        }
       /// <summary>
       /// 在鼠标按下时发生
       /// </summary>
       /// <param name="sender"></param>
       /// <param name="e"></param>
        private void _ctrl_MouseDown(object sender, MouseEventArgs e)
        {
            if (_mEnable)
            {
                if (e.Button == _translateBtn)
                {
                    _mouseDownX = e.X;
                    _mouseDownY = e.Y;
                    _imgStartX = _imgX;
                    _imgStartY = _imgY;
                    InTranslate = true;
                }
            }
            //if (e.Button == MouseButtons.Right)
            //{

            //    FrmHalconWindow f = new FrmHalconWindow("0");
            //    f.Show();
            //    //FrmHalconWindow frmHalconWindow = new FrmHalconWindow("0");
            //    //frmHalconWindow.TopLevel = false;
            //    frmHalconWindow.FormBorderStyle = FormBorderStyle.None;
            //    //frmHalconWindow.Dock = DockStyle.Fill;
            //    //_ctrl.Parent.Controls.Clear();
            //    //_ctrl.Parent.Controls.Add(frmHalconWindow);
            //    //frmHalconWindow.Show();
            //    cnt_rightClickMenu.Show();
            //}
            
        }

        #endregion

        #region 自定义事件

        /// <summary>
        /// 在开始平移时发生
        /// </summary>
        public event EventHandler StartTranslate;

        /// <summary>
        /// 在结束平移时发生
        /// </summary>
        public event EventHandler StopTranslate;

        /// <summary>
        /// 触发开始平移事件
        /// </summary>
        protected virtual void OnStartTranslate()
        {
            if (StartTranslate != null)
            {
                StartTranslate(this, EventArgs.Empty);
            }
        }

        /// <summary>
        /// 触发结束平移事件
        /// </summary>
        protected virtual void OnStopTranslate()
        {
            if (StopTranslate != null)
            {
                StopTranslate(this, EventArgs.Empty);
            }
        }

        #endregion
    }

    //文字显示参数类
    public class RecordTextData
    {
        public bool isok { get; set; }

        public float x { get; set; }

        public float y { get; set; }

        public string text { get; set; }

        public float fontSize { get; set; }

    }

    //直线显示参数类
    public class RecordLineData
    {
        public int x0 { get; set; }

        public int y0 { get; set; }

        public int x1 { get; set; }

        public int y1 { get; set; }

        public float line_width { get; set; }
    }

    //圆显示参数
    public class RecordCircleData
    { 
        public float center_x { get; set; }

        public float center_y { get; set; }

        public float radius { get; set; }
        
        public float circle_width { get; set; }
    }

    //矩形显示参数
    public class RecordRectangleData
    {
        public int x { get; set; }

        public int y { get; set; }

        public int width { get; set; }

        public int height{ get; set; }

        public float line_width{ get; set; }
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值