Difference between revisions of "PyQt5 Simple Example"

From dftwiki3
Jump to: navigation, search
(Create the Main Application)
(Running the App)
Line 465: Line 465:
 
Congrats, you have a simple template for building a more sophisticated main window in PyQt5!
 
Congrats, you have a simple template for building a more sophisticated main window in PyQt5!
 
<br />
 
<br />
 +
=Deploying=
 
<br />
 
<br />
 +
Deploying the newly created project can be done with [https://www.riverbankcomputing.com/software/pyqtdeploy/intro  pyqtdeploy].  Please stay tuned!
 
<br />
 
<br />
 
<br />
 
<br />

Revision as of 14:03, 13 June 2018

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.


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 contains a TAB widget with two tabs, both shown.

PyQt5GUI 2Tabs.png


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. They are highlighted in yellowin the listing below.

# -*- 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!" )


The addRandomTextSlot( self ) addition is the slot we attached to the Random Text push-button in the GUI, using Designer. The pyuic5 utility does not seem to generate code for it, and it's left up to us to do.

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  QtGui, QtWidgets
from mainwindow import Ui_MainWindow

def main():
    app = QtWidgets.QApplication( sys.argv )
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi( MainWindow )
    MainWindow.show()
    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!

Deploying


Deploying the newly created project can be done with pyqtdeploy. Please stay tuned!