Nec*_*ron 4 python user-interface qt-designer pyside uic
现在我像这样加载它们:
if __name__ == '__main__':
app = QApplication(sys.argv)
loader = QUiLoader()
file = QFile('main.ui')
file.open(QFile.ReadOnly)
window = loader.load(file)
file.close()
window.show()
# Here:
window.centralwidget.findChild(QListWidget, 'listWidget').addItems(['Item {0}'.format(x) for x in range(100)])
sys.exit(app.exec_())
Run Code Online (Sandbox Code Playgroud)
但我认为这很不舒服,有没有其他方法,可能加载整个命名空间或其他什么?
更新:
下面的原始解决方案是为 PySide (Qt4) 编写的。它仍然适用于 PySide2 (Qt5) 和 PySide6 (Qt6),但有一些附带条件:
loadUi(此外,应该提到的是,PySide2和PySide6现在有一个loadUiType函数,乍一看似乎提供了一个更简单的解决方案。但是,当前实现的一个主要缺点是需要在系统和用户路径中的可执行文件。这当然不能保证总是如此,因此它是否适合在生产环境中使用是有争议的)。
下面是一个更新的演示,说明了上述两个功能:

测试.py:
from PySide2 import QtWidgets, QtCore, QtUiTools
# from PySide6 import QtWidgets, QtCore, QtUiTools
class UiLoader(QtUiTools.QUiLoader):
_baseinstance = None
def createWidget(self, classname, parent=None, name=''):
if parent is None and self._baseinstance is not None:
widget = self._baseinstance
else:
widget = super().createWidget(classname, parent, name)
if self._baseinstance is not None:
setattr(self._baseinstance, name, widget)
return widget
def loadUi(self, uifile, baseinstance=None):
self._baseinstance = baseinstance
widget = self.load(uifile)
QtCore.QMetaObject.connectSlotsByName(baseinstance)
return widget
class MyLabel(QtWidgets.QLabel):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.setStyleSheet('background: plum')
class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
loader = UiLoader()
loader.registerCustomWidget(MyLabel)
loader.loadUi('main.ui', self)
@QtCore.Slot()
def on_testButton_clicked(self):
self.customLabel.setText(
'' if self.customLabel.text() else 'Hello World')
if __name__ == '__main__':
app = QtWidgets.QApplication(['Test'])
window = MainWindow()
window.show()
try:
app.exec()
except AttributeError:
app.exec_()
Run Code Online (Sandbox Code Playgroud)
主.ui:
from PySide2 import QtWidgets, QtCore, QtUiTools
# from PySide6 import QtWidgets, QtCore, QtUiTools
class UiLoader(QtUiTools.QUiLoader):
_baseinstance = None
def createWidget(self, classname, parent=None, name=''):
if parent is None and self._baseinstance is not None:
widget = self._baseinstance
else:
widget = super().createWidget(classname, parent, name)
if self._baseinstance is not None:
setattr(self._baseinstance, name, widget)
return widget
def loadUi(self, uifile, baseinstance=None):
self._baseinstance = baseinstance
widget = self.load(uifile)
QtCore.QMetaObject.connectSlotsByName(baseinstance)
return widget
class MyLabel(QtWidgets.QLabel):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.setStyleSheet('background: plum')
class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
loader = UiLoader()
loader.registerCustomWidget(MyLabel)
loader.loadUi('main.ui', self)
@QtCore.Slot()
def on_testButton_clicked(self):
self.customLabel.setText(
'' if self.customLabel.text() else 'Hello World')
if __name__ == '__main__':
app = QtWidgets.QApplication(['Test'])
window = MainWindow()
window.show()
try:
app.exec()
except AttributeError:
app.exec_()
Run Code Online (Sandbox Code Playgroud)
原始解决方案:
目前,PySide QUiLoader 类没有像PyQt uic 模块那样方便的方法将小部件加载到顶级类的实例中。
然而,添加等价的东西相当容易:
from PySide import QtGui, QtCore, QtUiTools
class UiLoader(QtUiTools.QUiLoader):
_baseinstance = None
def createWidget(self, classname, parent=None, name=''):
if parent is None and self._baseinstance is not None:
widget = self._baseinstance
else:
widget = super(UiLoader, self).createWidget(classname, parent, name)
if self._baseinstance is not None:
setattr(self._baseinstance, name, widget)
return widget
def loadUi(self, uifile, baseinstance=None):
self._baseinstance = baseinstance
widget = self.load(uifile)
QtCore.QMetaObject.connectSlotsByName(widget)
return widget
Run Code Online (Sandbox Code Playgroud)
然后可以像这样使用:
class MainWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(self, parent)
UiLoader().loadUi('main.ui', self)
self.listWidget.addItems(['Item {0}'.format(x) for x in range(100)])
Run Code Online (Sandbox Code Playgroud)
为了使其正常工作,baseinstance的参数loadUi必须是 Qt Designer 文件中顶级类的实例。然后,所有其他小部件将作为实例属性添加到其中。