图形化控件开发 - 矩形控件
最近这段时间,公司需要做一个图形化配置工具。
主要是有以下一些要求:
1、针对一些底层的智能设备(智能楼宇的控制器),通过COM口连接上,并通过相关协议读取参数值
2、支持一些基本的逻辑运算,以及公司业务的一些特性“点”,一种点可以看成一个图形化控件
3、参数在图形化工具上显示出来,工程人员直接设置图形属性设置参数值、连线等
4、支持在线和离线2种工作方式,设置好参数后直接在界面上下载到设备里
5、工作太支持拖动,连线,放大缩小,保存设计文件等
6、“点”的本身业务要求,略。。。
经过一番调研,winfrom的图形化控件技术,并没有成熟的框架出来。
只有一些零碎的demo,大体上的思路是通过重绘来实现具体的图形控件。
在这里也提一下Netron框架,这个框架代码我看了很多遍,很多思路都从这里来,但是太繁琐了,改动起来非常吃力
所以我自己重新写了一遍,大体思路没变,只是走精简路线,以下是我们的工具最终的界面样式,
我打算把每一步都分拆贴出来,做成一个教程。给大家一个参考
1、新建自定义控件抽象类
1.1 包含一些基本属性,如字体、是否悬停、是否选中、画布
1.2 包含几个抽象方法,绘制控件皮肤、移动、悬停判断、重新绘制
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | public abstract class AbstractShape { [Browsable( false )] public Font DefaultFont { get ; private set ; } [Browsable( false )] public Pen DefaultPen { get ; private set ; } [Browsable( false )] public bool IsHover { get ; set ; } [Browsable( false )] public bool IsSelected { get ; set ; } [Browsable( false )] public GraphControl Canvas { get ; set ; } public AbstractShape() { } public AbstractShape(GraphControl site) { DefaultFont = new Font( "宋体" , 10F); DefaultPen = new Pen(Brushes.Black, 1F); Canvas = site; IsHover = false ; IsSelected = false ; } public abstract void Paint(Graphics g); public abstract bool Hover(Point p); public abstract void Invalidate(); public abstract void Move(Point p); } |
2、绘制一个自定义控件基类
包含一些基本属性及一些共性方法实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | public class ShapeBase : AbstractShape { protected Rectangle RectangleBase; [Browsable( false )] public Brush ShapeBrush { get ; protected set ; } [Browsable( true ), Description( "Width" ), Category( "Layout" )] public int Width { get { return this .RectangleBase.Width; } set { Resize(value, this .Height); } } [Browsable( true ), Description( "Height" ), Category( "Layout" )] public int Height { get { return this .RectangleBase.Height; } set { Resize( this .Width, value); } } [Browsable( true ), Description( "X" ), Category( "Layout" )] public int X { get { return RectangleBase.X; } set { Point p = new Point(value - RectangleBase.X, RectangleBase.Y); this .Move(p); Canvas.Invalidate(); } } [Browsable( true ), Description( "Y" ), Category( "Layout" )] public int Y { get { return RectangleBase.Y; } set { Point p = new Point(RectangleBase.X, value - RectangleBase.Y); this .Move(p); Canvas.Invalidate(); } } [Browsable( true ), Description( "Text" ), Category( "Layout" )] public string Text { get ; set ; } public ShapeBase(GraphControl site) : base (site) { Init(); } private void Init() { RectangleBase = new Rectangle(0, 0, 100, 70); ShapeBrush = new SolidBrush(Color.SteelBlue); } public override void Paint(Graphics g) { return ; } public override bool Hover(Point p) { return false ; } public override void Invalidate() { Canvas.Invalidate(RectangleBase); } public override void Move(Point p) { this .RectangleBase.X += p.X; this .RectangleBase.Y += p.Y; } public virtual void Resize( int width, int height) { this .RectangleBase.Height = height; this .RectangleBase.Width = width; } } |
3、新建一个简单的矩形类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | public class LjrRectangle : ShapeBase { public LjrRectangle(GraphControl s) : base (s) { } public override void Paint(Graphics g) { g.FillRectangle( base .ShapeBrush, base .RectangleBase); if ( base .IsHover || base .IsSelected) { g.DrawRectangle( new Pen(Color.Red, 2F), base .RectangleBase); } else { g.DrawRectangle( base .DefaultPen, base .RectangleBase); } } } |
4、新建画布GraphControl
所以自定义图形控件都将在这个画布里绘制、移动等操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | public class GraphControl : ScrollableControl { /// <summary>属性控件绑定事件</summary> public delegate void ShowProperty( object ent); /// <summary>属性控件绑定事件</summary> public event ShowProperty OnShowProperty; /// <summary>当前悬停在哪个对象上边</summary> protected AbstractShape hoveredObject; /// <summary>当前选中的对象</summary> protected AbstractShape selectedObject; /// <summary>是否正在拖动</summary> protected bool draging = false ; /// <summary>图形对象集合</summary> public List<ShapeBase> Shapes { get ; set ; } public GraphControl() { Shapes = new List<ShapeBase>(); } protected override void OnPaintBackground(PaintEventArgs e) { base .OnPaintBackground(e); Graphics g = e.Graphics; Size gridSize = new Size(10, 10); ControlPaint.DrawGrid(g, this .ClientRectangle, gridSize, this .BackColor); } protected override void OnPaint(PaintEventArgs e) { Graphics g = e.Graphics; g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; for ( int k = 0; k < Shapes.Count; k++) { Shapes[k].Paint(g); } } public ShapeBase AddShape(ShapeBase shape) { Shapes.Add(shape); shape.Canvas = this ; this .Invalidate(); return shape; } } |
5、新建测试项目
5.1 新建demo.cs把控件拖入界面左边
5.2 再拖一个PropertyGrid用来显示属性值
5.3 Demo.cs代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 | private void Demo_Load( object sender, EventArgs e) { var shape = new LjrRectangle(graphControl1); shape.Location = new Point(100, 300); shape.Text = "图形化控件" ; this .graphControl1.AddShape(shape); this .graphControl1.OnShowProperty += graphControl1_OnShowProps; } private void graphControl1_OnShowProps( object ent) { this .propertyGrid1.SelectedObject = ent; } |
6、运行程序
阅读目录
- 图形化控件开发 - 矩形控件
- 图形化控件开发 - 控件移动
- 图形化控件开发 - 直线连线
- 图形化控件开发 - 折线连线
- 图形化控件开发 - 放大缩小
- 图形化控件开发 - 待定
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人