上一篇讲到:软件已经有“内孔心/探测”功能,面板上却不一定摆着它的按钮。这说明,功能已经定义好,和把它放到哪个按钮位置,是两件事。
这一篇先用更简单的现有功能把过程读通:把参数页的“组件部署”从 F5 移到空着的 F3。整个例子沿用现成按钮、菜单和脚本,不增加功能,也不执行组件部署。
点击截图可查看原图。
图 1 标准主界面中的“参数”页。图中打开的是“IO参数”子页,本课只看底部橙色功能键,不修改中间的 IO 设置。
从左往右数,底部共有 12 个位置。当前配置中:
| 位置 | 当前显示 | 本例结束后 |
|---|---|---|
| 第三个,对应 F3 | 空白 | F3/组件部署 |
| 第五个,对应 F5 | F5/组件部署 | 空白 |
空位置连 F3 文字也没有显示,但按钮位置仍在那里。右上角的“超级管理员”是本界面中开发者权限对应的身份名称;“管理员”是另一种身份,不能据名字相近就认为权限相同。
截图采用标准界面。坐标、文件名和参数数值为讲解示例,请以实际配置为准。
在练习副本中,使用该环境已有的开发者账号登录,使右上角显示“超级管理员”,然后进入“参数”。不同客户的按钮位置可能已经改过,应先找到自己界面上的“组件部署”。
第一步:右键原来的 F5“组件部署”,选择“空”。
点击截图可查看原图。
图 2 “功能键配置菜单”里的勾选表示原位置当前使用“组件部署”。此时它已经被占用,不能再次选择;“空”可以选择。
选“空”后,原 F5 位置变成空白。这只解除该位置与功能的对应关系,没有删除部署脚本,也没有卸载任何组件。
第二步:右键第三个空白位置,选择“组件部署”。
点击截图可查看原图。
图 3 第三个位置尚为空,所以勾选在“空”上。原位置已清空,“组件部署”现在可以选择。菜单的底色由原有样式决定,不要仅凭亮暗判断是否可选。
第三步:看按钮是否已经换好。
点击截图可查看原图。
图 4 原生功能键区的直接截图:F3/组件部署已经出现,原 F5 位置变为空白。其他位置保留原功能。
本课到这里即可观察结果,不必左键点击新按钮,也不必按 F3。那两种操作才会进入组件部署功能。
如果一开始就右键 F3,“组件部署”会因仍在 F5 而不可选。标准菜单要求先清空原位置,再选择新位置,它没有自动交换两个按钮的步骤。要恢复原布局,反过来清空 F3,再在第五个位置选择“组件部署”。
文件路径相对于软件运行目录。
| 文件 | 这次负责什么 |
|---|---|
env/main |
准备初始选页值和首次装入标记,请求打开主框架 |
env/maininterface/maininterface.ui |
主框架、“参数”入口及底部的功能键区域 |
env/mainInit |
主界面建立后,按已有配置装配程序页功能键和右侧控制按钮,准备程序页快捷键 |
env/parampage |
进入参数页,装入功能键 UI,把当前配置应用到各按钮,并更新本页快捷键 |
env/param/paramfunc.ui |
12 个按钮的形状、排列及对象名称 |
env/param/paramfuncmenu |
检查是否有配置权限,再打开菜单 |
env/param/selmenufunc |
选中菜单项后,修改对应关系并立即更新按钮 |
env/funcscripts/deployComponents |
后续真正使用“组件部署”时调用的脚本,本课不执行 |
env/i18n/translatPack-0、translatPack-1 |
菜单及界面的中文、英文文字 |
按钮配置主要放在已经装载的参数中:
| 参数 | 在本例中存什么 |
|---|---|
#915 及其子项 |
配置菜单的名称、条件、选择后调用的脚本;主值暂存当前选择的功能编号 |
#916 及其子项 |
每个位置放什么功能、按钮对象名称、功能动作文字和位置文字;主值暂存正在配置的位置 |
#9995 及其子项 |
当前页面的按键名称及按键对应的动作文字 |
#1026.item[0] |
当前身份,配置入口要求值为 2 |
这里不是要求用户手工编辑 setting-env 或备份文件。先从现有界面完成选择,再读这些字段,才能看懂系统如何把选择记录下来。
脚本中的位置从 0 开始,因此第三个按钮的位置编号是 2。而“组件部署”的功能编号是 5。调整以后,最关键的一项就是:
| 字段 | 调整后的值 | 怎样读 |
|---|---|---|
#916.item[2] |
5 |
第三个位置放 5 号功能 |
#916.itemtitle[2] |
paramFuncButton3 |
第三个位置对应这个 UI 对象 |
#916.itemdesc[5] |
部署功能的动作属性 | 5 号功能要执行什么 |
#916.itemunit[2] |
第三个位置的显示与右键属性 | 这个位置如何显示、如何再次配置 |
#915.itemtitle[7] |
组件部署 | 菜单中对应功能的名称 |
本菜单前面还有标题行和分隔线,功能 0“空”从子项 2 开始,所以本菜单的功能名称用“功能编号加 2”寻找:5 号功能的名称在 #915.itemtitle[7]。这不是所有菜单都必须遵守的通用编号规定。
同一组 #916 中,item、itemtitle、itemunit 在这几句里按位置取,itemdesc 按功能编号取。读到两个不同下标不要急着把它们改成相同数字。
还要注意,本例把 itemunit 用来存界面属性文字,把 itemdesc 用来存动作属性文字。它们在这里不是毫米等物理单位,也不是一段普通帮助说明。字段的实际用途,要看脚本怎样读取它。
前面看的是“用户选择之后,按钮怎样变”。还要补上另一半:刚启动软件、还没有右键选择过时,按钮怎样取得已经保存的功能? 这就要读 env/mainInit。
本节按标准独立运行方式说明启动过程:
| 顺序 | 哪一部分处理 | 做什么 |
|---|---|---|
| 1 | 软件的参数装载过程 | 读入基础参数及有效备份,使原来保存的功能选择进入当前参数 |
| 2 | env/main |
准备初始页面及“尚未装入”的标记,末尾用 MarcoDialog "/env/dmec-app-black.ui" 请求打开主框架 |
| 3 | 主窗体建立后的首次定时处理 | 软件内部调用 env/mainInit,把当前参数中的功能属性装到已经存在的按钮上 |
| 4 | 后续点击“参数”等页面入口 | 对应页面脚本装入该页需要的区域,再按该页参数装配按钮 |
main 和 mainInit 是两个不同文件。前者准备开界面,后者在界面建立后为控件补上运行时属性。控件对象已经存在,setWidgetAttribute 才能按对象名找到它。 这也是不能随意把 mainInit 中的按钮设置提前搬到开窗之前的原因。
mainInit 的自动调用写在软件内部,不需要用户在每个按钮上另配一次。标准独立运行分支在主窗体首次定时处理时,先调用 timer 脚本,再调用 mainInit;调用处用标记限制同一个主窗体实例自动初始化一次。后续定时处理不会每次重做这一段,普通切页也不靠重跑 mainInit。
这里说明的是标准独立运行分支。客户端等其他运行方式在源码中另选初始化脚本,不能把所有运行方式都概括为固定调用同一个 mainInit。
与功能键直接相关的工作有三组,按文件中的先后顺序是:
| 工作 | 使用哪些参数 | 处理数量 |
|---|---|---|
| 准备程序页的快捷键动作 | 从 #914 读取功能,写到 #9995.itemdesc |
12 项,位置 0~11 |
| 装配程序页底部功能键 | #914 中的对象名、所选功能及位置属性 |
12 个按钮 |
| 装配右侧手动控制按钮 | #911 中的对象名、所选功能及位置属性 |
36 个按钮,位置 0~35 |
先看第一组的第一个位置,原文是:
#9995.itemdesc[0]=#914.itemdesc[#914.item[0]]
先读 #914.item[0],知道程序页第一个位置选了哪项功能;再读该功能的 itemdesc,交给第一条快捷键记录。后面的第 1~11 项做相同处理。这里读取的是程序页的 #914,参数页则使用本课前面讲到的 #916。
第二组第一个按钮的完整语句是:
widgetFunc["setWidgetAttribute",#914.itemtitle[0],"",#914.itemdesc[#914.item[0]]+#914.itemunit[0]]
它先按 #914.itemtitle[0] 找到按钮,再把“当前选中功能的属性”和“这个位置的属性”接起来装到按钮上。动作、名称显示和右键配置入口,都由这份完整属性决定。
第三组右侧第一个控制按钮使用同样的做法,只是换成 #911:
widgetFunc["setWidgetAttribute",#911.itemtitle[0],"",#911.itemdesc[#911.item[0]]+#911.itemunit[0]]
以上分别摘自三组代码,并非原文件中连续的三行。原文件把每个位置逐项写出;无需为每个按钮另写一份业务脚本。
这里的“初始化”是把当前已载入的选择应用到界面。例如,右侧某个位置已经保存为另一项功能,mainInit 就读取那个功能编号来装配;这些语句没有把全部位置改回某套出厂编号,也没有执行这些按钮所对应的业务动作。前提仍是上一次的选择确实保存成功。
mainInit 末尾还按刀库配置设置主菜单,记录已有的加工文件选择,并在相应条件成立时同步虚拟机台部件。因此它还承担其他主界面准备工作。本课重点读上面的三组功能键代码;不应为了刷新某一个按钮而随意重跑整份脚本。
mainInit 装配的是主界面已有的程序页功能键和右侧控制按钮。参数页的底部按钮 UI 要在进入该页时装入,所以由 parampage 接着完成。两份脚本处理的是不同区域,不能漏掉其中一份。
env/parampage 中,装入底部区域的原文是:
IF#824.version==1GOTO10
#824.version=1
#824.itemdesc[0]="/env/param/paramfunc.ui"
widgetFunc["QFrame","paramFuncFrame","refresh",""]
这与程序页三子页的做法相通:先判断是否已经装过;第一次进入时,把 UI 路径放到参数里,再让指定区域装入它。
这里的 #824.version 在 main 中先设为 0。它表示本次启动后该区域尚未装入;随后 parampage 设为 1,并不是 mainInit 已经替它装好了。
后面依次为 12 个按钮设置属性。第三个位置对应这一句:
widgetFunc["setWidgetAttribute",#916.itemtitle[2],"",#916.itemdesc[#916.item[2]]+#916.itemunit[2]]
按本例调整后的值展开阅读:找到名为 paramFuncButton3 的按钮,把“5 号功能的属性”和“第三个位置的属性”接在一起,作为这个按钮的新属性。
setWidgetAttribute 的四项在这里分别是:操作名称、控件对象名、留空的第三项、完整属性文字。它会替换按钮的 accessibleDescription 并重新解析,不只是修改按钮上显示的名称。对象名必须与已经装入的 UI 一致;名字写错或控件尚未装入,不能指望参数改变后自动找到它。
用 Qt Designer 看 paramfunc.ui,有些按钮的静态文字与运行画面不同,例如原文件第三个按钮写着“厂商参数F3”。运行时页面脚本会按当前配置重新设置。因此,要解释实际按钮做什么,应继续看这段装配,不能止于 Designer 中的静态文字。
先看 #916.itemdesc[5] 中已有的完整动作属性:
-C((#319.item3==1||#319.item7==1)&&(#1026.item[0]!=2))
-E0
-A: (MouseButtonRelease:/env/funcscripts/deployComponents[1])
-A: (keyReleaseEvent:/env/funcscripts/deployComponents[1])
前两行用状态条件决定按钮是否禁用:条件 0 成立时,-E0 禁用按钮。后两行分别给鼠标释放和按键释放指定部署脚本。这里事件路径后的 [1] 表示辅助 Qt 脚本通道,不能把这份文件当作 NC 程序执行。
再看第三个位置的完整属性,即 #916.itemunit[2]。下面引号内保留了配置中的真实换行:
-T(#9995item2+"
"+#915.itemtitle[#916.item[2]+2])
-T("")
-C,1(#916item2==0)
-C,0(1)
-A: (rightClickedEvent:/env/param/paramfuncmenu[0](#916=2<<#915=#916item2))
-D
这段负责三个实际问题:
F3、换行、功能名组成;第二项文字是空字符串。当前位置的功能编号为 0 时选第二项,否则选第一项。paramfuncmenu。-D 保留动态显示。所以,选“空”只会让文字为空,右键入口仍然存在;换成部署功能后,也仍能再次右键配置。
这里的 #916item2、#9995item2 是原属性中的紧凑写法。对照普通脚本时可分别理解为读取第 2 项,但不需要把原 UI 属性全部改写成另一种形式。
两段接好后,所有 -C 会放在同一份条件列表里。-E0 的 0 指条件编号,-C,1 的 1 指文字编号,不是第一个或第二个功能键。若今后修改这些属性,要按拼接后的全文核对编号。只保留动作段而丢掉位置段,会同时丢失本例的标题和右键配置入口。
仍看上一节中的右键事件:它先把 #916 设为 2,再把这个位置当前的功能编号交给 #915,随后调用 /env/param/paramfuncmenu。
这里用 << 分开两条准备赋值,执行后再进入脚本。paramfuncmenu 的完整内容只有三行:
IF#1026.item[0]!=2GOTO1
widgetFunc["PopMenu","","",915]
N1
不是身份 2,就跳到结尾;是身份 2,就用参数 915 建立菜单。PopMenu 在本句中的第四项是菜单参数号,不是 UI 文件名,也不是位置编号。
打开第三个位置的菜单时,这两个主值可以这样读:
| 时刻 | #916 |
#915 |
|---|---|---|
| 第三个位置尚为空,刚右键 | 2 |
0 |
| 随后在菜单选择组件部署 | 2 |
5 |
12 个位置共用同一份脚本,靠右键时先写的位置编号区分目标。它们是共享参数;本例按一次菜单选择完成一次修改,不应理解为每个打开的窗口都另有一份独立数据。
菜单中“组件部署”这一项,关键字段如下:
| 字段 | 现有内容/用途 |
|---|---|
#915.itemtitle[7] |
中文为“组件部署”,英文为 Deployment |
#915.item[7] |
勾选和是否允许选择的条件文字,见下方 |
#915.itemdesc[7] |
/env/param/selmenufunc<<#915=5 |
#915.itemversion[7] |
1,本菜单的 Qt 脚本调用设置 |
#915.itemmin[7] |
0,这是普通菜单项 |
item[7] 中的完整条件是:
-C(#915==5)
-R0
-C(#916item0==5||#916item1==5||#916item2==5||#916item3==5||#916item4==5||#916item5==5||#916item6==5||#916item7==5||#916item8==5||#916item9==5||#916item10==5||#916item11==5)
-E1
先看第一条条件:当前功能为 5,就用 -R0 给菜单项打勾。在这个菜单里,它控制勾选;不能套用其他控件中的“只读”解释。
再看第二条条件:检查 12 个位置,只要任何一个已经放了 5 号功能,-E1 就让该菜单项不可选。这也解释了为什么图 2 中“组件部署”同时有勾选、又不能重复选择,以及为什么必须先清空 F5。
点击可选的“组件部署”后,菜单先执行 #915=5,再调用 selmenufunc。此时运行的是配置按钮的脚本。 名称同为“组件部署”,不表示这里就调用 deployComponents。
还要把两处数字分开:菜单的 itemversion=1 和前文事件路径的 [1] 使用不同的编号规则。这里保留标准设置即可,不要把它们互换。菜单处理会根据当前 Qt 脚本的忙状态安排调用,详细通道规则放在 功能键详细资料,入门时先把“选择配置”和“使用功能”分清。
env/param/selmenufunc 全文如下:
#916.item[#916]=#915
#9995.itemdesc[#916]=#916.itemdesc[#916.item[#916]]
#916.itemmin[#916.item[#916]]=#916
widgetFunc["setWidgetAttribute",#916.itemtitle[#916],"",#916.itemdesc[#916.item[#916]]+#916.itemunit[#916]]
将刚才的 #916=2、#915=5 代入,逐行看:
| 行 | 本例结果 | 为什么要做 |
|---|---|---|
| 1 | #916.item[2] 变成 5 |
记住第三个位置现在放组件部署 |
| 2 | #9995.itemdesc[2] 取得 #916.itemdesc[5] |
F3 对应的动作也换成部署功能 |
| 3 | #916.itemmin[5] 变成 2 |
记住 5 号功能现在在哪个位置 |
| 4 | paramFuncButton3 取得新的完整属性 |
当前按钮立即更新名称和动作,仍保留右键入口 |
第三行的 itemmin 在这里用于记录位置,不是最小允许值。有些功能会反过来查“我现在在哪个位置”,再显示对应的按键名,因此标准脚本也维护这个记录。清空旧位置时不会自动清除旧功能的这项记录;本例重新放置后,它才被更新为 2。
本次配置中,#916.itemmin[5] 最初为 0,并没有与原 F5 位置同步。因此不能单独拿这项旧记录判断按钮摆在哪里;原布局应看 #916.item[4]=5。经过本次菜单选择后,位置关系和这项记录才一起对应到第三个位置。
整个例子里,关键数值变化如下:
| 时刻 | 第三个位置 #916.item[2] |
第五个位置 #916.item[4] |
图中结果 |
|---|---|---|---|
| 原布局 | 0 |
5 |
F5 为组件部署 |
| 清空原位置 | 0 |
0 |
两个位置都空 |
| 放到第三个位置 | 5 |
0 |
F3 为组件部署 |
#9995.item[2] 当前保存按键名 F3,itemdesc[2] 保存它在当前页面所用的动作属性。选择脚本修改后者,不把按键名称改成部署功能名。
现有部署功能同时定义 MouseButtonRelease 和 keyReleaseEvent,所以同一份功能属性可以供按钮和按键使用。如果只写鼠标事件,就不能据按钮可用推断相应键盘动作也已定义。
进入参数页时,parampage 先更新本页的 12 条快捷键记录,然后才检查 #824.version。例如第三项原文是:
#9995.itemdesc[2]=#916.itemdesc[#916.item[2]]
因此,再次进入参数页即使跳过 UI 的首次装入,快捷键记录仍会按该页配置更新。本次实际核对了切到程序页再返回后,F3 按钮及记录仍对应组件部署。不要由此扩大为“所有页面都会重写全部 12 个键”;当前 programpage 的代码只回填前 7 项,其他键的跨页行为需要单独核对。
按钮禁用条件也不能代替动作脚本自己的检查:当前完整属性方式的快捷键处理读取按键事件,没有把按钮的 -E 条件当作执行前的同一项检查。本课验证了动作记录一致,没有实际按 F3 或执行部署。
最后区分“界面已经改变”和“已经写入磁盘”:
| 时机 | 当前设计怎样处理 |
|---|---|
| 主界面首次准备 | mainInit 从已载入的 #914/#911 装配程序页功能键和右侧按钮,并准备程序页 12 条快捷键记录 |
| 选择菜单项 | 四行脚本改当前参数并刷新按钮,没有调用保存文件命令 |
| 正常退出流程 | env/close 调用 widgetFunc["SysFunc","","saveParamBak",0],保存参数备份 |
| 再次启动 | 参数装载先读基础参数,再读有效备份;main 准备开窗,mainInit 装配程序页及右侧按钮,进入参数页时再由 parampage 装配该页按钮 |
这条保存和恢复过程已对照源码确认,但本次没有执行完整退出及重启。不能把关闭菜单当作保存成功,也不能把独立核对程序的内存结果当作客户环境已经持久保存的结果。env/close 还处理主轴、冷却等退出动作,不应为了保存按钮练习而单独随意执行它。
上一课的“内孔心/探测”属于右侧手动控制区,使用另一组参数和菜单:
| 比较项 | 本课底部参数页功能键 | 右侧手动控制区 |
|---|---|---|
| 菜单 | #915 |
#910,还包含分级子菜单 |
| 位置与功能记录 | #916,12 个位置 |
#911,36 个位置 |
| 打开菜单 | param/paramfuncmenu |
program/ctrlfuncmenu |
| 选择后处理 | param/selmenufunc |
program/selctrlfuncmenu |
右侧控制区也先记录选中的位置、再选择已有功能。探测功能编号为 50,菜单名称取自它所属的探测子菜单。当前配置没有把它放到面板上,不代表功能不存在。
不过,右侧的选择脚本只有两行:
#911.item[#911]=#910
widgetFunc["setWidgetAttribute",#911.itemtitle[#911],"",#911.itemdesc[#911.item[#911]]+#911.itemunit[#911]]
它没有本课更新 #9995 和记录功能位置的两行,不应照搬“右侧第几个按钮就对应 F 几”。它的空位置还按身份控制显示:开发者可以看见空位置进行配置,其他身份下空位置会隐藏。
理解本课后,再去读 右侧控制区与分级菜单,就能分清哪些做法相同、哪些字段要换。这里只衔接设计,不新增或运行探测功能。
selmenufunc 还是 deployComponents?说明配置与使用发生在不同操作中。main、mainInit、parampage 分别负责哪一步?再说明切页返回与退出重启怎样恢复,不要把当前参数、按钮显示和磁盘文件混在一起。遇到问题时,先按现象查:
| 现象 | 先查哪里 |
|---|---|
| 右键没有菜单 | 当前身份是否为开发者;按钮是否启用;位置属性是否还保留右键事件 |
| 菜单里功能不可选 | 本组其他位置是否已经使用该功能;当前条目是否还有自己的条件 |
| 刚启动时程序页或右侧按钮仍是原 UI 的静态文字 | 主界面对象是否装入,当前运行方式的初始化脚本是否执行,对象名是否与 mainInit 读取的名称一致 |
| 选了名称,当前按钮没有更新 | 位置编号、对象名、UI 是否装入;不要只看参数已改 |
| 字变了,但点击仍不是想要的动作 | 实际 itemdesc 及拼接后的完整属性,不只看静态文字 |
| 换功能后无法再右键 | 是否遗漏了 itemunit 中的位置属性,或替换后事件不完整 |
| 按钮有动作,快捷键没有 | 功能是否定义 keyReleaseEvent,当前页是否同步了 #9995 |
| 在程序页改过按键,切回参数页又变了 | 当前页面会把自己的功能配置写入快捷键记录 |
| 中文和英文显示不同名称 | 核对各自实际语言包;英文“组件部署”显示为 Deployment |
| 重启后没有保留 | 核对完整保存、退出和参数备份读取流程 |
接下来读右键菜单和多级菜单,沿右侧控制区进一步看懂子菜单、名称、图标、条件和选择脚本;随后用主界面的轴菜单练习同样的读法。