博途WinCC PRO V16脚本组态弹出画面:原理、代码与排查实战

发布时间:2026/10/29 1:07:51
博途WinCC PRO V16脚本组态弹出画面:原理、代码与排查实战

简介:针对西门子博途WinCC PRO V16项目类型缺少直接“弹出画面”设置的问题,这份docx文档提供了基于脚本与画面窗口实现动态弹窗的完整方法,适合使用WinCC Professional V16进行组态开发的工程师与自动化调试人员。内容从创建主画面与子画面开始,逐步说明添加画面窗口、配置按钮事件、设置画面窗口属性,并通过C脚本控制画面窗口关联目标画面及可见性,最终实现点击按钮弹出或隐藏子画面的效果。文档给出关键脚本代码和组态步骤,附带运行验证思路,可直接参考落地,也可作为学习WinCC脚本编程与画面切换机制的入门示例。资源为单个docx文件,体积约548KB,便于阅读保存。目前已有1190人学习下载,适合需要提升WinCC人机交互设计能力、在原生功能缺失时寻找替代方案的组态人员。

1. 博途WinCC PRO V16通过脚本组态弹出画面:到底解决什么问题

HMI 项目做到中期,弹窗需求会突然多起来:设备详情、报警提示、参数设定、历史曲线切换。如果你还在用复制画面的方式做弹窗,每个设备一张拷贝,改一个公共样式就要全家换一遍,后面全是血泪。博途WinCC PRO V16 通过脚本组态弹出画面,核心思路是在主画面上放一个画面窗口(Screen Window),运行时由 VBS 脚本来决定它显示哪张画面、什么时候显示、参数怎么传。它解决的不只是“少画几张画面”,而是把弹窗从组态期的静态摆设变成运行期的行为,新增一台设备只需要新增一个调用。适合正在做 TIA Portal V16 + WinCC Professional 运行系统的工程师。这篇文章给出具体代码、组态步骤和几个高频排查案例,从原理到踩坑一次说清。

2. 先理清 WinCC Pro V16 的脚本模型:VBS 脚本和画面窗口在运行系统里怎么配合

2.1 为什么这种弹窗用 VBS 而不是 C 脚本

在 TIA Portal V16 的 WinCC Professional 里,画面动作的脚本语言主要分 C 和 VBS 两类。很多从 S7-300/400 时代走过来的工程师习惯用 C,但做弹窗这类“改属性、切画面、发参数”的逻辑,我一般优先用 VBS。原因很简单:VBS 对对象属性的读写更直接,拿一个画面窗口对象,赋值 ScreenName、Visible 就完成了弹窗动作,可读性和维护成本都更友好。而且 WinCC Pro 的全局脚本面板默认就支持 VBS,触发器配置方式与画面事件一致,写起来不用在两种语言之间来回切换。

这不是说 C 不能用。如果你的弹窗逻辑里要大量做运算、字符串解析,或者要和画面里其他 C 脚本保持同一套风格,那就继续用 C。但只做“弹窗、隐藏、传参”这类界面行为,VBS 是最短路径。选型原则可以概括为:画面行为逻辑用 VBS,数据运算逻辑用 C,尽量不要在同一事件里混用。混用之后脚本执行顺序和变量作用域会变成一个黑匣子,排查起来非常难受。

2.2 弹出画面的本质:一个可在运行时改名的画面窗口

很多刚接触 WinCC Pro 的新手会从“弹出”两个字出发,以为要动态创建一个新窗口,类似桌面程序的模态对话框。实际上 WinCC Pro 的脚本弹窗不是一个独立弹出的系统窗口,而是主画面里的一个容器型显示对象——画面窗口(Screen Window)。它在组态阶段就被放在主画面上,平时隐藏;运行时脚本把它显示出来,并告诉它“你现在显示的是哪张画面”。

这个机制的关键属性是 ScreenName。组态时你可以把画面窗口的 ScreenName 设为一个默认画面,也可以在脚本里给它赋任意一个已经编译到运行系统的画面名。所以“弹出画面”的本质是:同一个画面窗口,在不同条件、不同时刻,显示不同的画面内容。把这个概念想清楚,许多脚本报错你就能自己推断出来——不是“窗口没弹出来”,而是“画面名没对上或者画面窗口没显示”。

