使用 PySide2 开发 Maya 插件系列二:继承 uic 转换出来的 py 文件中的类 Ui_Form

开发环境:

Wing IDE 6.1

步骤1:

打开 Wing IDE,创建一个新的 project,保存这个 project 到某个路径下,把之前生产的 py 文件所在的文件夹添加到该 project 中,然后在文件夹下新建一个 py 文件,我这里命名为 PySideTest.py

图中 PySide2ToPySide.py 是一个 PySide2 兼容 PySide 的一个补丁代码,出处链接:http://www.cnblogs.com/hksac/p/9502236.html,如果要用需要把不必要的测试代码删除,修改后的代码如下:

 from __future__ import with_statement

 import os
import functools
import imp
import subprocess
import sys
import webbrowser class PySide2Patcher(object):
_core_to_qtgui = set([
"QAbstractProxyModel",
"QItemSelection",
"QItemSelectionModel",
"QItemSelectionRange",
"QSortFilterProxyModel",
"QStringListModel"
]) @classmethod
def _move_attributes(cls, dst, src, names):
"""
Moves a list of attributes from one package to another. :param names: Names of the attributes to move.
"""
for name in names:
if not hasattr(dst, name):
setattr(dst, name, getattr(src, name)) @classmethod
def _patch_QTextCodec(cls, QtCore):
"""
Patches in QTextCodec. :param QTextCodec: The QTextCodec class.
"""
original_QTextCodec = QtCore.QTextCodec class QTextCodec(original_QTextCodec):
@staticmethod
def setCodecForCStrings(codec):
pass QtCore.QTextCodec = QTextCodec @classmethod
def _fix_QCoreApplication_api(cls, wrapper_class, original_class): wrapper_class.CodecForTr = 0
wrapper_class.UnicodeUTF8 = 1
wrapper_class.DefaultCodec = wrapper_class.CodecForTr @staticmethod
def translate(context, source_text, disambiguation=None, encoding=None, n=None): if n is not None:
return original_class.translate(context, source_text, disambiguation, n)
else:
return original_class.translate(context, source_text, disambiguation) wrapper_class.translate = translate @classmethod
def _patch_QCoreApplication(cls, QtCore): original_QCoreApplication = QtCore.QCoreApplication class QCoreApplication(original_QCoreApplication):
pass
cls._fix_QCoreApplication_api(QCoreApplication, original_QCoreApplication)
QtCore.QCoreApplication = QCoreApplication @classmethod
def _patch_QApplication(cls, QtGui): original_QApplication = QtGui.QApplication class QApplication(original_QApplication):
def __init__(self, *args):
original_QApplication.__init__(self, *args)
QtGui.qApp = self @staticmethod
def palette(widget=None): return original_QApplication.palette(widget) cls._fix_QCoreApplication_api(QApplication, original_QApplication) QtGui.QApplication = QApplication @classmethod
def _patch_QAbstractItemView(cls, QtGui): original_QAbstractItemView = QtGui.QAbstractItemView class QAbstractItemView(original_QAbstractItemView):
def __init__(self, *args):
original_QAbstractItemView.__init__(self, *args) if hasattr(self, "dataChanged"):
original_dataChanged = self.dataChanged def dataChanged(tl, br, roles=None):
original_dataChanged(tl, br)
self.dataChanged = lambda tl, br, roles: dataChanged(tl, br) QtGui.QAbstractItemView = QAbstractItemView @classmethod
def _patch_QStandardItemModel(cls, QtGui): original_QStandardItemModel = QtGui.QStandardItemModel class SignalWrapper(object):
def __init__(self, signal):
self._signal = signal def emit(self, tl, br):
self._signal.emit(tl, br, []) def __getattr__(self, name):
return getattr(self._signal, name) class QStandardItemModel(original_QStandardItemModel):
def __init__(self, *args):
original_QStandardItemModel.__init__(self, *args)
self.dataChanged = SignalWrapper(self.dataChanged) QtGui.QStandardItemModel = QStandardItemModel @classmethod
def _patch_QMessageBox(cls, QtGui): button_list = [
QtGui.QMessageBox.Ok,
QtGui.QMessageBox.Open,
QtGui.QMessageBox.Save,
QtGui.QMessageBox.Cancel,
QtGui.QMessageBox.Close,
QtGui.QMessageBox.Discard,
QtGui.QMessageBox.Apply,
QtGui.QMessageBox.Reset,
QtGui.QMessageBox.RestoreDefaults,
QtGui.QMessageBox.Help,
QtGui.QMessageBox.SaveAll,
QtGui.QMessageBox.Yes,
QtGui.QMessageBox.YesAll,
QtGui.QMessageBox.YesToAll,
QtGui.QMessageBox.No,
QtGui.QMessageBox.NoAll,
QtGui.QMessageBox.NoToAll,
QtGui.QMessageBox.Abort,
QtGui.QMessageBox.Retry,
QtGui.QMessageBox.Ignore
] def _method_factory(icon, original_method): def patch(parent, title, text, buttons=QtGui.QMessageBox.Ok, defaultButton=QtGui.QMessageBox.NoButton): msg_box = QtGui.QMessageBox(parent)
msg_box.setWindowTitle(title)
msg_box.setText(text)
msg_box.setIcon(icon)
for button in button_list:
if button & buttons:
msg_box.addButton(button)
msg_box.setDefaultButton(defaultButton)
msg_box.exec_()
return msg_box.standardButton(msg_box.clickedButton()) functools.update_wrapper(patch, original_method) return staticmethod(patch) original_QMessageBox = QtGui.QMessageBox class QMessageBox(original_QMessageBox): critical = _method_factory(QtGui.QMessageBox.Critical, QtGui.QMessageBox.critical)
information = _method_factory(QtGui.QMessageBox.Information, QtGui.QMessageBox.information)
question = _method_factory(QtGui.QMessageBox.Question, QtGui.QMessageBox.question)
warning = _method_factory(QtGui.QMessageBox.Warning, QtGui.QMessageBox.warning) QtGui.QMessageBox = QMessageBox @classmethod
def _patch_QDesktopServices(cls, QtGui, QtCore): if hasattr(QtGui, "QDesktopServices"):
return class QDesktopServices(object): @classmethod
def openUrl(cls, url):
if not isinstance(url, QtCore.QUrl):
url = QtCore.QUrl(url) if url.isLocalFile():
url = url.toLocalFile().encode("utf-8") if sys.platform == "darwin":
return subprocess.call(["open", url]) == 0
elif sys.platform == "win32":
os.startfile(url)
return os.path.exists(url)
elif sys.platform.startswith("linux"):
return subprocess.call(["xdg-open", url]) == 0
else:
raise ValueError("Unknown platform: %s" % sys.platform)
else:
try:
return webbrowser.open_new_tab(url.toString().encode("utf-8"))
except:
return False @classmethod
def displayName(cls, type):
cls.__not_implemented_error(cls.displayName) @classmethod
def storageLocation(cls, type):
cls.__not_implemented_error(cls.storageLocation) @classmethod
def setUrlHandler(cls, scheme, receiver, method_name=None):
cls.__not_implemented_error(cls.setUrlHandler) @classmethod
def unsetUrlHandler(cls, scheme):
cls.__not_implemented_error(cls.unsetUrlHandler) @classmethod
def __not_implemented_error(cls, method):
raise NotImplementedError(
"PySide2 and Toolkit don't support 'QDesktopServices.%s' yet. Please contact %s" %
(method.__func__, 'asdf@qq.com')
) QtGui.QDesktopServices = QDesktopServices @classmethod
def patch(cls, QtCore, QtGui, QtWidgets, PySide2): qt_core_shim = imp.new_module("PySide.QtCore")
qt_gui_shim = imp.new_module("PySide.QtGui") cls._move_attributes(qt_gui_shim, QtWidgets, dir(QtWidgets))
cls._move_attributes(qt_gui_shim, QtGui, dir(QtGui)) cls._move_attributes(qt_gui_shim, QtCore, cls._core_to_qtgui)
cls._move_attributes(qt_core_shim, QtCore, set(dir(QtCore)) - cls._core_to_qtgui) cls._patch_QTextCodec(qt_core_shim)
cls._patch_QCoreApplication(qt_core_shim)
cls._patch_QApplication(qt_gui_shim)
cls._patch_QAbstractItemView(qt_gui_shim)
cls._patch_QStandardItemModel(qt_gui_shim)
cls._patch_QMessageBox(qt_gui_shim)
cls._patch_QDesktopServices(qt_gui_shim, qt_core_shim) return qt_core_shim, qt_gui_shim import PySide2
from PySide2 import QtCore, QtGui, QtWidgets def _import_module_by_name(parent_module_name, module_name): module = None
try:
module = __import__(parent_module_name, globals(), locals(), [module_name])
module = getattr(module, module_name)
except Exception as e:
pass
return module QtCore, QtGui = PySide2Patcher.patch(QtCore, QtGui, QtWidgets, PySide2)
QtNetwork = _import_module_by_name("PySide2", "QtNetwork")
QtWebKit = _import_module_by_name("PySide2.QtWebKitWidgets", "QtWebKit")

