上一篇通过移动“组件部署”按钮,认识了配置菜单。这一篇接着读菜单本身:一行名称从哪里来,右侧的小箭头怎样出现,为什么有的项目不能选、有的项目根本看不到,选择后又怎样把结果交给脚本。
我们仍使用标准软件已有功能。贯穿例子是从右侧控制区的菜单选择“内孔心/探测”,把它放到一个原有空位置,只核对配置结果,不点击探测按钮。
点击截图可查看原图。
图 1 右键参数页原有 F5“组件部署”后出现的“功能键配置菜单”。这一菜单直接列出可选功能,没有再展开一层。
原入口中的关键一句是:
widgetFunc["PopMenu","","",915]
最后的 915 表示按参数 #915 的定义建立菜单。菜单的每一项主要来自参数子项,并不是另有一份 .ui 文件把这些菜单行逐个画出来。
上一课中,选择“空”或“组件部署”都会进入原 selmenufunc,由它改按钮配置。本课继续沿这个思路看有子菜单的情况;原有 F5 的配置没有在本课改动。
点击截图可查看原图。
图 2 从熟悉的“程序 → 刀路预览”开始。左侧显示原有程序的离线刀路,右侧是本课要看的控制区。第一排从左到右为“手轮引导、A+、Y+、Z+、空、空”,本例选择第五个位置。
在练习副本中,使用已有开发者账号登录,使右上角显示“超级管理员”。右键第一排第五个空位置,出现下面的菜单:
点击截图可查看原图。
图 3 菜单顶部的实际文字是“手控操控功能键配置菜单”。“空”前的勾表示这个位置当前为空。“手动控制”“对刀/探测”等行右侧的小箭头表示还有下一层。
展开 “对刀/探测”:
点击截图可查看原图。
图 4 该子菜单直接从原生弹出菜单截取,图中显示“内孔心 探测”。它的名称在参数中带换行,菜单中作为一行显示;按钮上则分成两行。
选择 “内孔心 探测”,结果如下:
点击截图可查看原图。
图 5 第一排第五个位置显示“内孔心/探测”。这里只把已有功能放到按钮位置,未定义新的探测方式,也没有执行探测。
本课到看到图 5 的结果为止。 再次左键点击这个按钮,才会进入真正的探测功能。本课不执行该操作;探测输入窗口的读法已在 参数窗口篇 讲解。恢复原布局时,右键这个按钮,在第一层菜单选择“空”即可。
截图采用标准界面。坐标、文件名和参数数值为讲解示例,请以实际配置为准。
路径均相对于软件运行目录。
| 文件或参数 | 本例看什么 |
|---|---|
env/maininterface/maininterface.ui |
右侧现有按钮及对象名,本例为 ctrlButton5 |
env/mainInit |
把 #911 中的动作与位置属性装到右侧按钮上 |
env/program/ctrlfuncmenu |
检查开发者身份,打开第一层菜单 |
env/program/selctrlfuncmenu |
选择后把功能放到刚才右键的位置 |
#910 |
第一层菜单;主值暂存当前功能编号 |
#924 |
“对刀/探测”子菜单 |
#911 |
36 个位置及已有功能定义;主值暂存正在配置的位置 |
env/i18n/translatPack-0、translatPack-1 |
两种语言的菜单及功能名称 |
第五个位置编号为 4,它的位置属性原文是:
-A: (rightClickedEvent:/env/program/ctrlfuncmenu[0](#911=4<<#910=#911item4))
-C(#911item4!=0||#1026item0==2)
-V
右键先记录 #911=4,再把这个位置当前选的功能交给 #910,随后运行 ctrlfuncmenu。后两行让有功能的位置可见;空位置则只有开发者身份能看见,以便配置。
ctrlfuncmenu 的完整内容是:
IF#1026.item[0]!=2GOTO1
widgetFunc["PopMenu","","",910]
N1
与上一篇的区别是菜单号从 915 换成了 910。配置权限来自入口脚本的判断,不是 PopMenu 自动要求每个菜单都必须以开发者身份打开。
以下是本系统 PopMenu 实际读取的主要字段。先对照本例,不必一次记住所有名称。
| 字段 | 菜单中怎样使用 | 本例 |
|---|---|---|
title |
整个菜单的标题;成为子菜单时,父菜单中显示这个标题 | #924.title 为“对刀/探测” |
description |
非空时作为该菜单的样式文字;为空时使用所在窗体的样式 | 决定原生菜单的颜色等外观 |
itemnum |
菜单参数的子项数量 | #924 有 12 个子项,编号 0~11 |
itemtitle[i] |
普通菜单项的名称 | 第 6 项是“内孔心/探测” |
item[i] |
该项的界面属性文字,如勾选、禁用和显示条件 | 检查是否已选、是否已占用 |
itemmin[i] |
区分普通项、分隔线或子菜单 | #910.itemmin[9]=924 指向子菜单 |
itemunit[i] |
普通项的图标文件名,以及可选的建立条件 | 可写成“图标文件名 << 条件” |
itemdesc[i] |
选中后的脚本路径及准备赋值 | /env/program/selctrlfuncmenu<<#910=50 |
itemversion[i] |
普通项选择后采用哪类脚本调用设置 | 本例为 1,调用 Qt 组态脚本 |
这些字段在这里按菜单规则使用。itemmin 不是数值输入的下限,itemunit 不是毫米等单位,itemdesc 也不是一段帮助说明。要按实际用途读。
菜单项可以用 item[i] 中的 -T(...) 改变显示文字;没有这种覆盖时使用 itemtitle[i]。本例功能名称来自 itemtitle,不用另外写一组 -T。
关键就是 itemmin:
| 值 | 软件怎样建立这一项 |
|---|---|
0 |
普通菜单项,点击后按该项的脚本定义处理 |
小于 0 |
分隔线 |
大于 0 |
把这个数作为另一组菜单参数号,再建立下一层 |
在本例第一层菜单中,可以核对这些实际值:
| 字段 | 当前值 | 结果 |
|---|---|---|
#910.itemmin[1] |
-1 |
标题行之后的分隔线,外观由样式决定 |
#910.itemmin[2] |
0 |
普通的“空”菜单项 |
#910.itemmin[3] |
919 |
“手动控制”子菜单 |
#910.itemmin[9] |
924 |
“对刀/探测”子菜单 |
#910.itemmin[11] |
926 |
“工艺策略”子菜单 |
#910.itemtitle[9] 当前为空,但图 3 仍显示“对刀/探测”,原因是:这一行是子菜单,显示的是 #924.title。 改父项的空名称,不一定会改到屏幕上看到的标题。
标题行也要分清。图 3 顶部不可选择的“手控操控功能键配置菜单”,是第 0 项的名称,配合如下属性显示:
-C(1)
-E0
条件恒成立,所以这行不可选。它不是设置了 #910.title 就自动额外生成的一行;原配置专门保留了第 0 项。
菜单还可以继续分层。现有配置中,#910 的第 11 项指向 #926,#926.itemmin[9] 又指向 #950,后者标题是“轴映射多面雕”。这项带 #929item7==1 的建立条件;本次装载值为 0,因此截图中没有展开这条路径。本课没有为取图开启该功能。当前英文语言包也未提供这组 #950 名称的英文赋值,不能把自行翻译的文字说成现有英文界面。
设计下一层时,应指向另一组正确的菜单参数,保持层次清楚。当前建立过程没有检测“子菜单又指回自己或上一级”的循环,不能这样相互引用。
这一项在 #924 的子项 6,现有定义如下:
| 字段 | 当前内容 |
|---|---|
#924.itemtitle[6] |
中文为“内孔心”换行“探测”;英文为 InnerHole 换行 Probe |
#924.itemmin[6] |
0,普通项 |
#924.itemunit[6] |
空字符串,没有图标,也没有额外的建立条件 |
#924.itemdesc[6] |
/env/program/selctrlfuncmenu<<#910=50 |
#924.itemversion[6] |
1 |
#924.item[6] 中的属性原文为:
-C(#910==50)
-R0
-C(#911item0==50||#911item1==50||#911item2==50||#911item3==50||#911item4==50||#911item5==50||#911item6==50||#911item7==50||#911item8==50||#911item9==50||#911item10==50||#911item11==50||#911item12==50||#911item13==50||#911item14==50||#911item15==50||#911item16==50||#911item17==50||#911item18==50||#911item19==50||#911item20==50||#911item21==50||#911item22==50||#911item23==50||#911item24==50||#911item25==50||#911item26==50||#911item27==50||#911item28==50||#911item29==50||#911item30==50||#911item31==50||#911item32==50||#911item33==50||#911item34==50||#911item35==50)
-E1
长条件只是逐一检查 36 个位置有没有使用功能 50。先读懂前两个位置,再顺着同样的写法往后看即可:
-R0 给这一项打勾,表示当前右键的位置使用该功能。-E1 禁用这一项,表示某个位置已经使用该功能。因此,选好后再次右键同一个按钮,该项既被勾选,又不能重复选择;右键另一个空位置时,它没有勾选,但仍因已被占用而不能选择。本次两种情况都已在原生菜单中核对。
本例一共出现三个不同编号:
| 编号 | 表示什么 |
|---|---|
4 |
第五个按钮的位置 |
6 |
“对刀/探测”菜单中的原始子项号 |
50 |
“内孔心/探测”的功能号 |
这三个数不需要相同。后面找动作要用功能号 50,找菜单名称要用子项号 6,找要更新的按钮则用位置号 4。
点击截图可查看原图。
图 6 从另一个空位置展开“手动控制”。当前配置中 X/Y/Z/A 的相应手控功能已放在面板上,B/C 项未放置;菜单显示情况反映的是功能配置,不表示某个轴正在运动。
| 状态 | 本系统菜单怎样实现 | 看到什么 |
|---|---|---|
| 不建立这项 | itemunit 中 << 后的条件不成立 |
菜单中没有这行 |
| 已建立但隐藏 | 普通项的属性中使用 -C(...) 配合 -V 或 -V编号 |
该动作不显示;不能据此认为参数被删除 |
| 不允许选择 | 属性中的 -E编号 指定条件成立 |
名称仍在,但不能选 |
| 当前已选中 | 属性中的 -R编号 指定条件成立 |
名称前出现勾选 |
-E1 的 1 是条件列表的编号,不是功能号,也不是第几行菜单。-R 在这里控制菜单勾选,不能按输入框的“只读”来解释。原有样式可能把不可选项画成亮底,不能只用颜色深浅作判断。
看一个原有建立条件:#919.itemunit[0] 的全文是:
<<#912itemmax0==1
<< 左侧为空,表示没有图标;右侧检查该轴的配置条件。成立时才建立“X+手控”。第 1 项“X-手控”使用同样条件。
本次局部核对中,临时把这个条件读取的值从 1 改为 0,重新打开菜单后,X+和X-两行不再建立;恢复为 1 后重新打开,两行又出现。其他轴的菜单项保留。这只是核对程序中的内存对照,不是要求读者为练习菜单修改机床轴配置。
另一个例子是第一层的刀库菜单:#910.itemunit[12] 为 <<#901item0!=0。本次刀库类型为 0,所以图 3 没有这一分支。
图 4 的子菜单虽然定义了 12 项,当前只显示 10 项;另外两项被各自条件过滤。可见行从上往下数的位置,不等于原始参数子项号。 隐藏项没有把后面的 #924.itemdesc[6] 变成别的编号。
PopMenu 每次打开时建立菜单并检查条件。修改菜单文字或建立条件后,应关闭再重新打开核对;不要把 -D 理解为当前悬停的弹出菜单会自动持续重建所有项目。
当前本例没有设置菜单图标。源码支持的读取位置如下,学习时先知道去哪里找即可:
| 对象 | 设置位置 | 读取规则 |
|---|---|---|
| 普通菜单项图标 | 该项的 itemunit[i] 中 << 前的文字;没有 << 时使用整个字符串 |
软件在运行目录的 images/ 下寻找该文件 |
| 普通菜单项的建立条件 | 同一字段的 << 后一段 |
无 << 时不附加这一条件;左侧可以留空 |
| 子菜单入口图标 | 子菜单参数本身的 unit,例如子菜单 924 对应 #924.unit |
同样从 images/ 读取 |
| 子菜单名称 | 子菜单参数的 title |
例如图 3 的“对刀/探测”来自 #924.title |
| 普通项名称 | itemtitle[i],或该项 -T(...) 给出的文字 |
中英文包可以给同一字段赋不同名称 |
| 菜单样式 | 该菜单参数的 description |
非空时采用该段样式;为空时用所在窗体的样式 |
有一个容易弄错的地方:父菜单中某项指向子菜单时,父项的 itemunit 仍可控制是否建立这一分支,但该入口的图标读取的是子菜单自己的 unit。不能照普通菜单项的办法只改父项图标文字。
图标和额外文字覆盖规则已按源码确认,本课没有新增图标或改名取图。引用文件应随组态资源一起交付,并核对实际文件是否存在。
本项的选择定义原文是:
/env/program/selctrlfuncmenu<<#910=50
<< 前是要调用的选择脚本,后面是先执行的准备赋值。右键时已经记下 #911=4,现在选择菜单项又写入 #910=50。随后原脚本的完整两行是:
#911.item[#911]=#910
widgetFunc["setWidgetAttribute",#911.itemtitle[#911],"",#911.itemdesc[#911.item[#911]]+#911.itemunit[#911]]
把本例数值带进去,结果就是:
| 顺序 | 改变什么 |
|---|---|
| 1 | #911.item[4] 写入 50,记住第五个位置选了该功能 |
| 2 | 找到 #911.itemtitle[4] 指定的 ctrlButton5,装入“50 号功能属性+第 4 号位置属性” |
因此新按钮取得原功能的名称和动作,同时保留再次右键配置的入口。它没有更新 F1~F12 的 #9995,这点与上一篇参数页的四行脚本不同。
菜单项的 itemversion[6]=1 是本菜单调用 Qt 脚本的设置。不要把按钮事件路径里的 [1] 与它当作同一套编号:
菜单 itemversion |
所请求的脚本类别 |
|---|---|
0 |
NC |
1 |
主 Qt |
2 |
辅助 Qt |
3 |
工具 Qt |
实际 Qt 调用还会结合当前窗体和脚本忙状态安排执行。本例保留原来的 1;不为了“让它更快”改成 NC。普通菜单项的动作入口来自 itemdesc,菜单建立过程会清掉 item 属性里解析出的事件列表,再采用这里的路径。
PopMenu 会等待菜单交互结束,但本分支选择脚本通过排队的调用执行。不能仅凭菜单已关闭,就假设写在 PopMenu 下一行的代码一定晚于选择脚本完成。 标准设计直接把更新放进 selctrlfuncmenu,所需编号也在调用前准备好;照这个流程理解即可。
菜单回调到这里已经结束。真正的探测入口在已有的 #911.itemdesc[50] 中:
-T(#924itemtitle6)
-D
-C(#319item3==1)
-E0
-A: (clickedEvent:customprobe/centerprobing.nc[2])
这段表示按钮显示对应菜单名称,并配置点击时调用探测 NC。这里事件路径的 [2] 才表示 NC 通道,与上一节菜单 itemversion=1 各管不同操作。
所以应分别追两条路径:
| 用户操作 | 调用路径 | 本课是否执行 |
|---|---|---|
| 在子菜单中选“内孔心 探测” | 菜单准备功能号 → selctrlfuncmenu → 设置按钮 |
已局部核对 |
| 左键点击配置好的探测按钮 | 按钮点击事件 → customprobe/centerprobing.nc |
未执行 |
这使第 4 篇参数窗口、第 5 篇功能键和本篇菜单接起来:已有探测功能 → 菜单允许选择 → 把功能放到按钮 → 使用按钮时才进入该功能的参数与动作流程。
center-install 可以帮助追溯这些名称和动作当初如何定义,但它是以前组件部署留下的文件,后续不再调用。当前菜单使用已装载的参数和实际语言包;不能通过修改这个遗留文件来期待下次开菜单自动更新。
先按下面的顺序读通现有定义,再决定改哪一项:
PopMenu 使用哪个参数号;如果没有弹菜单,先检查入口权限。itemmin,找到子菜单参数;不要只在父表里查可见名称。itemdesc;改真正动作还要继续找功能定义。常见现象可以这样查:
| 现象 | 先查哪里 |
|---|---|
| 没有右键菜单 | 按钮是否可见、启用,右键事件是否存在,入口身份检查是否通过 |
| 改了父项名称,子菜单标题没变 | 子菜单参数自己的 title |
| 分隔线成了可点击的空行 | itemmin 是否仍小于 0 |
| 参数有这项,但菜单看不到 | itemunit 的建立条件,以及普通项的 -V 条件 |
| 菜单出现了,但该项不能选 | -E 指向哪条条件,是否已有位置使用该功能 |
| 选择后改了别的按钮 | 右键时准备的位置参数是否正确,是否在选择前被其他脚本改写 |
| 写了点击事件,选菜单却没调用 | 普通菜单项应检查 itemdesc 和 itemversion;不能只照搬按钮的事件字段 |
| 图标不显示 | 普通项与子菜单图标字段是否用对,运行目录 images/ 中是否有对应文件 |
| 中文改好,英文仍是旧名称 | 对应语言包是否覆盖了同一个标题字段 |
| 菜单已关闭,后续数据还不是预期 | 后续处理是否安排在选择脚本里,是否误用了 PopMenu 后一行的时序 |
下一篇使用刚学过的功能键菜单,配置直接运行脚本和NC的入口:输入几行代码,执行并观察结果。随后再用主界面的轴配置继续读菜单与共用参数的关系。