2.3 脚本访问运行对象的路径:HMIRuntime 与 ScreenItems

在 WinCC Pro V16 的运行系统里,VBS 脚本想拿到画面对象,统一通过 HMIRuntime 根对象往下找。访问路径是:HMIRuntime.Screens("主画面名") 先定位到运行的画面实例,再用 .ScreenItems("画面窗口名") 定位到画面里的具体控件。这里的“画面名”和“对象名”必须和组态项目树里的名字完全一致,包括大小写。

一个最小访问片段长这样:

Dim objSW Set objSW = HMIRuntime.Screens("Main").ScreenItems("Win_Detail") objSW.Visible = True

第 1 行声明变量 objSW;第 2 行用 Set 把画面窗口的对象引用赋给变量,注意 VBS 里对象赋值必须用 Set,直接写 objSW = HMIRuntime... 会报类型不匹配;第 3 行修改该对象的 Visible 属性让窗口显示出来。脚本执行完,建议 Set objSW = Nothing 释放引用。虽然按钮事件脚本结束后局部变量会销毁,但全局脚本里长期保存引用不是好习惯,这一点后面避坑章节会再展开。

2.4 要提前建立的一个认知:脚本改的是内容,不是画面结构

脚本组态弹窗有一个边界必须清楚:你可以在运行时改画面窗口显示的“画面内容”、可见性、位置、大小,但你不能在运行系统里凭空创建一个新的画面窗口,也不能把一个组态时不存在画面名的窗口硬显示出来。原因在于 WinCC Pro 运行时画面是编译产物,对象结构在编译时就已经固化,脚本只能对编译好的对象做属性操作。

这个边界决定了你的组态策略:凡是将来可能被弹出来的画面,都必须提前建好并参与运行系统编译;弹窗里要用到的变量,必须提前在变量表里建好类型;画面窗口的位置和尺寸最好一开始就设计到位。这也是为什么“脚本组态弹窗”这个方案要组态和脚本两手一起做,而不是纯写几行代码就完事。

3. 用 VBS 脚本组态弹出画面:最小可运行代码与参数说明

3.1 场景定义与画面规划

用一个典型场景来落地:主画面 Main 上有个画面窗口 Win_Detail,平时隐藏;操作员按“查看详情”按钮,弹出一张 Popup_Detail 画面,里面显示当前设备的编号、名称和一条说明文本;关闭按钮把窗口隐藏。这个场景覆盖了打开、关闭、传参三件事,是弹窗的最小完整闭环。

组态规划时,我习惯在项目树里把这类页面统一命名:弹出内容页以 Pop_ 开头,画面窗口以 Win_ 开头,弹窗参数变量以 Pop_ 开头。这样做的好处是脚本里看到名字就能判断对象类型,排查 ScreenItems 找不到对象时也能快速定位,不用在几十个画面里翻。命名规范看似小事,但在多工程师协作的项目里能省下大量沟通成本。

3.2 打开弹窗的按钮脚本

在 Main 画面上放一个按钮,给它的事件里新增一个 VBS 动作,动作类型按实际需要选“鼠标按下”或“点击”,事件函数按 WinCC Pro 的签名来写。常见做法是直接在事件对话框里写以下代码:

Sub OnClick(ByVal Item) ' 1. 定位主画面里的画面窗口对象 Dim objSW Set objSW = HMIRuntime.Screens("Main").ScreenItems("Win_Detail") ' 2. 切换为要弹出的画面并显示 objSW.ScreenName = "Popup_Detail" objSW.Visible = True ' 3. 把弹窗需要的参数写入全局变量 HMIRuntime.Tags("Pop_Title").Write "设备 01 详情" HMIRuntime.Tags("Pop_DeviceNo").Write 101 ' 4. 释放对象引用 Set objSW = Nothing End Sub

这里每一步都有对应关系:第 2 行 Set 拿到画面窗口对象后,第 5 行 ScreenName 赋值为 "Popup_Detail",运行时这个画面窗口立即加载并显示 Popup_Detail 画面;第 6 行 Visible 置 True 让它可见。第 8、9 行把弹窗需要的标题和编号写入两个全局变量,弹窗内部的文本控件可以通过变量连接直接引用它们。