PySide2ToPySide.py

PySideTest.py 代码如下:

 # -*- coding: utf-8 -*-
import sys
try:
from PySide import QtCore, QtGui
import test_ui_pyside as ui
except:
from PySide2ToPySide import QtCore, QtGui #注意:不能确保完全兼容,但常用的基本兼容
import test_ui_pyside2 as ui #使用 pyside2-uic 生成 test_ui_pyside2 class MainWindow(QtGui.QWidget, ui.Ui_Form): # 如果 designer 新建的时候选的是 MainWindow,则要集成 QtGui.QMainWindow,其它的类型要对应好
def __init__(self, parent = None):
super(MainWindow, self).__init__(parent) # 执行父类的__init__()
self.setupUi(self) # 调用 ui.Ui_Form 的 setupUi() def main():
""" 和maya中的不一样 """
app = QtGui.QApplication(sys.argv) # window是基于application的,所以在没有application的情况下要创建一个,如果在 maya 中,则不需要,因为maya本身就是一个 application
win = MainWindow() #实例一个window
win.show() # 显示window
sys.exit(app.exec_()) # 退出application,同时会释放win if __name__ == '__main__': #对当前文件进行debug则会运行以下代码,import该文件不会运行,请了解模块默认属性 __name__ 的特点和用处
main()

