我在masterscada4D上面画了个饼状图svg,并有xml文件,要求每扇能够与标签数据连接,能...

Создано: 10 апреля 2026 г.

Отвечено с использованием GPT-5.4 Thinking от Chat01

Вопрос

image.png

我在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">
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>
</g> </svg>

,写了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>
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" />
</ParameterDefs> </SvgDef>

,我还在ST代码中写了

;VAR

text
GoodR : 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

text
GoodPath := '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;

text
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
GoodPath := 'M 0,0 Z';
BadPath := 'M 0,0 Z';

text
GoodOpacity := '0'; BadOpacity := '0'; LegendGoodContent := CONCAT('Годные: ', DINT_TO_STRING(GoodValue)); LegendBadContent := CONCAT('Чёрные: ', DINT_TO_STRING(BadValue));

ELSE
(* 3. 计算角度 *)
GoodDeg := GoodR * 360.0 / TotalR;

text
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文件进行仿真?又该怎么运行屏幕进行显示?详细告诉我应该点击哪里,又该怎么设置

Мысль

undefined

Мысль

Thought for 14s

Мысль

undefined

Мысль

undefined

Мысль

undefined

Мысль

Thought for 19s

Мысль

undefined

Мысль

undefined

Мысль

undefined

Мысль

Thought for 25s

Мысль

undefined

Мысль

undefined

Мысль

undefined

Мысль

Thought for 42s

Мысль

undefined

Мысль

undefined

Мысль

undefined

Мысль

Thought for 49s

Мысль

undefined

Мысль

undefined

Мысль

undefined

Мысль

Thought for 58s

Мысль

undefined

Мысль

undefined

Мысль

undefined

Мысль

Thought for 1m 35s

Мысль

undefined

Мысль

undefined

Мысль

undefined

Мысль

Thought for 1m 56s

Мысль

undefined

Мысль

undefined

Мысль

undefined

Мысль

Thought for 2m 2s

Мысль

undefined

Мысль

undefined

Мысль

Providing structured response with reasoning and citations

I think the response should focus on core reasoning without over-citing every line, considering we've already drawn from web sources when needed. I'll mention that testing can be done without PLC, and then outline the path the user should follow for object tags, ST programs, and SVG parameters.

At least two issues should be highlighted:

  1. XML ItemId mismatch: The user's provided code shows the need to unify legendGoodColor and legendBadColor with legendGoodRect and legendBadRect in the XML.

  2. For text parameters, the official example uses Path="content", so it's a good move to suggest switching LegendGoodContent and LegendBadContent from textContent to content, supported by official documentation.

Providing clarification on parameters and runtime modes

I should suggest changing the path to "content" with the advice that the official example uses this for text parameters, while I'm not sure if "textContent" will be compatible. I can mention this and cite the official example.

It’s also important to note that the XML file needs to match the name and folder structure of the SVG, so I'd cite the relevant document. I may also reference the import process from the library and selection of XML updates, with another citation.

Additionally, I'll mention that ST program properties must be compiled and applied to generate I/O, and the execution method should be periodic, with the task running in the parent object's settings — citing references for that.

Finally, to run the program, I’ll detail using F5 or the menu and explain that debugging mode is best for local testing. I'll emphasize that F5 enters runtime, but debug mode starts all elements on the current PC.

Thought for 3m 10s

Ответ

可以,不用实际 PLC 也能把这个饼图跑起来。你现在最适合的测试路径是:

Object1 里的人工测试标签 → ST_program_1 周期执行 → 输出 GoodPath/BadPath/Legend… → 绑定到 SVG 参数 → 用“调试模式”本机运行窗口。
MasterSCADA 的 ST 程序要先“编译”再“应用”才会生成输入输出参数;程序的“执行方式”里有“周期执行/按调用/启动时执行”;而“调试模式”会把所有对象和功能块都放在当前电脑上运行,这正适合你这种“没有 PLC、只做本机仿真”的场景。(MPS Soft Support)

先说你现在文件里最可能挡住动态显示的两个点

第一,你的 SVG 里图例色块 id 是 legendGoodColorlegendBadColor,但 XML 里写的是 legendGoodRectlegendBadRect,这两个名字对不上,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)

下面按“你现在这个工程”给你一步一步点:

1)先把 SVG/XML 重新导入或刷新

在左侧树里找到库/窗口,新建一个窗口后,右键这个窗口 → 导入 SVG(Импорт SVG)
如果你的 SVG 之前已经导入过,那么这次直接选对应的 XML 也可以更新描述。导入时,带 XML 的 SVG 会进入带参数化的导入流程。(MPS Soft Support)

2)检查 ST 程序是否真的已经生效

你截图里 ST_program_1 右侧已经能看到 GoodValue / BadValue / GoodPath / BadPath...,说明它至少编译并应用过一次
但你改过代码以后,还是要再做一遍:

打开 ST_program_1 → 在代码页点击 “编译” → 底部看到“编译成功” → 再点 “应用”
官方说明就是:编译成功后,点“应用”,这个 ST 程序的输入输出端口才会出现在对象树/属性里。(MPS Soft Support)

3)设置 ST_program_1 的执行方式

选中 ST_program_1,看右侧 Properties / 属性 面板,找到程序属性里的“任务/执行”那一组。你要这样设:

  • 执行位置(Место исполнения)在父对象任务中 / В задаче родительского объекта
  • 执行方式(Способ исполнения)周期 / Периодический

