可以让PySide的QUIloader像PyQt的uic.loadUi一样吗?

9 投票
3 回答
2610 浏览
提问于 2025-04-18 07:45

我有一个应用程序,正在考虑把它从PyQt4换成PySide。在这个应用中,我经常使用.ui文件,使用方式大致是这样的:

class BaseGUIWidget(QWidget):
    def __init__(self, parent = None, ui_file = None):
        '''
        :param parent: parent widget of this widget
        :param ui_file: path to UI file to load (optional)
        '''
        super(BaseGUIWidget, self).__init__(parent)
        if ui_file is not None:
            uic.loadUi(ui_file, self)

假设我有类似的类,比如QFrameQMainWindowQGroupBox等等。

这样,我就可以创建一些Python类,这些类可以使用UI文件中的数据,还可以添加我在代码中手动增加的功能。简单来说,我的BaseGUIWidget类就像是扩展了UI文件生成的类。应用中的很多功能都依赖于这种行为。

不过,从我了解到的情况来看,PySide的QUIloader并没有类似的功能。它不是把UI文件的内容“嵌入”到你的类中,而是内部直接从UI文件构建一个小部件,然后返回这个小部件,你再像使用其他小部件一样把它放到你的布局中。例如:

class BaseGUIWidget(QWidget):
    def __init__(self, parent = None, ui_file = None):
        '''
        :param parent: parent widget of this widget
        :param ui_file: path to UI file to load (optional)
        '''
        super(BaseGUIWidget, self).__init__(parent)
        self.setLayout(QVBoxLayout())
        if ui_file is not None:
            loader = QUILoader()
            uifile = QFile(ui_file)
            uifile.open(QFile.ReadOnly)                
            self.ui_widget = loader.load(ui_file, self)
            self.layout().addWidget(self.ui_widget)
            uifile.close()

这之间的差别很大。如果你想让你的UI文件包含一个QMainWindow,而你的Python类仍然是QMainWindow的扩展,这样它在其他类中也能表现得像一个QMainWindow,那么你就会得到一个QMainWindow里面再嵌套一个QMainWindow,这显然不是你想要的。这也意味着你需要通过widget.ui_widget.XXX来访问UI文件生成的小部件。

有没有办法让PySide的uic实现像PyQt的那样工作呢?

3 个回答

-2

其实我也在想这个问题,刚刚试了一下这个方法:

  1. 把PyQt4安装包里的uic文件夹复制到你的PySide包里(这些都是Python模块,没有编译过的库,所以应该不会有不兼容的问题)

  2. 在uic文件夹里进行搜索和替换,把“PyQt4”替换成“PySide”

  3. 然后就可以使用了:

    from PySide import uic
    
    w = uic.loadUi("mywidget.ui")
    w.show()
    

这个方法在你提到的用例(uic.loadUi(ui_file, self))中也对我有效哦 :) 当然,不能保证所有功能都能正常工作,但我很惊讶这个小技巧竟然能让它运行起来。

0

是的,这是可能的。
我知道这个问题比较老,但突然间可能会有人需要这个信息。
我在这里找到了解决方案:

https://robonobodojo.wordpress.com/2017/10/03/loading-a-pyside-ui-via-a-class/

ui_loader.py:

#!/usr/bin/env python

from PySide.QtUiTools import QUiLoader
from PySide.QtCore import QMetaObject

class UiLoader(QUiLoader):
    def __init__(self, base_instance):
        QUiLoader.__init__(self, base_instance)
        self.base_instance = base_instance

    def createWidget(self, class_name, parent=None, name=''):
        if parent is None and self.base_instance:
            return self.base_instance
        else:
            # create a new widget for child widgets
            widget = QUiLoader.createWidget(self, class_name, parent, name)
            if self.base_instance:
                setattr(self.base_instance, name, widget)
            return widget

def load_ui(ui_file, base_instance=None):
    loader = UiLoader(base_instance)
    widget = loader.load(ui_file)
    QMetaObject.connectSlotsByName(widget)
    return widget

示例:

#!/usr/bin/env python

from PySide import QtGui
from ui_loader import load_ui
import sys

class MainWindow(QtGui.QMainWindow):
    def __init__(self, parent=None):
        QtGui.QMainWindow.__init__(self, parent)
        load_ui('my_interface.ui', self)

def main():
    app = QtGui.QApplication(sys.argv)
    window = MainWindow()
    window.show()
    app.exec_()

if __name__ == '__main__':
    main()
0

使用QtPy这个包

pip3 install QtPy

它会自动识别你用的是哪个绑定(比如pyqt5或者pyside2)

from QtPy import uic # and all other QT modules

w = uic.loadUi("mywidget.ui")
w.show()

撰写回答