ARTICLE · 1026763
从0学Excel VBA编程 · 高阶应用·界面自定义 第5篇(收官):综合实战——把进销存系统做成开箱即用的 应用
从0学Excel VBA编程 · 高阶应用·界面自定义 第5篇(收官):综合实战——把进销存系统做成开箱即用的 Excel 应用
学习目标
能把 Ribbon 选项卡 + 右键菜单 + 窗体控制台 三层界面整合到一个 .xlsm,业务全收在标准模块搞懂 整合时的生命周期分工:Ribbon 靠 XML 自带、右键靠 Open 建 / BeforeClose 删、窗体靠 Open 自启 能照一份 部署清单 把成品发给老板,他打开启用宏就能用,不用碰一行代码
知识点精讲
前面四篇我们分别讲了菜单/工具栏、右键菜单、Ribbon 基础、Ribbon 动态。单拿出来都简单,真做一个"能交付"的应用,难点在整合和分工:
业务层:所有增删改查逻辑写在标准模块(如 m业务),这是地基,界面层只调用它,绝不把逻辑写进窗体或 ThisWorkbook。界面层有三块,各管各的: Ribbon 选项卡:最显眼,用 customUI.xml描述,Excel 打开自动渲染,不用在代码里建右键菜单:最顺手, Workbook_Open里加、Workbook_BeforeClose里按Tag删(第2篇做法),随文件生灭窗体控制台:最友好,给不懂 Excel 的人用, Workbook_Open里frmMain.Show开机自启调度铁律:三层界面上的每一个按钮,都只写一行"调用标准模块过程",不写业务细节。这样换界面、改逻辑互不拖累。
本篇就把进销存系统(第1~6篇的业务)套上这三层界面,做成一个成品。
【示意图】
3 个实战案例
案例 1(简单):完整 Ribbon 选项卡蓝图 + 调度骨架
功能说明:给进销存系统画一张完整的 Ribbon 图纸——"导航"组(下拉选表)、"操作"组(录入进货/录入销售/刷新报表/导出报表)、"开关"组(自动刷新)。每个按钮的 onAction 都指向一个只做调度的标准模块过程。
customUI.xml(成品完整版):
<customUIxmlns="http://schemas.microsoft.com/office/2009/07/customui"onLoad="onLoad"><ribbon><tabs><tabid="tabIPS"label="进销存"><groupid="grpNav"label="导航"><dropDownid="ddSheet"label="选择工作表"getItemCount="表数量"getItemLabel="表名"getItemID="表ID"onAction="选表点击" /></group><groupid="grpOp"label="操作"><buttonid="btnBuy"label="录入进货"onAction="btn录入进货"imageMso="TableInsert" /><buttonid="btnSale"label="录入销售"onAction="btn录入销售"imageMso="TableInsert" /><buttonid="btnRpt"label="刷新报表"onAction="btn刷新报表"imageMso="Refresh"getEnabled="报表可用" /><buttonid="btnExp"label="导出报表"onAction="btn导出报表"imageMso="FileSave" /></group><groupid="grpAuto"label="开关"><toggleButtonid="btnAuto"label="自动刷新"onAction="自动点击"getPressed="自动是否按下"imageMso="FollowOutline" /></group></tab></tabs></ribbon></customUI>标准模块「m界面调度」(只转调,不写业务):
' —— 以下每个过程只调用业务模块 m业务 里的真实过程 ——Sub btn录入进货(control As IRibbonControl) 录入进货单End SubSub btn录入销售(control As IRibbonControl) 录入销售单End SubSub btn刷新报表(control As IRibbonControl) 刷新库存报表End SubSub btn导出报表(control As IRibbonControl) 导出库存报表End Sub' 自动刷新开关 + 刷新按钮可用性(第3/4篇回调)Dim 自动刷新 As BooleanSub 自动点击(control As IRibbonControl, pressed As Boolean) 自动刷新 = pressedEnd SubSub 自动是否按下(control As IRibbonControl, ByRef returnedVal) returnedVal = 自动刷新End SubSub 报表可用(control As IRibbonControl, ByRef returnedVal) returnedVal = (Sheets("库存汇总").Range("A2").Value <> "")End Sub' 下拉选表 + onLoad 缓存(第3/4篇,略写四个回调,见前篇)Dim ribUI As IRibbonUI, 当前表序号 As LongSub onLoad(ribbon As IRibbonUI): Set ribUI = ribbon: End SubSub 表数量(control As IRibbonControl, ByRef r): r = ThisWorkbook.Worksheets.Count: End SubSub 表名(control As IRibbonControl, i As Integer, ByRef r): r = ThisWorkbook.Worksheets(i + 1).Name: End SubSub 表ID(control As IRibbonControl, i As Integer, ByRef r): r = "S" & i: End SubSub 选表点击(control As IRibbonControl, id As String, idx As Integer) 当前表序号 = idx If Not ribUI Is Nothing Then ribUI.InvalidateControl "btnRpt"End Sub操作步骤:把上面 XML 用 Custom UI Editor 写进 .xlsm,标准模块放 m业务(录入进货单/录入销售单/刷新库存报表/导出库存报表)和 m界面调度。打开即见"进销存"选项卡。
案例 2(中等):Ribbon + 右键菜单双界面整合
功能说明:在案例1 基础上,再加第2篇的"右键菜单"(标记完成/导出选区/清除标记),做到功能区按钮和右键命令并存不冲突。关键在于生命周期分工:Ribbon 由 XML 自带不用管,右键靠 Open 建、BeforeClose 删。
ThisWorkbook 模块(生命周期总控):
' —— 写在 ThisWorkbook 模块里 ——Private Sub Workbook_Open() 创建界面_右键 ' 第2篇过程:加标记完成/导出选区CSV/清除标记,全打 TagEnd SubPrivate Sub Workbook_BeforeClose(Cancel As Boolean) 删除界面_右键 ' 第2篇过程:遍历 CommandBars("Cell").Controls,只删 Tag="我的右键菜单" 的项End Subm界面调度 里补上右键的调度(标准模块,和第2篇素材宏衔接):
Sub 宏_标记完成() ' 右键"✓ 标记完成"调用 With Selection .Value = "已完成" .Interior.Color = RGB(198, 239, 206) End WithEnd SubSub 宏_导出选区CSV() ' 右键"导出选区CSV"调用(见第2篇) Dim p As String p = Application.DefaultFilePath & "\选区_" & Format(Now, "yyyymmdd_hhnnss") & ".csv" Selection.Copy: Workbooks.Add: ActiveSheet.Paste ActiveWorkbook.SaveAs Filename:=p, FileFormat:=xlCSV ActiveWorkbook.Close SaveChanges:=FalseEnd SubSub 宏_清除标记() ' 右键"清除标记"调用 With Selection: .Value = "": .Interior.ColorIndex = xlNone: End WithEnd Sub关键点:右键菜单的 创建界面_右键 / 删除界面_右键 复用第2篇代码(用 Tag 精准删,不 Reset 误伤)。Ribbon 完全不碰——两套界面一个管"顶部按钮"、一个管"右键命令",互不干扰。
案例 3(实用):窗体控制台总入口 + 部署交付清单
功能说明:给不懂 Excel 的老板做一个窗体 frmMain,上面六个按钮覆盖全部操作;Workbook_Open 时自动弹出。最后给一份部署清单,照着做成品就能发给任何人。
frmMain 窗体代码(只调度,不写逻辑):
' —— 写在窗体 frmMain 的代码页 ——Private Sub cmdBuy_Click(): 录入进货单: End SubPrivate Sub cmdSale_Click(): 录入销售单: End SubPrivate Sub cmdRpt_Click(): 刷新库存报表: End SubPrivate Sub cmdExp_Click(): 导出库存报表: End SubPrivate Sub cmdQuery_Click(): frmQuery.Show: End Sub ' 查库存窗体(进销存第6篇)Private Sub cmdExit_Click(): Unload Me: End SubThisWorkbook 改成开机自启控制台(在案例2 基础上加一行):
Private Sub Workbook_Open() 创建界面_右键 ' 建右键菜单 frmMain.Show ' 开机弹控制台End Sub部署交付清单(照做即可):
保存格式:文件另存为 .xlsm(启用宏的工作簿),否则宏和 Ribbon 全丢信任中心:文件 → 选项 → 信任中心 → 信任中心设置 → 宏设置 → 勾"启用所有宏"(或把文件放进"受信任位置");首次发给别人,对方打开若没出现选项卡/窗体,多半是宏被禁,点黄色警告条"启用内容" 打包内容:Ribbon 的 customUI.xml、右键菜单代码、窗体frmMain/frmQuery、标准模块m业务/m界面调度全在同一个.xlsm内,无需对方装任何工具发给谁:直接微信/邮件发文件,对方双击打开启用宏即用——按钮、右键、窗体三套入口齐全
操作步骤:建好 frmMain(六个按钮),ThisWorkbook 的 Workbook_Open 加 frmMain.Show,保存 .xlsm。双击打开→控制台自动弹出,点"录入进货"走标准模块逻辑,单元格右键有专属命令,顶部有"进销存"选项卡——一个开箱即用的进销存应用就成了。
本篇小结
架构分层:业务收在标准模块 m业务,Ribbon / 右键 / 窗体三层界面都只做调度,换皮不换骨生命周期分工:Ribbon 靠 XML 自带(不代码建)、右键靠 Open建 /BeforeClose按Tag删、窗体靠Open自启——各管各的,不打架三铁律收口:界面层零业务逻辑、Ribbon 自带而右键/窗体靠事件、删除右键用 Tag 精准删不误伤 可交付:存 .xlsm+ 信任中心启用宏,发给谁都能用,老板不开 VBE 也能操作
系列完结 · 学习地图
「高阶应用·界面自定义」5 篇到此收官。连同前面的基础,你的完整能力栈是:
从一个宏都不会写,到能交付带专属界面、开箱即用的 Excel 应用——这条路你已经走通了。
下一步建议(如想继续):可开新系列讲 Power Query 自动化清洗、图表动态美化,或 VBA 调用 Python 做更复杂的数据处理。需要哪个方向,说一声即可。