因为你这个程序是根据输入标签不断重新算饼图路径,不应该设成“按调用”,否则它不会自动刷新。官方对这两个属性的定义就是这样的。(MPS Soft Support)

4)把测试标签接到 ST 输入

你现在说测试标签建在 Object1,而 ST_program_1Object2。这没问题,但一定要真正建立连接
最直接的做法:

  • 在左侧树里找到 Object1 里的两个测试标签,比如 GoodValueTestBadValueTest
  • 把它们分别拖到 ST_program_1GoodValueBadValue 输入上,建立连接

如果只是名字像,但没连线,ST 不会收到值。
你截图里 GoodValueBadValue 是程序输入端口,正适合这么接。

5)把 ST 输出接到 SVG 实例参数

这一步最关键。不是把输出接到“SVG 文件”,而是接到窗口里那个 SVG 图元实例的参数。

做法:

  • 打开你的 pie_chart 窗口
  • 单击窗口里的那个饼图 SVG 元件
  • 右侧属性里应该能看到它暴露出来的参数:GoodPathBadPathGoodOpacityBadOpacityLegendGoodContentLegendBadContent……
  • ST_program_1 对应输出,一一绑定过去

对应关系如下:

  • ST_program_1.GoodPath → SVG.GoodPath
  • ST_program_1.BadPath → SVG.BadPath
  • ST_program_1.GoodOpacity → SVG.GoodOpacity
  • ST_program_1.BadOpacity → SVG.BadOpacity
  • ST_program_1.LegendGoodContent → SVG.LegendGoodContent
  • ST_program_1.LegendBadContent → SVG.LegendBadContent

如果你也想让颜色以后跟着变,再把 GoodFill/BadFill 也连上。

6)做一个最简单的“人工输入测试窗口”

因为你没有 PLC,最省事的测试方法不是去接驱动,而是在窗口上放两个输入框

在测试窗口里放:

  • 一个数值输入控件,绑定 Object1.GoodValueTest
  • 一个数值输入控件,绑定 Object1.BadValueTest
  • 再把你的 SVG 饼图也放在同一个窗口里

这样你运行后,直接在画面上输入 8020,就能看饼图变化。
推荐你先测这几组:

  • 80 / 20
  • 50 / 50
  • 0 / 100
  • 100 / 0
  • 0 / 0

这样能把你 ST 里 0%、100%、无数据 三种分支都测到。

7)把这个窗口设成启动窗口

如果你希望一进入运行态就自动看到这个饼图窗口:

  • 在系统树里选中计算机/Computer
  • 打开它的属性页里的 运行时 → 启动窗口(Стартовые окна)
  • 把你的 pie_chart 窗口拖进去
  • 在下拉框里选择要启动的文档类型

官方说明里,这个页面就是用来指定“运行模式启动时自动打开哪些窗口”的。(MPS Soft Support)

8)开始本机仿真

你现在没有 PLC,不要先用正式运行(Пуск),先用:

  • 顶部菜单 Режим → Отладка
  • 或者点工具栏上“调试/虫子样”的那个按钮

因为官方说明里,“调试模式”就是专门给单机调试项目用的:不管系统树里有多少节点,所有对象、功能块、OPC 服务器都在当前电脑创建并运行。(MPS Soft Support)

补充一下快捷键:

  • F5:进入运行模式
  • Shift + F5:退出运行模式

这是官方热键表里的定义。(MPS Soft Support)

9)如果想单独开可视化客户端

除了在开发环境里运行,你也可以单独打开客户端看画面:

  • 打开 MasterSCADA Launcher
  • “Запустить клиент визуализации”(启动可视化客户端)

官方说明里,Launcher 就是专门用来启动 MasterSCADA ClientMonitor 的。(MPS Soft Support)

如果你已经配置了客户端地址,也可以用 MasterSCADA 4D Client 直接连本机服务器。它支持启动后直接打开可视化界面。(MPS Soft Support)


你这个工程里,我建议你按下面顺序检查

  1. 先改 XML

    • legendGoodRectlegendGoodColor
    • legendBadRectlegendBadColor
    • textContentcontent
  2. 重新导入 XML/SVG

  3. 重新编译 + 应用 ST_program_1

  4. 把 ST_program_1 设成 周期执行

  5. 确认 GoodValue/BadValue 真的连到了 Object1 的测试标签

  6. 确认 ST 输出真的连到了“窗口中 SVG 实例”的参数

  7. 把 pie_chart 设成启动窗口

  8. 用 Режим → Отладка 本机运行


如果运行后还是不动,通常就是这 5 个原因

  • XML 里的 ItemId 和 SVG 元素 id 不一致
  • 文本参数路径写成了 textContent
  • ST 程序没点“应用”,端口还是旧的
  • ST 程序执行方式不是“周期”
  • 改的是 Object1 里的测试标签,但 SVG 绑定的是别的对象参数

你这套思路本身是对的,离跑起来已经很近了。现在最大概率不是 ST 算法问题,而是XML 参数映射运行方式/连接关系的问题。

你把当前 pie_chart 窗口里那个 SVG 实例的参数绑定截图再发我一张,我可以直接按你这个工程界面继续告诉你“下一下点哪里”。

Поделиться этим Q&A