1225 【万泉河】WINCC中获取窗口变量前缀以及跨窗口操控的方法
近段时间,不约而同的,网站论坛和烟台方法学员中都有提出这样的问题。
比如:
? 用C脚本如何获得窗口中对象的变量前缀?
? 用VBS如何获得?
? 用C脚本如何实现在一个窗口中操控父窗口下的另一个窗口内的控件?
? 用VBS如何实现?
这些问题,都有个特点, 提问的时候先把编程语言给限定了。
而咱就不太有办法拒绝。毕竟,人家有可能是在完成一个更复杂的工作,已经在选定的语言下实现了大部分的功能,现在就在这一点点功能搞不定被卡主了,过不去了,才来求助的。
而如果不指定语言的话,其实我都早就有答案,特别是VBS的解决方案,都写在《西门子WINCC入门到精通》的书里了,所以只需要从书柜里把我自己的书拿出来, 找到页码,把页码号告诉对方就可以了。
而且会发现,大部分提问者其实是有我的那本书的,只是通读不够细致,没发现,或者没记住有这方面的介绍。验证了一个道理,对一本书,最了解的还是作者自己。
当然,我也发现了我写书时候遗漏的该写而未写的技巧知识点。可能潜意识里面,我自己觉得反正另一条路上有解决方案了,这边这一条就没必要去重复啰嗦实现了。特别是C脚本,对西门子来说自从20年前的WINCC版本支持VBS之后,官方逐渐在弱化C脚本的地位, 我自己也逐渐淡化对其的研究和使用。想一碗水端平是永远不可能的。
在此先提醒大家, 提问问题的时候,尽可能不要限定编程语言。那样的答案多的是,可以唾手可得。而非要限定语言了,寻找起来就会有一些难度。
所以,我这里做了个例子,进行了测试,可以把这些坑填上了。 也算是对我自己著作中遗漏部分的补充。
主画面中是2个按钮,分别演示了VBS脚本和C脚本弹出窗口的方法。
而弹出的窗口外观相同,然而内部的程序语言不同, 分别有按钮按下后可以弹出对话框提示读取得到了前缀。
而后, 将上述2个按钮分别放到另一个叫做“窗口中操控”的窗口(PDL文件),脚本经过稍微修改,实现了上述同样的功能。
? 按钮11的单击鼠标中的VBS程序为:
Sub OnClick(ByVal Item)
ScreenItems("画面窗口1").TagPrefix="M001_"
ScreenItems("画面窗口1").PictureName=Item.Text
ScreenItems("画面窗口1").Visible=True
End Sub
而窗口中有2个获取前缀的按钮,同样可以得到结果,脚本分别为:
Sub OnClick(Byval Item)
'MsgBOX(ITEM.Parent.Parent.TagPrefix)
MsgBOX(Parent.TagPrefix)
End Sub
注释掉的脚本也同样可以执行。
Sub OnClick(Byval Item)
Dim name
name=HMIRuntime.Tags("aa").Name
Dim TagPrefix
TagPrefix=Split(name,"_")(0)
MsgBOX(TagPrefix)
End Sub
这里取了一个不存在的aa后缀的变量,然而也丝毫不影响功能。 因为语法本身获取的是变量名字,对变量是否有值是否合法根本不在意。
也注意两种方式得到的前缀分别有分隔符和无分隔符的区别。
标准的用法当然不能每次都通过脚本来获取,而是会在子窗口打开时即执行脚本,获取到前缀后,赋值到一个静态文本中,窗口中任何需要的地方,可以通过读取文本内容得到。
Sub OnOpen()
'MsgBOX(Parent.TagPrefix)
ScreenItems("窗口前缀").Text=Parent.TagPrefix
End Sub
而如果画面窗口中不需要显示这个前缀,可以设置静态文本为隐藏。这是官方例程中惯用的手法。
? 按钮12的单击鼠标中的C程序为:
#include "apdefap.h"
void OnClick(char* lpszPictureName, char* lpszObjectName, char* lpszPropertyName)
{
SetPropChar(lpszPictureName, "画面窗口1", "PictureName","窗口12-C获取前缀.Pdl");
SetPropChar(lpszPictureName, "画面窗口1", "TagPrefix", "M002_");
SetPropBOOL(lpszPictureName, "画面窗口1", "Visible", TRUE);
}
窗口内获取按钮的脚本:
#include "apdefap.h"
void OnClick(char* lpszPictureName, char* lpszObjectName, char* lpszPropertyName)
{
char Name[20];
HWND hwnd=NULL;
hwnd=FindWindow(NULL,"WinCC-运行系统 - "); //获得句柄
strcpy(Name,GetPropChar(GetParentPicture(lpszPictureName),GetParentPictureWindow(lpszPictureName),"TagPrefix")); //Return-Type: char*
MessageBox(hwnd,Name,"OK",MB_OK);
}
画面打开事件中文本内容得到的方法:
#include "apdefap.h"
void OnOpenPicture(char* lpszPictureName, char* lpszObjectName, char* lpszPropertyName)
{
char Name[20];
strcpy(Name,GetPropChar(GetParentPicture(lpszPictureName),GetParentPictureWindow(lpszPictureName),"TagPrefix")); //Return-Type: char*
SetPropChar(lpszPictureName,"窗口前缀","Text",Name); //Return-Type: BOOL
}
这里C脚本实现的核心是一个GetParentPicture的函数,可以得到窗口的父窗口的文件名字。而这个函数是个神仙函数,各种帮助资料中都没有见过介绍。所以只有从已有的使用演示程序中获取。
? 窗口中按钮11的单击鼠标中的VBS程序为:
Sub OnClick(ByVal Item)
Parent.Parent.ScreenItems("画面窗口1").TagPrefix="M001_"
Parent.Parent.ScreenItems("画面窗口1").PictureName=Item.Text
Parent.Parent.ScreenItems("画面窗口1").Visible=True
End Sub
? 窗口中按钮12的单击鼠标中的C程序为:
#include "apdefap.h"
void OnClick(char* lpszPictureName, char* lpszObjectName, char* lpszPropertyName)
{
char szParentPicture[512];
strncpy (szParentPicture, GetParentPicture(lpszPictureName), sizeof(szParentPicture));
SetPropChar(szParentPicture, "画面窗口1", "PictureName","窗口12-C获取前缀.Pdl");
SetPropChar(szParentPicture, "画面窗口1", "TagPrefix", "M002_");
SetPropBOOL(szParentPicture, "画面窗口1", "Visible", TRUE);
}
分别实现了上述同样的功能。
当然,我们也可以随意的组合搭配按钮和窗口内的程序,都可以实现同样的功能。 比如即便你程序的主体语言是C的或者VBS,然而窗口中的文本获得前缀部分可以用VBS简单得到。
最后,这些具体产品知识点的技巧内容我近几年确实很少触及了。 因为在我看来那都是基本功。我甚至也不去记忆具体的函数名字,比如上面的name还是tagname, TagPrefix还是Prefix, 都记不住的。我即便要使用,也都直接找现成的程序模块看一眼,抄来用下即可。
而事实上,随着标准化模块化的推进,这些技能已经很少用到了,因为早就封装完善在模块中了。
有一些年轻人看到我近年来写各种科普文章,很少提及这些具体的技术技能技巧,怀疑我从来没掌握这些技能,DISS我,甚至来跟我PK,只能是他们眼光太短浅了,你要从事技术工作,不是要把一项项的技能从年轻到年老记忆地牢牢的,以随时使用。相反的是,大部分技能是需要封装的,封装以后直接使用,甚至自己要主动把这些具体技能都遗忘掉,才可以有更多的精力去掌握更高层的知识。
最后,给大家的建议是,要尽量少自己从头造轮子。
虽然我自己在成长过程中,是摸着石头过河每个轮子逐个造过来的,遇到任何问题,也都抑制不住要自己亲自造轮子的冲动。 轮子的每一个细节,如果不亲自掌握,就会抓耳挠腮睡觉都不安心。
然而仍然要提醒同行后来者,这是一种非常低效率的行为。 你可以有好奇心,精力充沛的情况下可以对别人造好的轮子仔细研读原理,自己可以从中掌握些基本功,然而自己从头造轮子这件事,就要尽量避免了。
上述例程的实现方法,西门子官方的例子中其实原本就有,而且功能比我这里介绍的要全面而细致得多得多。
西门子官方例程中, BST例程较多的是使用了C脚本,而LBP例程(或者叫做BPL)相同的功能则更多是用VBS实现的。
这些例程我都已经写文章推荐过多次了。这回就不再提供链接以及亲自提供文件了,而只提供名字,需要者自己辛苦一点去找到并学习了解。 看来太容易得到的资料通常都不珍惜,只有自己辛苦一点,千辛万苦得到的才会更加倍的去学习。
另外,考虑到上面的乏味的语言讲述不够直观,有可能很多人看了并不能理解。 我有计划在元旦期间做2次视频直播讲座, 专门讲解展示这个例程的实现方法。第一次直播会在烟台方法学员群中,第二次直播会面向大众。 有感兴趣者请关注公众号、朋友圈,及时获取通知。