这时候已经可以点击debug,运行结果:

步骤2:

设置 wing IDE 的 project 属性 Project->Project Properties...

这样的好处是可以让 IDE 有maya python 模块的命令补全。

新建一个 PySideTest_maya.py,这是提供给 maya 运行的:

 # -*- coding: utf-8 -*-
import sys import PySideTest try:
from PySide import QtCore, QtGui
import shiboken
except:
from PySide2ToPySide import QtCore, QtGui
import shiboken2 as shiboken import maya.OpenMayaUI as omui
def maya_main_window():
main_window_ptr = omui.MQtUtil.mainWindow() #获得maya主窗口的指针,主要是为了让插件界面设置它为父窗口
return shiboken.wrapInstance(long(main_window_ptr), QtGui.QWidget) #把maya主窗口封装从QtGui对象 class MainWindow(PySideTest.MainWindow):
def __init__(self, parent = None):
super(MainWindow, self).__init__(parent) self.setWindowTitle("TestWindow") #设置窗口标题
self.setWindowFlags(QtCore.Qt.Window) #设置窗口标志为window,这样会使得widget成为独立窗口,不然会附着在maya的左上角,如果UI是继承的是QMainWindow,则不需要设置
self.setAttribute(QtCore.Qt.WA_DeleteOnClose) #设置属性为关闭窗口则释放它的对象,窗口关闭,实例对象还存在,只要再次show即可,如果win再main中不断的新建MainWindow,则需要设置 def main():
global win
try:
win.close() #为了不让窗口出现多个,因为第一次运行还没初始化,所以要try,在这里尝试先关闭,再重新新建一个窗口
except:
pass
win = MainWindow(maya_main_window()) #如果把win的初始化放在方法外,则不需要self.setAttribute(QtCore.Qt.WA_DeleteOnClose),同时关闭后再显示,还会保持上一次的窗口状态
win.show() if __name__ == "__main__":
main()

分别在 maya2015 和 maya2017 的 Script Editor 的 python tab 里编写如下代码:

 import sys
sys.path.append(r'E:\Works\Maya\Scripts\PySideTest') #把代码所在的路径添加到环境变量PATH中,这样可以import它们 import PySideTest_maya
reload(PySideTest_maya)
PySideTest_maya.main()

  选中需要运行的代码,Ctrl+Shift+Enter 运行:

运行结果:

回到总览使用 PySide2 开发 Maya 插件系列 总览

