我在masterscada4D上面画了个饼状图svg,并有xml文件,要求每扇能够与标签数据连接,能...
Created on: April 10, 2026
Answered using GPT-5.4 Thinking by Chat01
Created on: April 10, 2026
Answered using GPT-5.4 Thinking by Chat01
我在masterscada4D上面画了个饼状图svg,并有xml文件,要求每扇能够与标签数据连接,能够随着数据进行动态展示。我现在没有实际的plc设备,我只是在objects1上面进行了标签的创建,在基础图形上面是没有饼状图的,我是自己画了svg图像<svg width="500" height="400" viewBox="0 0 500 400"
xmlns="http://www.w3.org/2000/svg">
<g id="root">
</g> </svg>text<!-- 背景 --> <rect id="bgRect" x="0" y="0" width="500" height="400" fill="#dcdcdc"/> <!-- 标题 --> <text id="titleText" x="250" y="40" font-size="24" font-weight="bold" text-anchor="middle" fill="#333"> Сравнение годных и чёрных фишек </text> <!-- 饼图 --> <g id="pieGroup" transform="translate(180,220)"> <!-- 良品(动态) --> <path id="sliceGood" d="M 0,0 L 0,-150 A 150,150 0 1,1 -150,0 Z" fill="#6ec35a" stroke="white" stroke-width="2"/> <!-- 不良品(动态) --> <path id="sliceBad" d="M 0,0 L -150,0 A 150,150 0 0,1 0,-150 Z" fill="#e04b36" stroke="white" stroke-width="2"/> </g> <!-- 图例 --> <g id="legendGroup" transform="translate(320, 60)"> <rect id="legendGoodColor" x="0" y="0" width="16" height="16" fill="#6ec35a" rx="2" /> <text id="legendGoodText" x="24" y="12" font-size="16" fill="#333"> Годные </text> <rect id="legendBadColor" x="0" y="30" width="16" height="16" fill="#e04b36" rx="2" /> <text id="legendBadText" x="24" y="42" font-size="16" fill="#333"> Чёрные </text> </g>
,写了xml文件
<?xml version="1.0" encoding="utf-8"?> <SvgDef xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" CreateCommonAvary="false"> <ParameterDefs></ParameterDefs> </SvgDef>text<ParameterDef DisplayName="GoodPath" Type="STRING" ParamType="Attribute" ItemId="sliceGood" Path="d" /> <ParameterDef DisplayName="BadPath" Type="STRING" ParamType="Attribute" ItemId="sliceBad" Path="d" /> <ParameterDef DisplayName="GoodFill" Type="HMI.SolidColorType" ParamType="Attribute" ItemId="sliceGood" Path="fill" /> <ParameterDef DisplayName="BadFill" Type="HMI.SolidColorType" ParamType="Attribute" ItemId="sliceBad" Path="fill" /> <ParameterDef DisplayName="GoodOpacity" Type="STRING" ParamType="Attribute" ItemId="sliceGood" Path="opacity" /> <ParameterDef DisplayName="BadOpacity" Type="STRING" ParamType="Attribute" ItemId="sliceBad" Path="opacity" /> <ParameterDef DisplayName="LegendGoodFill" Type="HMI.SolidColorType" ParamType="Attribute" ItemId="legendGoodRect" Path="fill" /> <ParameterDef DisplayName="LegendBadFill" Type="HMI.SolidColorType" ParamType="Attribute" ItemId="legendBadRect" Path="fill" /> <ParameterDef DisplayName="LegendGoodContent" Type="STRING" ParamType="Attribute" ItemId="legendGoodText" Path="textContent" /> <ParameterDef DisplayName="LegendBadContent" Type="STRING" ParamType="Attribute" ItemId="legendBadText" Path="textContent" />
,我还在ST代码中写了
;VAR
textGoodR : REAL; BadR : REAL; TotalR : REAL; GoodDeg : REAL; BadDeg : REAL; EndDeg : REAL; EndRad : REAL; EndXr : REAL; EndYr : REAL; EndXi : INT; EndYi : INT; GoodPct : INT; BadPct : INT; LargeGood : STRING; LargeBad : STRING; SX : STRING; SY : STRING; T1 : STRING; T2 : STRING;
END_VAR
(* 1. 输入值转 REAL,便于后续三角函数计算 *)
GoodR := DINT_TO_REAL(GoodValue);
BadR := DINT_TO_REAL(BadValue);
TotalR := GoodR + BadR;
(* 2. 无数据时隐藏整个饼图 *)
IF TotalR <= 0.0 THEN
textGoodPath := 'M 0,0 Z'; BadPath := 'M 0,0 Z'; GoodOpacity := '0'; BadOpacity := '0'; LegendGoodContent := CONCAT('Годные: ', DINT_TO_STRING(GoodValue)); LegendBadContent := CONCAT('Чёрные: ', DINT_TO_STRING(BadValue));
ELSE
text(* 3. 计算角度 *) GoodDeg := GoodR * 360.0 / TotalR; IF GoodDeg < 0.0 THEN GoodDeg := 0.0; END_IF; IF GoodDeg > 360.0 THEN GoodDeg := 360.0; END_IF; BadDeg := 360.0 - GoodDeg; (* 4. 计算百分比文字 *) GoodPct := REAL_TO_INT(GoodR * 100.0 / TotalR); IF GoodPct < 0 THEN GoodPct := 0; END_IF; IF GoodPct > 100 THEN GoodPct := 100; END_IF; BadPct := 100 - GoodPct; T1 := CONCAT('Годные: ', DINT_TO_STRING(GoodValue)); T1 := CONCAT(T1, ' ('); T1 := CONCAT(T1, INT_TO_STRING(GoodPct)); T1 := CONCAT(T1, '%)'); LegendGoodContent := T1; T2 := CONCAT('Чёрные: ', DINT_TO_STRING(BadValue)); T2 := CONCAT(T2, ' ('); T2 := CONCAT(T2, INT_TO_STRING(BadPct)); T2 := CONCAT(T2, '%)'); LegendBadContent := T2; (* 5. 特殊情况:0% *) IF GoodDeg <= 0.001 THEN GoodPath := 'M 0,0 Z'; BadPath := 'M 0,0 L 0,-150 A 150,150 0 1,1 0,150 A 150,150 0 1,1 0,-150 Z'; GoodOpacity := '0'; BadOpacity := '1'; (* 6. 特殊情况:100% *) ELSIF GoodDeg >= 359.999 THEN GoodPath := 'M 0,0 L 0,-150 A 150,150 0 1,1 0,150 A 150,150 0 1,1 0,-150 Z'; BadPath := 'M 0,0 Z'; GoodOpacity := '1'; BadOpacity := '0'; (* 7. 正常情况:0% ~ 100% 之间 *) ELSE GoodOpacity := '1'; BadOpacity := '1'; (* 起点固定在圆顶点 (0,-150),终点按角度计算 *) EndDeg := -90.0 + GoodDeg; EndRad := EndDeg * 3.1415926 / 180.0; EndXr := 150.0 * COS(EndRad); EndYr := 150.0 * SIN(EndRad); (* 转整数,避免 SVG 路径里出现小数格式问题 *) EndXi := REAL_TO_INT(EndXr); EndYi := REAL_TO_INT(EndYr); SX := INT_TO_STRING(EndXi); SY := INT_TO_STRING(EndYi); (* 大弧标志 *) IF GoodDeg > 180.0 THEN LargeGood := '1'; ELSE LargeGood := '0'; END_IF; IF BadDeg > 180.0 THEN LargeBad := '1'; ELSE LargeBad := '0'; END_IF; (* 良品扇区路径 *) GoodPath := 'M 0,0 L 0,-150 A 150,150 0 '; GoodPath := CONCAT(GoodPath, LargeGood); GoodPath := CONCAT(GoodPath, ',1 '); GoodPath := CONCAT(GoodPath, SX); GoodPath := CONCAT(GoodPath, ','); GoodPath := CONCAT(GoodPath, SY); GoodPath := CONCAT(GoodPath, ' Z'); (* 不良品扇区路径 *) BadPath := 'M 0,0 L '; BadPath := CONCAT(BadPath, SX); BadPath := CONCAT(BadPath, ','); BadPath := CONCAT(BadPath, SY); BadPath := CONCAT(BadPath, ' A 150,150 0 '); BadPath := CONCAT(BadPath, LargeBad); BadPath := CONCAT(BadPath, ',1 0,-150 Z'); END_IF;
END_IF;
并且我还创建了ST文件,
;VAR
GoodR : REAL;
BadR : REAL;
TotalR : REAL;
textGoodDeg : REAL; BadDeg : REAL; EndDeg : REAL; EndRad : REAL; EndXr : REAL; EndYr : REAL; EndXi : INT; EndYi : INT; GoodPct : INT; BadPct : INT; LargeGood : STRING; LargeBad : STRING; SX : STRING; SY : STRING; T1 : STRING; T2 : STRING;
END_VAR
(* 1. 输入值转 REAL,便于后续三角函数计算 *)
GoodR := DINT_TO_REAL(GoodValue);
BadR := DINT_TO_REAL(BadValue);
TotalR := GoodR + BadR;
(* 2. 无数据时隐藏整个饼图 *)
IF TotalR <= 0.0 THEN
GoodPath := 'M 0,0 Z';
BadPath := 'M 0,0 Z';
textGoodOpacity := '0'; BadOpacity := '0'; LegendGoodContent := CONCAT('Годные: ', DINT_TO_STRING(GoodValue)); LegendBadContent := CONCAT('Чёрные: ', DINT_TO_STRING(BadValue));
ELSE
(* 3. 计算角度 *)
GoodDeg := GoodR * 360.0 / TotalR;
textIF GoodDeg < 0.0 THEN GoodDeg := 0.0; END_IF; IF GoodDeg > 360.0 THEN GoodDeg := 360.0; END_IF; BadDeg := 360.0 - GoodDeg; (* 4. 计算百分比文字 *) GoodPct := REAL_TO_INT(GoodR * 100.0 / TotalR); IF GoodPct < 0 THEN GoodPct := 0; END_IF; IF GoodPct > 100 THEN GoodPct := 100; END_IF; BadPct := 100 - GoodPct; T1 := CONCAT('Годные: ', DINT_TO_STRING(GoodValue)); T1 := CONCAT(T1, ' ('); T1 := CONCAT(T1, INT_TO_STRING(GoodPct)); T1 := CONCAT(T1, '%)'); LegendGoodContent := T1; T2 := CONCAT('Чёрные: ', DINT_TO_STRING(BadValue)); T2 := CONCAT(T2, ' ('); T2 := CONCAT(T2, INT_TO_STRING(BadPct)); T2 := CONCAT(T2, '%)'); LegendBadContent := T2; (* 5. 特殊情况:0% *) IF GoodDeg <= 0.001 THEN GoodPath := 'M 0,0 Z'; BadPath := 'M 0,0 L 0,-150 A 150,150 0 1,1 0,150 A 150,150 0 1,1 0,-150 Z'; GoodOpacity := '0'; BadOpacity := '1'; (* 6. 特殊情况:100% *) ELSIF GoodDeg >= 359.999 THEN GoodPath := 'M 0,0 L 0,-150 A 150,150 0 1,1 0,150 A 150,150 0 1,1 0,-150 Z'; BadPath := 'M 0,0 Z'; GoodOpacity := '1'; BadOpacity := '0'; (* 7. 正常情况:0% ~ 100% 之间 *) ELSE GoodOpacity := '1'; BadOpacity := '1'; (* 起点固定在圆顶点 (0,-150),终点按角度计算 *) EndDeg := -90.0 + GoodDeg; EndRad := EndDeg * 3.1415926 / 180.0; EndXr := 150.0 * COS(EndRad); EndYr := 150.0 * SIN(EndRad); (* 转整数,避免 SVG 路径里出现小数格式问题 *) EndXi := REAL_TO_INT(EndXr); EndYi := REAL_TO_INT(EndYr); SX := INT_TO_STRING(EndXi); SY := INT_TO_STRING(EndYi); (* 大弧标志 *) IF GoodDeg > 180.0 THEN LargeGood := '1'; ELSE LargeGood := '0'; END_IF; IF BadDeg > 180.0 THEN LargeBad := '1'; ELSE LargeBad := '0'; END_IF; (* 良品扇区路径 *) GoodPath := 'M 0,0 L 0,-150 A 150,150 0 '; GoodPath := CONCAT(GoodPath, LargeGood); GoodPath := CONCAT(GoodPath, ',1 '); GoodPath := CONCAT(GoodPath, SX); GoodPath := CONCAT(GoodPath, ','); GoodPath := CONCAT(GoodPath, SY); GoodPath := CONCAT(GoodPath, ' Z'); (* 不良品扇区路径 *) BadPath := 'M 0,0 L '; BadPath := CONCAT(BadPath, SX); BadPath := CONCAT(BadPath, ','); BadPath := CONCAT(BadPath, SY); BadPath := CONCAT(BadPath, ' A 150,150 0 '); BadPath := CONCAT(BadPath, LargeBad); BadPath := CONCAT(BadPath, ',1 0,-150 Z'); END_IF;
END_IF;
并将标签连接,下一步我想进行测试,该怎么运行ST文件进行仿真?又该怎么运行屏幕进行显示?详细告诉我应该点击哪里,又该怎么设置
可以,不用实际 PLC 也能把这个饼图跑起来。你现在最适合的测试路径是:
Object1 里的人工测试标签 → ST_program_1 周期执行 → 输出 GoodPath/BadPath/Legend… → 绑定到 SVG 参数 → 用“调试模式”本机运行窗口。
MasterSCADA 的 ST 程序要先“编译”再“应用”才会生成输入输出参数;程序的“执行方式”里有“周期执行/按调用/启动时执行”;而“调试模式”会把所有对象和功能块都放在当前电脑上运行,这正适合你这种“没有 PLC、只做本机仿真”的场景。(MPS Soft Support)
先说你现在文件里最可能挡住动态显示的两个点:
第一,你的 SVG 里图例色块 id 是 legendGoodColor 和 legendBadColor,但 XML 里写的是 legendGoodRect 和 legendBadRect,这两个名字对不上,MasterSCADA 就找不到那个 SVG 元素。
第二,文本参数我建议你把 Path="textContent" 改成 Path="content"。官方 XML 示例里,文本内容就是用 Path="content" 来做的;而且 XML 必须严格对应 SVG 结构。(MPS Soft Support)
你先把 XML 改成这样:
xml<?xml version="1.0" encoding="utf-8"?> <SvgDef xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" CreateCommonAvary="false"> <ParameterDefs> <ParameterDef DisplayName="GoodPath" Type="STRING" ParamType="Attribute" ItemId="sliceGood" Path="d" /> <ParameterDef DisplayName="BadPath" Type="STRING" ParamType="Attribute" ItemId="sliceBad" Path="d" /> <ParameterDef DisplayName="GoodFill" Type="HMI.SolidColorType" ParamType="Attribute" ItemId="sliceGood" Path="fill" /> <ParameterDef DisplayName="BadFill" Type="HMI.SolidColorType" ParamType="Attribute" ItemId="sliceBad" Path="fill" /> <ParameterDef DisplayName="GoodOpacity" Type="STRING" ParamType="Attribute" ItemId="sliceGood" Path="opacity" /> <ParameterDef DisplayName="BadOpacity" Type="STRING" ParamType="Attribute" ItemId="sliceBad" Path="opacity" /> <ParameterDef DisplayName="LegendGoodFill" Type="HMI.SolidColorType" ParamType="Attribute" ItemId="legendGoodColor" Path="fill" /> <ParameterDef DisplayName="LegendBadFill" Type="HMI.SolidColorType" ParamType="Attribute" ItemId="legendBadColor" Path="fill" /> <ParameterDef DisplayName="LegendGoodContent" Type="STRING" ParamType="Attribute" ItemId="legendGoodText" Path="content" /> <ParameterDef DisplayName="LegendBadContent" Type="STRING" ParamType="Attribute" ItemId="legendBadText" Path="content" /> </ParameterDefs> </SvgDef>
另外,SVG 和 XML 要同名,并放在同一文件夹里;如果 SVG 已经导入过,再选择对应 XML 文件,MasterSCADA 会更新它的参数描述。(MPS Soft Support)
下面按“你现在这个工程”给你一步一步点:
在左侧树里找到库/窗口,新建一个窗口后,右键这个窗口 → 导入 SVG(Импорт SVG)。
如果你的 SVG 之前已经导入过,那么这次直接选对应的 XML 也可以更新描述。导入时,带 XML 的 SVG 会进入带参数化的导入流程。(MPS Soft Support)
你截图里 ST_program_1 右侧已经能看到 GoodValue / BadValue / GoodPath / BadPath...,说明它至少编译并应用过一次。
但你改过代码以后,还是要再做一遍:
打开 ST_program_1 → 在代码页点击 “编译” → 底部看到“编译成功” → 再点 “应用”。
官方说明就是:编译成功后,点“应用”,这个 ST 程序的输入输出端口才会出现在对象树/属性里。(MPS Soft Support)
选中 ST_program_1,看右侧 Properties / 属性 面板,找到程序属性里的“任务/执行”那一组。你要这样设:
在父对象任务中 / В задаче родительского объекта周期 / Периодический因为你这个程序是根据输入标签不断重新算饼图路径,不应该设成“按调用”,否则它不会自动刷新。官方对这两个属性的定义就是这样的。(MPS Soft Support)
你现在说测试标签建在 Object1,而 ST_program_1 在 Object2。这没问题,但一定要真正建立连接。
最直接的做法:
Object1 里的两个测试标签,比如 GoodValueTest、BadValueTestST_program_1 的 GoodValue、BadValue 输入上,建立连接如果只是名字像,但没连线,ST 不会收到值。
你截图里 GoodValue、BadValue 是程序输入端口,正适合这么接。
这一步最关键。不是把输出接到“SVG 文件”,而是接到窗口里那个 SVG 图元实例的参数。
做法:
pie_chart 窗口GoodPath、BadPath、GoodOpacity、BadOpacity、LegendGoodContent、LegendBadContent……ST_program_1 对应输出,一一绑定过去对应关系如下:
ST_program_1.GoodPath → SVG.GoodPathST_program_1.BadPath → SVG.BadPathST_program_1.GoodOpacity → SVG.GoodOpacityST_program_1.BadOpacity → SVG.BadOpacityST_program_1.LegendGoodContent → SVG.LegendGoodContentST_program_1.LegendBadContent → SVG.LegendBadContent如果你也想让颜色以后跟着变,再把 GoodFill/BadFill 也连上。
因为你没有 PLC,最省事的测试方法不是去接驱动,而是在窗口上放两个输入框。
在测试窗口里放:
Object1.GoodValueTestObject1.BadValueTest这样你运行后,直接在画面上输入 80 和 20,就能看饼图变化。
推荐你先测这几组:
80 / 2050 / 500 / 100100 / 00 / 0这样能把你 ST 里 0%、100%、无数据 三种分支都测到。
如果你希望一进入运行态就自动看到这个饼图窗口:
pie_chart 窗口拖进去官方说明里,这个页面就是用来指定“运行模式启动时自动打开哪些窗口”的。(MPS Soft Support)
你现在没有 PLC,不要先用正式运行(Пуск),先用:
因为官方说明里,“调试模式”就是专门给单机调试项目用的:不管系统树里有多少节点,所有对象、功能块、OPC 服务器都在当前电脑创建并运行。(MPS Soft Support)
补充一下快捷键:
这是官方热键表里的定义。(MPS Soft Support)
除了在开发环境里运行,你也可以单独打开客户端看画面:
官方说明里,Launcher 就是专门用来启动 MasterSCADA Client 和 Monitor 的。(MPS Soft Support)
如果你已经配置了客户端地址,也可以用 MasterSCADA 4D Client 直接连本机服务器。它支持启动后直接打开可视化界面。(MPS Soft Support)
先改 XML
legendGoodRect → legendGoodColorlegendBadRect → legendBadColortextContent → content重新导入 XML/SVG
重新编译 + 应用 ST_program_1
把 ST_program_1 设成 周期执行
确认 GoodValue/BadValue 真的连到了 Object1 的测试标签
确认 ST 输出真的连到了“窗口中 SVG 实例”的参数
把 pie_chart 设成启动窗口
用 Режим → Отладка 本机运行
ItemId 和 SVG 元素 id 不一致textContent你这套思路本身是对的,离跑起来已经很近了。现在最大概率不是 ST 算法问题,而是XML 参数映射和运行方式/连接关系的问题。
你把当前 pie_chart 窗口里那个 SVG 实例的参数绑定截图再发我一张,我可以直接按你这个工程界面继续告诉你“下一下点哪里”。