Get Even More Visitors To Your Blog, Upgrade To A Business Listing >>

PyQt5 tutorial – Python GUI programming examples

In a previous tutorial, we talked about the Tkinter module and we saw how to build GUI apps using it. In this tutorial, we will continue building graphical interfaces in Python and this time we will use PyQt5.

PyQt5 is one of the most used modules in building GUI apps in Python and that’s due to its simplicity as you will see.

Another great feature that encourages developers to use PyQt5 is the PyQt5 designer which makes it so easy to develop complex GUI apps in a short time. You just drag your widgets to build your form.

In this PyQt5 tutorial, I will use Python 3.6 on Windows 10 and I assume that you know some Python basics.

Sound great! So let’s get started and install PyQt5 at first then we will see how to develop GUI apps with examples.

Install PyQt5

PyQt5 has two versions, the commercial version and the free GPL version that we will use in this tutorial.

To install PyQt5, you have two ways:

  • Using pip
  • Using source

Using pip

To install PyQt5 using pip, run the following command:

$ pip3 install PyQt5

To ensure the successful installation, run the following Python code:

import PyQt5

If no errors appeared, that means you have successfully installed PyQt5, but if you got errors, you may be using an unsupported version of Python.

Using source (On Linux)

To install PyQt5 from source, you have to do the following:

  • Install SIP.
  • Download PyQt5 source.
  • Configure & install.

As you might know, PyQt5 is a Python binding for the famous library Qt that is written in C++.

The tool that makes this binding is called SIP. So in order to install PyQt5 from source, you need at first to install SIP.

To install SIP, run the following command:

$ pip3 install PyQt5-sip

Now you are ready to download and install PyQt5 source.

Download PyQt5 source from here.

Then unpack the compressed source and run the following commands inside the root of the uncompressed folder:

$ python3 configure.py

$ make

$ make install

To ensure that everything is fine, try to Import PyQt5 as we did before and everything should be OK.

Using source (On Windows)

Since SIP needs GCC compiler, you need to install MinGW which is a Windows port of Linux GCC compiler.

The only thing needs to be changed is the configuration step; you need to tell Python about the platform.

This can be done like this:

$ python configure.py --platform win32-g++

$ make

$ make install

Congratulations! Now you have successfully installed PyQt5 from source.

Install PyQt5 designer

There are two ways to build GUI apps using PyQt5:

  • Design widgets by code.
  • Using PyQt5 designer.

In this PyQt5 tutorial, we will use the PyQt5 designer which makes it so easy to finish a lot of work in a matter of seconds.

PyQt5 designer is shipped with PyQt5 tools. To install it, you need to install PyQt5 tools.

$ pip3 install PyQt5-tools

Where is PyQt5 designer?

After successful installation, you can find the PyQt5 designer on this location:

C:\Program Files\Python36\Lib\site-packages\pyqt5-tools\

Also, If you installed Python for your current user only, you will find the PyQt5 designer on this location:

C:\Users\LikeGeeks\AppData\Local\Programs\Python\Python36-32\Lib\site-packages\ pyqt5-tools\

You can make a shortcut for it instead of going into this location every time you want to run the PyQt5 designer.

How to use PyQt5 designer

Open designer.exe and you will see a dialog asking you about the form template you want.

There are five templates available:

  • Dialog with Buttons Bottom: Creates a form with OK and Cancel buttons at the bottom right of the form.
  • Dialog with Buttons Right: Creates a form with OK and Cancel buttons at the top right of the form.
  • Dialog without Buttons: Creates a blank form.
  • Main Window: Creates a window with a menu bar and a toolbar and inherited from QMainWindow.
  • Widget: Creates a widget which is inherited from QWidget class, unlike the Dialogs templates which inherit from QDialog class.

So we have three types of templates, what is the difference?

Difference between QDialog, QMainWindow, and QWidget

  • QWidget is the base class for all GUI elements in the PyQt5.
  • QDialog is used for asking the user about something, like asking the user to accept or reject something or maybe asking for an input and is based on QWidget.
  • QMainWindow is the bigger template where you can place your toolbar, menu bar, status bar, and other widget and it doesn’t have a built-in allowance for buttons like those in QDialog.