参数说明:Main 是主画面在项目树里的画面名;Win_Detail 是画面窗口的实例名,不是默认名称;Popup_Detail 是弹出画面的画面名;Pop_Title 建议在 HMI 变量表里建为 String 类型,Pop_DeviceNo 建为 Int 或 DInt 类型。这三个名字只要有一个拼错,或者大小写不一致,运行时会报 Object required 或者变量不存在,这是最常见的翻车点。

3.3 关闭弹窗的脚本与对象释放

关闭弹窗更简单,在 Popup_Detail 画面上放一个“关闭”按钮,同样写 VBS 事件,代码是打开逻辑的逆操作:

Sub OnClick(ByVal Item) Dim objSW Set objSW = HMIRuntime.Screens("Main").ScreenItems("Win_Detail") objSW.Visible = False Set objSW = Nothing End Sub

这里只把 Visible 置为 False,没有清空 ScreenName。这样做的目的是保留“上次打开的画面名”,下次再打开时可以直接显示同一张画面,减少一次赋值。如果你希望每次关闭后下次打开强制刷新内容,可以在关闭时把 ScreenName 清空,或者在弹窗加载事件里重新读一次变量。两种行为模式看业务需要,没有绝对优劣。

另外一个细节:关闭弹窗后,如果弹窗内部用到了 PLC 变量订阅,建议确认变量在窗口隐藏后是否继续周期刷新。WinCC Pro 的画面窗口隐藏后,画面内部的 IO 域和文本控件不会再更新显示,但变量连接仍然存在,这点在大量弹窗复用时要注意,避免出现“窗口关了数据还在后台跑”的误解。

3.4 用全局脚本由变量或报警触发弹窗

按钮触发适合操作员主动查看。但很多场景是报警来了自动弹窗,这时按钮事件就不够了,要用全局脚本加触发器。在 TIA Portal 的 WinCC Pro 项目里,进入全局脚本面板,新建一个 VBS 脚本,把下面的代码放进去:

Dim objSW Set objSW = HMIRuntime.Screens("Main").ScreenItems("Win_Detail") If HMIRuntime.Tags("Alarm_Main").Read = 1 Then objSW.ScreenName = "Popup_Alarm" objSW.Visible = True Else objSW.Visible = False End If Set objSW = Nothing

这段脚本从变量表读取 Alarm_Main 的值,为 1 时把画面窗口切换为 Popup_Alarm 并显示,为 0 时隐藏。注意全局脚本里没有 Item 参数,直接访问 HMIRuntime 即可。

触发器配置在全局脚本编辑器的触发器页里完成。我一般选“变量触发器”,触发变量选 Alarm_Main,触发方式选“变量改变时”,这样只有当报警状态翻转时脚本才执行一次。不要图省事用周期触发每 100 毫秒扫一次。弹窗逻辑虽然简单,但周期触发会在运行系统里增加不少调度负担,画面多了之后整个 RT 的刷新节拍都会受影响。

3.5 弹窗尺寸与位置:组态固定还是脚本动态调

弹窗的画面窗口尺寸和位置,可以在组态属性里固定,也可以在脚本里动态赋值,两种做法我都用过。固定的好处是所见即所得,脚本少两行;动态赋值适合多分辨率屏幕,或者弹窗内容长短不一,需要根据内容调整布局。

脚本动态调整的写法是直接给对象赋值,比如:

objSW.Width = 480 objSW.Height = 320 objSW.PositionX = 100 objSW.PositionY = 60

PositionX 和 PositionY 是画面窗口左上角相对于主画面的坐标,单位是像素。要注意的是,不同 WinCC Pro 版本里屏幕分辨率的全局属性名不完全一致,做居中算法前先查一下在线帮助里运行系统屏幕对象的属性名,别直接抄旧版本代码。我通常的做法是:组态时把画面窗口放到理想位置,脚本里只改 ScreenName 和 Visible,位置这种纯布局的事交给组态,不在脚本里重复做,逻辑更清晰。

下面把本章用到的核心对象和参数整理成一张表,方便调试时对照:

