简介:这是一份西门子WinCC项目案例,聚焦画面图层的隐藏与显示,面向工业自动化工程师和SCADA系统开发者,用于解决人机界面动态展示与交互控制中的实际问题。资料系统梳理了图层概念、画面设计、VBS脚本编程、事件驱动机制,并给出通过按钮事件改变图层可见性的实现思路,兼顾基础理解与工程应用。压缩包内共298个文件,整体约10.1MB,文件类型以rpl、pdl、cfg、ini为主,覆盖项目数据、画面定义与配置信息,还包含图层控制相关的dcf文件,类型较全面,便于查阅。目前已有2284人学习,对于需要在WinCC中灵活控制图层显隐、实现复杂动态效果的开发者具有一定参考价值。借助其中完整的项目文件和示例脚本,可快速掌握图层独立可见性控制技巧,将隐藏图层用于数据加载提示、错误告警弹层等场景,从而提升系统可读性和交互体验,并让项目逻辑更清晰、维护更高效。
1. WINCC画面图层的隐藏显示是组态基本功,也是把画面“做活”的关键
很多刚接触WINCC的工程师会把一台设备的所有状态、按钮、提示都塞进同一个画面,结果画面越改越乱,运行时想临时隐藏一块区域只能靠移动对象。实际上WINCC早就提供了图层机制:把同类对象放进一个图层,用图层可见性控制整组显示或隐藏。wincc画面图层的隐藏显示就是利用这个机制,在开发期或运行期按条件切换画面内容,常用于多工况切换、报警提示浮层、维护界面复用等场景。这篇笔记适合正在做项目组态、被画面越堆越乱困扰的工程师,按下面步骤走,一个小时就能把图层体系搭起来。
2. 图层机制拆开看:对象归属、可见性规则与图层总量限制
2.1 图层是画面对象上的“层号”,不是独立容器
图层这个概念容易和画面窗口混淆。画面窗口是单独的页面实例,可以整体嵌入、移动;而图层是WINCC画面内部自带的一种“标签”,每个画面对象在创建时都会落到某个图层上。常见做法是在对象属性的“其他”分组里找到“图层”这一项,默认值是0或其他初始号。这就意味着图层并不是一个能往里面拖对象的容器,而只是一个编号属性。
实际组态时,你会看到图层管理界面里有一排图层,每个图层对应一个显示名称。把对象划归到某个图层,本质上是修改对象的图层编号。这个编号只对当前画面生效,另一个画面即使图层名称一样,也不会互相联动。项目里如果多个画面要统一风格,得在每个画面里分别建立同名的图层规划,或者复制整个画面再改内容。
图层机制的另一个特征是它属于画面属性,不属于单个对象。你用脚本隐藏一个图层,画面里所有位于该图层的对象会一起消失,而不需要逐个设置对象的“可见性”。这一点在运行期切换场景时非常省事——不需要遍历几十个ScreenItem去置Visible属性,只要改图层状态即可。这也是图层相比“给每个对象单独做变量可见性”最大的优势:维护成本低,一个图层一个条件就够了。
2.2 图层的可见性规则:隐藏后连开发期都看不到
WINCC对图层的隐藏显示有一个容易忽略的规则:开发环境里取消图层的“可见”勾选,画面编辑器里该图层上的对象也会不可见、不可选中。这意味着你在组态界面时如果误隐藏了图层,对象就像凭空消失了一样,不是被删掉了,而是“看不到了”。这个规则既方便开发期预览运行效果,也容易让人踩坑,后面避坑章节会专门展开。
从运行期的角度看,图层的可见性状态在画面被打开时生效。如果你在开发环境直接取消勾选某个图层并保存,运行时该图层默认就是隐藏的;如果运行时通过脚本或变量改变了可见性,那么只影响当前运行进程,画面关闭再打开时会回到初始保存状态。所以“运行时改了之后能不能记住”这个问题,答案是记不住,需要在画面打开事件里做初始化恢复,这一点决定了你把图层当“状态开关”用还是当“一次性显示”用。
2.3 图层总量与对象分配边界:哪些对象不该放进图层
每个WINCC画面能创建的图层数量不是无限的,常见版本里默认提供的图层数在8个左右,数量不足时可以在图层管理器里自行增加,但也不是无限制增加,过多图层会让图层管理器变得难用,维护成本迅速上升。我的习惯是每个画面最多用5到6个用户图层,分别对应:流程主图、运行状态、报警提示、维护浮层、备用扩展。
在分配对象时要考虑一个边界问题:操作按钮能不能放进可隐藏的图层。如果某个按钮放在图层2上,而运行时图层2被隐藏,这个按钮就不存在了,操作人员根本按不到它。所以最关键的操作按钮、退出按钮、画面切换按钮,一定要放在一个永久的、不参与隐藏的图层里。如果确实需要把整组操作浮层隐藏,那就要保证有另一个外部入口能把它调出来,否则按钮跟着图层一起消失,系统就“死”在某个状态里了。
3. 开发期静态隐藏显示:从图层分配到批量改属性的完整操作
3.1 先画一张图层分配表:对象分组比操作顺序更重要
动工之前先把要放进画面的对象分好类。拿一个典型的泵站监控画面举例,工艺流程管线、泵组状态、阀门状态是主画面,任何时候都要显示;设备故障闪烁提示、检修时打开的说明框、操作指导浮层则属于按需出现的内容。把这两类对象分开,前者放主图层,后者进提示图层或维护图层。
我在项目里会做一张表格,贴在项目文件夹里。下面是一份示例结构:
| 图层编号 | 规划用途 | 典型对象 | 默认可见性 |
|---|---|---|---|
| 0 | 永久主图层 | 流程管线、泵阀图标、总貌按钮 | 可见 |
| 1 | 运行状态层 | 设备启停状态、实时参数文本 | 可见 |
| 2 | 报警提示层 | 闪烁报警块、语音提示位图 | 可见 |
| 3 | 维护浮层 | 检修说明、密码输入框 | 隐藏 |
| 4 | 备用 | 后续增加的内容,避免挤占其他层 | 隐藏 |
表格的价值不只在开发期,还在于运行后维护。项目交出去,操作员反馈某个画面多了一块东西,你能根据图层号快速定位,而不是在几十个对象里挨个找。所以第一步不是打开软件,而是先把图层分配表画出来。
确定分组之后,打开画面编辑器,右键画面空白区域,在弹出菜单中找到“图层”或“Layer”相关入口,打开图层管理器。在里面把需要用的图层重命名,比如把2号图层改成“报警提示”,让后续识别更直观。重命名不影响对象的图层编号,旧对象仍然挂在原编号上。
3.2 批量把对象放进目标图层:多选与属性窗格统一修改
给单个对象设置图层很简单:选中对象,在属性窗格的“其他”分组里找到“图层”,输入目标编号即可。但画面里往往有成组对象,从模板导入的设备符号可能有几十个,一个一个改不现实。常见做法是按住Ctrl或Shift多选对象,然后统一在属性窗格里修改图层号。
批量修改时要注意一点:混合选择会把你不想移动的对象也一起改掉。我的操作流程是先通过“对象选择器”或者“查找功能”把同一类对象筛出来,比如筛选所有TagConnection开头的文本,再统一设置图层号。如果你用的版本支持按对象类型过滤,这一步会非常快,否则就手动多选后再看一眼状态栏里的对象数量。
另外还有一个技巧:先把目标图层设为唯一可见。操作方法是回到图层管理器,把其他图层的可见勾选全部去掉,只保留目标图层可见。此时画面编辑器里只能看到目标图层的内容,你一眼就能确认哪些对象属于这个图层、哪些对象漏在外面,补选时更精准。确认完再把可见性恢复。
3.3 静态隐藏与显示:在图层管理器里勾选可见性
静态隐藏显示就是直接控制图层管理器中每个图层前面的“可见”勾选项。取消勾选后,该图层上的所有对象在开发画面中隐藏;勾选后恢复。由于这个操作是保存进画面文件里的,所以它适合做“默认状态”,比如默认隐藏维护浮层,只有运行后通过按钮调用才出现。
有人会把图层管理器里的可见性和运行时变量混在一起用:开发期把可见性勾选取消,运行期再靠变量把图层打开。这个思路可行,但要注意一个前提——图层管理器里的可见性勾选是“初始状态”,变量控制则是“运行期覆盖”。如果你开发期就把图层设为隐藏,运行期通过动态向导绑定变量去显示它,这是正常的;但如果某个图层被其他逻辑写成了隐藏,而你在开发期勾了“可见”,运行时不一定能覆盖,优先级问题很容易变成玄学。
因此我建议把静态可见性当作“默认值”来管理,而不是当作唯一的控制手段。开发期阶段,取消勾选只是为了预览效果,真正提交项目前要把所有图层恢复到生产需要的默认状态,避免保存后才想起来“这个图层不该显示”。每次准备生成最终版本之前,我都会花两分钟把图层管理器逐层过一遍,这是最简单也最容易被遗漏的一步。
4. 运行期动态隐藏显示:动态向导、变量关联与脚本三种方式
4.1 用动态向导“图层可见性”把图层和变量绑定
运行期动态隐藏显示,最标准的做法是使用WINCC的动态向导功能。在画面编辑器中右键画面空白区域,打开“动态更新向导”或英文原版的Dynamic Wizard,找到“编辑画面/图层可见性”这一类条目。不同版本菜单叫法略有差异,直接按“Layer Visibility”关键字搜索也可以定位。
向导会列出当前画面的所有用户图层,并让你为每个图层设定显示条件。在这里可以选择“由变量控制”,然后关联一个变量并给出比较值。例如我给“报警提示”图层设定的条件是:图层2在变量SceneTag等于1时显示,SceneTag等于其他值时隐藏。这样运行期只要把SceneTag改成1,整个报警提示层就浮上来,改回0就消失,不需要写任何脚本。
这个环节有两个关键参数要提前想好。第一,变量的类型尽量选无符号整数或整数,不建议用浮点数,因为浮点比较在组态环境里容易出现精度问题,而且图层切换用整数足够。第二,变量的作用域。只在这个画面用的场景变量放在内部变量里,免得被外部通讯写乱;如果需要在多个画面里同步图层状态,那再考虑全局变量或外部变量。
关联完成后,动态向导会自动生成一段关联逻辑,它会监听变量值变化并实时刷新图层可见性。编译画面后,你可以先把变量表打开,手动修改该变量的值,看画面上的图层是否跟着变化。这是验证图层配置最直接的途径,比写一大堆脚本再调试要快得多。
4.2 通过按钮和输入域改变变量,运行期实时切换
变量绑定完成之后,剩下的工作就是给操作员一个入口。最简单的方案是放两个按钮,一个按钮控制场景A,一个按钮控制场景B。按钮的鼠标动作脚本里只写一行赋值:
SetTagWord("SceneTag", 1); // 按下后切换为场景1另一个按钮则赋值0。代码很好理解:第一行调用了WINCC标准接口SetTagWord,把内部变量SceneTag的值写成1。参数说明里,SceneTag是上一节在动态向导里绑定的那个整数变量,“1”对应的是向导中设定的显示条件。动态向导一旦监听到变量变化,就会自动刷新相关图层的可见性。
这段脚本看起来简单,但它是整个图层联动里最重要的“最后一公里”。很多人喜欢在按钮里写一个长长的脚本,逐个操作画面对象,其实完全没有必要。你要相信动态向导已经把“变量值到图层显示”的映射做好了,按钮脚本只需要负责改变量值,职责单一,排查问题也容易。
如果你需要控制多达几十个图层,不要给每个图层配一个变量。用一个整数变量,二进制位的每一位对应一个图层,或其他按值匹配的方式都可以。比如把变量值看成场景号,0是主画面,1是报警层,2是维护层,3是备用。这样画面里最多需要的按钮数量就是场景数量,而不是图层数量,维护起来清爽很多。
4.3 脚本控制图层的边界:推荐变量法,慎用直接API
除了动态向导,WINCC的C脚本接口里也能找到直接操作图层可见性的函数,常见形式是通过传一个图层掩码数组来设置哪些图层显示、哪些隐藏。这种方式在运行时更直接,不需要预先在向导里绑定变量,但它的缺点也很明显:不同版本的函数签名和参数顺序可能有差异,写错了编译不报错,运行时却没有任何效果。
我一般不建议在项目里直接调这种API,除非你非常确定当前项目版本下的函数定义,并且在开发机上做过多版本验证。更稳妥的做法是回到上文的变量法:动态向导负责图层映射,脚本只负责写变量。如果遇到“必须在某个事件里一次性切换多个图层”的场景,也不要去拼掩码,直接给场景变量赋一个值,让向导去处理那一组关联就好。
这里还要区分一个容易走偏的点:动态向导绑定变量之后,图层的当前状态就是“变量值的映射结果”。如果你非要再用SetLayerVisible之类的函数把某个图层直接隐藏,那么当变量再次变化时,向导会以变量值为准刷新状态,你之前用脚本设置的效果会被覆盖。这两个机制同时使用容易产生互相打架的现象,所以一个项目里建议只采用一种控制路径,不要今天用向导、明天用脚本,后期排查时会非常痛苦。
5. 图层隐藏显示的避坑与排查:四个高频翻车现场
5.1 运行时图层不切换:先查变量类型与按钮图层归属
现象:按钮按下,画面纹丝不动,该出现的浮层没有出现。把变量表调出来看,变量的值明明已经变化了,但画面里的图层就是不动。
原因一般有两种。第一种是动态向导里绑定的变量类型和按钮脚本写入的类型不一致,比如向导里关联的是无符号32位变量,脚本里用的是SetTagWord,写入的只是一个16位整数,部分版本会产生类型不匹配,联动逻辑不触发。第二种更隐蔽:你用来切换图层的按钮,它本身放在了那个被隐藏的图层上。运行时按钮一旦随图层隐藏消失,操作人员的第二次点击就落空了。
解决方法是先把按钮移动到永久显示的图层,比如0号主图层,再核对向导里绑定的变量名和脚本里写入的变量名是否完全一致,包括大小写和前缀。按这两个方向排查,绝大多数“图层不切换”的案例都能定位到。
5.2 打印时隐藏图层又冒出来:打印配置与显示图层不一致
现象:屏幕上运行显示一切正常,该隐藏的浮层全部藏得好好的,但操作员点打印报表,打印出来的画面里浮层内容赫然出现在纸上,客户收到纸质版后还以为是你的画面做错了。
原因是WINCC的打印功能默认并不会完全继承屏幕上的图层可见性。打印任务有自己的打印内容筛选,有的版本打印对话框里提供图层相关选项,有的版本默认把所有图层按“全部打印”处理,导致屏幕上隐藏的图层在打印任务里被原样输出。
解决时要分两步:先检查打印任务或打印对话框里有没有“图层”筛选选项,把它设为“按当前显示状态打印”或“仅打印可见图层”;如果打印对话框没有这个选项,那就需要单独准备一个打印专用画面,复制一份主画面并把需要打印时隐藏的图层直接删除,打印这个专用画面,绕过图层可见性的干扰。处理完以后一定要用打印预览确认一次,不要等纸质产出来了再看。
5.3 画面重开图层状态丢失:打开画面事件里恢复初值
现象:运行中切换图层一切正常,但操作员关闭这个画面再重新打开,画面回到了初始状态,之前选好的场景全部失效,必须再点一次按钮恢复现场。
原因是图层的运行时可见性状态没有被持久化。你通过变量或脚本在运行时改了图层的显示状态,这个状态只存在于当前进程里。画面重新打开时,WINCC读取画面文件里的初始值,文件里保存的是你在开发期设定的状态,自然不是你运行期最后的状态。
解决方法是把“图层状态恢复”放进画面的打开事件脚本。画面打开事件里读一遍场景变量的当前值,如果变量值是无效的、超过你的场景范围,就把它重置为默认场景号。如果项目要求记忆上次状态,也可以把场景号写入一个保持性变量或归档变量,打开画面时把它读出来赋给场景变量。这一点和做历史趋势曲线脚本时遇到的“变量初值”问题很相似,第一次吃过亏之后你就会习惯所有动态状态都要在打开事件里显式恢复。
5.4 对象在图层里“失踪”:开发期别急着删,先把图层全部打开
现象:开发环境里刚画好的设备图标忽然从画面上消失了,对象列表里还能看到,但编辑器里怎么都选不到,以为被人删了,急得满头汗。
原因是误操作把某个图层的可见勾选取消了,而图标恰好挂在这个图层上。由于图层隐藏后对象在编辑器里也不可见、不可选,看起来就是“丢”了,实际上只是被藏起来。
解决的顺序是:先打开图层管理器,把每一个图层的“可见”全部勾选上,再看消失的对象是否回来。回来后就说明只是可见性问题,对象没有丢。为了避免这个问题反复出现,我养成了一个习惯:每天结束组态工作前,把所有图层可见性恢复为全开再保存,第二天打开项目就不会“找不到东西”。如果你是在运行时状态下发现对象失踪,那大概率是某个场景变量把图层切走了,直接查场景变量的当前值,不要动开发环境。
6. 再进一步:用单变量做一键场景切换与画面状态恢复
6.1 单变量切换两组图层的按钮脚本
前面的方法只能让画面按固定场景切换,要想像遥控器一样一键轮换两个场景,可以在按钮脚本里写一个简单的状态翻转。这里我以内部变量SceneNo为例,它在动态向导里控制两套图层的可见性。
// 场景切换按钮:SceneNo为内部无符号整数变量 // 动态向导中已经配置:SceneNo=0显示主图层,SceneNo=1显示维护浮层 int nScene; nScene = GetTagWord("SceneNo"); // 读出当前场景号 if (nScene == 0) // 当前在主场景 { SetTagWord("SceneNo", 1); // 切换到维护浮层场景 } else // 当前在维护浮层场景 { SetTagWord("SceneNo", 0); // 切回主场景 }这段脚本的逻辑很直白:每次点击都把SceneNo在两个值之间翻转。GetTagWord读出的返回值是当前场景号,SetTagWord写回新值,动态向导监听到变化后自动刷新图层。参数说明里要特别注意:SceneNo的变量类型必须和向导绑定时的类型一致,都是无符号16位整数,避免类型错位;如果你的画面有多个场景,把if改成nScene = (nScene + 1) % 3,就能在三个场景之间循环。
6.2 画面打开事件里的状态恢复
配合一键切换,还需要在画面打开事件里做一次状态校正。运行期间用户切到维护浮层后如果直接退出整个项目,SceneNo变量可能停在1,下次重新打开项目时画面会直接显示维护浮层。如果你希望画面打开时永远从主场景开始,可以在画面打开事件里加上一段初始化脚本。
// 画面打开事件:确保SceneNo始终从有效场景开始 // 本画面定义了三个场景:0主图层、1报警浮层、2维护浮层 int nInit; nInit = GetTagWord("SceneNo"); if ((nInit < 0) || (nInit > 2)) // 变量值不在合法范围内 { SetTagWord("SceneNo", 0); // 强制回主场景,避免画面进入未知状态 }这里为什么要加合法性判断?因为场景号来自内部变量,掉电工况下它可能保持上一次的值,如果这个值不在向导配置的比较值集合里,图层会处于一个不可预期的组合状态。加一个范围判断就能把这种场景“兜住”,让画面打开时永远落在你配置过的状态上。
6.3 我的验证顺序与维护习惯
编完脚本之后不要急着打包,先按下面的顺序过一遍:编译画面并把项目激活;打开变量管理窗口,把SceneNo强制设为0,确认主图层对象显示、浮层对象隐藏;再分别强设为1和2,逐项核对图层切换;关闭画面再重新打开,确认初始化生效;最后做一次打印预览,确认隐藏图层不会从打印机里跑出来。这五步都通过,这套图层控制就算可靠了。
最后说一个我自己的血泪经验:早年间做画面,图层映射全记在脑子里,过了三个月连自己都看不懂某个对象为什么在3号图层上。后来我养成了两个习惯——第一,每个画面把图层用途写在备注里;第二,每次保存前把所有图层可见性恢复为全开,并记录一张图层分配表,放在项目文件夹的第一页。图层不是玄学,只要把规则和状态恢复都理顺,它就能稳定地替你管理画面内容。希望这些方法对你也有用,少走点我当年走过的弯路。
本文还有配套的精品资源,点击获取