前言

这个插件基于以下两款插件的启发进行开发

代码结构完全是在 CommandSearch 的源码上进行的修改
此外 Listary5.0 软件的使用逻辑也启发了我

  最近在看 mGear 开源绑定框架的教程。(已经是去年2019年的事情了)
  偶然发现了大佬使用一个相当方便的 quickLauncher 工具快速启动脚本
  于是激发了我研究的兴趣。

  后来,还是因为 mGear 提到的一些插件,于是去 Autodesk 官方的商店查找工具。
  在那里我找到了另一个UI做得非常棒的工具 CommandSearch

  最初是接触 3dsMax 和 Houdini 都相关的搜索框,而 Maya 的命令搜索功能非常落后。

alt

  于是我就萌生了进一步结合两个插件的功能进行开发,弄一个命令启动器。
  插件的使用方法参照 github 上的 readme 文档

插件分析

CommandSearch

  不愧是 RJ 大师的作品, CommandSearch 整体以及 UI 多做得特别棒。
  特别是还原了 Maya 的菜单显示风格,还有复选框的和图标的功能都逐一还原。
  整一个思路都非常好,我特别喜欢。


  可惜 这个插件搜索的结果需要鼠标点击,没有办法通过键盘来完成点击。
  并且只能搜索到 Maya 的菜单数据.

quicklauncher

  相对而言 quickLauncher 就小巧很多。
  但是它利用 Qt 的 completer 来实现补全触发。
  而且真正做到随处弹出的效果,继承了Maya的 cmds 命令,可以快速调用。


  可惜没有什么设计可言,UI非常简单。
  唤起需要手动设置快捷键调用代码才可以。

总结

  最后我将是将两个插件的有点全部集合到一起,所以 命名为 CommandLauncher ,两者合并之意。
  开发的过程中也的确遇到了很多问题,主要的插件框架是在 CommandSearch 上面进行魔改的。
  毕竟 CommandSearch 开发得比较完善,当然要事先看懂代码也花费了很多很多的时间。
  但是都怪我的开发断开了,我在2019年开发了大部分功能之后因为要肝学校的实训作业,所以就停止了开发。
  后来又遇到了很多事情,比如说突然想开发 mpdb 模块出来,然后这个插件的临门一脚就一直还没有完成。
  原本我是想在过年的时间把手尾都收拾好的,结果还是又搞这搞那的,拖到了现在了(:з」∠)

遇到的问题

使用 Tab 键作为启动快捷键

  无论是 Houdini 还是 Maya 的节点编辑器都是使用 Tab键打开输入的。
  原本是想在 快捷键编辑器 里面设置 Tab 快捷键的。
  没想到 Tab 居然不支持作为快捷键。


  后面我还是利用了 eventFilter 来帮我获取到键盘输入事件。
  通过抓取 Tab 键的点击来启动 命令启动器。
  但是在视窗里面 Tab 键使用来切换 Drag 拖拽选择的操作的,这样子我就和这个操作冲突了。
  不过 Drag 操作通常都是长按来使用的,于是我又加了一个计时器,如果点击时间少于 300 毫秒,就是启动器,否则就是长按。

任意位置弹出 | 点击其他地方隐藏

  默认 CommandSearch 是固定在 Status Line 上面的。
  因此弹出操作我参考 quickLauncher 的弹出效果。
  show 的时候将组件 move 到鼠标的位置


  点击其他地方就消失其实这个需求和我之前写的 Qt 教程想要的效果是一样的。
  还是利用 eventFilter ,如果点击了其他的地方就消失。

面板的键盘操作

  具体细节我已经不太记得了,隔离3个多月。
  不过按键的功能都单独分开成一个函数了。
  按箭头可以实现在菜单上的滚动,解决了 CommandSearch 极大的短板。
  按箭头之后会获取当前处于 菜单 的序号数字,然后选中的 item 需要给出颜色变化予以提示。
  然后当下箭头移动到相应的位置之后还要自动滚动滚动条。


  另外还添加了 alt+数字 进行快速跳转,以及 ctrl+数字 的快速触发组件。
  另外还有 ctlr + alt + 数字 跳到置顶图标上。
  ctrl + 数字键触发的想法是 根据 listary5.0 的新功能启发的。
  这个想法特别好,远在天边也可以快速启动我想要的功能。


  整个流程其实很清晰,就是写起来有点繁琐。
  我的 pressKeyEvent 通过 if else 来判断 keySequence 其实不太好。
  把 if else 写得太长了。
  其实应该用字典来调用,代码就会清晰很多,不过是以前写好的功能了,自己也懒得去修改了。

