Solved Qt Creator and Pyside2 - Blank Window
-
Hello there,
Just started experimenting with Pyside2 for use with a new Python project. Initially I was looking at using Qt Creator and loading the ".ui" file (no conversion) - but I simply cannot get the resulting window to display any widgets?
Using the Qt Creator I created a project, which automatically added a QDialogue ui file and included the code to load and run the window. I simply added a PushButton - then run the project. Just see a blank window.
I can successfully create gui's "manually" using Pyside2, so I know the framework is working. I just cannot load a UI file and show it? Tried multiple different projects.
For completeness, I've added the code loading the UI file - I guess this is a common issue, can you please let me know what I'm doing wrong:
# This Python file uses the following encoding: utf-8 import sys import os from PySide2 import QtWidgets from PySide2.QtCore import QFile from PySide2.QtUiTools import QUiLoader class main(QtWidgets.QDialog): def __init__(self): super(main, self).__init__() self.load_ui() def load_ui(self): loader = QUiLoader() path = os.path.join(os.path.dirname(__file__), "form.ui") ui_file = QFile(path) ui_file.open(QFile.ReadOnly) loader.load(ui_file, self) ui_file.close() if __name__ == "__main__": app = QtWidgets.QApplication([]) widget = main() widget.show() sys.exit(app.exec_())
Thanks for your help.
-
@Marcus-Adamski
Now going all the way back to your original Designer UI files, and why your code works with aQWidget
but not with aQMainWindow
.In your
QMainWindow
.ui
file you have:<widget class="QWidget" name="centralwidget"> <widget class="QPushButton" name="pushButton">
This is not right, and Designer will be showing you a warning "no-entry" marker on
centralwidget
in the pane where it shows your widget hierarchy. You ignore this at your peril! Layout will "go wrong" if you make aQWidget
a direct child on another (non-container)QWidget
such asQMainWindow.centralWidget
without you putting in a layout. The same would happen if you did this in your own code, though you wouldn't get any warning.Go back into Designer and give your central widget a layout: in the widget hierarchy pane, right-click on
main_window
, pick Lay out, pick Lay Out Horizontally.Now, to make it work in the
QMainWindow
case: I originally told you:@Marcus-Adamski
PySide 2 QUiLoader().load() returns a widget you need to show().
https://stackoverflow.com/questions/50128293/pyside2-quiloader-returns-an-empty-windowbut you did not act on this. You need to change two lines:
loader.load(ui_file, self).show() # widget.show()
So, I have made the return result from
loader.load(ui_file, self)
be the widget to callshow()
on, and got rid of yourshow()
on the object constructed viamain_window()
. Once you see that works you can tidy the code to do this in a better way.You should get the push button visible as you do in the plain
QWidget
-non-QMainWindow
case. You can then continue to use the Designer for your application if you wish to, as many do. -
@Marcus-Adamski
PySide 2QUiLoader().load()
returns a widget you need toshow()
.
https://stackoverflow.com/questions/50128293/pyside2-quiloader-returns-an-empty-window -
Thanks very much - I'll try tomorrow morning. The code I supplied was directly generated by Qt Creator ... strange it doesn't work?
I'll reply back once I've tested your suggestion.
-
@Marcus-Adamski
It's only a suggestion :) If it was generated by Creator I agree it would be odd. Compare your generated code to what they are saying in that post. Now that I look at it, maybe you/it are doing theshow()
, have a play with yourloader.load(ui_file, self)
line. -
OK - this is the currently situation. Using the latest QT Creator and just PySide2 installed,
- when creating a new project, and selecting "Qt for Python - Window (UI) file and "QMainWindow" as the base class, the following code is autogenerated (I've not modified it):
# This Python file uses the following encoding: utf-8 import sys import os from PySide2.QtWidgets import QApplication, QMainWindow from PySide2.QtCore import QFile from PySide2.QtUiTools import QUiLoader class main_window(QMainWindow): def __init__(self): super(main_window, self).__init__() self.load_ui() def load_ui(self): loader = QUiLoader() path = os.path.join(os.path.dirname(__file__), "form.ui") ui_file = QFile(path) ui_file.open(QFile.ReadOnly) loader.load(ui_file, self) ui_file.close() if __name__ == "__main__": app = QApplication([]) widget = main_window() widget.show() sys.exit(app.exec_())
When run, I only get a blank window. To me, it appears the UI file is not being loaded and associated to QMainWindow. Experimenting, in the designer, I've changed the window title and added one button, but when run, neither change is shown on the resulting blank window.
- However, instead, if I select "QWidget" as my base class, apart from the imports, the same code is geneated, but this works. (Again this code has not be altered):
# This Python file uses the following encoding: utf-8 import sys import os from PySide2.QtWidgets import QApplication, QWidget from PySide2.QtCore import QFile from PySide2.QtUiTools import QUiLoader class main_window(QWidget): def __init__(self): super(main_window, self).__init__() self.load_ui() def load_ui(self): loader = QUiLoader() path = os.path.join(os.path.dirname(__file__), "form.ui") ui_file = QFile(path) ui_file.open(QFile.ReadOnly) loader.load(ui_file, self) ui_file.close() if __name__ == "__main__": app = QApplication([]) widget = main_window() widget.show() sys.exit(app.exec_())
Could someone please explain why the QMainWindow based autogenerated code doesn't work, but the QWidget code does?
Many thanks
-
Hi,
Can you share the UI code as well ?
-
Sure, the following is the UI for QWidget.
<?xml version="1.0" encoding="UTF-8"?> <ui version="4.0"> <class>main_window</class> <widget class="QWidget" name="main_window"> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>800</width> <height>600</height> </rect> </property> <property name="windowTitle"> <string>main_window</string> </property> <widget class="QPushButton" name="pushButton"> <property name="geometry"> <rect> <x>40</x> <y>40</y> <width>75</width> <height>23</height> </rect> </property> <property name="text"> <string>PushButton</string> </property> </widget> </widget> <resources/> <connections/> </ui>
... and for the QMainApplication:
<?xml version="1.0" encoding="UTF-8"?> <ui version="4.0"> <class>main_window</class> <widget class="QMainWindow" name="main_window"> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>800</width> <height>600</height> </rect> </property> <property name="windowTitle"> <string>main_window</string> </property> <widget class="QWidget" name="centralwidget"> <widget class="QPushButton" name="pushButton"> <property name="geometry"> <rect> <x>70</x> <y>80</y> <width>75</width> <height>23</height> </rect> </property> <property name="text"> <string>PushButton</string> </property> </widget> </widget> <widget class="QMenuBar" name="menubar"> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>800</width> <height>21</height> </rect> </property> </widget> <widget class="QStatusBar" name="statusbar"/> </widget> <resources/> <connections/> </ui>
On both projects, in the above UIs the only change is the addition of a single pushbutton to identify the window
-
Actually, for QMainWindow, I don't think PySide2 allows the UI file to be loaded from within the constructor.
-
Note using the Creator or Designer produces XML code which does not play nicely with Python-Qt and unless you really need XML code for you GUI I would strongly suggest you learn to use Python-Qt the way it was meant to be used by coding it straight up. It is really easy and when you are done you will understand what you have and how to tweak it to make it do more things where as that XML code is just going to be an unnecessary (unless you do need that XML code for some reason) and constant pain (regardless) for you. I got your code to display your UI and found that it is just a simple button so I have created 2 versions of that button window -- one that uses the QMainWindow (which has a status bar) and a QWidget (that does not have that status bar) but in I have designed in a collaborative manner which you cannot do with the Creator/Designer as it does not allow for that nor a lot of other things you might want to do with your code.
from PySide2.QtWidgets import QApplication, QMainWindow, QWidget from PySide2.QtWidgets import QHBoxLayout, QVBoxLayout, QPushButton # Always declare all other imports after Qt imports to prevent the # issue of miss association that sometimes occurs with Qt from sys import exit as sysExit class MainUI(QWidget): def __init__(self, parent=None): QWidget.__init__(self) self.Parent = parent if self.Parent == None: self.setWindowTitle('Da Pusher') WinLeft = 550; WinTop = 350; WinWidth = 800; WinHigh = 600 self.setGeometry(WinLeft, WinTop, WinWidth, WinHigh) self.btnPusher = QPushButton('Push') self.btnPusher.clicked.connect(self.Pushed) BtnWdth = 75; BtnHght = 23 self.btnPusher.setFixedSize(BtnWdth, BtnHght) HBox = QHBoxLayout() HBox.addStretch(1) HBox.addWidget(self.btnPusher) HBox.addStretch(1) VBox = QVBoxLayout() VBox .addStretch(1) VBox .addLayout(HBox) VBox .addStretch(1) self.setLayout(VBox) def Pushed(self): if self.Parent == None: print('Stop pushing me.') else: self.Parent.SetStatus('Stop Pushing Me') class MainWindow(QMainWindow): def __init__(self): # One should not use super( ) in Python as it introduces 4 known issues that # must be handled properly. Further there were still actual bugs within the # usage of super( ) when used in Python. Yes while super( ) works fine within # C++ it does not work as seamlessly within Python due to the major differences # between these 2 languages. Next the reason it was created was to handle a # rather rare issue and unless you are doing some complicated inheritance you # will most likely never run into this extremely rare issue. However the 4 # major issues that get included by using super( ) you are much more likely # to occur than that rare issue its meant for to solve. Of course using the # basic explicit method, as follows, does not cause these issues and is as just # just as simple as using `super( )` further you do not actually gain anything # useful by using `super( )` in Python that could not be done in a much safer # manner QMainWindow.__init__(self) self.setWindowTitle('Da Pusher') WinLeft = 550; WinTop = 350; WinWidth = 800; WinHigh = 600 self.setGeometry(WinLeft, WinTop, WinWidth, WinHigh) self.CenterPane = MainUI(self) self.setCentralWidget(self.CenterPane) self.StatBar = self.statusBar() self.SetStatus('Ready') def SetStatus(self, StatusMsg): if len(StatusMsg) > 0: self.StatBar.showMessage(StatusMsg) if __name__ == "__main__": MainEvntThred = QApplication([]) # You comment out either line they work together or independently # However the QWidget I do not think comes with a StatusBar # MainApp = MainUI() MainApp = MainWindow() MainApp.show() sysExit(MainEvntThred.exec_())
-
Thanks @Denni-0 for the valuable input. It's really helpful to have a solid template from which to explore the rest of Qt. I planned to use Qt Designer to get the feel of how the Qt framework behaves, then start coding the UI by hand. Right - next step, become more familiar with the Qt layouts
Thanks again
-
Just ran your code - initially got the error "'MainWindow' object has no attribute 'SetStatusBar'".
However, after commenting out the following lines:#self.StatBar = self.statusBar() #self.SetStatusBar('Ready')
and running the code, unfortunately a single window is displayed with the title "Da Pusher" .... but there's no button, just a blank window.
Have to pop out now - will take another look at the code this evening.
Just out of interested, why does QWidget check:
if self.Parent == None:
is this so the QWidget can also run as an individual window if needed?
Thanks
-
@Marcus-Adamski
In the code you have been given there are a couple of mistakes.Apart from the
self.SetStatusBar
you noted, the problem you see stems from:VBox = QVBoxLayout() HBox.addStretch(1) HBox.addLayout(HBox) HBox.addStretch(1)
This gives a warning "QLayout: Cannot add layout QHBoxLayout/ to itself", and under Linux dumps core on exit from the app.
If you correct this to:
VBox = QVBoxLayout() VBox.addStretch(1) VBox.addLayout(HBox) VBox.addStretch(1)
the problems go away, and you will see the push button.
-
@Marcus-Adamski
Now going all the way back to your original Designer UI files, and why your code works with aQWidget
but not with aQMainWindow
.In your
QMainWindow
.ui
file you have:<widget class="QWidget" name="centralwidget"> <widget class="QPushButton" name="pushButton">
This is not right, and Designer will be showing you a warning "no-entry" marker on
centralwidget
in the pane where it shows your widget hierarchy. You ignore this at your peril! Layout will "go wrong" if you make aQWidget
a direct child on another (non-container)QWidget
such asQMainWindow.centralWidget
without you putting in a layout. The same would happen if you did this in your own code, though you wouldn't get any warning.Go back into Designer and give your central widget a layout: in the widget hierarchy pane, right-click on
main_window
, pick Lay out, pick Lay Out Horizontally.Now, to make it work in the
QMainWindow
case: I originally told you:@Marcus-Adamski
PySide 2 QUiLoader().load() returns a widget you need to show().
https://stackoverflow.com/questions/50128293/pyside2-quiloader-returns-an-empty-windowbut you did not act on this. You need to change two lines:
loader.load(ui_file, self).show() # widget.show()
So, I have made the return result from
loader.load(ui_file, self)
be the widget to callshow()
on, and got rid of yourshow()
on the object constructed viamain_window()
. Once you see that works you can tidy the code to do this in a better way.You should get the push button visible as you do in the plain
QWidget
-non-QMainWindow
case. You can then continue to use the Designer for your application if you wish to, as many do. -
Sorry for the errors I cannot run PySide2 and I am guessing I forgot to test this before posting
- Fixed the
SetStatusBar( )
mistake - Fixed the HBox calling HBox mistake
The reason it checks
if self.Parent == None
is because you have 2 choices in this template you can either start it by callingMainApp = MainWindow()
which then calls the MainUI class or you can start it by callingMainApp = MainUI()
by uncommenting that line out and commenting out the line that followsOkay I ran it after making the above changes using one then the other method of calling it and both work -- again my apologies for the errors must have gotten rushed
- Fixed the
-
-
I had the same problem with PySide6 on Ubuntu 22.04 and Windows 10: Creating a new project with QMainWindow does not work. See my question on StackOverflow.
Complete fixed example:
# This Python file uses the following encoding: utf-8 import os from pathlib import Path import sys from PySide6.QtWidgets import QApplication, QMainWindow from PySide6.QtCore import QFile from PySide6.QtUiTools import QUiLoader class MainWindow(QMainWindow): def __init__(self, parent=None): super().__init__(parent) self.load_ui() def load_ui(self): loader = QUiLoader() path = Path(__file__).resolve().parent / "form.ui" ui_file = QFile(path) ui_file.open(QFile.ReadOnly) - loader.load(ui_file, self) + widget = loader.load(ui_file, self) ui_file.close() + widget.show() if __name__ == "__main__": app = QApplication(sys.argv) widget = MainWindow() - # widget.show() sys.exit(app.exec())
As beginner I spent a lot of time to figure out why. Can someone please make the generated code functional in Qt Creator when creating a new project?
-
@Erriez said in Qt Creator and Pyside2 - Blank Window:
Can you please fix this issue when creating a new project?
Hi. What does this mean? If you mean can somebody here fix what Python code Designer generates you would have to report an issue to Qt developers, we are just a forum of users like yourself!
-
@JonB Yes, my question is for the Qt developers to fix the generated code in Qt Creator. I had a bad start when creating a new project which does not work out of the box.
You're right, https://bugreports.qt.io is used to report bugs and not this forum. I'll follow-up here. Thanks!