Load .ui VS convert .ui to .py

In this tutorial, we will use the PyQt5 designer, but before we dig deeper, let’s see how we will use the generated design from the PyQt5 designer.

Open PyQt5 designer, and choose Main Window template and click create button.

Then from the file menu, click save; PyQt5 designer will export your form into XML file with .ui extension. Now, in order to use this design, you have two ways:

  • Loading the .ui file in your Python code.
  • Converting the .ui file to a .py file using pyuic5.

Loading the .ui file in your Python code

To load the .ui file in your Python code, you can use the loadUI() function from uic like this:

from PyQt5 import QtWidgets, uic

import sys

app = QtWidgets.QApplication([])

win = uic.loadUi("mydesign.ui") #specify the location of your .ui file

win.show()

sys.exit(app.exec())

If you run your code, you should see a window with nothing but a label.

That means the ui file loaded successfully!

We used sys.exit(app.exec()) instead of using app.exec() directly to send the correct status code the parent process or the calling process.

If you used app.exec() directly, the application will send zero which means success and this will happen even if the application crashed.

Converting the .ui file to a .py file using pyuic5

Now, let’s try the second way by converting the .ui file to a Python code:

$ pyuic5 mydesign.ui -o mydesign.py

Yes! A new file was created with the name mydesign.py. Now, let’s import that file to show our window.

The pyuic5 stands for Python user interface converter version 5.

from PyQt5 import QtWidgets

from mydesign import Ui_MainWindow  # importing our generated file

import sys

class mywindow(QtWidgets.QMainWindow):

def __init__(self):

    super(mywindow, self).__init__()

    self.ui = Ui_MainWindow()
    
    self.ui.setupUi(self)

app = QtWidgets.QApplication([])

application = mywindow()

application.show()

sys.exit(app.exec())

If you run this code, you should see the same window again as we did in the first method.

The benefit of using the second method is the auto-completion that the IDE will provide since all of your widgets are imported, while the first method you just load the .ui file and you need to be aware of your widgets names.

Another benefit of using the second method. The speed, since you don’t need XML parsing to load the UI.

So we can say that converting the .ui file to a .py file is safer in coding and faster in loading!Click To Tweet

Now, let’s get our hands dirty and play with the PyQt5 widgets.

QLabel widget

To add a QLabel widget to your form, do the following:

  • Open PyQt5 designer and choose Main Window template.
  • Drag a label widget from the widget box on the left.

Now, save the design to a .ui file and convert it to a .py file and let’s play with the label widget using code.

Change Font

To change the QLabel font, use the setFont() method and pass a QFont to it like this:

from PyQt5 import QtWidgets, QtGui

from mydesign import Ui_MainWindow

import sys

class mywindow(QtWidgets.QMainWindow):

    def __init__(self):
    
        super(mywindow, self).__init__()
        
        self.ui = Ui_MainWindow()
        
        self.ui.setupUi(self)
        
        self.ui.label.setFont(QtGui.QFont('SansSerif', 30)) # change font type and size


app = QtWidgets.QApplication([])

application = mywindow()

application.show()

sys.exit(app.exec())

If you run this code, you will note that the label does not appear correctly because the size is smaller than the font size we used. So we need to set the label size.

Change size

To change the QLabel size, you need to set its geometry using setGeometry() method like this:

from PyQt5 import QtWidgets, QtGui,QtCore

from mydesign import Ui_MainWindow

import sys

class mywindow(QtWidgets.QMainWindow):

    def __init__(self):

        super(mywindow, self).__init__()

        self.ui = Ui_MainWindow()

        self.ui.setupUi(self)

        self.ui.label.setFont(QtGui.QFont('SansSerif', 30))

        self.ui.label.setGeometry(QtCore.QRect(10, 10, 200, 200)) # change label geometry


app = QtWidgets.QApplication([])

application = mywindow()

