尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
分享一个鼠标按下就能画线的绘图窗体VBA
大家好这里是晚间有雨伴人眠。之前咱们聊过怎么创建自定义对话框窗口也聊过怎么让窗口显示在屏幕正中间。今天再分享一个新玩法——在窗体上画线绘图。这个功能说大不大但用对了场景还挺实用的。比如你可以把它做成一个简易的批注工具在表格数据上画圈标记或者做一个签名板让用户在窗体上手写签名甚至只是给演示文稿加个临时的标注图层都行。效果很简单鼠标左键按住拖动就能在窗体上画出一条连续的黑色线条松开就停止绘制。先看效果再说实现。一、核心思路在Windows里画线用的是GDI图形设备接口。这套接口里有两个最基础的函数MoveToEx 把“画笔”移动到某个坐标LineTo 从当前位置画一条线到目标坐标所以整个绘图的逻辑就是鼠标按下 → 记录起始位置 → 鼠标移动 → 不断从上一个位置画到当前位置 → 鼠标松开 → 停止绘制说白了就是一个连续画线的过程和你在Windows自带的画图软件里用铅笔工具画画是完全一样的道理。二、代码解析完整代码你直接复制就能用这里我挑几个关键点简单说一下方便你理解原理。1. 窗体事件的配合代码里用了三个鼠标事件UserForm_MouseDown 左键按下时设置一个“正在绘制”标记UserForm_MouseUp 左键松开时清除这个标记UserForm_MouseMove 鼠标移动时如果标记为真就执行画线这三个事件一配合就实现了“按下画、松开停”的效果。2. 坐标转换这里有个细节需要注意 GetCursorPos 获取的是鼠标在屏幕上的坐标但画线需要的是在窗体客户区内的坐标所以必须用 ScreenToClient 做一次转换否则画出来的位置就全偏移了。代码里是这样处理的GetCursorPos prpt 获取屏幕坐标 ScreenToClient Uf.Form, prpt 转换成窗体坐标3. 画笔的创建与释放在窗体初始化时创建画笔Uf.Penr CreatePen(PS_SOLID, 1, RGB(0, 0, 0))这里创建了黑色、1像素宽的实线画笔。想要换颜色或粗细改这里就行RGB(0, 0, 0) 改成 RGB(255,0,0) 就是红色中间那个1改成3就是3像素宽窗体关闭时记得释放画笔和设备上下文避免内存泄漏DeleteObject Uf.Penr ReleaseDC Uf.Form, Uf.Fhdc三、可以玩的花样这个基础版本还可以继续扩展给你几个思路换颜色加几个按钮点击后修改画笔颜色调整粗细加一个滚动条控制画笔宽度清空画布加一个“清除”按钮重绘窗体画直线/矩形把自由画线改成从起点到终点的规则图形这些都是在这个基础上顺理成章的扩展有兴趣的话可以自己动手试试。四、完整代码新建一个UserForm把下面的代码全部粘贴进去直接运行就能看到效果。晚间有雨伴人眠202607161122 #If VBA7 And Win64 Then Private Declare PtrSafe Function LineTo Lib gdi32 (ByVal hdc As LongPtr, ByVal X As Long, ByVal Y As Long) As Long Private Declare PtrSafe Function MoveToEx Lib gdi32 (ByVal hdc As LongPtr, ByVal X As Long, ByVal Y As Long, lpPoint As POINTAPI) As Long Private Declare PtrSafe Function CreatePen Lib gdi32 (ByVal nPenStyle As Long, ByVal nWidth As Long, ByVal crColor As Long) As LongPtr Private Declare PtrSafe Function DeleteObject Lib gdi32 (ByVal hObject As LongPtr) As Long Private Declare PtrSafe Function GetDC Lib user32 (ByVal hwnd As LongPtr) As LongPtr Private Declare PtrSafe Function ReleaseDC Lib user32 (ByVal hwnd As LongPtr, ByVal hdc As LongPtr) As Long Private Declare PtrSafe Function FindWindowA Lib user32 (ByVal lpClassName As String, ByVal lpWindowName As String) As LongPtr Private Declare PtrSafe Function GetCursorPos Lib user32 (lpPoint As POINTAPI) As Long Private Declare PtrSafe Function ScreenToClient Lib user32 (ByVal hwnd As LongPtr, lpPoint As POINTAPI) As Long #Else Private Declare Function LineTo Lib gdi32 Alias LineTo (ByVal hdc As Long, ByVal x As Long, ByVal y As Long) As Long Private Declare Function MoveToEx Lib gdi32 Alias MoveToEx (ByVal hdc As Long, ByVal x As Long, ByVal y As Long, lpPoint As POINTAPI) As Long Private Declare Function CreatePen Lib gdi32 Alias CreatePen (ByVal nPenStyle As Long, ByVal nWidth As Long, ByVal crColor As Long) As Long Private Declare Function DeleteObject Lib gdi32 Alias DeleteObject (ByVal hObject As Long) As Long Private Declare Function GetDC Lib user32 Alias GetDC (ByVal hwnd As Long) As Long Private Declare Function ReleaseDC Lib user32 Alias ReleaseDC (ByVal hwnd As Long, ByVal hdc As Long) As Long Private Declare Function FindWindowA Lib user32 Alias FindWindowA (ByVal lpClassName As String, ByVal lpWindowName As String) As Long Private Declare Function GetCursorPos Lib user32 Alias GetCursorPos (lpPoint As POINTAPI) As Long Private Declare Function ScreenToClient Lib user32 Alias ScreenToClient (ByVal hwnd As Long, lpPoint As POINTAPI) As Long #End If #If VBA7 And Win64 Then Private Type POINTAPI X As Long Y As Long End Type Private Type UserForm1Type Form As LongPtr Fhdc As LongPtr Penr As LongPtr GotoLine(1) As Boolean End Type #Else Private Type POINTAPI X As Long Y As Long End Type Private Type UserForm1Type Form As Long Fhdc As Long Penr As Long GotoLine(1) As Boolean End Type #End If Private Const PS_SOLID 0 Private Uf As UserForm1Type Private Sub UserForm_Initialize() Uf.Form FindWindowA(IIf(Application.Version 9, ThunderXFrame, ThunderDFrame), Me.Caption) Uf.Penr CreatePen(PS_SOLID, 1, RGB(0, 0, 0)) Uf.Fhdc GetDC(Uf.Form) End Sub Private Sub UserForm_Terminate() DeleteObject Uf.Penr ReleaseDC Uf.Form, Uf.Fhdc Dim EmptyUf As UserForm1Type: Uf EmptyUf End Sub Private Sub UserForm_MouseDown(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single) If Button 1 Then Uf.GotoLine(0) True: Uf.GotoLine(1) True End Sub Private Sub UserForm_MouseUp(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single) If Button 1 Then Uf.GotoLine(0) False End Sub Private Sub UserForm_MouseMove(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single) If Uf.GotoLine(0) Then Dim prpt As POINTAPI GetCursorPos prpt ScreenToClient Uf.Form, prpt If Uf.GotoLine(1) Then MoveToEx Uf.Fhdc, prpt.X, prpt.Y, prpt Uf.GotoLine(1) False Else LineTo Uf.Fhdc, prpt.X, prpt.Y End If End If End Sub五、写到最后GDI绘图是Windows编程里非常基础的一块VBA通过API调用也能玩起来。它的学习曲线不算陡但掌握了之后能做的事情比想象中多得多——从简单的画线画图到自定义控件的外观都能派上用场。代码不长但“按下拖动画线”这个交互是很多绘图工具的基石。如果你刚好需要一个轻量级的标注或签名功能这份代码改改就能用。你平时在VBA里有没有遇到过需要在窗体上画图的需求或者想在这份代码基础上增加什么功能欢迎在评论区聊聊。
RELATED