使用 PySide2 开发 Maya 插件系列二:继承 uic 转换出来的 py 文件中的类 Ui_Form的更多相关文章

  1. 使用 PySide2 开发 Maya 插件系列 总览

    使用 PySide2 开发 Maya 插件系列 总览 使用 PySide2 开发 Maya 插件系列一:QT Designer 设计GUI, pyside-uic 把 .ui 文件转为 .py 文件 ...

  2. 使用 PySide2 开发 Maya 插件系列三:qt语言国际化(internationalization)

    使用 PySide2 开发 Maya 插件系列三:qt语言国际化(internationalization) 前言: 这是 qt for python 的语言国际化,基于 UI 的,python 也有 ...

  3. 使用 PySide2 开发 Maya 插件系列一:QT Designer 设计GUI, pyside-uic 把 .ui 文件转为 .py 文件

    使用 PySide2 开发 Maya 插件系列一:QT Designer 设计GUI, pyside-uic 把 .ui 文件转为 .py 文件 前期准备: 安装 python:https://www ...

  4. 探索ASP.Net Core 3.0系列二:聊聊ASP.Net Core 3.0 中的Startup.cs

    原文:探索ASP.Net Core 3.0系列二:聊聊ASP.Net Core 3.0 中的Startup.cs 前言:.NET Core 3.0 SDK包含比以前版本更多的现成模板. 在本文中,我将 ...

  5. 【开发者portal在线开发插件系列二】多条上下行消息(messageId的使用)【华为云技术分享】

    前言和基本操作请参考[开发者portal在线开发插件系列一]profile和基本上下行消息,此处不再复述,没操作过的小伙伴一定要先去看看哦~ 话不多说,开始今天的演(表)示(演) 场景说明: 假设一: ...

  6. 自己开发chrome插件生成二维码

    摘要: 最近在开发微信项目时,需要在微信调试,所以经常会在微信中输入本地服务地址,输入起来特别麻烦,所以自己就想了想微信中的扫一扫,然后开发了这款chrome插件,将当前url生成二维码,用微信扫一扫 ...

  7. Apollo系列(二):Apollo在ASP.NET Core 3.1中使用

    关于Apollo怎么安装,我就不介绍,可以看这篇文章:https://www.cnblogs.com/vic-tory/p/13736192.html 一.Apollo使用: 1.创建项目 2.添加配 ...

  8. Android开发环境搭建 for windows (linux类似) 详细可参考“文件”中“Android开发环境搭建.pdf ”

    ADT-Bundle for Windows 是由Google Android官方提供的集成式IDE,已经包含了Eclipse,你无需再去下载Eclipse,并且里面已集成了插件,它解决了大部分新手通 ...

  9. 【.Net 学习系列】-- 利用Aspose转换Excel为PDF文件

    功能: 从数据库中查询出数据 利用Aspose.cell + Excel模板绑定数据源生成Excel文件 通过Aspose.pdf + 生成好的Excel生成PDF文件 实现: 查询数据,根据Exce ...

随机推荐

  1. python-GIL、死锁递归锁及线程补充

    一.GIL介绍 GIL全称 Global Interpreter Lock ,中文解释为全局解释器锁.它并不是Python的特性,而是在实现python的主流Cpython解释器时所引入的一个概念,G ...

  2. Android&Java面试题大全—金九银十面试必备

    声明本文由作者:Man不经心授权转载,转载请联系原文作者原文链接:https://www.jianshu.com/p/375ad14096b3, 类加载过程 Java 中类加载分为 3 个步骤:加载. ...

  3. PID控制器开发笔记之九:基于前馈补偿的PID控制器的实现

    对于一般的时滞系统来说,设定值的变动会产生较大的滞后才能反映在被控变量上,从而产生合理的调节.而前馈控制系统是根据扰动或给定值的变化按补偿原理来工作的控制系统,其特点是当扰动产生后,被控变量还未变化以 ...

  4. 基于C#net4.5websocket客户端与服务端

    只支持win8以上系统以及windows server2012以上系统 最近在研究视频传输给浏览器,然后使用H5标签解码.视频流采用websocket传输.所以研究了一下C#的websocket. 首 ...

  5. 【Java】SpringBoot配置文件读取中文乱码

    [问题]在配置文件application.properties中配置一个值含有中文的变量.spring加载配置之后,读取的变量中文部分出现乱码.根据CSDN说的一堆办法,改encoding为UTF-8 ...

  6. Python中字符串的截取,列表的截取

    字符串的截取 Python中的字符串用单引号 ' 或双引号 " 括起来,同时使用反斜杠 \ 转义特殊字符. 字符串的截取的语法格式如下: 变量[头下标:尾下标] 索引值以 0 为开始值,-1 ...

  7. 统计nginx日志里访问次数最多的前十个IP

    awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -nr -k1 | head -n 10

  8. scss文件使用笔记

    1.编写兼容性代码 例如透明度,兼容IE @mixin mOpacity($o){ opacity:$o/100; filter:alpha(opacity=$o); } //引用 .box{ @in ...

  9. python爬虫快递查询系统(源码)

    import requestsimport json def get_express_type(postid): '''根据快递单号来智能判断快递类型''' url = 'http://www.kua ...

  10. vue——vue-resource

    get请求 getSearch () { return this.$http.get('https://xxx.xxx.com/xxx.json', {params: {name: this.sear ...