一半君的总结纸

听话只听一半君

近年来依然中古的PyQt写UI的方法总结纸

Maya帮助自带一个用loadUI命令的方法,不过这方法和屎一样,不会有人用的,正确方法如下: 此文中的举例有着这样或者那样的问题,比如

  • from xxx import *
  • 使用了global var, 其实应该避免

lz觉得现在比较推荐的方法在这里

如果ui上没有太多动态元素的话,你可以用qt designer 画一个.ui文件出来,也可以直接在代码里写。对于不想当代码民工的人来说,用designer画就可以了,不过也许你画多了以后也就会写了

fuckme_designer

上图的.ui文件可以用

pyuic4 -o ui_pyqt_example.py pyqt_example.ui

来转换成.py文件,然后下面的用法稍有不同,下面的几个例子都是直接读取.ui文件,没有预先转换,因为我们Maya里平常用的UI都不是特别复杂,所以预先转换以换取读取速度的意义不大

The Single Inheritance Approach

方法1:

import os,sys
from PyQt4.QtGui import *
from PyQt4.QtCore import *
from PyQt4 import uic

import maya.OpenMayaUI as apiUI
import sip

uiFile=os.path.join(os.path.dirname(__file__), 'pyqt_example.ui')

def getMayaWindow():
    ptr = apiUI.MQtUtil.mainWindow()
    return sip.wrapinstance(long(ptr), QObject)

class MyWindow(QDialog):
    def __init__(self,parent=getMayaWindow()):
        super(MyWindow,self).__init__(parent)
        self.ui = uic.loadUi(uiFile,self)
        self.ui.show()

def main():
    global win
    try:
        win.close()
    except:
        pass
    win = MyWindow()

if __name__ == '__main__':
    main()

方法1 在外部运行:

import sys
from PyQt4.QtGui import *
from PyQt4.QtCore import *
from PyQt4 import uic

# enable ctrl-c to kill the app
import signal
signal.signal(signal.SIGINT, signal.SIG_DFL)

class MyWindow(QDialog):
    def __init__(self,parent=None):
        super(MyWindow,self).__init__(parent)

        self.ui = uic.loadUi('pyqt_example.ui',self)
        self.ui.show()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    win = MyWindow()
    sys.exit(app.exec_())

  • 但是上面的方法访问ui上的widgets的时候得 self.ui.xxx,好像有点长.
  • 还有上面都是直接用 .ui文件的,如果你用pyuic4把.ui转成了py, 那也许你就可以用 self.ui.setupUi(self)了吧,我猜…
  • getMayaWindow()这个不是必要的,但是如果你的window的parent不是Maya的MainWindow的话,当Maya最小化的时候,你的窗口会浮在外面,不跟着Maya一起最小化

The Multiple Inheritance Approach

方法2:
(来自nathan网站)


import os
import sip

import maya.cmds as cmds
import maya.OpenMayaUI as mui

from PyQt4 import QtGui, QtCore, uic

def getMayaWindow():
    'Get the maya main window as a QMainWindow instance'
    ptr = mui.MQtUtil.mainWindow()
    return sip.wrapinstance(long(ptr), QtCore.QObject)

uiFile=os.path.join(os.path.dirname(__file__), 'pyqt_example.ui')

#Load the ui file, and create my class
form_class, base_class = uic.loadUiType(uiFile)
class MyWindow(base_class, form_class):
    def __init__(self, parent=getMayaWindow()):
        #init our ui using the MayaWindow as parent
        super(base_class, self).__init__(parent)
        #uic adds a function to our class called setupUi, calling this creates all the widgets from the .ui file
        self.setupUi(self)

def main():
    global win
    try:
        win.close()
    except:
        pass
    win = MyWindow()
    win.show()

if __name__ == '__main__':
    main()

方法2:在外部运行

import os,sys
from PyQt4 import QtGui, QtCore, uic
import sip

# enable ctrl-c to kill the app
import signal
signal.signal(signal.SIGINT, signal.SIG_DFL)

uiFile=os.path.join(os.path.dirname(__file__), 'pyqt_example.ui')

#Load the ui file, and create my class
form_class, base_class = uic.loadUiType(uiFile)
class MyWindow(base_class, form_class):
    def __init__(self, parent=None):
        #init our ui using the MayaWindow as parent
        super(base_class, self).__init__(parent)
        #uic adds a function to our class called setupUi, calling this creates all the widgets from the .ui file
        self.setupUi(self)

