资讯动态

WinCC图层显隐实战:VBA/C脚本与状态保持避坑

发布时间:2026/10/27 4:01:03 来源:尧图企业网站定制
简介面向西门子WinCC项目开发者的一份图层显隐控制实例包围绕画面图层可见性这一常见交互需求给出可直接参考的项目文件与脚本思路。内容涉及画面分层组织、VBS脚本中通过Layer.Visible属性切换图层状态、以按钮点击等事件驱动图层切换以及用隐藏图层承载数据加载提示或报警信息等典型做法适合已具备一定WinCC组态基础、希望提升画面交互性与工程可维护性的工程师参考。压缩包共298个文件、约10.1MB以262个rpl报表布局文件为主体另含3个pdl画面文件、sav与dum等数据转储文件、xml与ini配置文件以及mdf、ldf数据库文件和cfg、dcf等工程配置项基本覆盖完整WinCC项目的目录构成便于整体还原与对照调试。目前已有2288人学习下载。1. 接手一个 WinCC 项目案例图层问题往往出在“看不见”上上周帮人看一个 WinCC 项目案例画面上一排按钮叠在趋势图下面操作工误触之后把整条线的参数改了。原开发者用的是最直接做法给每个对象绑“显示”动画一个按钮一条变量改到第三十处的时候自己都记不清哪个变量管哪块。其实 WinCC 画面图层的隐藏显示不需要这么铺开图形编辑器里 0~31 层本身就是一套现成的显隐开关配合少量脚本和内部变量能把几十个对象收进一个按钮里管。这篇按我实际改画面的顺序拆层机制到底控制什么、VBA 和 C 脚本各管哪一段、状态怎么在画面切换后保住、以及五个我踩过的坑。适合手上有 WinCC 画面维护任务、又不想逐个对象改属性的同行。2. 图层机制先吃透0~31 层到底控制了什么2.1 层不是分组是渲染与命中测试的边界WinCC 图形编辑器里每个对象都有一个层号取值范围 0~31新建对象默认落在当前激活层。很多人把层当成“分组”用觉得把按钮放同一层就能一起控制这个理解只对了一半。层的可见性首先影响的是渲染层被隐藏后该层上的对象不参与画面绘制这是最直观的效果。但它不影响对象背后的变量连接、动态化对话框和脚本触发器对象该刷新的变量还在刷新该执行的脚本还在执行。这一点如果不提前搞清楚后面排查“层都隐藏了怎么还有动作”会绕很大弯。层和对象自身“显示”属性的区别也要说清。对象属性里的“显示”是单对象粒度绑一个 BOOL 变量0 隐藏 1 显示适合少量关键元素层可见性是整层粒度一次影响该层所有对象适合成组切换。两者不是替代关系实际项目里常见组合是用层做粗粒度分区比如背景层、操作层、诊断层用对象“显示”做细粒度例外比如操作层里某个按钮要单独受权限控制。选型的时候先问自己一句这次要藏的是一个对象还是一整块界面答案不同落点就不同。还有一个容易被忽略的边界层的隐藏显示状态属于画面编辑期的组织信息不是运行期的业务数据。你在图形编辑器里把第 5 层关掉保存的是编辑状态运行系统里通过脚本改层可见性改的是当前会话的运行状态。这两者不会自动同步也不会因为你保存了画面就固化到项目里。所以凡是需要“下次打开还保持”的显隐逻辑都不能只靠层开关必须落到变量上。2.2 用宏录制器把层对象路径问出来WinCC 的 VBA 对象模型在不同版本、不同安装组件下会有些差异层集合的对象名和访问路径我不敢凭记忆写死翻车的代价是脚本在客户机上直接报“对象为空”。我一般先用宏录制器把路径问出来打开画面编辑器点“工具”里的宏录制手动点一次层的显示隐藏按钮停止录制看生成的代码里层对象是怎么取的。这个动作花两分钟能省掉半小时猜对象名。录制出来的骨架大概长这样不同环境变量名可能不同以你录到的为准 宏录制得到的层访问骨架先别改结构只替换层号 Sub OnClick(ByVal Item) Dim scr As Object Dim lyr As Object Set scr HMIRuntime.ActiveScreen Layers 下标从 0 开始3 表示第 4 层 Set lyr scr.Layers(3) 取反当前可见性实现点一次切换一次 lyr.Visible Not lyr.Visible End Sub这段代码里HMIRuntime.ActiveScreen取的是当前活动画面画面窗口里嵌套的画面要用ScreenItems往下找不能直接套。Layers(3)的参数是层号减一写 3 对应界面上的第 4 层这里最容易差一位。lyr.Visible是布尔读写属性读出来是当前状态写进去立即生效不需要刷新画面。宏录制的好处是它连对象类型都给你带出来了照着声明变量别自己改成Variant以外的类型。录完之后不要急着把代码贴到按钮里先在画面打开事件里加一句HMIRuntime.Trace把层号和当前状态打到诊断窗口确认运行时ActiveScreen不为空。服务器项目和客户端项目的行为不一样客户端上某些画面对象在没激活的时候取不到这一步验证能提前暴露问题。2.3 三种显隐方案怎么选层、对象动画、画面窗口同样是“隐藏显示”WinCC 里至少有三条路选错了后面维护成本翻倍。我把实际项目里的判断整理成下面这张表参数是按常见画面规模给的不是绝对标准但能帮你快速定位。方案控制粒度典型响应适合场景主要代价层可见性VBA整层 0~31脚本执行即生效背景/操作/诊断分区切换需要脚本状态不持久对象“显示”动画单个对象跟随变量刷新周期少量按钮、文字的权限控制对象多时变量爆炸画面窗口切换整幅子画面切换画面窗口源多工况界面整块替换需要规划画面结构层可见性适合“整块界面藏起来”的需求比如调试层、诊断层平时不显示点维护按钮才出来。对象“显示”动画适合“同一块界面里个别元素受控”比如只有管理员能看到参数修改按钮。画面窗口切换适合“同一位置显示不同工况画面”它本质是换画面源不是隐藏对象所以不存在对象还在后台跑的问题但要求你把画面拆得足够干净。我一般的做法是先用画面窗口把大结构分开再用层做层内分区最后才用对象“显示”补例外。顺序反过来先给每个对象绑动画后期加一个分区就要改几十处血泪经验。层号规划也要提前做0~7 给背景和静态元素8~15 给操作按钮16~23 给趋势和报警24~31 留给调试和诊断这个约定写进项目规范后面谁接手都不会乱。3. 运行时切换层VBA 与 C 脚本两套写法3.1 VBA 按钮脚本按层号切换并回写状态真正到运行时层的显隐要靠脚本触发。最稳妥的落点是画面上的“维护模式”按钮单击事件里做三件事切换目标层、把新状态写进内部变量、更新按钮自己的文字提示。下面这段是我在一个 WinCC 项目案例里用的写法去掉项目相关对象名后可以直接套 维护模式按钮切换第 20 层诊断层的显示隐藏 Sub OnClick(ByVal Item) Dim scr As Object Dim lyr As Object Dim bNewState As Boolean Set scr HMIRuntime.ActiveScreen Set lyr scr.Layers(20) 层号 20对应界面上的第 21 层 bNewState Not lyr.Visible 取反实现点一次切一次 lyr.Visible bNewState 状态落到内部变量画面切换后靠它恢复 HMIRuntime.Tags(gDiagLayerVisible).Write bNewState 按钮文字跟着变避免操作工看不出当前状态 If bNewState Then Item.Text 关闭诊断层 Else Item.Text 打开诊断层 End If End Sub逐段说明scr.Layers(20)里的 20 是层索引不是层号写之前先确认你的层规划表。bNewState先算后写避免lyr.Visible Not lyr.Visible在某些版本上读回值不同步。HMIRuntime.Tags(...).Write写的是内部变量变量名按项目规范起我这里用g前缀表示全局。Item.Text是按钮自身文字改它比另做一个指示灯省事但要注意多语言项目里直接写中文会破坏翻译表这种项目就改成切画面或切图标。这段脚本只负责“当前画面”的层画面窗口里的子画面取不到。子画面的层要在子画面自己的按钮里处理或者用全局脚本按画面名遍历。别在一个按钮里写跨画面操作运行起来对象路径一错就整段失效。3.2 C 脚本做对象级同步SetPropBOOL 的四个参数层级别的切换用 VBA 顺手但对象级别的显隐我更愿意用 C 脚本原因是 C 脚本在全局脚本、按钮事件、变量触发里都能跑部署位置灵活。WinCC 的 C 脚本操作对象属性用SetPropBOOL签名是“画面名、对象名、属性名、布尔值”四个参数缺一不可。// 按钮单击事件按内部变量批量控制明细区对象显隐 #include apdefap.h void OnClick(char* lpszPictureName, char* lpszObjectName, char* lpszPropertyName) { BOOL bShow GetTagBit(gDetailVisible); // 读当前状态 bShow !bShow; // 取反 SetTagBit(gDetailVisible, bShow); // 先回写变量 // 逐个设置对象可见性对象名必须与画面里完全一致 SetPropBOOL(lpszPictureName, btnDetailEdit, Visible, bShow); SetPropBOOL(lpszPictureName, txtDetailValue, Visible, bShow); SetPropBOOL(lpszPictureName, barDetail, Visible, bShow); }lpszPictureName是脚本自带的当前画面名不要硬编码画面名否则画面一改名全部失效。Visible是属性名大小写不敏感但建议照抄对象属性窗口里的写法。对象名必须唯一同一画面里复制粘贴出来的对象会自动加后缀脚本里写的是复制前的名字就会静默失败不报错但也不生效这是最常见的翻车点。每次改完脚本我都会在画面上留一个测试按钮只放一个对象确认路径通了再批量加。对象多的时候不要一条条写SetPropBOOL用一个数组加循环对象名放字符串数组里逻辑只写一遍。这样后面加对象只改数组不动逻辑维护成本差很多。3.3 变量驱动的对象显隐直接连接和动画怎么配有些场景不适合点按钮比如设备运行时自动隐藏手动操作区。这种就用变量驱动配置落在对象属性的“动画”里不写脚本。步骤是选中对象打开属性窗口找到“显示”属性右键选“动画”类型选“直接连接”源变量选gAutoMode比较方式选“等于”比较值填 1有效范围就是显示否则隐藏。参数上要注意两点。第一源变量的刷新周期决定显隐延迟内部变量默认周期可能是 250ms 或 1s操作工点下去感觉“慢半拍”多半是这个原因把变量周期的采集类型改成“循环连续”并调短或者改用事件触发。第二直接连接适合布尔量多状态切换要用“变量”类型的动画配多个范围范围之间不要留空隙否则会出现既不显示也不隐藏的中间态。变量驱动的对象多了以后变量表会膨胀排查时很难看出哪个变量管哪块。我的习惯是变量名带画面缩写和功能缩写比如P01_AutoMode再在变量注释里写清楚影响哪些对象。后面接手的人翻变量表就能对上不用去画面里一个个点。4. 权限、画面切换与状态保持4.1 用内部变量存层状态别指望层自己记住层可见性是运行时会话状态画面一切换、一关闭再打开层就回到编辑期的默认状态。如果业务上要求“上次关掉的诊断层下次进来还是关的”必须自己用变量记。我一般建一组内部变量命名规则是gLayerXXVisibleXX 是层号类型 BOOL初始值按安全侧给诊断层默认 0操作层默认 1。写变量只是第一步读回来才是关键。画面打开事件里遍历这组变量把每个层的Visible设成变量值。层多了可以只恢复关键层不必 32 层全遍历遍历本身开销不大但代码长了容易漏。变量初始值要和画面编辑期的层状态对齐否则第一次打开会出现“变量说隐藏、画面却显示”的错位操作工一看就懵。内部变量不掉电保持项目重启后回到初始值这通常是想要的。如果确实需要断电保持用外部变量或脚本读写文件但那种场景很少别为了少数需求把简单逻辑复杂化。4.2 画面打开事件里恢复层状态恢复逻辑放在画面的“打开画面”事件里不要放在按钮里。打开事件触发时画面对象已经加载ActiveScreen可取层对象也能拿到。下面这段是按变量恢复的骨架 画面打开事件按内部变量恢复关键层可见性 Sub OnOpen(ByVal Item) Dim scr As Object Set scr HMIRuntime.ActiveScreen 只恢复需要记忆的层其余保持编辑期默认 scr.Layers(20).Visible HMIRuntime.Tags(gDiagLayerVisible).Read scr.Layers(24).Visible HMIRuntime.Tags(gDebugLayerVisible).Read End SubOnOpen里不要做耗时操作变量读写在本地很快但如果里面再调数据库或远程变量会拖慢画面打开。层恢复只读内部变量控制在几条以内。画面窗口嵌套时子画面的打开事件也会触发恢复逻辑写在各自画面里别在父画面统一处理父子画面层号不通用。还有一点OnOpen执行时画面还没完成第一次绘制这时候改层可见性不会有闪烁反而比在“画面显示之后”再改更干净。如果发现打开瞬间闪一下再隐藏多半是恢复逻辑放晚了挪到OnOpen里就能消掉。4.3 权限判断放在脚本入口不要放在层里层本身没有权限概念谁能切层全靠脚本判断。常见错误是把用户名写死在按钮脚本里换个人维护就要改代码。正确做法是用 WinCC 的用户管理脚本入口读当前用户级别够级别才执行切换。 权限判断放在切换动作之前不满足直接退出 If HMIRuntime.User.Name Then Exit Sub 具体级别判断按项目用户管理配置来这里只示意入口位置 If Not CheckUserLevel(3) Then HMIRuntime.Trace 层切换被拒绝权限不足 Exit Sub End IfCheckUserLevel是项目里封装的函数实际用 WinCC 自带的权限检查接口不同项目封装不同别照抄函数名照抄的是“先判断再动作”的位置。拒绝时写一条 Trace排查权限问题时能直接看到是谁在什么时候被拦了。权限不足不要弹模态框操作工在生产线上点错一下弹个框还要多点一次用按钮置灰或文字提示更合适。5. 避坑与排查层隐藏了鼠标还能点中的五个现场5.1 隐藏层里的按钮仍然响应单击现象诊断层已经隐藏画面上看不到按钮但操作工在原来按钮的位置点一下功能还是触发了。原因层可见性影响绘制不等于禁用对象。对象还在画面对象树里命中测试按对象矩形算隐藏层上的对象照样接收鼠标消息。这一点和 Web 前端里display:none与visibility:hidden的差别类似但 WinCC 更偏向后者。解决切换层的同时把该层关键对象的Enabled置 FALSE或者把可交互对象移到专门的“操作层”隐藏时用画面窗口整体移走。最省事的做法是隐藏层里只放显示类元素按钮一律不放隐藏层从设计上避开这个问题。已经放了按钮的在层切换脚本里补一句批量SetPropBOOL(..., Enabled, bShow)。5.2 切画面再回来层全亮了现象在画面 A 里关掉诊断层切到画面 B 再切回 A诊断层又显示出来。原因层可见性不随画面保存每次画面打开按编辑期状态初始化前面 4.1 说的变量记忆没做或者没生效。解决按 4.2 在OnOpen里恢复变量初值与编辑期状态对齐。排查时先在OnOpen里加 Trace 打出变量值和恢复后的层状态确认是变量没写进去还是读出来是默认值。常见的是按钮脚本写变量名和OnOpen读变量名差一个字母编译器不报错运行时静默。5.3 客户端上脚本报对象为空现象服务器上点按钮正常客户端上点同一个按钮没反应诊断窗口报对象为空或“不支持该属性”。原因客户端激活时画面对象的可取范围受限制HMIRuntime.ActiveScreen在某些客户端配置下取不到或者层集合对象在客户端未暴露。解决先确认客户端是“完整客户端”还是“仅监视”仅监视客户端本来就不该执行切换脚本。需要交互的客户端把脚本改成 C 脚本挂在按钮上用lpszPictureName取画面名绕开ActiveScreen。改完在客户端本机跑一遍别只在工程师站验证。5.4 变量驱动的显隐慢半拍现象模式切换后手动操作区要过一两秒才消失操作工在这期间还能点到。原因对象“显示”动画跟随源变量刷新周期内部变量默认周期偏长或者变量采集类型设成了“非循环”。解决把源变量改成循环连续采集周期调到 100~250ms对实时性要求高的改用按钮事件直接SetPropBOOL不走变量刷新。还要检查是不是同一个对象上叠了多个动画后执行的覆盖前面的表现就是延迟或状态不对。5.5 隐藏层里的动画脚本还在跑现象诊断层隐藏后里面的趋势控件还在刷新CPU 占用没降甚至因为脚本里访问了已隐藏对象而报错。原因隐藏不等于停用对象的动态化、变量连接、全局脚本触发都还在执行前面 2.1 提过这个边界。解决在动画脚本或全局脚本入口加可见性判断层隐藏时直接Exit不执行后续逻辑趋势控件这类持续刷新的对象用变量控制其“更新”属性隐藏时停更。CPU 占用高的项目先查隐藏层里有没有高频脚本比查画面数量更有效。6. 验收技巧做一张 32 个开关的层调试画面层显隐做完别只靠点按钮看效果我习惯单独做一张调试画面把 0~31 层各放一个开关按钮再加一列状态指示灯和一个“全部显示”复位按钮。这张画面不进生产导航只挂在工程师菜单里验收和排障都用它。具体做法是新建画面按层号排 32 个按钮按钮单击事件里调同一个脚本层号从按钮对象名里截取避免写 32 段重复代码。 调试画面通用按钮从对象名末尾取层号如 LayerBtn_20 Sub OnClick(ByVal Item) Dim sName As String Dim iLayer As Integer Dim lyr As Object sName Item.ObjectName iLayer CInt(Mid(sName, InStrRev(sName, _) 1)) Set lyr HMIRuntime.ActiveScreen.Layers(iLayer) lyr.Visible Not lyr.Visible 状态灯同步灯的对象名约定为 Lamp_层号 HMIRuntime.ActiveScreen.ScreenItems(Lamp_ iLayer).BackColor _ IIf(lyr.Visible, RGB(0, 255, 0), RGB(128, 128, 128)) End Sub这段脚本的关键在InStrRev取最后一个下划线后的数字按钮名按LayerBtn_20命名就能复用同一段代码加层只加按钮不改脚本。状态灯用BackColor同步绿显灰隐一眼能看出哪层没关干净。IIf在两个分支里都要求值这里都是常量没有副作用可以放心用如果分支里要读变量改成If...Else更稳。验收顺序我固定走三步先逐个开关点一遍确认每层只影响自己再切画面往返三次确认状态恢复最后在客户端上重复前两步。三步里任何一步不对回到第 5 章对现象。这套调试画面我从一个返工两次的项目之后就一直保留每次新画面交付前强制走一遍比在脑子里推层号靠谱得多。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