简介:面向工业自动化与SCADA系统开发者的WinCC画面图层控制实践资源,适合正在学习WinCC组态、或需实现画面动态交互的工程师。资源以实际项目案例形式,完整展示图层隐藏/显示功能的实现过程:包含rpl、pdl等WinCC画面与项目文件,以及sav、mdf等数据库及日志文件,还有用于控制图层可见性的VBS脚本与配置文件,共298个文件,压缩包约10.1MB。通过研读示例中的脚本逻辑与事件驱动方式,读者可掌握用代码切换图层可见状态的具体方法,理解图层管理在复杂画面设计中的组织作用,并学会将隐藏图层用于数据加载、错误提示等交互场景,提升WinCC项目的灵活性与可维护性。目前已有2283人学习下载,对希望深入WinCC项目案例、快速上手图层控制的中高级组态工程师具有直接参考价值。
1. WinCC 画面图层隐藏显示:现场调试最常见的软钉子
做 WinCC 项目组态的人,几乎都撞过这道坎:画面上的弹窗、报警条、操作面板叠在一起,工艺画面被盖住一半;或者操作员要找某个面板,翻遍画面窗口找不到入口。问题的核心就是画面图层的隐藏显示没做好。WinCC 本身没有像 CAD 那类直观的图层管理器,工程上靠的是对象命名、动态属性、C 脚本和画面窗口的配合,把一批对象组织成逻辑图层,按条件显示或隐藏。这份 WinCC 项目案例正好把我踩过的完整套路拆出来了:从命名规范到脚本实现,从变量联动到报警弹窗强制显示,再到授权、偏移、脚本报错这些高频坑。适合刚接 WinCC 工程的组态工程师,也适合接手别人项目时快速理清画面层级关系的调试人员。
2. 先搞懂图层机制:对象可见性、动态属性与三套方案选型
2.1 WinCC 没有“图层面板”,所谓图层是对象可见性的分组管理
初学 WinCC 时,我总想找一块像 PS 或 CAD 那样的图层面板,把对象往不同层一拖,想显示哪层就显示哪层。找了一圈发现,WinCC 图形编辑器里并没有这种可视化图层管理器。虽然画面对象内部有层信息,但工程上说的“图层”,本质是一批对象的可见性集合:给它们一套统一的命名规则,再用同一个变量、同一条脚本或同一个画面窗口去驱动它们的“显示/隐藏”属性。
画面对象的“显示/隐藏”属性在对象右键的属性对话框里,通常位于“其他”类别下,英文版叫 Visibility 或 Display。这个属性最右侧有闪电图标,点开是动态对话框,可以把属性的取值交给变量或表达式来决定。这就是 WinCC 图层控制的底层机制:先有对象属性,再绑定驱动源,最后归组成图层。
把机制理解清楚再动手,比一上来抄脚本重要得多。图层的坑大多出在驱动源的冲突上,比如动态对话框和脚本同时控制同一个对象,后写的那一遍未必生效,甚至会出现画面闪烁。
2.2 三套方案对比:动态对话框、C 脚本、画面窗口复用
| 方案 | 实现方式 | 适用场景 | 注意点 |
|---|---|---|---|
| 动态对话框 | 属性对话框里选变量或表达式 | 单个或少量对象,条件固定 | 表达式写错不报错,现场难查 |
| C 脚本 | SetVisible、SetTagBit 等函数驱动 | 批量对象、复杂联动、按钮控制 | 语法严格,标点容易踩坑 |
| 画面窗口复用 | 一套画面 + 变量前缀 + SetPictureName | 多台同工艺设备复用同一画面 | 对象坐标与变量名需要统一 |
动态对话框是 WinCC 最省事的办法。比如让某个指示灯在变量为 1 时显示、为 0 时隐藏,在动态对话框里把表达式写成“TagA@Bit0”,结果表填好 0 和 1 对应值即可,不需要写任何代码。但它的缺点藏得深:表达式语法错了,系统不会在编译期报错,运行时只是属性不变,现场排查时很难发现是这里出了问题。
C 脚本是图层控制的主力。它可以把一个按钮事件里完成“隐藏旧图层、显示新图层、置位状态变量”一串动作,逻辑集中、可读性好。代价是 WinCC 的 C 脚本走 ANSI C 标准,对语法要求苛刻,中英文标点混用、变量声明位置不对都可能导致编译失败。
画面窗口复用适合设备多、画面结构相同的项目。把公共画面放进画面窗口,通过窗口的“变量前缀”属性,让同一套画面在不同设备实例中读取各自的变量;再配合 C 脚本里 SetPictureName 动态切换内嵌画面,就能搭出“一套模板管十台设备”的层级结构。很多项目里说的组显示控件,其实就是这个思路的具体应用。
2.3 我的选型经验:按“数量和联动复杂度”决定
三套方案不是互斥的。我在项目里按两条线来选:对象数量少、条件固定,优先动态对话框;对象多、条件有交叉、需要联动,优先 C 脚本;画面结构重复度高,优先画面窗口复用。
具体到图层隐藏显示这个场景,我一般以 C 脚本为核心。原因是图层的控制逻辑大概率会在调试阶段反复改,比如“报警时弹窗要置顶”“工程师登录后才能看到参数层”,这些逻辑集中在脚本里,改动时影响面小。动态对话框适合那些定死不变的显示条件,比如某台设备永远显示、某块区域永远隐藏。这个原则写在这份项目案例的开篇部分,后面的脚本也都是按这个思路组织的。
3. 搭一套可复用的图层控制:命名规范、C 脚本与画面窗口
3.1 第一步:图层分组与对象命名规范
图层控制的第一步不是写脚本,而是定命名规范。WinCC 画面里的对象,默认名是“对象3”“多边形5”之类,靠这种名字根本没法组织图层。我习惯把所有参与图层控制的对象,统一按“类型_功能_图层号”命名,例如:
| 命名格式 | 示例 | 含义 |
|---|---|---|
| 类型前缀_L层号_功能 | LED_RUN_L1 | 运行指示灯,图层 1 |
| 类型前缀_L层号_功能 | RECT_ALARM_L2 | 报警底色块,图层 2 |
| 类型前缀_L层号_功能 | WIN_MAIN_L4 | 主画面窗口,图层 4 |
| 类型前缀_L层号_功能 | GRP_ENGINEER_L6 | 工程师参数组,图层 6 |
“LED_RUN_L1”这样的名字同时带了对象类型、功能和图层三个信息。L1、L2 这种图层号统一写在名称中间,脚本里搜索前缀就能定位整组对象。命名规范定好后,把它贴在项目共享目录里,所有组态人员按同一套规则写。这份项目案例里附了一张命名规范模板表,接手项目时先对照模板检查现有画面。
需要注意的是,对象名修改要趁早。画面组态到后段再改名,脚本里的对象名引用全部要跟着改,漏一处就是不显示。我吃过这个亏,后来所有参与脚本控制的对象,在组态一开始就按规范命名,不再用默认名。
3.2 第二步:C 脚本实现图层显示与隐藏
命名规范定好后,图层控制的核心就是 C 脚本了。WinCC 画面对象的事件编辑器里,常见的入口是按钮的鼠标点击事件,脚本框架如下:
#include "apdefap.h" // 按钮点击:显示运行指示灯层,同时隐藏报警底色块层 void OnClick(char* lpszPictureName, char* lpszObjectName, char* lpszPropertyName) { SetVisible(lpszPictureName, "LED_RUN_L1", 1); // 1 表示显示 SetVisible(lpszPictureName, "RECT_ALARM_L2", 0); // 0 表示隐藏 }SetVisible 是 WinCC 画面对象的标准控制函数,第一个参数传当前画面名,第二个参数传目标对象名,第三个参数是可见性开关。这里直接使用 WinCC 传入的 lpszPictureName,而不是硬编码画面字符串,这样脚本在多个画面里复用时不至于改错画面名。同一事件里可以连续调用多次 SetVisible,WinCC 会按顺序逐条执行。
如果图层要记状态,更好的做法是让脚本只翻变量,由动态对话框去驱动对象可见性:
#include "apdefap.h" // 运行层状态位翻转换 void OnClick(char* lpszPictureName, char* lpszObjectName, char* lpszPropertyName) { int nOldState; nOldState = GetTagBit("L1_State"); SetTagBit("L1_State", !nOldState); }这段脚本把图层状态存进“L1_State”这个二进制变量,对象可见性由动态对话框关联该变量位。相比直接 SetVisible,这种方式的优势是状态有变量承载,画面关闭再打开时,图层状态能按变量当前值恢复,而且变量可以被报警记录、外部系统读取,联动范围更广。缺点是要先建好变量,再配置好动态对话框,初始化工作量略大。
3.3 第三步:画面窗口与变量前缀做多画面切换
多设备项目里,最省力的图层结构是用画面窗口做载体。先做一个设备模板画面,画面里只放动态对象,所有变量引用写成相对形式;再把模板整体放进一个画面窗口中。画面窗口有一个关键属性“变量前缀”,运行时窗口内的变量引用会自动加前缀,比如前缀设为“Line1_”,画面内引用的“Alm_Flag”就变成“Line1_Alm_Flag”。同一套画面,放十个画面窗口、填十个不同前缀,就管十台设备。
画面窗口内嵌哪个画面,也可以由脚本在运行时切换:
#include "apdefap.h" // 切换主画面窗口的内容到 Device_01 画面 void OnClick(char* lpszPictureName, char* lpszObjectName, char* lpszPropertyName) { SetPictureName(lpszPictureName, "WIN_MAIN_L4", "Device_01.Pdl"); }SetPictureName 用来指定画面窗口当前加载的画面文件,画面文件后缀按项目实际版本写,经典 WinCC 一般是 Pdl。配合变量前缀后,切换画面和切换变量前缀可以分开做:设备选择按钮负责改前缀,画面内容按钮负责改画面名,互不干扰。要注意画面窗口内的对象坐标需要预留统一的设计基准,否则不同设备画面切换时会轻微偏移。
4. 图层与变量、报警联动:从静态显示到状态管理
4.1 动态对话框:把图层可见性绑到变量位
脚本能控制图层,但很多场景里图层显示与否是运行时的状态决定的,更适合由变量直接驱动。动态对话框就是干这个的,操作步骤不复杂:
- 选中画面对象,右键进入“属性”对话框;
- 找到“其他”类别下的“显示/隐藏”属性,点击闪电图标;
- 在动态对话框里选择表达式类型,写入“变量名@位号”,例如 L3_State@Bit0;
- 在结果表里配置:值为 0 时隐藏,值为 1 时显示。
| 参数项 | 推荐配置 | 说明 |
|---|---|---|
| 表达式类型 | 整数/二进制变量 | 位号用@BitN 形式 |
| 结果表 | 0 隐藏 / 1 显示 | 其他值按默认处理 |
| 触发周期 | 默认即可 | 不需要写 10ms 这类短周期 |
动态对话框的触发是按画面周期扫描的,所以变量变化后对象可见性会自动刷新,不需要额外写脚本。注意表达式里的位号写法是“变量名@Bit序号”,顺序不能反,写反了运行时变量读不出来,但系统也不报错,只能在画面调试时用变量监控工具去看实际值。
4.2 报警弹窗强制显示:报警时图层必须弹出来
报警弹窗是所有图层逻辑里最讲究的一部分。正常工况下弹窗是隐藏的,一旦发生报警,弹窗必须无条件弹出,并且盖在最高层;操作员确认后,弹窗才允许关闭。这个“无条件弹出”如果用普通按钮的脚本逻辑做,容易漏掉报警的同时性。工程上常用报警记录的消息事件触发:
#include "apdefap.h" // 报警发生时:显示报警弹窗,并置位弹窗占用标志 void OnAlarm(char* lpszPictureName) { SetVisible(lpszPictureName, "WIN_ALARM_L5", 1); SetTagBit("ALM_POP_FLAG", 1); }这段脚本挂在报警记录某条消息的“到达”事件里,报警一旦触发,WinCC 无论当前画面在哪个窗口,都会执行 OnAlarm 把弹窗层的可见性置为 1。弹窗自身的显示属性还可以挂“ALM_POP_FLAG”变量位,这样弹窗出现与标志位是同一状态,后续的确认复位只需要在确认按钮脚本里把标志位翻回 0。
比较常见的翻车做法是:报警恢复时直接把弹窗隐藏掉。这在单条报警时没问题,但如果两条报警先后到达,第一条已确认、第二条还在,弹窗就会被错误关闭。规范解法是“报警恢复不复位、操作员确认才复位”,确认按钮里判断是否还有其他未确认报警,没有才关闭弹窗层。这个判断逻辑在现场调试里很容易被忽略。
4.3 权限分级:不同登录用户看到不同图层
权限分级是图层隐藏显示的高频需求。操作员只需要看运行层,工程师需要看到参数设置层,维护人员还要看到诊断层。做法不复杂:登录时把当前用户权限级别写入内部变量,各图层控制脚本里先读级别再决定是否显示。
#include "apdefap.h" // 工程师权限控制:级别 2 及以上显示工程师层 void OnClick(char* lpszPictureName, char* lpszObjectName, char* lpszPropertyName) { int nLevel; nLevel = GetTagWord("UserLevel"); if (nLevel >= 2) SetVisible(lpszPictureName, "GRP_ENGINEER_L6", 1); else SetVisible(lpszPictureName, "GRP_ENGINEER_L6", 0); }GetTagWord 读取的“UserLevel”变量在登录脚本里写入,级别 1 对应操作员、2 对应工程师、3 对应维护人员。这种由脚本同步控制的方式简单直接,但要注意:权限变化发生在画面已经打开的情况下,需要手动触发一次刷新脚本,否则画面保持旧状态。更稳妥的做法是给权限相关图层全部挂上动态对话框,把权限级别变量直接作为驱动源,权限一变,图层自动刷新。
5. 避坑与常见问题:脚本报错、画面偏移、授权与通信
5.1 脚本报“语句未结束”:先查标点和变量声明
现象:在 WinCC 画面编辑器里保存 C 脚本或编译画面时,提示“statement missing;”或“unexpected end of file”,脚本整体无法运行。编译失败后,画面上按钮的点击事件全部失效,操作员点任何按钮都没反应,看起来像整个画面死掉了。
原因:WinCC 的 C 脚本遵循 ANSI C,最常见的原因是中文输入法状态下混入了全角分号,或者函数体内变量声明出现在语句中间;字符串引号不对称也会导致这类报错。此外,在 for 循环里直接声明循环变量这种 C99 写法,老版本编译器也会拒绝。
解决:把脚本复制到纯文本编辑器里,打开标点符号显示,逐行检查分号和单双引号是否半角;函数体内所有变量声明集中放到首部;编译前把输入法切到英文模式。现场改脚本前,我习惯先检查一遍标点再改逻辑,能省掉一半的后台验证时间。
5.2 画面整体往左偏移:分辨率不匹配的根本原因
现象:运行画面打开后整体往左偏移,右侧露出大片空白,操作按钮跑出可视区域,鼠标要点半天才能点到。这个问题在更换显示器或者把项目从笔记本放到工控机上时特别容易出现。
原因:项目运行画面尺寸大于显示器分辨率时,WinCC 按像素坐标定位画面,画面宽度超出屏幕就出现水平偏移。显示器分辨率低于项目设定值时,偏移量会特别明显,而且不会自动居中。
解决:先确认显示器实际分辨率,再把项目的运行画面尺寸改成一致。如果现场显示器型号不统一,统一使用 1920x1080 并在每台显示器上设置相同缩放比例。WinCC 画面适应模式可以设成自缩放,但缩放会带来字体和控件变形,工控画面一般不建议,宁可统一分辨率。
5.3 图层切换时对象闪烁或闪现
现象:用脚本切换图层时,目标对象闪了一下、或者短暂出现又立刻消失,看起来像系统抽风。反复点按钮几次,每次表现还不完全一样,很难稳定复现。
原因:一个对象的可见性同时被动态对话框和脚本驱动,两种机制在画面扫描周期里互相覆盖。脚本 SetVisible 置 1,下一帧动态对话框又按变量位把它拉回 0,画面就闪。
解决:一个对象的可见性只保留一种驱动方式。脚本控制的对象,删除动态对话框关联;变量驱动在对象,脚本里只翻变量,不再直接调 SetVisible。这个原则要写在各图层脚本的注释里,避免后面接手的人加了一段脚本就互相打架。
5.4 授权报错导致画面无法运行:版本不一致的排查
现象:打开项目、编辑画面都正常,一点“激活运行”就报授权相关错误,画面根本起不来。有时候项目在开发机上跑得好好的,拷到现场工控机就不行。
原因:WinCC 版本与授权版本不匹配,例如安装的是 WinCC 8.1,授权对应的是 TIA V15.1 的 WinCC 授权;或者授权组件缺失,画面编译无法完整释放。查看系统事件日志时,往往能看到 License 相关错误记录。
解决:打开 Automation License Manager,检查已安装授权与软件版本是否对应;授权组件缺失时补齐对应版本。现场排查顺序是:先确认软件版本,再查授权版本,最后看释放的运行时许可证是否包含图形系统。注意不要混用不同版本的授权文件,否则激活画面时仍会弹错。
5.5 OPC UA 连接失败让画面数据不刷新
现象:画面能打开,但工艺值长时间不变,看起来像图层没切换,实际上是数据没在更新。操作员切换画面、点按钮都没反应,但脚本本身没有报编译错误。
原因:OPC UA 服务器地址或安全策略配置错误,变量更新停住。WinCC 侧脚本依赖的变量状态不动,图层逻辑自然不执行。这种问题最迷惑人,因为它不直接报错,只是数据僵住。
解决:先用 OPC UA 测试客户端连接服务器端点,确认 Endpoint URL、安全策略和用户名密码没问题;再回到 WinCC 的通道配置里核对地址。常见坑是安全策略选错导致握手失败,排查时优先看这条。
6. 进阶:集中控制函数、日志调试与图层状态反馈
图层控制跑起来之后,真正决定调试效率的是维护手段。我习惯把这段经验拆成三个点:集中函数、日志验证、颜色反馈。
集中函数是所有控制脚本的公分母。把 SetVisible 包一层自己的函数,后面所有按钮只调用这一处:
#include "apdefap.h" // 图层控制统一入口:objName 为目标对象名,nShow 为 1/0 void LayerControl(char* lpszPictureName, char* lpszObjName, int nShow) { SetVisible(lpszPictureName, lpszObjName, nShow); }按钮事件里写 LayerControl(lpszPictureName, "LED_RUN_L1", 1),逻辑变化时只改函数内部,不用逐个按钮找。另一个习惯是留日志。WinCC 脚本没有直接的调试打印窗口,现场排查脚本时我直接用文本日志:
#include "apdefap.h" #include <stdio.h> // 写调试日志到 D 盘目录 void TraceLog(char* lpszMsg) { FILE* pf; pf = fopen("D:\\WinCC_Log\\layer_debug.log", "a"); if (pf != NULL) { fprintf(pf, "%s\n", lpszMsg); fclose(pf); } }在按钮脚本里加一句 TraceLog("ALARM_L1 shown"),就能确认脚本到底执行了没有、执行顺序对不对。日志文件路径要固定,并注意工控机对 D 盘目录的写入权限。最后是颜色反馈:图层显示状态下给边框一个颜色提示,C 脚本里用 RGB 函数:
SetBackColor(lpszPictureName, "RECT_ALARM_L2", RGB(0, 200, 0));RGB 函数的三个参数分别是红绿蓝分量,取值范围 0 到 255。WinCC 里颜色参数要注意字节顺序,不同版本表现不一致,建议用项目里已验证的颜色值,不要全靠现场试验。从那以后我每次做图层控制,都强制走一遍“命名规范、脚本集中、状态变量、日志验证”这条路,调试时间至少缩短一半。这份 WinCC 项目案例里的命名规范表、脚本片段和踩坑清单,正好把这条路铺好了,希望帮到你。
本文还有配套的精品资源,点击获取