工具架搜索支持

  菜单搜索 CommandSearch 已经做好了
  Maya cmds 模块搜索也可以根据 quickLauncher 里面的写法依葫芦画瓢。
  最后唯独缺少了工具架的搜索功能。


  一开始的想法也是按照 菜单 的获取方法一样。
  获取 Maya 的工具架 Qt 组件,然后逐一遍历。
  但是发现很多工具架上的 按钮都是空的。

  经过一番折腾之后才发现(找 mel 源码查看),原来工具架上面的标签切换点击之后才读取相关的 mel 脚本生成图标。
  因此一打开 Maya 其实工具架都是空的,处理一开始看见的工具架之外。
  针对这个情况,我将 mel 的读取 工具架的源码抽出来,然后在获取的时候自动读取生成。
  读取完了之后再用 cmds 的命令获取图标、名称、点击事件。

cmds命令拆分

  根据 quickLauncher 的方法,我发现不仅仅获取 cmds 模块的命令,还顺带将 Maya 的 runTimeCommand 以及一些插件引入的命令都索引进来了。
  分析了函数的类型之后,我发现 cmds 模块的原生命令都是 builtinFunctionType 的
  因此可以通过 types 模块引入 builtin 类型进行判断。
  当然即便是 builtin 也有一些 cmds 文档没有收录的命令,可能是一些测试命令。

  根据上面的方法就成功将 cmds 的命令拆分成 cmds 和 command 两个过滤组。

搜索过滤

  通过快捷键 ctlr + q w e r t 可以切换不同的过滤标签。
  实现搜索结果的过滤。
  其实主要过滤的是 item 里面的 category 类型。
  获取数据的时候已经实现分好类了,因此不匹配的类型隐藏过滤掉就可以了。

多线程启动

  这一次的代码虽然有多线程的部分,但是启动时间耗费还是很巨大。
  主要是最耗费时间的部分没有办法放到多线程里面优化速度。


  其中遇到很多坑,坑了我非常多的时间。
  多线程代码没有报错显示,其实我是知道有 traceback 库可以通过 try 来打印详细的报错信息。
  但是我自己死脑筋,就没有想到这个方案试一下,反而是注释代码来测试。
  由于这一次也接入了 i18n ,reload代码会有一堆报错,所以每次测试都需要重开 Maya , 等了我不少的时间啊。
  而且花了很多时间之后,还对报错不明不白,不知道为啥引入某个模块报错了。
  后来是通过 traceback 之后才发现,原来按个模块是互相引入的,有些变量需要提前声明在 导入 才不会报错。
  后面也有遇到过报错没有插件生成,但是 Maya 脚本编辑器完全没有报错信息提示的。
  我又用了土办法,注释代码测试到底是那里出错了,后来偶然在 output window 上看到了报错的信息,才知道原来报错的位置去到了那里。
  知道错误的话修改总比无头苍蝇地测试要好很多了。


  除了开了上面的坑,多线程主要优化是数据获取的时候可以保持Maya的响应。
  然而这次可能是数据比较多,即便用了多线程也还是会卡死 Maya 窗口(:з」∠)(也有可能是我的使用姿势不对)
  而且遇到了两个获取数据的坑

  首先就是上面获取工具架的时候需要提前加载工具架才能获取,但是这个加载过程如果放到多线程执行的话就爆炸了。
  Maya直接就是运行不正常,还会生成一大堆的窗口,然后脚本编辑器会提示一大堆的错误。
  后来是把加载功能提出来,放到主线程加载了。

  另一个问题就是多线程状态下无法通过递归方法来获取到菜单数据。
  明明菜单数据是最多的,但是递归方法在多线程下执行之后获取的数据为空,
  这个也不知道应该如何解决,于是只好把这个耗时较长的方法放到了主线程去获取了,因此这次多线程的提速并没有达到预期。
  写完文章之后还是非常好奇为啥获取的数据为空,于是又进一步研究 RJ 之前写的代码。
  后来发现原来 getMenu 里面有有一句 aboutToShow.emit 来触发显示的信号槽。
  这个显示操作显然是异步的,因此只要将这个语句搬到主线程里面提前执行就不会有数据为空的问题,而且多线程获取 Menu 数据之后。
  加载速度有了不少的提升,只是加载工具架和菜单就要花费5-6秒,后续多线程就有响应了,这个过程也大概只要1-2秒,之前不用多线程总共要10秒

总结

  这个插件虽然拖了很久,不过因为后续有 mpdb 模块开发的经验铺路,因此 i18n 多线程之类的坑都少了很多。
  这次没有怎么截图,而是录了一个视频进行讲解。
  一直有录制 vlog 之类的想法,但是实在是太多东西要做了,自己的进度总是跟不上(:з」∠)