application.show()

sys.exit(app.exec())

Change text

To change the QLabel text, you can use the setText() method like this:

from PyQt5 import QtWidgets, QtGui,QtCore

from mydesign import Ui_MainWindow

import sys

class mywindow(QtWidgets.QMainWindow):

    def __init__(self):
    
        super(mywindow, self).__init__()
        
        self.ui = Ui_MainWindow()
        
        self.ui.setupUi(self)
        
        self.ui.label.setFont(QtGui.QFont('SansSerif', 30))
        
        self.ui.label.setGeometry(QtCore.QRect(10, 10, 200, 200))
        
        self.ui.label.setText("LikeGeeks") #change label text


app = QtWidgets.QApplication([])

application = mywindow()

application.show()

sys.exit(app.exec())

That was easy! Let’s check some other widgets.

QLineEdit widget

The QLineEdit is an editable place where you can accept input from the user. LineEdit has many methods to work with.

I will create a new design with the PyQt5 designer and I’ll add six QLineEdit widgets and I’ll export it to .py file.

Now, let’s see some QLineEdit methods:

from PyQt5 import QtWidgets,QtCore

from mydesign import Ui_MainWindow

import sys

class mywindow(QtWidgets.QMainWindow):

    def __init__(self):
    
        super(mywindow, self).__init__()
        
        self.ui = Ui_MainWindow()
        
        self.ui.setupUi(self)
        
        self.ui.lineEdit.setText("Welcome to LikeGeeks website") #change text
        
        self.ui.lineEdit_2.setMaxLength(10) #set maximum length
        
        self.ui.lineEdit_3.setEchoMode(QtWidgets.QLineEdit.Password) # password input
        
        self.ui.lineEdit_4.setReadOnly(True) #QLineEdit readonly
        
        self.ui.lineEdit_5.setStyleSheet("color: rgb(28, 43, 255);") #change text color
        
        self.ui.lineEdit_6.setStyleSheet("background-color: rgb(28, 43, 255);") #change QLineEdit background color


app = QtWidgets.QApplication([])

application = mywindow()

application.show()

sys.exit(app.exec())

The first QlineEdit, we changed the text using setText() method.

The second QlineEdit, we set the maximum allowed characters to 10 so nothing more is accepted.

The third QlineEdit, we set it to password mode so all your input appears as asterisks.

The fourth QlineEdit, we set it to read-only so you can’t edit its content.

The fifth QlineEdit, we changed the font color using the setStyleSheet() method and we insert the color like web pages CSS values.

The sixth QlineEdit, we changed the background color using the setStyleSheet() method.

The setStyleSheet() method

The setStyleSheet() method can be used with all PyQt5 widgets to change the style.

You can change the following using setStyleSheet() method:

  • Font type and size
  • Text Color
  • Background color
  • Border color
  • Border top color
  • Border bottom color
  • Border right color
  • Border left color
  • Selection color
  • Selection background color

These are the most important values you can pass to the setStyleSheet() method.

QPushButton Widget

Most of your Python programs will have this QPushButton widget. You click the button and some code is executed.

If you have a programming background, you may hear about event handling where you interact with a widget and a function is executed.

The idea in PyQt5 is the same but the definitions are a bit different.

The click event in PyQt5 is called a signal and the method which gets executed is called a slot.Click To Tweet

So when you click a QPushButton, a signal is emitted. The signal name in this case is called clicked().

In order to bind the emitted signal with a slot, you need to use the connect() method as you will see now.

This event handling process continues to work until you close your form or main widget.

Let’s build a form with a QLabel and a QPushButton and export it to a .py file.

Now, We will connect the clicked() signal with a slot using connect() method like this:

self.ui.pushButton.clicked.connect(self.btnClicked)

The btnClicked here is the slot or the function that will be executed when you click the QPushButton.

So your code will be like this:

from PyQt5 import QtWidgets

from mydesign import Ui_MainWindow

import sys

