开发封装一个图形化界面的类,实现图片的缩放、平移、适配变化、显示文本、直线、圆、多边形等功能,主要利用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; }
}
}