PyQt5 Simple Example
D. Thiebaut (talk) 11:46, 13 June 2018 (EDT)
In this tutorial we create a GUI with Qt5's designer, take the ui file resulting from it, convert it to a py file with the pyuic5 utility, and add a custom slot associated with the clicked signal of one of the push-buttons.
Contents
Environment
- Mac OSX Sierra
- Qt5.10.1, with Qt Creator 4.6.2 (Clang 8.0 (Apple), 64 bits)
- Python 3.5
The GUI
We assume that you are familiar with creating a Qt5 GUI with Designer. If not, check out this tutorial which will take you through the required steps. The tutorial assumes Qt4, but should translate easily to Qt5.
Generating the GUI
- Open Qt5
- Create a New Project
- Pick Qt for the type of project
- Pick Qt Designer Form
- Pick Main Window as a template
- Accept mainwindow.ui as the name of the file
- Click Done
- Follow steps similar to those illustrated in this tutorial to create a main window with 2 tabs.
- First tab: label, line edit, push-button labeled Clear
- Second tab: textEdit, two push-buttons, labeled "Clear" and "Random Text"
- Edit signals and slots to create these connections
- On Tab 1, connect "clicked" signal of Clear push-button to clear() method of LineEdit widget
- On Tab 2, connect "clicked" signal of Clear push-button to clear() method of TextEdit widget
- ON Tab 2, connect "clicked" signal of Random Text push-button to a new slot called addRandomTextSlot() belonging to the main window.
The GUI with the two tabs
The Main Window GUI is shown below. It contins a TAB widget with two tabs, both shown.
The UI File
Once the GUI is created in Designer, save it to mainwindow.ui, shown below for reference.
<?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>482</width> <height>600</height> </rect> </property> <property name="windowTitle"> <string>MainWindow</string> </property> <widget class="QWidget" name="centralwidget"> <layout class="QGridLayout" name="gridLayout"> <item row="0" column="0"> <widget class="QTabWidget" name="tabWidget"> <property name="currentIndex"> <number>1</number> </property> <widget class="QWidget" name="tab"> <attribute name="title"> <string>Processor</string> </attribute> <layout class="QGridLayout" name="gridLayout_2"> <item row="0" column="0"> <layout class="QHBoxLayout" name="horizontalLayout"> <item> <widget class="QPushButton" name="clearButton"> <property name="text"> <string>Clear</string> </property> </widget> </item> <item> <widget class="QLineEdit" name="EAXlineEdit"/> </item> <item> <widget class="QLabel" name="label"> <property name="text"> <string>EAX</string> </property> </widget> </item> <item> <spacer name="horizontalSpacer"> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> <property name="sizeHint" stdset="0"> <size> <width>40</width> <height>20</height> </size> </property> </spacer> </item> </layout> </item> </layout> </widget> <widget class="QWidget" name="tab_2"> <attribute name="title"> <string>Memory</string> </attribute> <layout class="QGridLayout" name="gridLayout_4"> <item row="0" column="0"> <widget class="QTextEdit" name="textEdit"/> </item> <item row="1" column="0"> <layout class="QGridLayout" name="gridLayout_3"> <item row="0" column="0"> <layout class="QHBoxLayout" name="horizontalLayout_2"> <item> <widget class="QPushButton" name="pushButton"> <property name="text"> <string>Clear</string> </property> </widget> </item> <item> <spacer name="horizontalSpacer_2"> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> <property name="sizeHint" stdset="0"> <size> <width>40</width> <height>20</height> </size> </property> </spacer> </item> <item> <widget class="QPushButton" name="pushButton_2"> <property name="text"> <string>Random Text</string> </property> </widget> </item> </layout> </item> </layout> </item> </layout> </widget> </widget> </item> </layout> </widget> <widget class="QMenuBar" name="menubar"> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>482</width> <height>22</height> </rect> </property> <widget class="QMenu" name="menuFile"> <property name="title"> <string>File</string> </property> <addaction name="actionSave_Program"/> <addaction name="actionLoad_Program"/> </widget> <widget class="QMenu" name="menuQuit"> <property name="title"> <string>Quit</string> </property> </widget> <widget class="QMenu" name="menuHelp"> <property name="title"> <string>Help</string> </property> </widget> <addaction name="menuFile"/> <addaction name="menuQuit"/> <addaction name="menuHelp"/> </widget> <widget class="QStatusBar" name="statusbar"/> <action name="actionSave_Program"> <property name="text"> <string>Save Program</string> </property> </action> <action name="actionLoad_Program"> <property name="text"> <string>Load Program</string> </property> </action> </widget> <resources/> <connections> <connection> <sender>clearButton</sender> <signal>clicked()</signal> <receiver>EAXlineEdit</receiver> <slot>clear()</slot> <hints> <hint type="sourcelabel"> <x>71</x> <y>301</y> </hint> <hint type="destinationlabel"> <x>192</x> <y>299</y> </hint> </hints> </connection> <connection> <sender>pushButton_2</sender> <signal>clicked()</signal> <receiver>MainWindow</receiver> <slot>addRandomTextSlot()</slot> <hints> <hint type="sourcelabel"> <x>363</x> <y>521</y> </hint> <hint type="destinationlabel"> <x>476</x> <y>440</y> </hint> </hints> </connection> <connection> <sender>pushButton</sender> <signal>clicked()</signal> <receiver>textEdit</receiver> <slot>clear()</slot> <hints> <hint type="sourcelabel"> <x>78</x> <y>521</y> </hint> <hint type="destinationlabel"> <x>92</x> <y>449</y> </hint> </hints> </connection> </connections> <slots> <slot>addRandomTextSlot()</slot> </slots> </ui>
PyQt5
Generating the Python version of the UI file
- Convert the .ui file to a Python .py file. Open a Terminal window and type the following command:
pyuic5 -x mainwindow.ui -o mainwindow.py
- the -x option creates a main section to the mainwindow.py file that will allow us to test quickly whether the GUI looks as we intended. Try running the newly created file with Python 3:
python3 mainwindow.py
- You should see the GUI as illustrated above. Flip between the two tabs to verify that both have been populated.
Edit the mainwindow.py File
There are few edits you need to make to the mainwindow.py file, illustrated with the diff output below, between the original (on the right) and the edited version (on the left). We omitted many lines that were identical in both versions. Just concentrate on the lines that have a "<" or "|" sign in the middle of the two columns.
# -*- coding: utf-8 -*- # Form implementation generated from reading ui file 'mainwindow.ui' # # Created by: PyQt5 UI code generator 5.10.1 # # WARNING! All changes made in this file will be lost! from PyQt5 import QtCore, QtGui, QtWidgets from PyQt5.QtCore import QObject, pyqtSlot class Ui_MainWindow( QObject): def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") MainWindow.resize(482, 600) self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") self.gridLayout = QtWidgets.QGridLayout(self.centralwidget) self.gridLayout.setObjectName("gridLayout") self.tabWidget = QtWidgets.QTabWidget(self.centralwidget) self.tabWidget.setObjectName("tabWidget") self.tab = QtWidgets.QWidget() self.tab.setObjectName("tab") self.gridLayout_2 = QtWidgets.QGridLayout(self.tab) self.gridLayout_2.setObjectName("gridLayout_2") self.horizontalLayout = QtWidgets.QHBoxLayout() self.horizontalLayout.setObjectName("horizontalLayout") self.clearButton = QtWidgets.QPushButton(self.tab) self.clearButton.setObjectName("clearButton") self.horizontalLayout.addWidget(self.clearButton) self.EAXlineEdit = QtWidgets.QLineEdit(self.tab) self.EAXlineEdit.setObjectName("EAXlineEdit") self.horizontalLayout.addWidget(self.EAXlineEdit) self.label = QtWidgets.QLabel(self.tab) self.label.setObjectName("label") self.horizontalLayout.addWidget(self.label) spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.horizontalLayout.addItem(spacerItem) self.gridLayout_2.addLayout(self.horizontalLayout, 0, 0, 1, 1) self.tabWidget.addTab(self.tab, "") self.tab_2 = QtWidgets.QWidget() self.tab_2.setObjectName("tab_2") self.gridLayout_4 = QtWidgets.QGridLayout(self.tab_2) self.gridLayout_4.setObjectName("gridLayout_4") self.textEdit = QtWidgets.QTextEdit(self.tab_2) self.textEdit.setObjectName("textEdit") self.gridLayout_4.addWidget(self.textEdit, 0, 0, 1, 1) self.gridLayout_3 = QtWidgets.QGridLayout() self.gridLayout_3.setObjectName("gridLayout_3") self.horizontalLayout_2 = QtWidgets.QHBoxLayout() self.horizontalLayout_2.setObjectName("horizontalLayout_2") self.pushButton = QtWidgets.QPushButton(self.tab_2) self.pushButton.setObjectName("pushButton") self.horizontalLayout_2.addWidget(self.pushButton) spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.horizontalLayout_2.addItem(spacerItem1) self.pushButton_2 = QtWidgets.QPushButton(self.tab_2) self.pushButton_2.setObjectName("pushButton_2") self.horizontalLayout_2.addWidget(self.pushButton_2) self.gridLayout_3.addLayout(self.horizontalLayout_2, 0, 0, 1, 1) self.gridLayout_4.addLayout(self.gridLayout_3, 1, 0, 1, 1) self.tabWidget.addTab(self.tab_2, "") self.gridLayout.addWidget(self.tabWidget, 0, 0, 1, 1) MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtWidgets.QMenuBar(MainWindow) self.menubar.setGeometry(QtCore.QRect(0, 0, 482, 22)) self.menubar.setObjectName("menubar") self.menuFile = QtWidgets.QMenu(self.menubar) self.menuFile.setObjectName("menuFile") self.menuQuit = QtWidgets.QMenu(self.menubar) self.menuQuit.setObjectName("menuQuit") self.menuHelp = QtWidgets.QMenu(self.menubar) self.menuHelp.setObjectName("menuHelp") MainWindow.setMenuBar(self.menubar) self.statusbar = QtWidgets.QStatusBar(MainWindow) self.statusbar.setObjectName("statusbar") MainWindow.setStatusBar(self.statusbar) self.actionSave_Program = QtWidgets.QAction(MainWindow) self.actionSave_Program.setObjectName("actionSave_Program") self.actionLoad_Program = QtWidgets.QAction(MainWindow) self.actionLoad_Program.setObjectName("actionLoad_Program") self.menuFile.addAction(self.actionSave_Program) self.menuFile.addAction(self.actionLoad_Program) self.menubar.addAction(self.menuFile.menuAction()) self.menubar.addAction(self.menuQuit.menuAction()) self.menubar.addAction(self.menuHelp.menuAction()) self.retranslateUi(MainWindow) self.tabWidget.setCurrentIndex(1) self.clearButton.clicked.connect(self.EAXlineEdit.clear) self.pushButton_2.clicked.connect( self.addRandomTextSlot) self.pushButton.clicked.connect(self.textEdit.clear) QtCore.QMetaObject.connectSlotsByName(MainWindow) def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) self.clearButton.setText(_translate("MainWindow", "Clear")) self.label.setText(_translate("MainWindow", "EAX")) self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), _translate("MainWindow", "Processor")) self.pushButton.setText(_translate("MainWindow", "Clear")) self.pushButton_2.setText(_translate("MainWindow", "Random Text")) self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_2), _translate("MainWindow", "Memory")) self.menuFile.setTitle(_translate("MainWindow", "File")) self.menuQuit.setTitle(_translate("MainWindow", "Quit")) self.menuHelp.setTitle(_translate("MainWindow", "Help")) self.actionSave_Program.setText(_translate("MainWindow", "Save Program")) self.actionLoad_Program.setText(_translate("MainWindow", "Load Program")) @pyqtSlot( ) def addRandomTextSlot( self ): self.textEdit.insertPlainText( "Hello World!" ) if __name__ == "__main__": import sys app = QtWidgets.QApplication(sys.argv) MainWindow = QtWidgets.QMainWindow() ui = Ui_MainWindow() ui.setupUi(MainWindow) MainWindow.show() sys.exit(app.exec_())
For simplicity, we have listed below only the lines that need to be edited, with proper indentation:
from PyQt5.QtCore import QObject, pyqtSlot class Ui_MainWindow( QObject): self.pushButton_2.clicked.connect( self.addRandomTextSlot) @pyqtSlot( ) def addRandomTextSlot( self ): self.textEdit.insertPlainText( "Hello World!" )
Create the Main Application
The -x option of the pyuic5 command generated the code (below) at the end of the mainwindow.py file:
if __name__ == "__main__": import sys app = QtWidgets.QApplication(sys.argv) MainWindow = QtWidgets.QMainWindow() ui = Ui_MainWindow() ui.setupUi(MainWindow) MainWindow.show() sys.exit(app.exec_())
We use this directly to generate our app.py main file:
# app.py # D. Thiebaut # Main application for the Main Window PyQt5 example. # import sys from PyQt5 import QtCore, QtGui, QtWidgets from mainwindow import Ui_MainWindow from PyQt5.QtCore import pyqtSlot class MyFirstGuiProgram( Ui_MainWindow ): '''The subclass that will run the GUI ''' def __init__( self, dialog ): Ui_MainWindow.__init__(self) self.setupUi( dialog ) def main(): '''The main application, which creates the window, initializes it, and run the event loop. ''' app = QtWidgets.QApplication(sys.argv) MainWindow = QtWidgets.QMainWindow() ui = Ui_MainWindow() ui.setupUi(MainWindow) MainWindow.show() # exit with the same exit code as the application sys.exit( app.exec_() ) main()
Running the App
Simply type
python3 app.py
to run the application. You should see a GUI appearing, as illustrated at the top of this page, that responds to user interactions. In particular, verify that the clear buttons work, and that the Random Text button prints "Hello World!" in the TextEdit widget.
Congrats, you have a simple template for building a more sophisticated main window in PyQt5!