Create QUiLoader before QUiApplication?
-
I've encountered strange behaviour in PySide6 which seems to contradict documentation online, whereby the Python interpreter freezes if I attempt to create an instance of QUiLoader AFTER creating an instance of QUiApplication, but works fine if I create it before. I've also found a Stack post where other people have had the same issue.
Is this a bug? It seems counterintuitive, contradicts documentation & also looks like its going to require some awkward work arounds. If so, does anyone know if there a fix planned, or if there is a slightly older version of PySide6 I can use which doesn't feature the bug? It seems strange that there isn't more online about this, altho I am new to using so Qt so maybe I'm just missing something?
I am using Windows 11 Pro version 23H2, Python 3.12.2, PySide6 version 6.6.3
Thank you
-
Hi and welcome to devnet,
You should provide a minimal runnable project that shows this issue.
-
@SGaist sorry been on holiday. heres the script im running, lifted directly from a pyside6 tutorial:
import sys from PySide6.QtUiTools import QUiLoader from PySide6.QtWidgets import QApplication from PySide6.QtCore import QFile, QIODevice if __name__ == "__main__": app = QApplication(sys.argv) ui_file_name = "tester.ui" ui_file = QFile(ui_file_name) if not ui_file.open(QIODevice.ReadOnly): print(f"Cannot open {ui_file_name}: {ui_file.errorString()}") sys.exit(-1) loader = QUiLoader() window = loader.load(ui_file) ui_file.close() if not window: print(loader.errorString()) sys.exit(-1) window.show() sys.exit(app.exec())
When I run this script the command window just freezes, and is unresponsive to keyboard interrupt command. However if I tweak the above script like so:
import sys from PySide6.QtUiTools import QUiLoader from PySide6.QtWidgets import QApplication from PySide6.QtCore import QFile, QIODevice if __name__ == "__main__": loader = QUiLoader() app = QApplication(sys.argv) ui_file_name = "tester.ui" ui_file = QFile(ui_file_name) if not ui_file.open(QIODevice.ReadOnly): print(f"Cannot open {ui_file_name}: {ui_file.errorString()}") sys.exit(-1) window = loader.load(ui_file) ui_file.close() if not window: print(loader.errorString()) sys.exit(-1) window.show() sys.exit(app.exec())
It works fine. Any idea whats going on?
-
@SmnTrbt
Always good to provide the refence! I notice that a comment there saysI cannot reproduce this on Linux using Qt 6.6.1 and PySide-6.6.1.
So I will be no use to you, I am Qt5/PySide2, plus I am Linux! Are you able to test with a different version of PySide6 to see if this is only in certain versions? have you had a look through https://bugreports.qt.io/browse ?
-
@JonB
Thanks for your reply. I tried all the versions of PySide6 that are compatible with the version of Python I'm running (the back end is already built so I can't use an older version of Python) and had the same issue.Haven't had a look thru the bugreports, will do so now, thank you for that.
-
@SmnTrbt
It looks like a surprising error, because I would expect to do it the "buggy" way and would have thought lots of other people would do same, plus you say a "tutorial" does not work Could you also put in reference link to the tutorial? And the fact that others are reporting it on SO also looks like it's a "thing".You will have to wait for someone else here to try with PySide6. Is PySide 6.7 out yet/available to you?
In the SO post one person actually asked about the content of the
.ui
file. You wouldn't think that would matter, but please test with about the smallest, simplest.ui
content you can think of (e.g. just oneQWidget
, nothing else?). -
@JonB This is the link to the tutorial: https://doc.qt.io/qtforpython-6/tutorials/basictutorial/uifiles.html
Just tried with a basic widget like you suggested and got the exact same behaviour; it works if the loader is initialised before, otherwise it freezes.
I agree that its a very strange problem and its surprising more people haven't encountered it. Could it be that most of the PySide community uses Linux like yourself, as the problem appears to be Windows specific?
-
@SmnTrbt
No, there will be people using PySide under Windows.I will say that I never use the
QUiLoader
approach to Qt UI apps. Are you at least aware that the alternative is to generate.py
code from the.ui
viapyside6-uic
at design time, and not distribute your.ui
file at all? That way you get decent design-time support in your IDE for accessing the widgets as variables, I think much preferable. Of course that does not obviate it being a bug withQUiLoader
, but if you do the other way it won't matter. -
@JonB Ah okay I see. Strange then that there isn't more discussion around this, hopefully someone here can test and provide further insight.
Re PySide 6.7, it is available and I've just updated to it, but the problem remains.
I am aware of this other method, but I chose to use the loader method as I am still learning and I felt the additional flexibility would be helpful for me to be able to quickly change things whilst learning. However in light of this issue, I think I agree with you that it might be worth me trying the other approach instead. Thank you for the suggestion, I will give this a go now. Is my concern about flexibility valid? Or is it relatively straightforward to change things on the fly? To clarify; I'm just making super basic versions of the widgets to get things working, and then I want to add extra functionality and tweak layouts etc as I get more confident with PySide and develop a clearer vision for my final app.
-
@SmnTrbt
Either way you still use the Designer and produce the.ui
, no difference at all there.-
The con is that you have to do an extra step: any time you change the
.ui
filepyside6-uic
has to be run on it. It only takes a second, but it is an extra step. I don't know how it works nowadays, if you are in Qt Creator is there an (automatic?) "build" step for this? There is for C++ and we all use that way. -
The pro is that you get a
.py
file with actual variables for every widget you have added. Your IDE (Creator? PyCharm?) will pick that up and you will get code completion while editing your Python code. Your way is hopeless IMHO, you have tofind...()
every widget at run time to access it. I cannot imagine working this way. As a small bonus you actually can look at the generated.py
file code, can be useful understanding how everything works while you learn.
Give it a go. Once you have the "build" step worked out I don't think you will regret it or want to go back to
QUiLoader
. -
-
@JonB Ahhh okay, in that case I completely agree that the uic method is far superior. I will proceed with this approach.
Many thanks for your patience & thorough answers, I only started coding a few months ago so advice like this is invaluable to me! Much appreciated.