class mywindow(QtWidgets.QMainWindow):

    def __init__(self):

        super(mywindow, self).__init__()

        self.ui = Ui_MainWindow()

        self.ui.setupUi(self)

        self.ui.pushButton.clicked.connect(self.btnClicked) # connecting the clicked signal with btnClicked slot

    def btnClicked(self):

        self.ui.label.setText("Button Clicked")


app = QtWidgets.QApplication([])

application = mywindow()

application.show()

sys.exit(app.exec())

Awesome!

Visual signal/slot editor

We saw how to connect the widget signal to a slot using the connect() method, but this is not the only way.

Actually, there are some predefined slots for each widget. You can connect a signal to any predefined slot without coding in the PyQt5 designer.

Drag a QPushButton and a QLineEdit on your form.

Press F4 and drag the mouse from the QPushButton and release it on the top of the QLineEdit.

The signal/slot editor will show up.

On the left, the predefined signals while on the right the predefined slots. Let’s say that we want to connect the clicked() signal with the clear slot.

Choose the clicked from the left and choose clear from the right and click OK.

After finishing your signal/slot connections, you can escape from this mode by pressing ESC or F3.

Now, if you run this form and click the QPushButton, any text on the QLineEdit will be cleared. You can edit or delete this connection from the signal/slot editor panel.

How to emit a signal

We saw how signals and slots work. All signals we worked with are predefined for us.

What about emitting our own custom signal?

Very easy! You can do that by using the pyqtSignal class as follows:

  • Define your event with type pyqtSignal.
  • Call emit() method at the place you want your event to be fired.

Let’s say we have a nut class and we want to fire the cracked signal to be emitted when we crack it.

from PyQt5.QtCore import pyqtSignal,QObject

class nut(QObject):

    cracked = pyqtSignal()
    
    def __init__(self):
    
        QObject.__init__(self)
    
    def crack(self):
    
        self.cracked.emit()

How to use a signal

Now, let’s make our example more practical by instantiating an instance of the nut class and emitting the cracked signal:

def crackit():

    print("hazelnut cracked!")

hazelnut = nut()

hazelnut.cracked.connect(crackit) # connecting the cracked signal with crackit slot

hazelnut.crack()

The cracked signal was successfully emitted.

QComboBox widget

Instead of letting the user enter values in a QLineEdit or any editable widget, we can use a QCombobBox widget to give the user a list of choices to select from.

Let’s drag a combo box to our form and take a look at some of its methods.

If you run the app now, you will note that the QComboBox is empty. To add items to the QComboBox, use the addItem() method:

from PyQt5 import QtWidgets

from mydesign import Ui_MainWindow

import sys

class mywindow(QtWidgets.QMainWindow):

    def __init__(self):
    
        super(mywindow, self).__init__()
        
        self.ui = Ui_MainWindow()
        
        self.ui.setupUi(self)
        
        self.ui.comboBox.addItem("First item") #add item
        
        self.ui.comboBox.addItem("Second item")


app = QtWidgets.QApplication([])

application = mywindow()

application.show()

sys.exit(app.exec())

Get all items

There is no direct method to get all items from a QComboBox, but you can use a for loop to do that.

for i in range(self.ui.comboBox.count()):

    print(self.ui.comboBox.itemText(i))

Select an item

To select an item from the QComboBox, you have two methods:

self.ui.comboBox.setCurrentIndex(1) #select by index which is zero-based

self.ui.comboBox.setCurrentText("Second item") #select by text

Note that when selecting an item by text; make sure you write the correct text otherwise. The QComboBox will stay at the first element.

QTableWidget

If you want to view your database data in a tabular format, PyQt5 provides the QTableWidget for that.

QTableWidget consists of cells, each cell is an instance of QTableWidgetItem class.

Let’s design a form that contains a QTableWidget and a QPushButton. Drag a table widget and a push button from the widget box. Then save and convert the design to use it.

To add rows to the QTableWidget, you can use the setRowCount() method.

To add columns to the QTableWidget, you can use the setColumnCount() method.

from PyQt5 import QtWidgets

from mydesign import Ui_MainWindow

