WinCC画面图层隐藏显示:状态字+VBS脚本与权限控制
发布时间:2026/10/27 20:38:16 锦皓数字建站

简介这份资源围绕西门子WinCC画面图层控制展开面向工业自动化领域从事SCADA组态开发的初、中级工程师与项目调试人员重点解决画面中图层可见性无法灵活切换、动态交互实现困难的问题。资源包共收录298个文件压缩后约10.1MB以rpl、pdl、dcf、dum等WinCC项目与运行文件为主体辅以xml、ini、cfg等配置文件及mdf、ldf数据库文件构成一套可直接打开研究的完整组态工程。其中LayerVisible相关文件与VBS脚本示例演示了通过Layer.Visible属性在按钮点击等事件中控制图层显示与隐藏的写法便于理解事件驱动编程的组织方式。已有2288人学习该案例读者可借此掌握多图层画面分层管理、隐藏图层承载数据加载或错误提示等实用技巧并参考工程目录结构搭建自己的调试环境。1. 一个误触引出的图层需求画面越做越大之后隐藏显示成了刚需某包装线项目的操作画面上一个手动阀按钮被压在趋势曲线底下换型时操作工误触整线停了十几分钟。复盘下来不是操作工的责任而是画面把“常用”和“偶尔用”的东西全堆在同一层靠位置和透明度互相遮挡。这类问题在 WinCC 项目里很常见工艺流程图、报警面板、参数表、维护按钮挤在一屏上删不掉也放不下。这套“WinCC 画面图层隐藏显示”方案要解决的就是这件事——用图层号把画面对象分组运行期按需显示或隐藏并按用户权限区分谁能打开哪一层。适合正在做 WinCC 课程设计、毕设或者手里有一个越改越乱的现场画面、想把它重新收拢的读者。2. 需求拆解与选型四种隐藏显示手段各自的适用边界动手写脚本之前先要把“隐藏”这件事拆细。很多人一上来就在按钮里写十几行SetVisible画面能跑但改一次工艺就要重写一遍脚本返工量比画画面本身还大。合理的顺序是先定图层职责再定用什么手段去控制它。2.1 图层要解决的不是“看不见”而是遮挡顺序和权限边界WinCC 的画面编辑器里对象本身就有前后叠放的顺序图层Layer在这一层之上又给了一个逻辑分组。同样是“把维护按钮藏起来”两种做法的后果完全不同靠位置藏对象还在画面上鼠标点过去依然可能命中靠图层藏把整组对象的可见性关掉交互和显示一起消失才是真正的隐藏。所以图层的第一个职责是收拾遮挡。工艺流程图放底层管道、设备、流向属于“永远要看”的内容报警横幅、参数面板、维护工具栏放上层属于“需要时再看”的内容。第二个职责是切权限。现场操作工只该看到操作层维护层、标定层、诊断层应该由更高权限的用户打开。把这两件事想清楚图层编号才有依据否则编到后面自己都记不住第 17 层放的是什么。2.2 四种手段的对比对象属性、图层脚本、画面窗口、弹出画面WinCC 里能做“显示/隐藏”的路径不止一条选错了不是不能用是后面维护成本会不断放大。我一般按下面这张表来定手段做法优点代价适用场景对象可见性给单个对象的“显示”属性绑定 BOOL 变量不用脚本改起来直观对象多了要一个个绑容易漏少量固定对象如某个铭牌、某段说明文字图层脚本按对象名前缀批量设置Visible一次控制一整层扩展性好依赖命名规范需要脚本功底主体方案工艺层/报警层/维护层切换画面窗口切换用画面窗口控件切换PictureName各画面独立互不干扰状态不共享跨窗口同步麻烦差异很大的整屏内容如手动/自动两套界面弹出画面按钮触发弹出画面或对话框不占主画面聚焦单一任务弹出位置和层级要额外调参数设定、确认提示这类短交互我的结论是主体内容用图层脚本零星对象用属性绑定整屏切换才用画面窗口。弹出画面只用于短交互不要拿它当图层用否则一个画面上弹出三四个窗口操作工反而更乱。三种手段混用没问题但要约定清楚边界哪一层归脚本管哪几个对象归变量管写进设计说明别让下一个人靠猜。2.3 图层编号规划表从 L00 到 L31 的职责分配WinCC 的对象图层号通常可用 031正好能和 32 位状态字一一对应。编号不要随手定按“越底层越基础、越上层越专用”排并且留出空位图层前缀内容默认可见最低权限L00L00_背景、边框、标题栏是操作员L01L01_工艺流程图与管道是操作员L02L02_设备状态与数值显示是操作员L03L03_操作按钮启动、停止、复位是操作员L04L04_报警横幅与提示条是操作员L05L05_参数设定面板否班组长L06L06_趋势与历史曲线否班组长L07L07_维护与手动点动否维护工程师L08L08_标定与诊断否维护工程师L09L31Lxx_预留否按需前缀固定四位L 两位编号 下划线后面直接接英文功能名例如L05_ParaPanel、L07_JogValve。这套前缀不是为了好看是让脚本能靠字符串比较批量找对象——名字规范了脚本就只有一份名字乱了每加一个对象都要回去改代码。提示编号表要作为项目文档的一部分随画面一起交付画面改了多少次这张表就跟着更新到哪一版。现场调试时最怕的就是“文档上一套、画面上另一套”。3. 总体设计状态字 图层管理器 画面脚本的三段式结构图层方案真正的难点不在“怎么把对象设成不可见”而在“关掉之后下次打开画面它还记不记得”。我见过不少课设按钮点一下能隐藏切到别的画面再回来就全亮了答辩时被问一句就卡住。解决办法是把状态从画面里拎出来存到一个独立的地方。3.1 数据层用一个 32 位状态字承载全部图层开关状态字用一个 32 位无符号变量建议建在内部变量里命名LayerState位 0 对应 L00位 1 对应 L01依此类推。值为 1 表示该层可见为 0 表示隐藏。这样整个项目的图层状态只占一个变量读写一次就够不用维护几十个 BOOL。为什么不用几十个 BOOL 变量一是脚本里读 32 次和读 1 次的差别在低配工控机上体现得很明显二是状态字方便做整体操作比如“恢复默认视图”就是往变量里写一个常量三是备份和复位简单清 0 就是全部隐藏写0x1F就是前五层可见。如果项目里还要记录操作日志一次写变量也好过连写几十条。 状态字约定bit0bit31 依次对应 L00L31 常量集中定义改约定只改这里 Const LAYER_BASE_VISIBLE 31 前五层默认可见二进制 0001 1111默认视图的初值一般在画面启动时写入或者干脆在 PLC 侧或全局脚本里初始化一次。我倾向于在启动画面里初始化理由很实际现场调试时要能一个人把默认值改掉重看效果不用去动全局脚本。3.2 逻辑层图层管理器的函数划分与调用时机图层管理器不用做成多复杂的东西三个函数就够ApplyLayer(sPrefix, bShow)负责把当前画面里匹配前缀的对象统一设成显示或隐藏WriteLayerBit(iBit, bShow)负责把状态写回状态字ReplayLayers()负责在画面打开时按状态字把本画面的图层重放一遍。前两个被按钮调用第三个挂在画面的事件上。调用时机很关键我一般固定三处画面打开事件OnOpen重放状态图层按钮点击OnClick切换并写状态权限切换或用户注销之后强制回到默认视图。第三处最容易被漏掉结果是高权限用户开着维护层走了换操作工上来维护按钮还亮着这就是个实实在在的隐患。还有一个设计取舍要提前定状态字是全局的还是每画面一份全局的实现简单但不同画面对“第 5 层”的定义必须一致每画面一份灵活代价是要多维护一张对照表。中小项目我一般用全局状态字 严格统一的图层编号表够用且不容易乱。画面特别多、图层含义差异大的项目才拆成每画面独立。3.3 交互层按钮、权限与状态回显怎么串起来按钮本身要做三件事判断当前状态、执行切换、把结果反馈给操作工。第三件经常被忽略导致按钮按下去没反应操作工以为死机其实是他没有权限。我一般把图层按钮做成两种形态。工具栏上的小按钮用图标或文字切换比如“参数”按钮在面板打开时高亮画面角落的锁形按钮只负责切换整组维护层按下后弹出确认。权限判断一定要写在脚本内部而不是只依赖按钮的“权限”属性——按钮的权限属性拦得住鼠标拦不住别的地方调用这个脚本。 从内部变量读当前登录用户做图层权限校验 Function CanOpenLayer(ByVal iBit) Dim sUser sUser HMIRuntime.Tags(CurrentUser).Read Select Case iBit Case 7, 8 L07、L08 属维护层 CanOpenLayer (sUser And sUser operator) Case 5, 6 L05、L06 属班组长层 CanOpenLayer (sUser And sUser operator) Case Else CanOpenLayer True End Select End FunctionCurrentUser是用户管理里的当前用户名没登录时读到空串。不同版本对这个内部变量的支持略有差别上线前先在测试画面上打一行日志确认能读到值别直接照抄。用户组名按项目实际的用户管理配置来改我这里用operator只是举例。4. 关键实现命名约定、批量脚本与动态化配置设计定完落地就三件事对象名字要能被脚本找到、脚本要能正确处理组对象、不写脚本的部分要配到位。这三件事任何一件出问题表现都是“按钮点了没反应”排查起来很折磨人。4.1 命名约定与对象清单让脚本找得到对象WinCC 的 VBS 里画面对象通过名称访问脚本能拿到的判断依据主要是ObjectName。所以命名不是风格问题是接口问题。约定四条前缀固定四位且大写前缀后紧跟英文功能名用下划线或驼峰都行但全项目统一同一个逻辑元素拆成多个图元时全部带同一前缀例如L04_AlarmBar_Text、L04_AlarmBar_Bg组对象本身也要带前缀否则递归进去的入口就没了。画面上对象一多光靠肉眼核对前缀很不靠谱。我一般让脚本自己数一遍做一张对象清单跟设计文档对照 图层自检统计每个图层前缀下的对象数量 Sub LayerAudit() Dim d, n, o, k Set d CreateObject(Scripting.Dictionary) For n 0 To Screen.Items.Count - 1 Set o Screen.Items(n) k Left(o.ObjectName, 4) 取前四位当前缀 If Left(k, 1) L Then If d.Exists(k) Then d(k) d(k) 1 Else d.Add k, 1 End If End If Next For Each k In d.Keys HMIRuntime.Trace 图层 k 对象数 d(k) vbCrLf Next End Sub这段只统计顶层对象跑一次就能发现两类问题某个图层一个对象都没有编号写错了或者漏了前缀某个图层对象数比文档多后来加的对象没登记。我在项目里会把它挂在一个隐藏的诊断按钮上交付前跑一遍比人工翻画面快得多。4.2 VBS 批量切换的实现与递归处理核心难点是组对象。画面上的管道、阀门经常被编成一个组脚本只遍历顶层就只能改到组本身组里面的图元仍然按原样显示。所以必须往下递归。 把当前画面里带指定前缀的对象统一设成显示或隐藏 Sub ApplyLayer(ByVal sPrefix, ByVal bShow) Dim n, o For n 0 To Screen.Items.Count - 1 Set o Screen.Items(n) If Left(o.ObjectName, Len(sPrefix)) sPrefix Then o.Visible bShow End If WalkGroup o, sPrefix, bShow 组对象继续向下钻 Next End Sub 递归处理组对象内部成员普通对象没有 Items按错误跳过 Sub WalkGroup(ByVal oParent, ByVal sPrefix, ByVal bShow) Dim c On Error Resume Next For Each c In oParent.Items If Err.Number 0 Then Exit For If Left(c.ObjectName, Len(sPrefix)) sPrefix Then c.Visible bShow End If WalkGroup c, sPrefix, bShow Next Err.Clear End SubScreen指当前画面Screen.Items.Count是顶层成员数ObjectName是对象名Visible就是要改的属性。On Error Resume Next在这里是权宜之计普通图元没有Items集合访问就报错靠错误跳过比判断类型更省事。但正式项目里我建议先判断对象是否支持子集合再用On Error兜底否则一旦有别的错误也被一并吃掉排查时连线索都没有。按钮事件把三层串起来Sub OnClick(ByVal Item) Dim dw, bShow dw CLng(HMIRuntime.Tags(LayerState).Read) bShow ((dw And 32) 0) 第 5 位为 0 表示当前隐藏点击后显示 If Not CanOpenLayer(5) Then HMIRuntime.Trace 无权限打开 L05 vbCrLf Exit Sub End If ApplyLayer L05_, bShow If bShow Then dw dw Or 32 Else dw dw And (Not 32) End If HMIRuntime.Tags(LayerState).Write dw End Sub这里32就是2^5对应第 5 位。CLng不能省VBS 里位运算碰到浮点会出意外结果。权限判断放在切换之前避免先改了画面再判断出现“闪一下又弹回来”的诡异现象。画面打开时重放状态Sub OnOpen() Dim dw, i dw CLng(HMIRuntime.Tags(LayerState).Read) For i 0 To 8 只重放本画面用到的图层 ApplyLayer L Right(0 CStr(i), 2) _, ((dw And CLng(2 ^ i)) 0) Next End Sub注意循环上界写的是 8不是 31。每调用一次ApplyLayer都要遍历一遍画面对象循环 32 次就是 32 遍全遍历画面对象多的时候打开会明显迟钝。只重放本画面实际用到的图层是这里最有效的一步优化。4.3 C 脚本版本什么时候必须换语言VBS 写起来舒服但在两种情况下我建议换 C 脚本一是老项目或者低配工控机逻辑一多就感觉按钮有延迟二是需要调用 WinCC 里只有 C 接口才提供的函数。C 版本的思路完全一样只是改成逐个对象调用SetVisible#include apdefap.h void OnClick(char* lpszPictureName, char* lpszObjectName, char* lpszPropertyName) { /* 一次处理一个图层的成员对象名已按前缀约定命名 */ SetVisible(lpszPictureName, L05_ParaPanel, FALSE); SetVisible(lpszPictureName, L05_ParaTable, FALSE); SetVisible(lpszPictureName, L05_ParaFooter, FALSE); /* 状态写回状态字供画面打开时重放 */ DWORD dw GetTagDWord(LayerState); dw ~(1u 5); /* 清第 5 位 */ SetTagDWord(LayerState, dw); }lpszPictureName是当前画面名SetVisible的第三个参数是目标状态GetTagDWord/SetTagDWord读写 32 位变量。C 版本没法像 VBS 那样遍历集合只能一个对象一行这是它的短板——图层里对象一多代码就长得没法看而且改画面就得改代码。折中的办法是用 C 脚本按位写状态字把批量设置可见性的活儿留给 VBS各干各擅长的事。真要追求速度可以用 C 脚本配合对象名数组循环把对象名集中在一张表里但维护成本会上升中小项目没必要。4.4 不写脚本的做法动态化对话框绑定变量不是所有隐藏都要写脚本。对象少、关系固定的时候直接在动态化对话框里给“显示”属性绑一个 BOOL 变量最省事改起来连代码都不用看。典型用法是给画面窗口控件的“显示”属性绑定变量或者给某段说明文字绑定LayerState的某一位。这里有个坑要提前说变量绑定是“跟随”关系变量一变属性就变脚本是“一次性”动作改完就结束。两者混用的时候同一层既绑了变量又被脚本改就会出现“按下去又弹回来”的现象。我的做法是一层只用一种方式脚本管理的图层对象上就不要绑可见性变量。顺便说一句图层可见性和对象“使能”属性是两回事。隐藏一个按钮按钮看不见也点不到把按钮设成禁用它还在那儿只是变灰。维护层的按钮我倾向用隐藏因为它压根不该出现在操作工的视野里工艺条件不满足的操作才用禁用加提示文字。5. 避坑与排查图层方案最容易翻车的五个点5.1 隐藏不生效先查组对象、前缀和事件挂载现象按钮点下去画面上大部分元素隐藏了但管道里几个阀门还在。原因这些阀门被编成了组脚本只遍历到组本身组内成员没跟着变或者组对象的名称没带前缀递归的入口就断了。解决确认组对象自身带前缀并且WalkGroup真的被调用到。排查时在递归里加一行HMIRuntime.Trace c.ObjectName vbCrLf把钻进去的对象全打出来一眼就能看出断在哪一层。现象某个对象无论怎么点都不隐藏。原因前缀拼错L05写成L5或者大小写不一致字符串比较不匹配也可能这个对象是后来加的压根没起名前缀。解决跑一遍 4.1 里的自检脚本对比对象数量命名统一大写前缀长度用Len(sPrefix)动态取不要写死。现象画面打开时图层状态是乱的像“回放旧状态”。原因OnOpen没挂上或者挂在画面的事件里但函数名写错OnOpen大小写敏感。解决在OnOpen里先Trace一行确认事件确实进得来再看状态字的值是不是上一次留下的。5.2 隐藏生效但行为异常点击穿透与闪烁现象图层隐藏后原位置还能点到东西或者点到下面的按钮。原因用改背景色、改透明度的方式“假隐藏”对象仍然响应鼠标也有的是用了画面窗口叠加窗口本身还占着位置。解决一律用Visible属性不要靠颜色伪装。如果确实需要“看得见但不能点”那要用使能属性并配灰显别和隐藏混为一谈。现象切换时画面明显闪一下或者面板先消失再出现。原因先改了某个对象、又改回来中间状态被刷出来了常见于脚本里写了两次相反的赋值或者按钮事件和变量绑定同时生效。解决一层只保留一条控制路径。脚本里先把目标状态算完再统一赋一遍不要边算边改。5.3 状态丢失与性能拖慢现象切到别的画面再切回来之前隐藏的图层全亮了。原因状态只存在画面对象上没写回状态字或者写回了但OnOpen没做重放。解决每次切换必须同时做两件事——改画面、写状态字。这两步写在一个函数里别拆开拆开就一定有人漏。现象对象多的画面点图层按钮要等一两秒才有反应操作工以为卡死连点好几下。原因每次点击都全画面遍历甚至嵌套递归里反复访问集合或者OnOpen里循环了全部 32 层。解决只处理目标前缀只重放本画面用到的图层必要时把对象集合先缓存到数组里复用。按钮点击后立刻改按钮自身的高亮状态做即时反馈操作工就不会连点。注意连点导致的状态错乱很难复现但在现场确实会发生。按钮事件开头加一个简单的防抖标志位能省掉很多排查时间。6. 验收与答辩用一张检查表和一段自检脚本证明图层是可靠的图层这种东西演示时点两下看着都对一验收就露馅。我一般按下面这张表逐项过一项不过就不算完成检查项验证方法通过标准图层前缀完整跑LayerAudit与编号表逐行对比无空层、无未登记对象组对象递归生效隐藏含组对象的图层逐一点击组内图元原位置组内成员全部不可见、不可点状态持久性切换图层后进出其他画面三次返回后状态与离开时一致权限边界用操作员账号点维护层按钮无变化且有日志记录默认视图复位注销后重新登录回到 L00L04 可见响应速度在对象最多的画面上连续切换五层无明显迟滞、无闪烁答辩演示有个小技巧别只演“点一下藏起来”要演“藏起来之后状态还在”。顺序是先打开参数层切到工艺画面再切回来让评委看到状态被记住再用低权限账号点维护层让评委看到被拦住。这两个动作一做完方案的说服力比讲十分钟设计思路强。现场留个后手也重要。我习惯在画面角落放一个隐藏的诊断入口点开就跑一次自检脚本把各图层的对象数、当前状态字的值打出来。调试期靠它定位问题交付前把它连同状态字一起复位。这套东西我第一次做的时候没当回事觉得按钮能隐藏就算完事结果现场换型时操作工把维护层打开了关不掉电话打过来我只能在电话里指挥他切画面。从那以后我每次做图层都强制走一遍状态字先定、编号表先写、自检脚本先挂三项齐了才动手画对象。希望帮到你。本文还有配套的精品资源点击获取
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。