前言
这篇文章针对 Python Qt 开发教程的扩展说明单独开辟的。
因为这里占用的篇幅很多,然而和教程本身并无太大关系,属于对教程一些操作原理的细化说明。
如果是零基础的人,可以在这里了解到更多我对 Python Qt 的一些理解以及我的个人经验。
如果你已经对这些内容有了一定的认识,我觉得放在教程里会很冗余。
Qt.py
正如第一期教程所示,通过 Qt.py 就可以用 Qt5.0 的方式兼容 Qt4.0 即可以以 PySide2 的书写格式兼容 PySide。
那如何使用这个脚本呢?
去到 Qt.py 的 github 网址,下载名为Qt.py
的文件下来。
可以将
Qt.py
的文件解压到我的文档/maya/scripts
目录下
如此一来就可以在 maya 的脚本编辑器直接导入 Qt
1 | from Qt.QtCore import * |
通过这种方法就可以兼容 PySide2 的写法在 Maya2015 中写脚本了。
当然虽然 Qt.py 实现了兼容效果,遗憾的是在脚本编辑器里面就没有了代码提示了。
因此建议在脚本测试完毕之后再将导入的包修改掉。
sys.path
在学习的时候,有些细节总是被我们不经意间忽视了。
我当初学习写插件,用别人做好的插件也从来没有想过这个问题,只是按部就班按照别人写的文档操作,将相关的maya脚本拷贝到 scripts 目录下。
其实为什么将脚本拷贝到 scripts 目录下就可以在 maya 里面直接执行脚本呢?
后面经过我自己的发掘,我才发现,原来这都多亏了 sys 模块的 sys.path
sys.path 是一个数组,你完全可以在 maya 的编辑器里面 打印这个数组出来。
我们可以将数组排列好,捋一捋里面都有什么
1 | # -*- coding:UTF-8 -*- |
可以看到打印的数组里面是一堆路径,而这些就是 python 的环境变量路径。
每当我们import的时候就会自动从这些路径中寻找相关的包。
我们可以跳出maya来看正常 Python 编译器输出的 sys.path
1 | # -*- coding:UTF-8 -*- |
可以看到相关的 site-packages 都在路径当中,这也就是为什么我们 pip 安装完成之后就可以直接 import 这些包的原因。
如果你将这个这个变量清空的话,那么绝大多数的包都将无法识别。
扩展
- sys.path 对比 系统环境变量 参考下面
命令行的使用方法
这里我们以调用maya的 python 程序 mayapy.exe 进行说明讲解
我们可以任意目录下
shift + 鼠标右键
,菜单栏会多出在此处打开命令窗口
的选项,如果你是 win10 用户 则会是在此处打开 Powershell 窗口
。
点击选项就会弹出 CMD 或者 Powershell 窗口 并且已经自动定位到当前路径上。
还可以在文件夹的路径上输入 cmd 打开命令行窗口并且跳转到当前路径。
当然,更加传统的做法则是按
win + R
,调出运行窗口,输入cmd
打开命令行
打开命令行窗口之后又要如何使用它呢?
在默认情况下我们可以输入绝对路径来访问程,比如通过绝对路径访问 python.exe
在输入的过程按 Tab 会搜索路径下的文件自动补全文件名称。
在 win7 下的命令行是不支持 ctrl+v 粘贴操作,需要鼠标右键选择粘贴。
也可以去到命令行的属性编辑中开启快速编辑功能,这样右键就不是菜单了,选中内容是复制,没有选择是粘贴。
通过上面的方法访问 mayapy.exe 会报错。
这是因为这里的路径存在空格,命令行会断开空格,导致识别失败。
这个时候需要用双引号包裹路径才可以使用,也只有这样才可以使用自动补全
手动输入很麻烦,其实也可以将文件拖拽到命令行工具中,命令行会获取到文件的路径。
那么除了用绝对路径,还可以通过命令行上的路径直接获取程序,
除了上述自动定位打开命令行的方法之外,也可以手动去定位, 可以用命令行的cd
命令来跳转到对应的目录。
只要在相应路径下就可以调用程序
可见使用命令行需要知道程序的路径,就会对程序调用带来极大的不便,那么有没有更方便调用程序的方法呢?
这就需要用到环境变量来方便快捷调用程序了。
环境变量
Python的环境变量其实和系统的环境变量是一样原理的。
当我们安装了 Python 之后,为什么可以通过命令行进入 python 编译器,也可以在命令行输入 pip 安装相关的包。
其实这是因为安装 Python 的时候自动给你设置了相关路径的环境变量,让你的 cmd 命令行可以找到命令对应的运行程序。
如果你有安装过 java 编译器就会学习到如何设置系统的环境变量。(因为官方提供的安装包没有自动设置的操作(:з」∠))
我的电脑安装的是 win7 系统,这里以 win7 举例,如果看不懂的话,网上也有大量的文章甚至是视频帮助你。
在Path属性下可以也可以看到大量的路径,这个地方就是系统的环境变量路径。
通过这里设置的路径,就可以通过cmd命令行调用到相关的命令。
在没有设置环境变量的情况下,如果不在对应的路径启动程序将会报错。
下面我们可以将maya的bin路径添加到系统的环境变量中。
这样我们就可以在任意路径上调用 mayapy 了。(环境变量设置完了之后需要重新打开命令行才能生效)
当然环境变量是有优先级的,如果在多个目录下找到相同名称的程序,会优先执行第一个找到的,所以设置路径的时候应该注意。
另外环境变量路径下调用的程序应该以exe
后缀结尾,调用的时候可以省略 exe 后缀。
如何使用 PySide API 文档
PySide API 文档
文档的左侧有搜索按钮,搜索 QWidget 会弹出大量 QWidget 相关的API函数,任意点其中一个进入 QWidget 界面。
在 Virtual functions 下有大量 API 提供的固定用法的函数。
如果网页内容太多,寻找得很累,可以在浏览器上按 ctrl + F 打开搜索。
如果英文看不懂也不用慌,可以用一些浏览器插件来翻译网页,也可以下载 有道词典 之类的工具来快速翻译。
Python Qt 用搜索引擎解决问题
当我们遇到问题的时候,特别是诸如使用 API 的问题无从下手的时候,我们要学会自己在网上搜索找到解决方案。
这样做不仅不用麻烦别人,拒绝当伸手党,也可以让自己学到的知识印象更加深刻。
下面我就一如何实现 Python Qt 的 右键菜单 为搜索例子。
要解决问题,我们首先需要选择好的搜索引擎方可事半功倍。
关于代码上的问题,我个人还是比较推荐外网的搜索引擎,毕竟框架是外国人做的,更加容易搜到准确的解决方案。
下面是我推荐的国外的搜索引擎。
- DuckDuckGo
- Bing
Google 谷歌 已经无需多言,只是因为众所周知的原因是个404网站。
DuckDuckGo 是一个将用户隐私放到第一位的搜索引擎,在国外的知名度并不比Google差,可惜后来也变成了 404 网站。
Bing 必应 是微软推出的搜索引擎,最让人兴奋的是这个网站居然不是404网站,可以正常访问,有国际版和国内版。
个人强烈推荐使用 必应 ,使用必应的国际版搜索和 谷歌 搜索相差不大,而且可以省去一笔科学上网的费用,岂不美哉。
至于国内的搜索引擎,其实也不怎么需要我推荐了,大家都知道了。
- 百度
- 搜狗
- 360
这里必须义正言辞的批评百度,通常最前面的几个搜索都是广告,虽然链接后面有标注,但是看到就觉得烦。
不过由于常年的使用习惯,用起来…我只能表示…真香(:з」∠)
另外需要强调一下 360 和 搜狗都有英文搜索,可以搜索国际内容,不过我自己用不惯,还是推荐必应。(百度没有找到英文搜索)
搜索代码问题时候我一般是直接去 Bing 打英文进行搜索,比如这里我要查 Python Qt 的右键菜单实现。
如果不知道英文怎么拼写可以用翻译软件解决。(CG行业有很多知识是国内搜索不到,要学会善用国外的搜索引擎)
我们可以将关键字用空格隔开输进去, 比如:
Python Qt right click menu
通常最上面的网站都是 Stackoverflow 网站,强推这个网站。
这个网站是国外知名的程序员问题社区,基本可以理解为专门给程序员提供的百度知道。
基本上任何编程的问题都有一大批热心的外国人为你解答,很多都是直接奉上代码,美滋滋。
根据上面的搜索第一条点进去,虽然网站全部是英文的,但是不用慌,看不懂也没关系,直接抄回答上的代码测试即可。
1 | import sys |
当然上面代码需要安装 PyQt4 才可以运行的。如果你想要在 maya 里面跑上面的代码可以 参照这里
而 PyQt4 已经无法通过pip安装了(被淘汰了)
问题真的是接踵而至对吧,这个时候你也可以把搜索引擎用起来。
还是 Stackoverflow 那个熟悉而亲切的平台。
点开问题看最上面的答案。
答案会告诉你可以用 wheel 来安装 PyQt4,而具体的地址也提供了。直接去相关网页下载即可。
不知道 wheel 怎么安装,不慌,把搜索引擎用起来。
这一次我们甚至都不需要打开网页,Bing已经将操作代码贴出来了。
你可能会觉得,每次都是英文,真的是太难受了。
关于这点也不用担心,一些比较常见基础的问题也完全可以通过度娘解决的,(或者用 Bing 的国内版,比较干净)
而且国内学习 PyQt 做桌面开发的人还是很多的,可以通过百度搜索到很多 博客文章 诸如 CSDN 博客园,里面很多内容以及代码都很有帮助。
只是我个人觉得博客文章的针对性不够强,讲得比较空泛(毕竟是总结性的文章),不如 Stackoverflow 上针对问题解决所提出的短小精悍的代码来得直接。
当然国内的博客总结也很棒,很多时候会有更多预料之外的收获。
另外搜索的时候多用 PyQt ,PySide的虽然开源,但是使用上更多的是 PyQt ,反正框架基本共通的,搜索 PyQt 能更快找到你想要的答案。
以上就是我学习 Python Qt 框架时候解决问题的方法,Stackoverflow 真的是一个非常好的平台,我有很多不懂的代码问题都是在上面解决的。
学会使用搜索引擎,从此不求人!
扩展
- 如何在 maya 运行 Stackoverflow 里面的 PyQt 代码 参考下面
在 Maya 中运行 PyQt 中的桌面开发代码
承接上面搜索引擎上搜索到的代码,上面为了将代码跑起来,需要安装 PyQt 相关的库,这过程的周折不然而喻。
maya 本身就搭建好了 PySide 的运行环境,能否直接运行上面代码呢?
直接硬上肯定是不行的,而且 PyQt4 是 Qt4.0 的风格 并不符合 PySide2 的 Qt5.0 风格。
使用 Qt.py 也需要将代码转换为 Qt5.0 的风格才行。
因此为了避免麻烦,最快速的方法就是去掉代码中QtCore.
和QtGui.
的关键字,然后将导入修改为 * 导入
然而上述的代码在 maya 中执行依然会报错。
报错的问题也很显然了,因为 maya 本身就已经运行了 QApplication,因此可以将 QApplication 相关的代码删除。
另外if __name__ == '__main__':
这个语句可以删除,脚本编辑器中可以没有这个语句。
1 | # -*- coding:UTF-8 -*- |
partial 方法分析
我们在使用 槽函数 以及 函数复写的时候都可以通过 funtools库 的 partial 偏函数 来实现函数的额外传参。
而且partial最大的好处在于它可以额外添加参数但是不会影响到原函数的传参。
但是偏函数是如何实现的呢? 链接
stackoverflow 的高分答案已经解析的很清楚,官方也有提供相关的例子。
1 | def partial(func, *part_args): |
partial 偏函数类似于装饰器,将函数的执行封装到
wrapper
函数当中。
因此使用了偏函数之后,偏函数实际上是返回了wrapper
函数。
1 | # Note 例如这里使用了 偏函数 复写 PyQt 的虚函数 |
形如上面的代码,执行的时候是 先将
child.mousePressEvent
加入到函数的参数列表当中,然后再去将参数列表传入到函数中实现偏函数。
CSS|QSS 颜色码
参照颜色码相关的百度百科
也可以参照我以前翻译的视频
我们可以看到计算机软件表现颜色有几种方案。
- 颜色名称 - (red,green)
- rbg - (rgb(0,123,255),rgb(123,0,0))
- HEX 16进制 - (#123123,#233233)
- HSL|HSV -(hsl(187, 100%, 100%),hsl(4, 40%, 50%))
颜色名称是顾名思义的表达方式
rbg - 分别对应 red(红色) green(绿色) blue(蓝色)
在计算机种使用2进制,这里认为规定 三种颜色的范围为 2的六次方 即 256份
当我们把零也算上之后就会得到 0 - 255 的颜色范围。
HEX 16进制其实本质上和 rgb 表达式方式是一样的
#FF22AA
有6个数位,每个数位可以填写 0-9 和 A-F 共计 16 个字符。
我们可以将每个两个数位进行拆分,就可以得到FF
22
AA
刚好 16 * 16 是 256 ,也就是说 每两个数位之间的组合有 256 种匹配方式。
因此这和 rgb 的表达式方式是一样的,只不过rgb是10进制的表达而Hex是16进制表达。
HSL或者HSV 是指 Hue(色调) Saturation(饱和度) Luminance或Value(亮度)
这是有别于 RGB 的颜色表达方法,不过其实两者也有共同之处。
PySide 创建类似 MEL|cmds 的窗口
相信在学习Maya生成窗口的过程中,通过 show() 方法显示的窗口是独立的,会被Maya主窗口所遮挡,交互体验非常糟糕。
那有没有办法创建出类似于 MEL或者cmds 命令生成的窗口呢?
其实方案有很多,下面介绍我知道的三种方案。
方案一:窗口置顶
Qt支持给窗口设置一个状态,让其永远独立于 Maya 窗口的显示。
QWidget下都有setWindowFlags
方法,通过设置setWindowFlags(Qt.WindowStaysOnTopHint)
可以实现置顶。
1 | from PySide2.QtGui import * |
当然这个方案也显然是治标不治本的,这个窗口依然是独立于Maya主窗口,最小化Maya也不会影响到这个窗口。
因此这个方案虽然简单粗暴,同样也有缺陷。
方案二:结合 OpenMaya 将 Maya 的组件转成 Qt 组件进行操作
OpenMaya 是更为底层的 Maya API,有 2.0 和 1.0 之分。 OpenMaya分析
OpenMaya1.0是将 Maya 的 C++ API 用转换工具,生成的,使用上保留了很多 C++ 的代码风格,用起来很诡异。
OpenMaya2.0是用 python 底层重写的,因此更加 pythonic ,调用起来更加友好。
这里将演示如何通过 OpenMaya1.0 来获取 Qt 组件
1 | from Qt.QtGui import * |
这个方案是教程提供的,详细的使用方法可以参照 教程
omui.MQtUtil 可以获取 UI 相关的 C++ 指针。
获取到的指针需要通过wrapInstance
函数转换为 Python 可以调用的对象。
这里我们使用 Qt.py 获取转换wrapInstance
在 PySide2 中可以通过 shiboken2 获取到 wrapInstance
在 PyQt 的写法不一样from sip import wrapinstance as wrapInstance
,导入的模块也有大小写区别。
上面的
mayaToQT
可以将任意的maya UI 转换成 Qt 对象来调用
wrapInstance 可以将长整型的指针 转换为后面参数的 Qt 类型。
这样我们就可以将 Maya 的窗口当成 Qt 的实例来使用,非常方便。
由于 Maya 的窗口就是我们想要的效果,因此这里是用 cmds 生成窗口,然后将 Qt 的组件添加到这个窗口上。
这里我还额外添加了窗口多开的检测,确保插件的窗口是唯一的。
方案三:利用 QApplication 用纯 PySide 的方法实现
方案二虽然已经完美实现了我们想要的效果,但是不免得有些繁琐。
不仅要 OpenMaya 转Maya的UI,还需要用 wrapInstance 转换 C++ 指针。
在第四期实战的时候,我们介绍了 QApplication ,其实这是个好东西。
通过QApplication.activeWindow()
可以直接获取到 Maya 的主窗口。
上面的函数就相当于OpenMayaUI.MQtUtil_mainWindow()
获取到的 C++ 指针再转 QMainWindow 了。
因此我自己研究了一下,觉得这个方案更加简单,更为简洁。
1 | # -*- coding:UTF-8 -*- |
需要注意,这里必须使用 QDialog 作为窗口的形式依附,如果是 QWidget 就会没有窗口,而是将整个组件放到了Maya主窗口上,效果是耸人听闻的。
由于使用了 QDialog ,因此需要设置一下才能让最大化最小化显示出来,从而达成原生 MEL 窗口的效果。
后面的用法都是 Qt 的用法,比较好理解了。
扩展
- OpenMaya 分析 参考下面
OpenMaya 分析
什么是 OpenMaya
OpenMaya是 Maya C++ API 用 Python 做了链接绑定的产物。
换句话说就是借助 Python 来调用 C++ 的命令。
最初诞生的 API 是 OpenMaya 1.0 ,后面又诞生了 OpenMaya 2.0
OpenMaya 1.0 || OpenMaya 2.0 区别和选择
OpenMaya 1.0 是纯粹的 C++ 转换而来。
因此在使用上保留了大量的 C++ 风格,最典型的就是指针传参。
而且很多数据无法直接 print 出来,需要查找文档用相关的方法获取。
因为以上这些问题,OpenMaya 1.0 在 Python 的使用上非常奇葩。
于是后面 OpenMaya 2.0 呼应群众的呼声出来了。
两者的关系如同 cmds 和 pymel。
maya 的 cmds 库也是因为调用起来各种奇葩,因此才有 pymel 来救场。
OpenMaya 2.0 出现的原因也是类似的。