相关推荐

OpenClaw 合规公开数据采集入门:合法边界、数据源选型与反爬规避实操指南

OpenClaw 合规公开数据采集入门:合法边界、数据源选型与反爬规避实操指南

一、引言:为什么我们需要一套合规的数据采集框架在大模型训练、市场竞品分析、舆情监控以及学术研究等多个领域,公开数据的获取已经从“锦上添花”变成了“刚性需求”。然而,随着全球数据隐私保护法规(如 GDPR、CCPA、中国的《个人…

📅 2026/9/10 2:18:26
使用 C# 将 HTML 转 Word 或者 Word 转 HTML

使用 C# 将 HTML 转 Word 或者 Word 转 HTML

清理收藏夹。HTML作为Web内容的标准格式,与Word这种通用的办公文档格式之间的相互转换,是许多企业级应用中的常见需求。无论是将数据库中的动态内容生成为Word报告,还是将现有的Word文档发布为网页,掌握高效的转换方法都能显著提升…

📅 2026/10/7 1:10:22
EMB3531-RK3399工控机救砖!进maskrom模式

EMB3531-RK3399工控机救砖!进maskrom模式

参考下恩山的https://www.right.com.cn/forum/thread-8482116-1-1.html文档

📅 2026/10/8 12:11:20
MORE NEWS

更多资讯

📰

电工证盗用真实经历揭秘:学历不高怕报不上名?教你如何避坑

电工证盗用真实经历揭秘:学历不高怕报不上名?教你如何避坑 最近,我接到了一个学员的咨询,他担心自己学历不高,连电工证报名都可能报不上。说实话,我理解他的担忧,因为每年都有很多人因为学历问题放弃报考,甚至有人听信了“电工证盗用”这种消息,结果…

📰

宿豫区电工证复审报名费多少钱,真实经历告诉你别被中介坑

宿豫区电工证复审报名费多少钱,真实经历告诉你别被中介坑 你是不是也遇到过这种情况?手头拿着电工证,眼看快到期了,却不知道在哪复审,怕被中介骗钱、怕走弯路、怕错过时间节点?别急,我来跟你聊聊我的 真实经历…

📰

保山电工证在哪办 上岗必备的全流程详解

保山电工证在哪办 上岗必备的全流程详解 你是不是也这样,学历不高怕报不上名?别急,今天就带你从零开始,搞定【保山电工证在哪办】这件事,让你顺利拿到上岗必备的电工证,不再被门槛拦住。 保山电工证在哪办?正规渠道有哪些?…

📰

特种设备安装维修工上岗必备:实操考试心里没底怕挂科?全流程避坑指南

特种设备安装维修工上岗必备:实操考试心里没底怕挂科?全流程避坑指南 实操考试心里没底怕挂科,这几乎是每个想考特种设备安装维修工的人心里的“坎”。特别是在郑州金水区,很多建筑工人刚接触这个证书,总觉得自己操作不熟练,怕考试挂了白忙一场。其实,…

📰

石家庄特种工领取补贴别走弯路 这份郑州报考避坑指南送给你

石家庄特种工领取补贴别走弯路 这份郑州报考避坑指南送给你 你是不是也担心去哪报名怕被中介坑?石家庄特种工领取补贴政策虽然好,但很多人因为不了解流程、怕被骗,干脆就搁置了。特别是像你这种南阳卧龙区的项目现场管理员,手里有证能多一份保障,也更利…

📰

泰州考电工证有黄牛吗 值不值得考?看懂这些再决定

泰州考电工证有黄牛吗 值不值得考?看懂这些再决定 你还在为找不到工作发愁?特种作业证没到手,面试都过不了。泰州考电工证有黄牛吗?值不值得考?这是很多想进工地、进厂、进维修单位的人最关心的问题。别急,我来帮你理清楚。…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