news 2026/8/29 13:14:01

WinForm应用实战开发指南 - 应用程序如何实现手写签名?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
WinForm应用实战开发指南 - 应用程序如何实现手写签名?

由于项目的需要,需要在项目的WinForm系统的一个模块中集成手写签名的功能,一开始对这块不是很了解,只是了解他能够替代鼠标进行签名。既然是签名,一般就是需要记录手稿图片,作为一个记录核实的凭证,因为有效的签名是很难模拟的。市场上也存在很多类型的电子签名笔,一时间还真不知道那种适合。

WinForm应用的界面开发有个很好用的界面控件推荐——​​​​​​​​DevExpress WinForm​s,拥有180+组件和UI库,能为Windows Forms平台创建具有影响力的业务解决方案。

DevExpress新旧版本帮助文档下载可进QQ qun获取:169725316

1. 电子手写签名介绍

电子手写签名,其实就是模拟真实的笔进行签名的过程,我这里主要是介绍使用外部设备来记录手稿图片的需求,这样其实就是类似于把我们真实在纸张上的签名内容,放到了电脑记录面板上进行操作了,而这个操作模拟,其实就是利用了类似鼠标功能的接触笔来实现的。

有些笔是在纸上或者电脑屏幕上进行模拟签名,通过一个接收器方式接受笔的接触信号,一般要先设定纸张或者屏幕的范围,然后进行签名书写。

由于签名笔淘宝上也有很多,开始淘到的就是类似这种,不过效果不理想,好像总是定位不准,而且和鼠标发生严重冲突,基本上操作不了,商家客服说很少有这种现象发生,但是却发生在我身上,于是只有退货。然后淘到的是一款汉王手写板笔,开始用的还可以,其实就是代替了鼠标进行操作,试过可以后,就搁置起来。

一直用鼠标模拟签名进行开发,写该篇随笔的时候,本来想用来展示下效果,可惜又用不了,不知道什么原因。

做签名功能开发的时候,其实我是不关注手写笔功能的,因为我想其实如果鼠标能操作就可以,手写笔其实也就应该可以操作。因此只需要在输入的地方记录鼠标操作的痕迹,类似手写签名的效果即可,大概如下所示。

2. 手写签名的实现

从上图可以看到,只需要提供一个类似绘图的面板即可记录鼠标的轨迹,也就是功能有点类似Windows自带的白板(或者绘图板)软件即可。

其实要模拟鼠标签名的效果,只需要利用功能强大的GraphicsPath对象就差不多了,剩下的就是记录点和绘制点,设置绘图笔的宽度和颜色等方面。下面我们看看具体的实现代码吧。

首先要申明几个必要的对象,来承载相关的信息。

//记录直线或者曲线的对象 private System.Drawing.Drawing2D.GraphicsPath mousePath = new System.Drawing.Drawing2D.GraphicsPath(); //画笔透明度 private int myAlpha = 100; //画笔颜色对象 private Color myUserColor = new Color(); //画笔宽度 private int myPenWidth = 3; //签名的图片对象 public Bitmap SavedBitmap;

从上图效果图上,我们看到,我们在其中放置了一个绘图面板,其实就是一个PictureBox对象而已,我们只需要在PictureBox对象,记录鼠标的移动、鼠标按下,以及对象刷新操作事件即可实现模拟签名的效果了,如下代码所示。

private void pictureBox1_MouseMove(object sender, MouseEventArgs e) { if (e.Button == System.Windows.Forms.MouseButtons.Left) { try { mousePath.AddLine(e.X, e.Y, e.X, e.Y); } catch (Exception ex) { MessageBox.Show(ex.Message); } } pictureBox1.Invalidate(); } private void pictureBox1_MouseDown(object sender, MouseEventArgs e) { if (e.Button == System.Windows.Forms.MouseButtons.Left) { mousePath.StartFigure(); } } private void pictureBox1_Paint(object sender, PaintEventArgs e) { try { myUserColor = System.Drawing.Color.Blue; myAlpha = 255; Pen CurrentPen = new Pen(Color.FromArgb(myAlpha, myUserColor), myPenWidth); e.Graphics.DrawPath(CurrentPen, mousePath); } catch { } }

保存及清空操作,其实很简单,清空的时候,记得把绘图面板清空,并重置路径对象即可。保存也是记录PictureBox对象的大小宽度,把图片存储到图片对象里面,供控件使用。

具体实现如下所示。

private void btnClear_Click(object sender, EventArgs e) { pictureBox1.CreateGraphics().Clear(Color.White); mousePath.Reset(); } private void btnSave_Click(object sender, EventArgs e) { SavedBitmap = new Bitmap(pictureBox1.Width, pictureBox1.Height); pictureBox1.DrawToBitmap(SavedBitmap, new Rectangle(0, 0, pictureBox1.Width, pictureBox1.Height)); this.DialogResult = System.Windows.Forms.DialogResult.OK; }

上面实现还不能完成一个最终的签名效果,有时候,我们需要把这些图片放到数据库里面,如果是把上面的操作的图片记录下来,发现很大,一般我们签名的效果显示,不会很大,一方面只需要辨认其笔迹即可,另外一方面也不会过于增大数据库的存储空间。那么我们就需要对图片大小进行一定的处理了。其实可能在详细信息里面,我们就这样记录显示即可。那么就一定要裁剪图片的大小。

以上的医生签名,我们触发的操作就是弹出一个签名窗体,在其中绘制签名,确认后返回,并把图片进行显示在详细信息窗体里面。

private void btnDoctorSign_Click(object sender, EventArgs e) { FrmSignicture dlg = new FrmSignicture(); if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK) { this.picDoctor.Image = dlg.SavedBitmap; } }