对象示例值含义常见问题
主画面名Main脚本访问的入口画面必须与项目树中的画面名一致
画面窗口名Win_Detail承载弹出内容的容器实例必须先在属性里命名,不能用默认名
弹出画面名Popup_Detail运行时加载的画面内容该画面必须参与编译
弹窗参数变量Pop_Title / Pop_DeviceNo传给弹窗内部使用的 HMI 变量类型要与弹窗内绑定一致
VisibleTrue / False画面窗口可见性隐藏后对象仍在后台

4. 组态侧要做的四件事:画面窗口、触发方式、变量绑定与编译

4.1 主画面放一个有名字的画面窗口

先动手从组态开始。在 WinCC Professional 画面编辑器里,从工具箱拖一个 Screen Window 控件到 Main 画面,这是承载所有弹窗内容的容器。放好后第一件事是改名字:在属性对话框里把默认名改成一个有业务含义的实例名,比如 Win_Detail。默认名通常是一串无关字符,脚本里用默认名既难记又容易拼错。

初始属性建议这样设置:Visible 为 False,让运行系统启动时不显示弹窗;ScreenName 留空,不预载任何画面,等脚本指定。画面窗口的尺寸按弹窗内容设计,比如 480×320,位置放在主画面中央附近。这里有一个小经验:不要把画面窗口放在主画面的边缘,否则弹窗弹出时会被导航栏或其他控件遮挡,还要额外调层级,纯属给自己挖坑。

如果项目里弹窗种类多,比如有设备详情、报警确认、趋势曲线三种,我的建议是每个弹窗单独用一个画面窗口,不要共用一个窗口反复切 ScreenName。共用窗口省了组态控件,但会让脚本里到处是 if 判断当前弹的是什么,维护起来很容易出错。三个画面窗口叠加摆放、初始化全部隐藏,是最省心的一种组织方式。

4.2 把参数传给弹出画面:变量绑定与画面窗口 Tag 映射

弹窗内容需要数据。最简单的方式是全局变量:调用方写 HMIRuntime.Tags("Pop_Title").Write,弹窗内部的文本、IO 域直接绑定同名变量。这种方式对单实例弹窗非常直观,参数少(两三个)时我推荐直接用。

但如果同一个弹窗要被多个调用点复用,比如 A 设备弹 A 详情、B 设备弹 B 详情,全局变量方式容易出现“最后一次写值覆盖前一次”的串台问题。这时用画面窗口的 Tag 映射更稳。具体做法是在画面窗口的属性对话框里,找到 Tag 配置区域,新增一个条目,比如把 PLC 变量 MB20 映射为窗口的 DeviceNo;弹窗内部的动态属性再绑定到该条目上。调用时通过画面窗口对象写入这个条目,弹窗读取的就是本次调用传入的值。

两种方式不是互斥的。复杂弹窗里我一般混用:画面级参数用 Tag 映射,全局提示文本用全局变量。关键是项目里要形成约定,不要今天用 A 明天用 B,否则半年后维护脚本时,光判断参数从哪条路径进来的就够你折腾半天。

4.3 触发方式怎么选:按钮、变量、报警、画面切换

脚本弹窗的触发方式取决于业务场景,选型表如下:

触发方式适用场景配置位置注意点
画面按钮操作员主动查看详情按钮 VBS 事件事件函数签名要匹配
变量触发器报警/状态自动弹窗全局脚本触发器触发变量选变化沿
周期触发器定时巡检内容展示全局脚本触发器周期不宜过密
画面打开事件进入主画面就展示画面对象事件编译后才生效

按钮触发写起来最直接,但要注意按钮事件里 VBS 和 C 是两个独立的脚本体系。如果按钮上已经有一个 C 脚本动作,再挂一个 VBS 事件,两个脚本可能各自执行,后执行的那个会覆盖前面对对象属性的修改。这个坑我踩过不止一次,现在做弹窗按钮时只保留一种脚本语言。

报警自动弹窗用变量触发器最合适。在变量表里建一个报警汇总位,比如 Alarm_Main,PLC 里有任意报警就置位;全局脚本变量触发器检测到位变化后弹窗。这样逻辑不依赖 WinCC 报警控件,排查看起来更直白。需要提示的是,不要把报警弹窗做得太激进,频繁弹窗会打断操作员正在进行的操作,一般会配合消音确认逻辑使用。