import sys

class mywindow(QtWidgets.QMainWindow):

    def __init__(self):
    
        super(mywindow, self).__init__()
        
        self.ui = Ui_MainWindow()
        
        self.ui.setupUi(self)
        
        self.ui.tableWidget.setColumnCount(2)
        
        self.ui.tableWidget.setRowCount(4)


app = QtWidgets.QApplication([])

application = mywindow()

application.show()

sys.exit(app.exec())

Now you can type text manually inside QTableWidget cells.

Clear QtableWidget content

To clear QTableWidget content, you can use the clear method like this:

def clear():

    self.ui.tableWidget.clear()
    
    self.ui.pushButton.clicked.connect(clear)

Populate QTableWidget by code

To fill QTableWidget programmatically, you should use the setItem() method for each QTableWidgetItem.

from PyQt5.QtWidgets import QTableWidgetItem

from mydesign import *

import sys

data = []

data.append(('Populating', 'QtableWidget'))

data.append(('With data', 'In Python'))

data.append(('Is easy', 'Job'))


class mywindow(QtWidgets.QMainWindow):

    def __init__(self):

        super().__init__()

        self.ui = Ui_MainWindow()

        self.ui.setupUi(self)

        self.ui.tableWidget.setRowCount(3)

        self.ui.tableWidget.setColumnCount(2)

        row=0

        for tup in data:

            col=0

            for item in tup:

                cellinfo=QTableWidgetItem(item)

                self.ui.tableWidget.setItem(row, col, cellinfo)

                col+=1

            row += 1


app = QtWidgets.QApplication([])

win = mywindow()

win.show()

sys.exit(app.exec())

  • First, we create a Python list of three tuples.
  • Inside the constructor of the main window, we set the rows and columns count.
  • Then we iterate over the list and get every tuple on the list to fill the table cells using setItem() method.
  • Finally, we show the main window.

Make QTableWidget not editable (read-only)

You may not like leaving your table cells editable for the user in some cases. Like showing a read-only data and any editing process makes no sense.

To make QTableWidget not editable, you can use setFlags() method to set each  QTableWidgetItem not editable.

cellinfo.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) #make it not editable

You must set the flags before setting your cell content.

Therefore, your code will be like this:

from PyQt5.QtWidgets import QTableWidgetItem

from mydesign import *

import sys

data = []

data.append(('Populating', 'QtableWidget'))

data.append(('With data', 'In Python'))

data.append(('Is easy', 'Job'))


class mywindow(QtWidgets.QMainWindow):

    def __init__(self):

        super().__init__()

        self.ui = Ui_MainWindow()

        self.ui.setupUi(self)

        self.ui.tableWidget.setRowCount(3)

        self.ui.tableWidget.setColumnCount(2)

        row=0

        for tup in data:

            col=0

            for item in tup:

                cellinfo=QTableWidgetItem(item)
                
                cellinfo.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)  # make cell not editable

                self.ui.tableWidget.setItem(row, col, cellinfo)

                col+=1

            row += 1


app = QtWidgets.QApplication([])

win = mywindow()

win.show()

sys.exit(app.exec())

Now, if you try to edit any cell, you can’t; because the QTableWidgetItem is not editable.

Set QTableWidget column (header) name

Until now, the column names of the QTableWidget are numbers. What about setting the column names to something else.

To set QTableWidget header text, you can use setHorizontalHeaderLabels() method like this:

from PyQt5.QtWidgets import QTableWidgetItem

from mydesign import *

import sys

data = []

data.append(('Populating', 'QtableWidget'))

data.append(('With data', 'In Python'))

data.append(('Is easy', 'Job'))


class mywindow(QtWidgets.QMainWindow):

    def __init__(self):

        super().__init__()

        self.ui = Ui_MainWindow()

        self.ui.setupUi(self)

        self.ui.tableWidget.setRowCount(3)

        self.ui.tableWidget.setColumnCount(2)

        self.ui.tableWidget.setHorizontalHeaderLabels(('Column 1', 'Column 2'))  # set header text

        row=0

        for tup in data:

            col=0

            for item in tup:

                cellinfo=QTableWidgetItem(item)

                self.ui.tableWidget.setItem(row, col, cellinfo)

                col+=1

            row += 1