为了安装最终显示的PictureBox的大小保存图片,我们需要裁减,裁减就是重新根据图片大小进行保存Bitmap对象,这种可以从全屏最初的几M缩小到十几K,方便存储。

至于图片对象存储到数据库,这个由于利用了我Winform开发框架里面的数据库基础对象,基本上不需要特别对待及处理,只需要把图片字段的Byte数组获得即可了。这里就不在赘述Winform开发框架的功能及相关的基类处理了。

public Bitmap SaveImage(PictureBox pictureBox1) { Bitmap SavedBitmap = new Bitmap(pictureBox1.Width, pictureBox1.Height); pictureBox1.DrawToBitmap(SavedBitmap, new Rectangle(0, 0, pictureBox1.Width, pictureBox1.Height)); return SavedBitmap; }

最后,有时候,签名还需要在列表里面显示,这样方便对一些关键信息进行查看核对。如下图所示:

那么对于列表中显示图片,我们在
DevExpress界面的分页控件中应该如何处理呢,这估计也是​​​​​​​DevExpress开发中很多常见问题之一?

其实也很简单,就是在DataSourceChanged 变化的事件中改变单元格的对象属性即可。

this.winGridViewPager1.OnRefresh += new EventHandler(winGridViewPager1_OnRefresh); this.winGridViewPager1.ShowLineNumber = true; this.winGridViewPager1.gridView1.Appearance.Row.TextOptions.HAlignment = DevExpress.Utils.HorzAlignment.Center; this.winGridViewPager1.gridView1.Appearance.HeaderPanel.TextOptions.HAlignment = DevExpress.Utils.HorzAlignment.Center; this.winGridViewPager1.AppendedMenu = this.contextMenuStrip1; this.winGridViewPager1.gridView1.DataSourceChanged += new EventHandler(gridView1_DataSourceChanged); this.winGridViewPager1.gridView1.RowHeight = 44; void gridView1_DataSourceChanged(object sender, EventArgs e) { RepositoryItemPictureEdit pic1 = new RepositoryItemPictureEdit(); pic1.SizeMode = DevExpress.XtraEditors.Controls.PictureSizeMode.Zoom; pic1.NullText = " "; pic1.CustomHeight = 44; pic1.BestFitWidth = 100; this.winGridViewPager1.gridView1.Columns["Signature"].ColumnEdit = picFlight; this.winGridViewPager1.gridView1.Columns["Signature"].MaxWidth = 100; this.winGridViewPager1.gridView1.Columns["Signature"].MinWidth = 100; RepositoryItemPictureEdit picDoctor = new RepositoryItemPictureEdit(); picDoctor.SizeMode = DevExpress.XtraEditors.Controls.PictureSizeMode.Zoom; picDoctor.NullText = " "; picDoctor.CustomHeight = 44; picDoctor.BestFitWidth = 100; this.winGridViewPager1.gridView1.Columns["DoctorSignature"].ColumnEdit = picDoctor; this.winGridViewPager1.gridView1.Columns["DoctorSignature"].MaxWidth = 100; this.winGridViewPager1.gridView1.Columns["DoctorSignature"].MinWidth = 100; }

以上就基本上解决了,签名,以及图片保存,以及列表显示图片效果的问题了。

本文转载自:博客园 - 伍华聪

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/29 13:13:52

效率工具评审从用户任务出发

效率工具评审从用户任务出发 在 AI 效率工具的产品化与 PMF(产品市场契合度)验证阶段,许多研发团队容易陷入演示效果(Demo)与生产可用性之间的认知误区。Demo 阶段的惊艳展现,往往基于特定上下文与预设样例…

作者头像 李华
网站建设 2026/8/29 13:13:22

STM8 I2C BUSY位卡死排查与恢复:从寄存器状态到总线释放方案

1. Busy bit卡死的第一现场:现象记录与初步判断如果你在STM8S105K6上调试I2C外设,八成会遇到一个让人抓狂的问题:I2C通信跑着跑着突然卡死,读I2C_SR2寄存器,BUSY位死活是1,主设备既发不了起始条件&#xff…

作者头像 李华
网站建设 2026/8/29 13:12:04

DV-1100边缘计算工控机选型与部署实战:从车载到产线

最近在给一个边缘计算项目做设备选型,前后拖了两周,最后换了 Cincoze 的 DV-1100 才把进度拉回来。之前我一直在普通工控机和高性能迷你主机之间犹豫,总觉得边缘场景不过就是"放一台小电脑"而已,直到真正把设备放进产线…

作者头像 李华
网站建设 2026/8/29 13:11:21

蓝桥杯国赛真题深度解析:Java算法实战与避坑指南

1. 项目概述:一次对经典赛题的深度复盘 最近整理硬盘,翻到了2016年参加第七届蓝桥杯国赛JAVA B组时的备赛资料和当时自己写的解题代码。时间过去这么久,再看这些题目,依然觉得很有嚼头。蓝桥杯的比赛,尤其是国赛级别&a…

作者头像 李华
网站建设 2026/8/29 13:11:12

Vue3折叠面板(Collapse)

可自定义设置以下属性: 折叠面板数据(items),可使用 slot 替换指定 key 的 header、content、arrow、extra、lang,类型:Item[],默认 [] 当前激活 tab 面板的 key(v-model:activeKey…

作者头像 李华
网站建设 2026/8/29 13:10:53

唯品会校招数据结构笔试题复盘:链表、二叉树与排序考点全解析

那年校招季,我在电脑前点开唯品会2018校招数据结构的笔试链接,A卷的时限是九十分钟。说实话,做之前我以为会是网上流传的那种"大小堆求中位数""手写红黑树"之类的硬核题,真正把卷子从头到尾过了一遍之后&…

作者头像 李华