4.4 编译运行系统与许可证问题

组态和脚本都做完,最后一步是编译。很多工程师在这里翻车:只在主画面里按了 Ctrl+S 保存画面,然后启动运行系统,脚本里引用的 Popup_Detail 始终加载失败,弹窗黑屏。原因是 WinCC Pro 运行系统加载的不是散落的画面文件,而是编译后的运行系统镜像。新增画面、新增变量、改脚本后,都要对整个运行系统执行一次编译,而不是只保存单个画面。

编译出现在项目树的运行系统设置里。编译前先检查弹出画面是否被包含在运行系统的画面组里。有些项目为了提升启动速度,把画面组划分得很细,新画面没挂进运行系统引用的画面列表,编译也不会报错,但运行时就是找不到对象。这类问题最烦人,因为它不是语法错误,编译完全通过。

许可证问题也要放在编译之前排查。如果你遇到博途 V16 启动运行系统时报“找不到许可证”,先确认你安装的是 WinCC Professional 运行系统授权,而不是只安装了 TIA Portal 的工程授权。WinCC Comfort 的授权不能用于 Professional 运行系统,这个区别在 V15.1、V16 里一直存在。授权没解决时,编译偶尔能过,但运行系统启动会被拦下,脚本自然也就不会执行。

5. V16 脚本弹窗常见问题排查:从黑屏到变量传不过去的六个案例

5.1 按钮点了没反应,脚本好像没执行

现象:Main 上的按钮配置了 VBS 事件,运行时点击后画面窗口纹丝不动。

原因:最常见的是按钮上的事件脚本实际挂在了 C 脚本事件里,或者事件类型选错(选成了“鼠标按下”但实际要“点击”)。另一个高频原因是对象名写错:ScreenItems("Win_Detail") 里的名字和组态属性里的实例名不一致,脚本运行时找不到对象,异常被静默吞掉。

解决:先在事件脚本第一行加 HMIRuntime.Trace "button clicked" 并查看运行系统日志,确认脚本是否真的执行;再核对画面窗口的实例名。我一般会从属性对话框里复制名字粘贴进脚本,绝不手打,手打必出错,这不是玄学,是大小写和拼写问题。

5.2 弹窗黑屏白屏,只有边框没有内容

现象:画面窗口 Visible 已经是 True,ScreenName 也赋了值,但窗口区域空白。

原因:ScreenName 指向的画面不存在,或者画面没有参与运行系统编译。如果只是名字拼写差一个字符,运行时不会以弹窗形式提示,只会显示空窗口。还有一种情况:画面确实存在,但画面里所有对象都绑定了不存在的变量,导致内容全部空着,看起来也是黑屏。

解决:把项目树里的画面名复制到脚本里,确认精确匹配;然后在运行系统设置里重新编译整个运行系统,确保 Popup_Detail 被编译进去。重新编译后如果还黑屏,就把 ScreenName 赋值为一个已知正常的画面做对比测试,很快就能定位是画面内容问题还是窗口问题。

5.3 弹窗出来了,但里面的文本和设备名全是空的

现象:弹出画面能显示,但文本控件、IO 域没有任何内容,或者显示的是上一次的值。

原因:参数没有传进去。调用方写的是 Pop_DeviceNo 这个全局变量,但弹窗内部绑定的变量名拼写不同,或者绑定的是画面窗口的 Tag 映射而调用方没有写映射条目。另一个常见原因是变量类型不匹配:调用方写入的是字符串,弹窗内控件绑定的是整型变量,运行时连接失败,显示为空。

解决:在运行系统变量监控表里查看 Pop_DeviceNo 的实际值,确认调用时写入成功;然后检查弹窗内文本控件的属性,看变量连接指向哪个变量。如果弹窗要显示 PLC 数据,最好在弹窗画面的加载事件里再主动读一次变量,避免依赖界面的自动刷新节拍。

5.4 一弹窗就报 Object required 或类型不匹配

现象:脚本执行到 Set objSW 所在行报错 "Object required",或者赋值 Visible 时报类型不匹配。

原因:对象引用没有拿到,也就是前面的定位路径出了问题。常见于主画面名写错、画面窗口实例名不存在、或者画面窗口被放在了一个模板组合画面里,运行时实例名的前缀和你组态时看到的名字不一样。

