ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

WinCC面板类型与画面窗口:从重复组态到高效复用

WinCC面板类型与画面窗口:从重复组态到高效复用 做WinCC组态项目的人十个有九个估计都遇到过这种重复劳动泵、风机、阀门十几台同型号设备每台都要单独画控制画面、写一遍启停脚本、再做一次关联好不容易全部搞完甲方又提新需求要求在弹窗里看实时趋势结果弹窗关一次就再也点不开了。这两个痛点其实正好对应WinCC里两个经常被搞混的功能——面板类型Faceplate和画面窗口Picture Window。这篇文章我就把这两个东西掰开揉碎讲清楚从基本概念、选型思路到面板实例的创建步骤、画面窗口弹窗打开一次的坑再给一个“电机控制面板趋势弹窗”的综合示例。内容主要面向正在做WinCC V7或TIA Portal WinCC项目的组态工程师也适合刚接触面板类型、想少走弯路的初学者直接照抄。1. 先搞清楚面板实例和画面窗口到底解决什么问题1.1 画面窗口把“画面”变成可复用的控件画面窗口Picture Window本质上是一个容器对象你可以在它里面再嵌套一幅独立的画面。它的核心价值是把“整幅画面”当作一个控件来用。举个例子项目里有十几台设备每台都需要一个“参数设置页”页面布局几乎一样只是对象名和变量不同。传统做法是复制粘贴十几个画面然后逐个改变量连接后续想改一个公共样式就得全改一遍。用画面窗口的做法是单独做一页“参数设置”画面在主画面放多个画面窗口让每个画面窗口都指向同一个参数设置画面。这样后续只需要维护一个画面其他窗口会自动跟随变化。但画面窗口有个天然限制它复用的是“整张画面”不做变量替换。窗口内的按钮、IO域、趋势控件绑定了哪个变量打开后还是哪个变量。所以当复用的对象不是“整页”而是“页里的某个设备控制模块”时画面窗口就不够用了。1.2 面板类型把“逻辑画面”打包成“对象”面板类型Faceplate是WinCC里更高级的复用单元。它不光能把你画好的按钮、指示灯、IO域拼在一起还能把属性接口、脚本逻辑、过程变量绑定关系一起打包成一个“对象”。比如我做了一个“电机控制面板”的面板类型里面包含启动按钮、停止按钮、运行状态灯、电流显示和故障复位按钮。使用的时候我在主画面里放三个面板实例分别绑定M1、M2、M3三台电机的变量。后续如果要在面板里增加一个“累计运行时间显示”我只需要修改面板类型三个实例会同步更新。这才是面板类型和画面窗口最根本的区别画面窗口复用的是“静态页面结构”面板类型复用的是“完整的控制逻辑”。1.3 二者选哪个我的判断标准这几年做项目我基本用下面这个标准来判断比较维度画面窗口面板类型复用粒度整幅画面画面中的局部控件组变量处理不做变量替换依然绑定原变量支持面板参数映射实例化时绑定不同变量脚本逻辑随画面走复用性弱封装在面板内部实例间共享修改维护改一幅画面引用处全部生效改面板类型所有实例同步更新适用场景弹窗、多页面切换、局部区域刷新多台同类设备控制、重复功能块复用还有一条我的个人经验如果一个设备模块要在项目里被复制使用超过三次我宁愿先花时间做成面板类型如果只是临时弹窗、页面跳转直接用画面窗口更省事。两种工具不是互相替代的关系配合使用效果最好。2. 面板实例实操以电机控制面板为例2.1 新建面板类型的五步法先拿一个最典型的“电机控制面板”来演示。以TIA Portal WinCC为例操作步骤如下在项目树中右键“类型”选择“面板类型”新建一个名为FPMotor的面板类型。进入面板编辑器先在布局里画好需要的控件启动按钮、停止按钮、状态指示灯、电流显示IO域、故障复位按钮。在右侧“属性”窗口里切换到“属性接口”页签添加需要对外暴露的面板属性比如MotorPrefix变量前缀字符串类型、MotorRun运行状态Bool类型、MotorCurrent电流值数值类型。把这些面板属性和画面中控件的“动态属性”连接起来。比如状态指示灯的“背景色”动态属性关联MotorRun电流IO域的“输出值”关联MotorCurrent。保存面板类型然后回到主画面从“控件库”里把FPMotor拖到画面上就是一个面板实例。这一步里最关键的是“属性接口”的设计。很多初学者一开始把面板属性建得很随意叫a1、b2过两个月再看根本看不懂。我的习惯是属性名直接表达业务含义比如MotorPrefix、FaultTag、SpeedDisplay后面所有脚本都用可读性强的命名。2.2 面板参数与过程变量的绑定方式面板类型写得好不好全看参数和变量的绑定方式。这里分享一个我常用的套路用“变量前缀”作为面板实例的入口而不是直接传一堆变量名。假设项目里三台电机的变量是Pump1_CMD、Pump1_RUN、Pump1_CurrentPump2_CMD、Pump2_RUN、Pump2_CurrentPump3_CMD、Pump3_RUN、Pump3_Current那么我在面板类型里只需要定义一个字符串类型的面板属性Prefix然后在面板内部把所有变量引用都写成“前缀后缀”的动态拼接。实例化FPMotor时在属性窗口里把Prefix分别填成Pump1、Pump2、Pump3这个面板就自动对应到不同电机了。这样做的好处非常明显以后新增一台电机不需要再复制面板、改脚本只要拖一个新实例、填一个前缀就完事。脚本逻辑只在面板类型里维护一份杜绝了“改了三号机忘了改四号机”的经典事故。2.3 给面板加属性和脚本事件面板里的按钮仍然要写脚本区别在于脚本要写成“相对”逻辑。拿启动按钮举例我不会直接在按钮的鼠标事件里写HMIRuntime.Tags(Pump1_CMD).Write 1而是先读取当前面板实例的前缀再拼接出完整变量名。不同版本的WinCC在脚本接口上会有些差异我用伪代码示意一下核心思路Sub OnClick_Start(ByVal Item) Dim sPrefix, tag sPrefix ScreenItems(FPMotor1).GetProperty(Prefix) 获取当前实例的前缀 HMIRuntime.Tags(sPrefix _CMD).Write 1 写入启动命令 End Sub实际工程里按钮脚本里还应该加上互锁逻辑比如“运行状态下启动按钮置灰”“故障状态下禁止启动”。这些逻辑同样可以封装在面板类型内部实例化后每个设备都能获得一致的防误操作保护。2.4 实例化时最容易踩的三个坑第一个坑是面板属性的数据类型不匹配。比如电流IO域连的是数值类型但实例化时在属性接口里填了个字符串常量运行后显示不出来。解决方法是属性定义时明确类型实例化时严格按类型填写。第二个坑是面板内部对象名的冲突。面板类型里的控件在运行时会自动生成内部对象名但如果你在面板Libraries里复制了一个实例又手改了里面的对象名可能导致脚本找不到对象。我建议所有面板内部对象名保持自动生成不要手动改名。第三个坑是变量路径问题。面板类型内部尽量使用相对变量路径不要写死“站名/连接名/变量名”的绝对路径。项目换电脑、换连接名称时绝对路径很容易导致变量断开排查起来特别头疼。3. 画面窗口示例弹窗关闭后为什么打不开怎么解决3.1 弹窗最基本的组态方式画面窗口一个特别常见的用法是做弹窗。基本组态是主画面上放一个画面窗口PIC_Pop设置好尺寸和显示属性单独建一个弹窗画面PopUp.pdl里面放需要展示的内容然后在主画面的“打开弹窗”按钮事件里写脚本ScreenItems(PIC_Pop).PictureName PopUp.pdl ScreenItems(PIC_Pop).Visible True弹窗内部放一个“关闭”按钮关闭按钮的事件脚本最简单也最安全的写法是ScreenItems(PIC_Pop).Visible False这里有一个容易被忽略的点画面窗口的PictureName一旦设置好就不要在关闭时去改变它。你只需要控制Visible属性弹窗下次打开时还是原来的画面加载速度也更快。3.2 “关闭一次就打不开”的根本原因网上搜索“wincc画面弹窗关闭一次就打不开了”能搜到一大串求助帖。我自己排查过几次总结下来绝大多数原因都出在关闭脚本上。最常见的错误关闭脚本是ScreenItems(PIC_Pop).PictureName 这段代码会把画面窗口内部的画面卸载掉窗口变成一个空容器。如果此时再把Visible设置成False下次打开按钮的脚本只写了Visible True没有重新给PictureName赋值那自然什么都显示不出来。还有一种情况是关闭时执行了ScreenItems(PIC_Pop).Enable False。这个属性控制的是画面窗口是否允许交互禁用后再点按钮没有任何反馈看起来就像“打不开了”。实际上根本不是打不开而是整个窗口被禁用了。3.3 标准修复方案重新关联画面名称如果你的项目已经出现了“弹窗关闭一次就打不开”的现象修复思路很简单在打开按钮的事件脚本里每次都重新指定画面名称和显示属性ScreenItems(PIC_Pop).PictureName PopUp.pdl ScreenItems(PIC_Pop).Enable True ScreenItems(PIC_Pop).Visible True这段代码放在打开按钮事件里就能覆盖掉之前被清空或被禁用的状态。但要注意如果关闭脚本里把PictureName清空了打开脚本就必须先重新指定画面名称。如果关闭脚本里只是隐藏窗口那打开脚本只需要把Visible设为True。两种方式的区别要搞清楚别混着用。3.4 更稳的做法用面板类型包住画面窗口如果项目里需要多个一模一样的弹窗我更推荐把“画面窗口”再封装到面板类型里面。也就是说你先做一个“弹窗面板”的面板类型内部放一个画面窗口和打开/关闭按钮面板类型对外暴露的属性包括“要加载的画面名称”“弹窗标题”等。这样做的好处是弹窗的打开关闭逻辑在面板类型里只维护一份十几台设备各放一个弹窗面板实例都复用同一套逻辑。以后要修改弹窗样式只需要改面板类型而不是去十几个画面里翻按钮事件。这种组合用法在综合示例里会更加直观。4. 综合示例电机控制面板 画面窗口弹出实时趋势4.1 场景设计用一个真实场景来收尾某水处理项目中控画面里排列4台泵每台泵需要启停控制、运行状态显示、电流显示同时单击泵面板上的“趋势”按钮弹出一个小窗口显示这台泵的电流实时趋势。这个场景如果不用面板类型常规做法是复制4套泵控制画面再复制4个趋势弹窗每个变量单独配置。等调试时你会发现光改一个泵的按钮位置都要改四遍。用“面板类型画面窗口”组合拳的话结构会清晰很多电机控制面板FPMotor负责启停、状态、电流显示。趋势弹窗画面TrendPop.pdl负责显示一台泵的电流趋势。一个主画面放置4个FPMotor实例和1个画面窗口。4.2 创建趋势图面板类型趋势弹窗我也建议直接做成面板类型FPTrendPop而不是用散落的画面窗口。面板类型内部放一个画面窗口对象PIC_Trend窗口内嵌TrendPop.pdl面板类型对外暴露一个属性TrendPrefix用来接收当前是哪个泵。趋势画面的变量配置在面板内部实现。WinCC在线趋势控件的具体操作方法在不同版本里略有差异但思路一致第一步在趋势控件的属性里预先配置好数据源类型为“变量”第二步在启动脚本中用面板实例传进来的TrendPrefix拼出完整变量名然后调用趋势控件的“添加趋势”方法完成动态切换。面板类型封装的打开按钮脚本大致长这样Sub OpenTrend(ByVal Item) Dim sPrefix sPrefix ScreenItems(FPMotor1).GetProperty(Prefix) HMIRuntime.Tags(CurrentPumpPrefix).Write sPrefix 记录当前要显示趋势的泵 ScreenItems(PIC_Trend).PictureName TrendPop.pdl ScreenItems(PIC_Trend).Visible True End Sub4.3 通过VBS脚本刷新趋势并弹出画面窗口然后在TrendPop.pdl画面的加载事件里读取这个内部变量并设置趋势控件。Sub OnOpenPicture() Dim sPrefix, sTrendTag, objTrend sPrefix HMIRuntime.Tags(CurrentPumpPrefix).Read sTrendTag sPrefix _Current 假设趋势控件对象名为 TrendCtrl Set objTrend ScreenItems(TrendCtrl) objTrend.ClearAllTrends 清空之前加载的趋势 objTrend.AddTrend sTrendTag 添加当前泵的电流变量 End Sub这里的ClearAllTrends和AddTrend在不同版本里可能叫别的名字你可以在趋势控件上右键选择“属性”-“方法”查看当前环境实际支持的方法名。这个思路本身是通用的。整个流程串起来就是操作员点击某台泵面板上的“趋势”按钮面板实例通过前缀把泵编号写入内部变量然后画面窗口加载趋势画面趋势画面在加载事件中根据泵编号动态切换趋势曲线。4.4 现场调试时需要关注的几个细节第一个细节是趋势控件的初始化速度。WinCC在线趋势控件首次加载需要一点时间如果弹出窗口后立刻要看到曲线建议在加载事件里做一小段延时或者先让弹窗显示一个“正在加载”的提示。第二个细节是画面窗口的模态属性。如果希望弹窗显示期间不能操作主画面就把Modal属性设为True如果希望既能看趋势又能操作主画面就保持False。这个一定要在打开前设置好运行中动态切换模态状态经常会有兼容性问题。第三个细节是弹窗位置。很多工程师直接用画面窗口默认位置结果在不同分辨率屏幕下弹窗跑到屏幕外。建议在打开弹窗的脚本里显式指定Left和Top比如让弹窗居中显示ScreenItems(PIC_Trend).Left (ScreenWidth - ScreenItems(PIC_Trend).Width) / 2 ScreenItems(PIC_Trend).Top (ScreenHeight - ScreenItems(PIC_Trend).Height) / 25. 常见问题速查与经验心得5.1 问题速查表症状常见原因解决方案画面窗口弹窗关闭一次后打不开关闭脚本清空了PictureName或禁用了窗口打开脚本里重新赋值PictureName和Enable面板实例不显示变量数据面板属性类型不匹配或变量路径错误检查属性接口类型改用相对变量路径多个面板实例控件互相干扰脚本内硬编码了对象名或变量名面板内部逻辑全部改为通过面板属性传递趋势弹窗打开后曲线不刷新加载事件执行太快趋势控件未初始化完成在加载事件中加入延时或手动触发刷新修改面板类型后实例没变化项目未重新激活或缓存未刷新保存后重新激活运行系统画面窗口加载的画面脚本报错画面名称写错或画面不在当前项目路径检查PictureName是否与画面文件完全一致5.2 面板与画面窗口复用的几条经验面板类型和画面窗口的搭配说到底就是把“重复”变成“一次”。我现在的习惯是只要一个设备模块会在项目里被复制超过三次就先把模块做成面板类型只要画面窗口要在多个位置复用就考虑把画面窗口也封装进面板让打开关闭逻辑跟着面板走。面板属性命名一定要规范。我见过太多项目里属性叫P1、P2等做后期维护的时候完全猜不出含义。宁可名字长一点也要让人一眼看懂这个属性是干什么的。另外面板类型内部尽量不要写死ScreenItems(...)这种绝对对象引用尤其在弹窗和主画面配合的场景下脚本越“参数化”面板的复用性越好。正确做法是脚本里的所有可变部分都通过面板属性传到面板内部实例之间互不干扰。最后分享一个我踩过的大坑早年在十几个画面里手工改变量每次增加一台设备就要复制粘贴好几遍改到第三台就已经眼花缭乱后来才下决心研究面板类型。把四台泵的控制全部改成面板实例后新增第五台泵只花了十分钟。这种东西用一次就再也回不去了。
返回列表