可以让PySide的QUIloader像PyQt的uic.loadUi一样吗?
我有一个应用程序,正在考虑把它从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)
假设我有类似的类,比如QFrame
、QMainWindow
、QGroupBox
等等。
这样,我就可以创建一些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 个回答
其实我也在想这个问题,刚刚试了一下这个方法:
把PyQt4安装包里的uic文件夹复制到你的PySide包里(这些都是Python模块,没有编译过的库,所以应该不会有不兼容的问题)
在uic文件夹里进行搜索和替换,把“PyQt4”替换成“PySide”
然后就可以使用了:
from PySide import uic w = uic.loadUi("mywidget.ui") w.show()
这个方法在你提到的用例(uic.loadUi(ui_file, self))中也对我有效哦 :) 当然,不能保证所有功能都能正常工作,但我很惊讶这个小技巧竟然能让它运行起来。
是的,这是可能的。
我知道这个问题比较老,但突然间可能会有人需要这个信息。
我在这里找到了解决方案:
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()
使用QtPy这个包
pip3 install QtPy
它会自动识别你用的是哪个绑定(比如pyqt5或者pyside2)
from QtPy import uic # and all other QT modules
w = uic.loadUi("mywidget.ui")
w.show()