[Python] PyQt vs PySide uic loader difference

Discussão em 'Python' iniciado por Stack, Julho 11, 2025.

  1. Stack

    Stack Membro Participativo

    I'm migrating some code from PtQy5 to PySide6. I'm experiencing a significant behavioural difference when loading .ui files.

    The original PyQt5 code:

    import sys
    import os

    from PyQt5.QtWidgets import QApplication
    from PyQt5.QtWidgets import QWidget, QMainWindow
    from PyQt5 import uic

    ui_content = '<?xml version="1.0" encoding="UTF-8"?>\
    <ui version="4.0">\
    <class>Form</class>\
    <widget class="QWidget" name="Form">\
    <layout class="QVBoxLayout" name="verticalLayout">\
    <item>\
    <widget class="QPushButton" name="myButton">\
    <property name="text">\
    <string>PushButton</string>\
    </property>\
    </widget>\
    </item>\
    </layout>\
    </widget>\
    <resources/>\
    <connections/>\
    </ui>\
    '

    if __name__ == '__main__':

    app = QApplication(sys.argv)

    mainWindow = QMainWindow()

    class MyCentralWidget(QWidget):
    def __init__(self):
    super().__init__()

    import tempfile

    tmp = tempfile.NamedTemporaryFile(delete=False)
    tmp.write(ui_content.encode())
    tmp.close()

    self.ui = uic.loadUi(tmp.name,self)

    self.ui.myButton.setText(self.ui.myButton.text() + " Foo")
    self.myButton.setText(self.myButton.text() + " Bar")

    os.remove(tmp.name)

    centralWidget = MyCentralWidget()

    mainWindow.setCentralWidget(centralWidget)

    mainWindow.show()
    app.exec()


    As you can see, objects declared in the .ui (like myButton) end up being both attributes of the returned ui object and the MyCentralWidget object. Meaning that both self.ui.myButton and self.myButton work. This is because I pass self as second parameter to loadUi, but if I don't do this the widget remains blank, so I suppose that's the right way to do.

    When migrating to PySide6, I had to adapt a bit the code:

    import sys
    import os

    from PySide6.QtWidgets import QApplication
    from PySide6.QtWidgets import QWidget, QMainWindow, QVBoxLayout
    from PySide6.QtUiTools import QUiLoader
    from PySide6.QtCore import QFile

    ui_content = '<?xml version="1.0" encoding="UTF-8"?>\
    <ui version="4.0">\
    <class>Form</class>\
    <widget class="QWidget" name="Form">\
    <layout class="QVBoxLayout" name="verticalLayout">\
    <item>\
    <widget class="QPushButton" name="myButton">\
    <property name="text">\
    <string>PushButton</string>\
    </property>\
    </widget>\
    </item>\
    </layout>\
    </widget>\
    <resources/>\
    <connections/>\
    </ui>\
    '

    if __name__ == '__main__':

    ui_loader = QUiLoader()

    app = QApplication(sys.argv)

    mainWindow = QMainWindow()

    class MyCentralWidget(QWidget):
    def __init__(self):
    super().__init__()

    import tempfile

    tmp = tempfile.NamedTemporaryFile(delete=False)
    tmp.write(ui_content.encode())
    tmp.close()

    uifile = QFile(tmp.name)
    uifile.open(QFile.ReadOnly)
    self.ui = ui_loader.load(uifile,self)
    uifile.close()

    # Needed to have self.ui be centered
    self.mainLayout = QVBoxLayout(self)
    self.mainLayout.addWidget(self.ui)

    self.ui.myButton.setText(self.ui.myButton.text() + " Foo")
    #self.myButton does not exist
    #self.myButton.setText(self.myButton.text() + " Bar")

    os.remove(tmp.name)

    centralWidget = MyCentralWidget()

    mainWindow.setCentralWidget(centralWidget)

    mainWindow.show()
    app.exec()


    But now, the objects are not cloned to self and so self.myButton does not exist.

    Is that expected? Or am I doing something wrong?

    My code was written using PyQt5, so there's many places where we use self.XXX instead of self.ui.XXX just because it used to work just fine, and it's hard to identify all the places. To fix all the runtime issues, we duplicate the objects:

    self.__dict__.update(self.ui.__dict__)


    Is this a bad idea/workaround?

    Continue reading...

Compartilhe esta Página