Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

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 a QWidget but not with a QMainWindow.

    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 a QWidget a direct child on another (non-container) QWidget such as QMainWindow.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-window

    but 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 call show() on, and got rid of your show() on the object constructed via main_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 2 QUiLoader().load() returns a widget you need to show().
    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 the show(), have a play with your loader.load(ui_file, self) line.



  • OK - this is the currently situation. Using the latest QT Creator and just PySide2 installed,

    1. 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.

    1. 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


  • Lifetime Qt Champion

    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.


  • Banned

    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.

    window.jpg

    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 a QWidget but not with a QMainWindow.

    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 a QWidget a direct child on another (non-container) QWidget such as QMainWindow.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-window

    but 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 call show() on, and got rid of your show() on the object constructed via main_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.


  • Banned

    Sorry for the errors I cannot run PySide2 and I am guessing I forgot to test this before posting

    1. Fixed the SetStatusBar( ) mistake
    2. 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 calling MainApp = MainWindow() which then calls the MainUI class or you can start it by calling MainApp = MainUI() by uncommenting that line out and commenting out the line that follows

    Okay 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



  • Thanks to both @JonB and @Denni-0 , I now have a solid template (and better understanding) to explore QT further. Much appreciated.


Log in to reply