if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    win = MyWindow()
    win.show()
    sys.exit(app.exec_())

  • 上面的例子里,我有些地方用的是
from PyQt4.QtGui import *
from PyQt4.QtCore import *

最好不要这样,还是应该

from PyQt4 import QtGui, QtCore
  • ctrl-c关闭程序的那一段要不要都可以,但是有时候在console测试的时候比较方便
  • 最终效果图:(左边是在Maya里运行,右边是在外面运行)

    inMaya
    outsideMaya

    参考:
    Using Qt Designer
    Using a Designer UI File in Your Application

    拓展阅读:
    使用Qt设计师文件的3种方式 by Jimmy Kuu
    这虽然是在Maya外面使用,但是你在Maya里也一样,上面的方法相当于文中的方法1+3

    edit:
    lz觉得用 uic.loadUI() 比较好,不过如果文件拆成很多个单独的(widget class 放在单独的文件里了,也就无所谓了吧),或者没想着以后这个工具可以当成个python 的package, 方法2也行(我觉得想简单写写就方法2了,因为可以省去每次敲self.ui.xxx)

    edit: 上述例子中检测现在是不是在maya里的try/except不好,应该用

    QApplication.applicationName()
    # Result: PyQt4.QtCore.QString(u'Maya-2012-x64') #
    
    # 或者如果你已经from PyQt4.QtGui import *了, 你也可以用
    qApp.applicationName()
    

    pssss: 综上所述,最后全部合起来就是这样

    import os
    import sys
    from PyQt4 import QtCore, QtGui
    from PyQt4 import uic
    
    uiFile = os.path.join(os.path.dirname(__file__), 'pyqt_example.ui')
    
    try:
        import maya.OpenMayaUI as apiUI
        import sip
    
        def getMayaWindow():
            ptr = apiUI.MQtUtil.mainWindow()
            return sip.wrapinstance(long(ptr), QtCore.QObject)
    except:
        pass
    
    class MyWindow(QtGui.QDialog):
    
        def __init__(self, parent=None):
            super(MyWindow, self).__init__(parent)
            self.ui = uic.loadUi(uiFile, self)
            self.ui.show()
    
    def main():
        if QtGui.qApp.applicationName().startswith('Maya'):
            global win
            try:
                win.deleteLater()
            except:
                pass
            win = MyWindow(getMayaWindow())
        else:
            app = QtGui.QApplication(sys.argv)
            win = MyWindow()
            sys.exit(app.exec_())
    
    if __name__ == '__main__':
        main()
    
    

    写代码的时候套用上面这个模板就行了

    update:
    此模板用于懒人提问

    import os
    import sys
    from PyQt4.QtCore import *
    from PyQt4.QtGui import *
    from PyQt4 import uic
    
    class MyWindow(QDialog):
    
        def __init__(self, parent=None):
            super(MyWindow, self).__init__(parent)
            layout = QVBoxLayout()
            textedit = QTextEdit()
            button = QPushButton('test')
            layout.addWidget(textedit)
            layout.addWidget(button)
            self.setLayout(layout)
    
    def main():
        if qApp.applicationName().startsWith('Maya'):
            global win
            try:
                win.deleteLater()
            except:
                pass
            win = MyWindow()
            win.show()
        else:
            app = QApplication(sys.argv)
            win = MyWindow()
            win.show()
            sys.exit(app.exec_())
    
    if __name__ == '__main__':
        main()
    
    
    

    update:
    deleteLater()比close()要好一些,此外如果不想使用global var, 也可以(以Qt.py为例)

    app = QtWidgets.QApplication.instance()
    for obj in app.topLevelWidgets():
        if obj.objectName()=='your_gui_obj_name' and obj.isVisible():
        obj.deleteLater()
        del obj
    

    下载链接:
    pyqt_example.ui

    发表评论

    Fill in your details below or click an icon to log in:

    WordPress.com 徽标

    You are commenting using your WordPress.com account. Log Out /  更改 )

    Google photo

    You are commenting using your Google account. Log Out /  更改 )

    Twitter picture

    You are commenting using your Twitter account. Log Out /  更改 )

    Facebook photo

    You are commenting using your Facebook account. Log Out /  更改 )

    Connecting to %s

    %d 博主赞过: