PySide vs PyQt ui file load.
-
Why does PySide ui load differ from PyQt? I'd like to use PySide since it is 'official' and has (hopefully) a more robust update cycle. Code fragments highlight the issue. Thanks, Scott
PyQt6 ui or py files work and matches my development flow.
PySide6 py file works, ui file fails here with:
File "...\qt_test.py", line 53, in event_loop
print(self.label.text())
^^^^^^^^^^
AttributeError: 'main' object has no attribute 'label'Minimal ui:
qt_mainwindow.ui -> default 'Main Window' and a label. DT Widget Designer v6.82
pyuic6 qt_mainwindow.ui -o qt_mainwindow_pyqt6.py
pyuic6 qt_mainwindow.ui -o qt_mainwindow_pyside6.py
"""
class main(PySide6.QtWidgets.QMainWindow, Ui_MainWindow):
def init(self, ui_file_flag, ui_file):
super(main, self).init()
if ui_file_flag:
print('loading ui_file file')
# PyQt6.uic.loadUi(ui_file, self)
# both PySide6 ui loads fail at the same place and with the same message (line-53)
# PySide6.QtUiTools.loadUiType(ui_file)
PySide6.QtUiTools.QUiLoader().load(ui_file)
else:
print('loading py file')
self.setupUi(self) -
Why does PySide ui load differ from PyQt? I'd like to use PySide since it is 'official' and has (hopefully) a more robust update cycle. Code fragments highlight the issue. Thanks, Scott
PyQt6 ui or py files work and matches my development flow.
PySide6 py file works, ui file fails here with:
File "...\qt_test.py", line 53, in event_loop
print(self.label.text())
^^^^^^^^^^
AttributeError: 'main' object has no attribute 'label'Minimal ui:
qt_mainwindow.ui -> default 'Main Window' and a label. DT Widget Designer v6.82
pyuic6 qt_mainwindow.ui -o qt_mainwindow_pyqt6.py
pyuic6 qt_mainwindow.ui -o qt_mainwindow_pyside6.py
"""
class main(PySide6.QtWidgets.QMainWindow, Ui_MainWindow):
def init(self, ui_file_flag, ui_file):
super(main, self).init()
if ui_file_flag:
print('loading ui_file file')
# PyQt6.uic.loadUi(ui_file, self)
# both PySide6 ui loads fail at the same place and with the same message (line-53)
# PySide6.QtUiTools.loadUiType(ui_file)
PySide6.QtUiTools.QUiLoader().load(ui_file)
else:
print('loading py file')
self.setupUi(self)@swoiwode Where is this print statement in your code?
You do not store what load(ui_file) returns anywhere - how are you going to use it?
https://doc.qt.io/qtforpython-6/tutorials/basictutorial/uifiles.htmlPlease format you code properly when posting.
-
@swoiwode Where is this print statement in your code?
You do not store what load(ui_file) returns anywhere - how are you going to use it?
https://doc.qt.io/qtforpython-6/tutorials/basictutorial/uifiles.htmlPlease format you code properly when posting.
@jsulm , @swoiwode
PySide6.QtUiTools.QUiLoader().load(ui_file)is the function to use. I presume the OP's issue is that he has existing code usingPyQt6.uic.loadUi(ui_file, self), which loads intoselfwhile the PySide call instead returns some newly created widget? PySide and PyQt are mostly similar/identical, but I do not they do their dynamic loading of a.uifile differently. I don't know whether you can achieve same from PySide.Further, I only expected these dynamic loadings to produce a widget tree you can access via
findChild<>(). But the existing code is apparently failing on some existingself.label.text()call.self.labelmust be a Python variable/referencelabelset to someQLabelfound in the.uifile. I do not know how that gets set in the first place. Is it done explicitly somewhere in OP's code? Did I read that either or both of the respective PySide and PyQt calls actually do someuicrunning magic at runtime to (perhaps?) produce Python code with variables for the widgets in the.uifile? I think the OP needs to examine the documentation or code of the respective PySide/PyQt methods. -
@JonB, @jsulm,
Thanks for the replies. I will upload the complete code, ui file and format too.I was afraid that ui loading was one of the differences between PySide and PyQt, prior searches gave me that belief.
BTW - Any non-functional print statements are my breadcrumbs :p. The development flow starts with a uniquely named ui file and template. Converted to py, so the ‘wiring’ can be confirmed. Then further GUI development is done with live user engagement/presence, rapid visuals of the GUI are needed and changes made as required. Converting ui to py, adjusting code as needed, passing through pyinstaller and checking functionality are done afterwards. I can deliver a solution within ~hour.
Thanks, Scott
-
@jsulm, @JonB
Sample error message, python code and ui file, as requested.**** error message start ****
C:\Users\Scott\Desktop\PythonDev\qt\.venv\Scripts\python.exe C:\Users\Scott\Desktop\PythonDev\qt\qt_test.py -iuf .\qt_mainwindow.ui Traceback (most recent call last): File "C:\Users\Scott\Desktop\PythonDev\qt\qt_test.py", line 70, in <module> window: PySide6.QtWidgets.QMainWindow = main(m_ui_file_flag, m_ui_file) ~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\Scott\Desktop\PythonDev\qt\qt_test.py", line 44, in __init__ self.event_loop() ~~~~~~~~~~~~~~~^^ File "C:\Users\Scott\Desktop\PythonDev\qt\qt_test.py", line 57, in event_loop print(self.label.text()) ^^^^^^^^^^ AttributeError: 'main' object has no attribute 'label'**** error message end ****
**** python code start ****
""" barebone implementations to load ui file for Pyside or PyQt, enable one or the other qt_mainwindow.ui -> default 'Main Window' and a label. DT Widget Designer v6.82 This code should print 'TextLabel' to the console every second """ import sys # ---- PyQt ---- comment/uncomment as needed # import PyQt6.QtWidgets # import PyQt6.uic # import PyQt6.QtGui # import PyQt6.QtCore # ---- PySide ---- comment/uncomment as needed import PySide6.QtWidgets import PySide6.QtUiTools import PySide6.QtGui import PySide6.QtCore # ---- PyQt ---- comment/uncomment as needed # from qt_mainwindow_pyqt6 import Ui_MainWindow # ---- PySide ---- comment/uncomment as needed from qt_mainwindow_pyside6 import Ui_MainWindow # ---- PyQt ---- comment/uncomment as needed # class main(PyQt6.QtWidgets.QMainWindow, Ui_MainWindow): # ---- PySide ---- comment/uncomment as needed class main(PySide6.QtWidgets.QMainWindow, Ui_MainWindow): def __init__(self, ui_file_flag, ui_file): super(main, self).__init__() if ui_file_flag: # ---- PyQt ---- comment/uncomment as needed # PyQt6.uic.loadUi(ui_file, self) # ---- PySide ---- comment/uncomment as needed PySide6.QtUiTools.QUiLoader().load(ui_file) else: self.setupUi(self) self.event_loop() # ---- PyQt ---- comment/uncomment as needed # self.timer = PyQt6.QtCore.QTimer() # ---- PySide ---- comment/uncomment as needed self.timer = PySide6.QtCore.QTimer() self.timer.timeout.connect(self.event_loop) # noqa self.timer.start(1000) # FAIL, PySide ui fiie for AttributeError: 'main' object has no attribute 'label' def event_loop(self) -> None: print(self.label.text()) if __name__ == '__main__': m_ui_file_flag: bool = True # <- developer switch, False for release. m_ui_file = r'.\qt_mainwindow.ui' # ---- PyQt ---- comment/uncomment as needed # app = PyQt6.QtWidgets.QApplication(sys.argv) # window: PyQt6.QtWidgets.QMainWindow = main(m_ui_file_flag, m_ui_file) # ---- PySide ---- comment/uncomment as needed app = PySide6.QtWidgets.QApplication(sys.argv) window: PySide6.QtWidgets.QMainWindow = main(m_ui_file_flag, m_ui_file) window.show() sys.exit(app.exec())**** python code end ****
**** ui code start ****
<?xml version="1.0" encoding="UTF-8"?> <ui version="4.0"> <class>MainWindow</class> <widget class="QMainWindow" name="MainWindow"> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>800</width> <height>600</height> </rect> </property> <property name="windowTitle"> <string>MainWindow</string> </property> <widget class="QWidget" name="centralwidget"> <widget class="QLabel" name="label"> <property name="geometry"> <rect> <x>370</x> <y>250</y> <width>49</width> <height>16</height> </rect> </property> <property name="text"> <string>TextLabel</string> </property> </widget> </widget> <widget class="QMenuBar" name="menubar"> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>800</width> <height>33</height> </rect> </property> </widget> <widget class="QStatusBar" name="statusbar"/> </widget> <resources/> <connections/> </ui>**** ui code end ****
-
@jsulm, @JonB
Sample error message, python code and ui file, as requested.**** error message start ****
C:\Users\Scott\Desktop\PythonDev\qt\.venv\Scripts\python.exe C:\Users\Scott\Desktop\PythonDev\qt\qt_test.py -iuf .\qt_mainwindow.ui Traceback (most recent call last): File "C:\Users\Scott\Desktop\PythonDev\qt\qt_test.py", line 70, in <module> window: PySide6.QtWidgets.QMainWindow = main(m_ui_file_flag, m_ui_file) ~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\Scott\Desktop\PythonDev\qt\qt_test.py", line 44, in __init__ self.event_loop() ~~~~~~~~~~~~~~~^^ File "C:\Users\Scott\Desktop\PythonDev\qt\qt_test.py", line 57, in event_loop print(self.label.text()) ^^^^^^^^^^ AttributeError: 'main' object has no attribute 'label'**** error message end ****
**** python code start ****
""" barebone implementations to load ui file for Pyside or PyQt, enable one or the other qt_mainwindow.ui -> default 'Main Window' and a label. DT Widget Designer v6.82 This code should print 'TextLabel' to the console every second """ import sys # ---- PyQt ---- comment/uncomment as needed # import PyQt6.QtWidgets # import PyQt6.uic # import PyQt6.QtGui # import PyQt6.QtCore # ---- PySide ---- comment/uncomment as needed import PySide6.QtWidgets import PySide6.QtUiTools import PySide6.QtGui import PySide6.QtCore # ---- PyQt ---- comment/uncomment as needed # from qt_mainwindow_pyqt6 import Ui_MainWindow # ---- PySide ---- comment/uncomment as needed from qt_mainwindow_pyside6 import Ui_MainWindow # ---- PyQt ---- comment/uncomment as needed # class main(PyQt6.QtWidgets.QMainWindow, Ui_MainWindow): # ---- PySide ---- comment/uncomment as needed class main(PySide6.QtWidgets.QMainWindow, Ui_MainWindow): def __init__(self, ui_file_flag, ui_file): super(main, self).__init__() if ui_file_flag: # ---- PyQt ---- comment/uncomment as needed # PyQt6.uic.loadUi(ui_file, self) # ---- PySide ---- comment/uncomment as needed PySide6.QtUiTools.QUiLoader().load(ui_file) else: self.setupUi(self) self.event_loop() # ---- PyQt ---- comment/uncomment as needed # self.timer = PyQt6.QtCore.QTimer() # ---- PySide ---- comment/uncomment as needed self.timer = PySide6.QtCore.QTimer() self.timer.timeout.connect(self.event_loop) # noqa self.timer.start(1000) # FAIL, PySide ui fiie for AttributeError: 'main' object has no attribute 'label' def event_loop(self) -> None: print(self.label.text()) if __name__ == '__main__': m_ui_file_flag: bool = True # <- developer switch, False for release. m_ui_file = r'.\qt_mainwindow.ui' # ---- PyQt ---- comment/uncomment as needed # app = PyQt6.QtWidgets.QApplication(sys.argv) # window: PyQt6.QtWidgets.QMainWindow = main(m_ui_file_flag, m_ui_file) # ---- PySide ---- comment/uncomment as needed app = PySide6.QtWidgets.QApplication(sys.argv) window: PySide6.QtWidgets.QMainWindow = main(m_ui_file_flag, m_ui_file) window.show() sys.exit(app.exec())**** python code end ****
**** ui code start ****
<?xml version="1.0" encoding="UTF-8"?> <ui version="4.0"> <class>MainWindow</class> <widget class="QMainWindow" name="MainWindow"> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>800</width> <height>600</height> </rect> </property> <property name="windowTitle"> <string>MainWindow</string> </property> <widget class="QWidget" name="centralwidget"> <widget class="QLabel" name="label"> <property name="geometry"> <rect> <x>370</x> <y>250</y> <width>49</width> <height>16</height> </rect> </property> <property name="text"> <string>TextLabel</string> </property> </widget> </widget> <widget class="QMenuBar" name="menubar"> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>800</width> <height>33</height> </rect> </property> </widget> <widget class="QStatusBar" name="statusbar"/> </widget> <resources/> <connections/> </ui>**** ui code end ****
@swoiwode
As already said: your code hasself.label.text(). How or where didself.labelever get created? Certainly it is not byPySide6.QtUiTools.QUiLoader().load(ui_file). So was it (somehow) created before byPyQt6.uic.loadUi(ui_file, self)? We don't know, it's a third party product. No, they are not the same. At some level they both load a.uifile, but what they then do is different and unknown forPyQt6.uic.loadUi().I suggested you examine its documentation and code if you want to understand what you would need to do from PySide. Just directly replacing one call with the other clearly does not work, as you have discovered.
P.S.
Read https://www.pythonguis.com/faq/pyqt5-vs-pyside2/ , UI files section. It's for PyQt5 vs PySide2, but it will be same for PyQt6 vs PySide6. It mentions "but you can work around this with a separate function" and gives some code. But I'm still not sure who that to relates to your existing usage ofself.label.See also https://www.pythontutorial.net/pyqt/qt-designer/#using-ui-file-directly. And https://python-forum.io/thread-35619.html.
I don't know where
PyQt6.uicis documented? [Good luck tracking it down: the only instance in The Universe turns out to be https://riverbankcomputing.com/static/Docs/PyQt6/api/uic/uic-module.html#loadUi and goodness knows how you get there.]If by any chance that
uicin its name indicates that it requires the PyQt6 equivalent ofuicto be shipped and found at runtime, and that is run to generated Python code at runtime which is somehow imported and hence you can get a variable likelabelcreated at runtime, then I don't think PySide has an equivalent and you would have to change some of your code. [The preceding may not be the case at all, I am not sure where I might have seen that it might work like that.]Hmm, I think that https://python-forum.io/thread-35619.html may be key and the only docs I have seen so far. Someone says
Is there any way to load ui with Pyside6 that the widgets become attributes of the class instead of attributes of another attribute of the class e.g. "self.ui"
So that does imply that
PySide6.QtUiTools.QUiLoader().load(ui_file)creates Python "attributes/variables" at runtime for named widgets in the.uifile (I still don't know where this behaviour is documented) and so doesPyQt6.uic.loadUi(). The difference is that in PyQt you can put that directly intoselfviaPyQt6.uic.loadUi(ui_file, self)whereas fromPySide6.QtUiTools.QUiLoader().load(ui_file)you get back a "dummy" class you must use, likeself.ui = PySide6.QtUiTools.QUiLoader().load(ui_file)and then you can accessself.ui.label. I think you will need to change your code to work offself.uiwhere appropriate.FWIW, loading a
.uifile intoself.uiis the direct equivalent of the way it is done inthis->uifrom C++. In that sense the PySide interface follows this pattern whilePyQt6.uic.loadUi(ui_file, self)is "non-standard". -
self.labelcomes from the .ui file.
It is working now with
self.ui = PySide6.QtUiTools.QUiLoader().load(ui_file)and using
self.ui.label.text()will print 'TextLabel', ever second to the console.
Adding
self.ui.show()as the last line of
__init__and removing
window.show()in
if __name__ == '__main__':Displays:

I will embrace this methodology going forward.Thanks, Scott
-
self.labelcomes from the .ui file.
It is working now with
self.ui = PySide6.QtUiTools.QUiLoader().load(ui_file)and using
self.ui.label.text()will print 'TextLabel', ever second to the console.
Adding
self.ui.show()as the last line of
__init__and removing
window.show()in
if __name__ == '__main__':Displays:

I will embrace this methodology going forward.Thanks, Scott
@swoiwode
Yes, you have made the right changes! Note how you changed fromPyQt6.uic.loadUi(ui_file, self), which loaded intoselfand gave youself.labeletc. over toself.ui = PySide6.QtUiTools.QUiLoader().load(ui_file), which returned into a newly createdself.ui(or whatever you choose to call it) and hence gave youself.ui.labeletc. It's just a different way of doing things, and PySide just does not offer that parameter or loading intoself.Looking around at what examples there are on the web I found that actually even in PyQt more people had worked from
self.ui = PyQt6.uic.loadUi(ui_file)which is also available and similar to the PySide way than that "non-standard"PyQt6.uic.loadUi(ui_file, self)which the code you inherited had chosen to use.Honestly you came across one of the few difference between PyQt and PySide right from the outset in the small script you were working on. 99% of the time you should find that same code simply works from PyQt to PySide.