Loading UI Files in Qt for Python

Qt for Python (i.e. PySide2) was announced recently and got me interested in trying to use it to load up a UI file. If you don’t know, PyQt and PySide / PySide2 can use the Qt Creator application to create user interfaces using a drag-and-drop interface. This is actually very similar to the way you would create an interface using Visual Studio. Qt Creator / Designer will generate an XML file with a *.ui extension that you can then load inside of your PySide2 application (or PyQt).


Creating the User Interface

For this example, I opened up Qt Creator and went to File –> “New File or Project”. Then I chose the “Qt Widgets Application” choice. See screenshot below:

Then I opened up the mainwindow.ui that Qt Creator made for me. You can just double-click it or click on the Design button that should be on the left-hand side of the program. Here’s a screenshot that might help:

I added three widgets to my UI:

  • QLabel
  • QLineEdit
  • QPushButton

When I saved the file, I got the following in my UI file:

<?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>400</width>
    <height>300</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralWidget">
   <widget class="QPushButton" name="pushButton">
    <property name="geometry">
     <rect>
      <x>160</x>
      <y>210</y>
      <width>80</width>
      <height>25</height>
     </rect>
    </property>
    <property name="text">
     <string>OK</string>
    </property>
   </widget>
   <widget class="QLineEdit" name="lineEdit">
    <property name="geometry">
     <rect>
      <x>130</x>
      <y>30</y>
      <width>113</width>
      <height>25</height>
     </rect>
    </property>
   </widget>
   <widget class="QLabel" name="label">
    <property name="geometry">
     <rect>
      <x>20</x>
      <y>30</y>
      <width>111</width>
      <height>17</height>
     </rect>
    </property>
    <property name="text">
     <string>Favorite Language:</string>
    </property>
   </widget>
  </widget>
  <widget class="QMenuBar" name="menuBar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>400</width>
     <height>22</height>
    </rect>
   </property>
   <widget class="QMenu" name="menuTest">
    <property name="title">
     <string>Test</string>
    </property>
   </widget>
   <addaction name="menuTest"/>
  </widget>
  <widget class="QToolBar" name="mainToolBar">
   <attribute name="toolBarArea">
    <enum>TopToolBarArea</enum>
   </attribute>
   <attribute name="toolBarBreak">
    <bool>false</bool>
   </attribute>
  </widget>
  <widget class="QStatusBar" name="statusBar"/>
 </widget>
 <layoutdefault spacing="6" margin="11"/>
 <resources/>
 <connections/>
</ui>

Now we just need to learn how to load this file in Qt for Python.


Loading the UI File in Qt for Python

There are a couple of different ways that I discovered I could use to load the UI file in Qt for Python (PySide2). The first is taken pretty much wholesale from Qt for Python’s wiki:

import sys
 
from PySide2.QtUiTools import QUiLoader
from PySide2.QtWidgets import QApplication
from PySide2.QtCore import QFile
 
 
if __name__ == "__main__":
    app = QApplication(sys.argv)
    file = QFile("mainwindow.ui")
    file.open(QFile.ReadOnly)
    loader = QUiLoader()
    window = loader.load(file)
    window.show()
    sys.exit(app.exec_())

While this works, it doesn’t really show you how to hook up events or get anything useful out of the user interface. Frankly, I thought this was kind of a dumb example. So I looked up some other examples on other websites and eventually put the following together:

import sys
 
from PySide2.QtUiTools import QUiLoader
from PySide2.QtWidgets import QApplication, QPushButton, QLineEdit
from PySide2.QtCore import QFile, QObject
 
class Form(QObject):
 
    def __init__(self, ui_file, parent=None):
        super(Form, self).__init__(parent)
        ui_file = QFile(ui_file)
        ui_file.open(QFile.ReadOnly)
 
        loader = QUiLoader()
        self.window = loader.load(ui_file)
        ui_file.close()
 
        self.line = self.window.findChild(QLineEdit, 'lineEdit')
 
        btn = self.window.findChild(QPushButton, 'pushButton')
        btn.clicked.connect(self.ok_handler)
        self.window.show()
 
    def ok_handler(self):
        language = 'None' if not self.line.text() else self.line.text()
        print('Favorite language: {}'.format(language))
 
if __name__ == '__main__':
    app = QApplication(sys.argv)
    form = Form('mainwindow.ui')
    sys.exit(app.exec_())

In this example, we create a Form object and load up the UI file using QUiLoader and QFile. Then we use the findChild method on the object that was returned from QUiLoader to extract the widget objects that we are interested in. For this example, I extracted the QLineEdit widget so I could get what the use entered and the QPushButton widget so I could catch the button clicked event. Finally I connected the click event to an event handler (or slot).


Wrapping Up

At this point you should have a general idea of how you might create a user interface using Qt’s Creator / Designer application and then how to load up the UI file it generates into your Python application. It is fairly straight-forward, but not exactly well documented. You can also just skip creating the UI file and code everything by hand too. Regardless of the method you choose, this does appear to be a fairly easy toolkit to get into, although I am hoping the documentation / tutorials increase in detail soon.


Related Reading

Print Friendly, PDF & Email