app = QtWidgets.QApplication([])

win = mywindow()

win.show()

sys.exit(app.exec())

The same way, you can change the row header by using setVerticalHeaderLabels() method:

self.ui.tableWidget.setVerticalHeaderLabels(('Row 1', 'Row 2', 'Row 3'))

How to sort QTableWidget

You can make your QTableWidget sortable by using the setSortingEnabled() method.

self.ui.tableWidget.setSortingEnabled(True)

Now, if the user clicks on any column header, he can sort the data in ascending or descending order.

You can use this method before or after populating the QTableWidget with data.

What about sorting the QTableWidget to a specific column only?

You can use the sortByColumn() method and set the column index and the sorting order like this:

from PyQt5.QtWidgets import QTableWidgetItem

from mydesign import *

import sys

data = []

data.append(('Populating', 'QtableWidget'))

data.append(('With data', 'In Python'))

data.append(('Is easy', 'Job'))


class mywindow(QtWidgets.QMainWindow):

    def __init__(self):

        super().__init__()

        self.ui = Ui_MainWindow()

        self.ui.setupUi(self)

        self.ui.tableWidget.setRowCount(3)

        self.ui.tableWidget.setColumnCount(2)

        row=0

        for tup in data:

            col=0

            for item in tup:

                cellinfo=QTableWidgetItem(item)

                self.ui.tableWidget.setItem(row, col, cellinfo)

                col+=1

            row += 1
            
        self.ui.tableWidget.sortByColumn(0, QtCore.Qt.AscendingOrder)  # sort by the first column


app = QtWidgets.QApplication([])

win = mywindow()

win.show()

sys.exit(app.exec())

Also, you can use the sortItems() method to sort QTableWidget in ascending order by default.

self.ui.tableWidget.sortItems(0)

Or you can specify the sorting order:

self.ui.tableWidget.sortItems(0,QtCore.Qt.DescendingOrder)

Keep in mind that if you want to sort your columns programmatically, you must use the sorting methods after populating the QTableWidget with data otherwise, your data won’t be sorted.

Add QComboBox in QTableWidget

You may need the user to choose a value inside the QTableWidget instead of entering a text.

What about adding a QComboBox inside QTableWidgetItem?

To add a QComboBox inside QTableWidgetItem, you can use the setCellWidget() method:

from PyQt5.QtWidgets import QTableWidgetItem

from mydesign import *

import sys

data = ['PyQt5','Is','Awesome']

class mywindow(QtWidgets.QMainWindow):

        def __init__(self):

            super().__init__()

            self.ui = Ui_MainWindow()

            self.ui.setupUi(self)

            self.ui.tableWidget.setRowCount(3)

            self.ui.tableWidget.setColumnCount(2)

            row=0

            for item in data:

                cellinfo=QTableWidgetItem(item)

                combo = QtWidgets.QComboBox()

                combo.addItem("First item")

                combo.addItem("Second item")

                self.ui.tableWidget.setItem(row, 0, cellinfo)

                self.ui.tableWidget.setCellWidget(row, 1, combo)

                row += 1


app = QtWidgets.QApplication([])

win = mywindow()

win.show()

sys.exit(app.exec())

Cool!

Don’t stop your mind from imagination and try to insert different widgets like a QCheckbox or even a QProgressBar.

The above code will be the same except the line where you create the QComboBox, you will add the widget you want.

The only limit is your imagination.

I tried to keep everything as simple as possible. I hope you find the tutorial useful.

Thank you.

The post PyQt5 tutorial – Python GUI programming examples appeared first on Like Geeks.



This post first appeared on LikeGeeks, please read the originial post: here

Share the post

PyQt5 tutorial – Python GUI programming examples

×

Subscribe to Likegeeks

Get updates delivered right to your inbox!

Thank you for your subscription

×