解决:先用 HMIRuntime.Screens 遍历一下实际画面对象名,或者在一个临时按钮上把 ScreenName 写死测试。有一点要记住:对象定位路径里的每一段都必须存在于编译后的运行对象树中,任何一段拼错都会让 objSW 变成 Nothing,后续所有属性赋值全部报错。调试期间可以把定位语句包在 On Error Resume Next 里快速定位,但生产脚本不要随便吞异常。

5.5 反复开关弹窗后运行系统明显变慢

现象:弹窗开关几十次后,画面切换变得卡顿,内存占用缓慢上涨。

原因:VBS 脚本创建的对象引用没有释放。虽然按钮事件脚本结束后局部变量会销毁,但部分版本的运行系统对 VBS 脚本引擎的资源回收存在延迟;全局脚本里如果用了全局变量保存对象引用,更是会一直占着不清。

解决:每个脚本里用 Set objSW = Nothing 显式释放对象,全局脚本尤其要做。另外检查是否有人复制了多个画面窗口堆在同一画面里,有些项目的“弹窗”实际是十几个互相重叠的画面窗口,每次只改 Visible,画面数量和资源占用一起涨,这种组态问题靠脚本优化救不回来。

5.6 运行系统启动失败,或者提示找不到许可证

现象:启动 WinCC RT Professional 时弹窗报“找不到许可证”,有时编译过程也终止;也遇到过程序能启动但脚本弹窗区域始终不加载的情况。

原因:运行系统授权缺失或授权类型不对。TIA Portal V16 的工程组态授权和 WinCC Professional 运行系统授权是两个东西;V15.1 WinCC Comfort 的授权也不能平移到 Professional 上,这是 WinCC 授权体系里最常见的理解误区。

解决:在授权管理器里确认运行系统授权是否存在且未过期。重装 TIA Portal V16 后最容易出现授权丢失的情况,因为授权信息不一定存在本机,可能留在存储卡或授权 U 盘里。没有正式授权时,可以先确认你是否在试用期内运行;试用期内能跑,不代表正式部署环境里不需要配置。这条排查顺序应该放在脚本调试之前,因为授权缺失会直接阻断运行系统,一旦启动不了,脚本对不对就无从谈起。

6. 把弹窗做成可复用的参数化模板:传参规范与调试习惯

6.1 多设备公用一张弹窗

脚本弹窗最大的收益不是“少写几行代码”,而是“新增设备时不用复制画面”。做法是把弹窗内容参数化:Popup_Detail 里只有变量连接,没有写死的设备名;每次打开弹窗前,先写参数变量,再弹窗。打开逻辑可以抽成一段统一的 VBS,放在全局脚本里供各处调用,避免每个画面里重复维护同样代码。项目里弹窗调用点多的时候,我一般会把参数写入和窗口显示定义成同一个脚本逻辑,参数从按钮所在画面的局部调用传入,这样维护时只改一处。

6.2 与历史趋势曲线联动

弹窗不是只能放文本和 IO 域,趋势曲线同样可以做成弹窗内容。操作员在总览画面双击某台设备,脚本先写趋势起始时间和要显示的变量名,再弹窗,弹窗里的趋势控件读取这两个参数完成数据加载。这样就避免了“每台设备都做一个趋势画面”的重复劳动。如果你搜索过“WinCC 历史趋势曲线脚本”,多半就是在找这条路:用脚本把趋势画面的显示对象参数化,让多个设备共用一张趋势弹窗。

6.3 我现在的调试习惯与命名规范

弹窗调试我有三个固定动作。第一,先手动置变量验证触发条件,再验证脚本逻辑;第二,用 HMIRuntime.Trace 写日志,不在运行画面上用 MsgBox,生产画面弹调试框会把操作员吓一跳;第三,每次改动脚本后重新编译运行系统,不编译就看不出效果。命名规范上,我已经习惯把所有弹窗参数统一加 Pop_ 前缀,所有画面窗口统一叫 Win_,所有弹出内容画面统一叫 Pop_,这个习惯从 V16 用到现在,配合多工程师项目时几乎零解释成本。希望这个思路也能帮到你。

本文还有配套的精品资源,点击获取