简介针对博途WinCC Professional V16项目类型未提供直接“弹出画面”设置这一常见问题这份资料以图文笔记形式梳理了运用脚本组态实现动态画面弹出的完整方法。面向需要提升上位机界面交互性的自动化工程师与HMI组态开发者从创建主画面“pic1”和子画面“pic2”入手依次讲解画面窗口的添加与重命名、按钮配置、画面窗口默认不可见属性设置再到按钮点击事件中编写C脚本通过GetObject、GetPicture、SetPicture、SetVisibility等关键API完成画面挂载与显示控制并给出运行测试及再次点击隐藏画面的处理逻辑。读者可据此快速复现弹出效果还可参考文末思路延伸到多画面切换、动画过渡等高级交互场景对理解WinCC Professional脚本机制也有直接帮助。资源共1个文件为docx格式文档压缩包整体548KB内容结构紧凑、步骤明确。目前已有1189人学习下载适合WinCC初至中级用户作为案头参考。1. 博途WinCC PRO V16 脚本组态弹出画面解决的是弹窗失控问题设备级上位机项目里弹窗需求几乎是一路追着设计跑的报警要弹详情配方要弹选择操作出错要弹提示。第一次做这类功能的人最容易想到的方法是在组态画面里多放几个画面窗口哪个需求来了就拖一个。等弹窗数量超过十个组态页面上找对象都费劲改位置要一层层翻想根据 PLC 条件决定弹哪一页更绕。博途 WinCC PRO V16 里说的“通过脚本组态弹出画面”核心思路只有一个运行期用 VBS 脚本动态修改画面窗口的 ScreenName 和 Visible让一个窗口模板按条件加载不同画面。下面按最小实现、参数联动、模态控制和现场排错展开新手能照着做老手也能在边界和坑上对一遍自己的做法。2. V16 弹出画面的三条实现路线画面窗口、OpenScreen 与脚本组态2.1 画面窗口只是载体脚本才是决定“弹什么”的那只手WinCC Professional V16 里能承担“弹出”功能的控件是画面窗口也就是工具栏里的 Screen Window。它本质是一个容器组态时把它拖到主画面上划定一块矩形区域再关联一个画面运行时就显示那个画面的内容。这里有个容易被忽略的机制“关联哪个画面”这个动作既可以发生在组态期也可以发生在运行期。组态期关联是固定用法一个窗口永远显示一个画面运行期由脚本写入 ScreenName就变成了动态组态这也是“脚本组态弹出画面”这个说法的来源。另一种经常被拿来当弹窗用的是系统函数 OpenScreen。它负责整屏切换执行后当前画面会被目标画面整个替换。现场经常有人图省事在按钮事件里调 OpenScreen 来“弹”出一个页面结果用户点完发现原来的主画面不见了返回逻辑还得单独做。OpenScreen 不是弹窗它是页面跳转这个边界必须在方案一开始就划清楚。脚本组态和上面两种都不同画面窗口仍然放在主画面上但显示什么内容、什么时候显示都由 VBS 脚本在运行期决定。脚本本身不做渲染、不做动画它只负责把“弹什么、什么时候弹”从一个静态组态变成一个可计算的逻辑。比如同一个弹窗位置上午显示配方页下午显示报警页完全可以用脚本判断。2.2 三条路线怎么选一张表看完区别实现方式是否支持弹出运行期换内容典型场景最常见的坑组态期固定画面窗口支持不支持固定帮助面板、固定报警窗弹窗一多组态页面上对象堆成山OpenScreen 整屏切换不支持不支持主菜单跳转、页面切换被当成弹窗用主画面直接没了脚本组态画面窗口支持支持一个窗口复用多个弹出内容对象名或画面名写错运行时报找不到这个表是我做方案对比时常用的口径。如果项目里弹窗数量少于三个且每个弹窗内容固定用第一种完全没问题没必要上脚本。如果弹窗内容会随工艺、配方、报警类型变化或者同一个窗口要在不同条件下显示不同页面直接选第三种。OpenScreen 只在页面跳转场景用别让它混进弹窗逻辑里。2.3 脚本组态的底层逻辑ScreenName 加 Visible脚本组态的底层逻辑只有两件事给画面窗口的 ScreenName 赋一个新画面名然后把 Visible 置为 True。把这两行抽出来看objPop.ScreenName Face_Recipe objPop.Visible True参数说明objPop 是脚本里对画面窗口对象的引用变量ScreenName 接收的值必须是项目树“画面”文件夹里真实存在的画面名Visible 置 True 表示显示窗口。这里不涉及窗口的位置和大小那些属性在组态阶段就已经摆好脚本只关心“显示什么”和“显不显示”。这样做的好处是弹窗的位置只在一处维护脚本里维护的是业务逻辑两边不互相干扰。3. 用 VBS 脚本组态弹出画面的最小可运行实现3.1 组态画面窗口的三个准备动作第一步在主画面 Main 上拖入一个画面窗口把对象名改成 PopWin。注意属性表里的“对象名”和显示文本是两回事脚本引用的是对象名不是界面上显示的那行字。对象名里不要带空格不要用中文全工程保持统一的命名前缀比较好。第二步在画面窗口的属性表里找到 Visible 属性把初始勾选去掉也就是让它在运行系统启动时不显示。这个初始状态很重要否则开机后主画面中央就顶着一个窗口。第三步画面窗口关联的画面先留空。留空时运行系统启动不会预加载任何页面脚本第一次给 ScreenName 赋值时才真正加载目标画面。如果组态时已经关联了画面WinCC 启动就会把它加载进内存弹窗模板多了以后启动时间会变长。留空是延迟加载代价是第一次弹出时有一瞬间的加载延迟现场一般能接受。3.2 按钮单击事件里的第一段 VBS在主画面上放一个“显示配方”按钮在事件属性里找到“单击”选择 VBS 动作写入下面代码Dim objScreen Dim objPop 取得主画面对象 Set objScreen HMIRuntime.Screens(Main) 取得主画面里的画面窗口对象PopWin 是组态时填的对象名 Set objPop objScreen.ScreenItems(PopWin) 指定这次要加载哪个画面 objPop.ScreenName Face_Recipe 加载完成后显示窗口 objPop.Visible True逻辑说明第一组 Dim 声明两个对象变量Set objScreen 拿到主画面运行期对象Set objPop 从当前画面的 ScreenItems 集合里按对象名取到画面窗口。ScreenItems 的索引键是组态时填的对象名不是画面窗口上显示的文字。给 ScreenName 赋值后窗口内部开始加载目标画面最后再 Visible True。顺序不要反过来否则窗口先变成可见但内容还没指定现场会看到一个一闪而过的空白框视觉上像系统卡了一下。3.3 关闭弹窗的写法以及 ScreenName 留不留关闭按钮的脚本比打开简单Dim objScreen Dim objPop Set objScreen HMIRuntime.Screens(Main) Set objPop objScreen.ScreenItems(PopWin) 隐藏弹窗保留画面引用 objPop.Visible False这段只改 Visible不清 ScreenName。关闭后上次加载的画面还保留在窗口里下次打开时直接把 Visible 改回来就行响应很快。如果弹出画面里有实时曲线、归档表这类吃内存的页面对象建议关闭时把 ScreenName 清空objPop.ScreenName objPop.Visible False清空后窗口会释放页面对象内存占用低但下次打开需要重新加载会有一两秒的白屏间隔。两种做法没有绝对对错我的习惯是按弹窗内容决定纯参数显示页面不清空带趋势曲线、报表的页面清空。3.4 画面窗口运行期常用属性表属性类型作用脚本写法示例ScreenNameString决定窗口加载哪个画面objPop.ScreenName Face_RecipeVisibleBoolean窗口显示或隐藏objPop.Visible TruePositionXInteger窗口左上角 X 坐标objPop.PositionX 300PositionYInteger窗口左上角 Y 坐标objPop.PositionY 200PositionX、PositionY 一般不在脚本里动位置在组态阶段摆好就够了。如果一定要运行期移动弹窗位置可以直接给这两个属性赋值但要注意多分辨率显示屏下绝对坐标会偏位那是另一个排错点。另外补一句如果只是想让 PLC 变量直接控制弹窗的显示和隐藏组态里把 Visible 属性关联变量就行不需要写脚本脚本的价值在于变量只能控制显隐控制不了“换画面”换画面必须走 ScreenName。3.5 新手最容易跑不起来的三个点第一对象名写错。PopWin 写成 PopWindow或者中间混入了全角空格。输入法在中文状态下手滑一下引号和括号都会变成全角字符VBS 编辑器不报错但运行系统找不到对象。遇到弹窗没反应第一件事就是把脚本里所有引号、括号、对象名和组态属性表逐字对一遍。第二画面没有编译进运行系统。新建了 Face_Recipe 画面但没触发运行系统的重新生成脚本里引用这个画面名运行时会提示画面不存在。V16 里新建画面后要重新编译运行系统不能只保存就启动。第三跨画面引用不写全路径。按钮在副画面 Face_Sub 上画面窗口在主画面 Main 里脚本里必须写 HMIRuntime.Screens(Main).ScreenItems(PopWin)不能省略 Main 直接写 ScreenItems(PopWin)。省略后运行系统会在当前画面里找当前画面里没有 PopWin自然报错。4. 参数传递、报警联动与模态控制弹出画面从能弹到好用4.1 给弹出画面传参数用内部变量中转画面窗口只是个容器调用方按钮并不能直接把参数“塞”给弹出画面。V16 里最常见的做法是中间经过变量。比如点按钮时先把要显示的配方编号写进内部变量弹出画面被加载后再读这个变量刷新文本控件。在弹出画面的“加载”事件里写Dim tagValue tagValue HMIRuntime.Tags(PopParam).Read If tagValue 1 Then HMIRuntime.Screens(Face_Recipe).ScreenItems(Label_RecipeName).Text 一号配方 ElseIf tagValue 2 Then HMIRuntime.Screens(Face_Recipe).ScreenItems(Label_RecipeName).Text 二号配方 End If逻辑说明调用方按钮在打开弹窗之前先执行 HMIRuntime.Tags(PopParam).Write 目标值弹出画面加载时触发上面这段脚本从 Tag 里读出值并刷新文本。这样调用方和弹出画面之间通过变量通信不直接互相引用对象结构清晰排错也直观。这个方式同样适用于把设备编号、报警编号传进弹窗做二次显示。4.2 报警触发自动弹出对应画面把映射收进函数现场经常有这样的需求报警确认后自动弹出该报警对应的诊断画面。因为报警控件事件里的上下文和画面窗口不在一个层级不要在报警事件里直接写画面切换逻辑。我一般让报警事件只负责写变量弹窗按钮再去读变量做映射。映射逻辑集中到一个函数里Function GetPopFaceByKey(ByVal key) Select Case key Case alarm GetPopFaceByKey Face_AlarmDetail Case recipe GetPopFaceByKey Face_Recipe Case Else GetPopFaceByKey Face_Default End Select End Function调用处只要两行objPop.ScreenName GetPopFaceByKey(HMIRuntime.Tags(PopKey).Read) objPop.Visible True参数说明PopKey 是报警或按钮写入的内部变量存储的是业务条件的键值GetPopFaceByKey 负责把键值映射为画面名查不到时返回默认画面 Face_Default。这样新增业务场景时只改函数一处按钮、变量和其他脚本都不用动。脚本组态相对纯组态最大的收益就在这种映射上业务变化集中在一个函数而不是散落在十几个按钮事件里。4.3 模态控制V16 没有原生 Modal用遮罩和锁来搭WinCC Professional 的画面窗口默认是非模态的弹窗显示时用户依然可以点主画面的按钮。如果弹窗只是提示信息非模态问题不大如果弹窗要求用户必须确认就需要自己搭模态控制。三种做法对比方案实现思路适用场景注意非模态弹窗直接 Visible True提示、状态展示用户可能漏看弹窗遮罩层拦截用全屏遮罩窗口盖住主画面需要强制确认的操作遮罩窗口必须置于最上层互斥变量锁弹窗打开时写 1关闭写 0同一时间只允许一个弹窗注意 PLC 侧不要同时复位遮罩层做法组态时再放一个全屏画面窗口背景色设为深灰右键置于最上层。弹出确认框时同时打开遮罩确认框关闭时再关遮罩。遮罩上没有可点按钮主画面的所有操作都被它挡住。互斥变量锁的脚本片段Dim lockValue lockValue HMIRuntime.Tags(PopLock).Read If lockValue 0 Then HMIRuntime.Tags(PopLock).Write 1 objPop.ScreenName Face_Recipe objPop.Visible True End If逻辑说明先把锁变量读出来等于 0 说明没有其他弹窗占用把锁写成 1再打开弹窗。弹窗关闭脚本里要把锁写回 0。PopLock 用 HMI 内部变量就可以不用到 PLC响应完全由 VBS 控制。4.4 三个反复出现的误用第一OpenScreen 当弹窗用。前面说过OpenScreen 会替换整屏画面原来的画面窗口全部卸载弹窗自然也没了。脚本组态弹窗的前提是画面窗口还在主画面上OpenScreen 直接把这个前提破坏了。第二跨画面引用不写全路径。在副画面的按钮脚本里引用主画面的画面窗口不写 HMIRuntime.Screens(Main)运行系统会在当前画面里找对象报错后还以为是画面窗口名字错了其实缺的是上级路径。第三多个弹窗同时打开。没有锁控制时两个按钮先后点下去两个画面窗口同时可见互相遮挡。WinCC Professional 运行期没有提供 Z 序管理脚本层叠关系只能在组态时固定。所以项目里最好约定同一时刻最多一个弹窗用互斥锁保证。5. 脚本弹出画面的排错顺序与一个收敛技巧5.1 现场排错按这个顺序查两步内定位典型现象是按钮点了没反应。先看脚本是否真的触发了在按钮脚本第一行写一个临时动作比如给内部变量写个固定值。如果变量变了说明脚本有触发问题在后面的对象引用如果变量没变先检查按钮的“单击”事件是不是绑到了别的鼠标事件上V16 里容易误绑到“按下”或“释放”。脚本触发了但弹窗还是不出来把 ScreenName 临时赋成一个肯定存在的画面比如 Face_Default排除映射问题如果能弹出来就是画面名映射逻辑的问题按 4.2 的函数排查。注意V16 改动脚本后直接点运行按钮有时跑的还是旧逻辑。这不是缓存玄学是 WinCC 脚本编辑器和运行系统分开编译导致的。改了脚本弹出相关的内容先重新生成运行系统再启动。5.2 把画面名映射收敛到一个函数里附命名约定项目后期弹窗数量会停在某个固定值但报警类型、配方类型还会继续增加。与其在十几个按钮里分别改 ScreenName不如把“业务条件到画面名”的映射集中到一个函数里。函数写法见 4.2 的 GetPopFaceByKey平时维护只改这个函数不用翻按钮逻辑。配合一套命名约定会省很多事画面窗口统一以 Pop 开头比如 PopWin、PopOverlay弹出画面统一以 Face_ 开头比如 Face_Recipe、Face_AlarmDetail。脚本报错时按 Pop 和 Face_ 两个前缀全局搜索就能把所有相关对象和引用捞出来。改脚本、查组态、找人交接都方便。5.3 最后一道保护按钮点击前先读互斥锁按 4.3 的锁逻辑把所有弹窗按钮脚本的开头都加上锁判断。锁不为 0 时直接退出不做任何弹窗动作。这个保护很朴素但能挡住最常见的双击误触和两个弹窗同时弹出的混乱。互斥锁和遮罩层配合使用弹窗在 V16 工程里就能一直保持可控状态而不是靠操作员小心手速。本文还有配套的精品资源点击获取
