PyQt5 is a comprehensive Python binding for Qt, a powerful cross-platform GUI toolkit. With PyQt5, you can build desktop applications for Windows, MacOS, Linux, as well as mobile apps for Android and iOS. In this guide, we will cover the basics of using PyQt5 to build graphical user interfaces in Python.

Getting Started with PyQt5

To get started with PyQt5, first install it using pip:

pip install PyQt5

This will install PyQt5 along with its dependencies. Now create a Python file and import the necessary PyQt5 modules:

import sys
from PyQt5.QtWidgets import (QApplication, QWidget, QPushButton, 
                             QLabel, QLineEdit, QGridLayout)

This imports QApplication which is the heart of all PyQt5 applications, QWidget which is the base class for all UI elements, and some common UI elements like QPushButton, QLabel, QLineEdit.

Next, create a subclass of QWidget for the application window and override its __init__ method to add UI elements:

class Window(QWidget):
    def __init__(self):
        super().__init__()

        # Add UI elements here

app = QApplication(sys.argv)
window = Window()
window.show()
app.exec()

This creates the application object, instantiates the window, shows it and starts the event loop. Now let‘s start adding some UI elements.

Adding UI Elements

Setting Window Geometry with setGeometry()

We can set the initial size and position of the window using the setGeometry() method. It takes four arguments:

  • x position
  • y position
  • width
  • height

For example:

self.setGeometry(100, 100, 800, 600)

This will set the window size to 800×600 pixels and place it 100 pixels from the top-left of the screen.

You can also retrieve the geometry using the geometry() method which returns a QRect.

Setting Window Title and Icon

Use the setWindowTitle() method to set the title displayed in the titlebar:

self.setWindowTitle("My App")

And the setWindowIcon() method to set the window icon from a .png image:

icon = QIcon("icon.png") 
self.setWindowIcon(icon)

Make sure the icon image is 64×64 pixels.

Adding Push Buttons

The QPushButton class represents a clickable button:

button = QPushButton("Click Me") 

We can get notified when it‘s clicked by connecting to its clicked signal:

button.clicked.connect(self.buttonClicked)   

def buttonClicked(self):
    print("Button clicked!")  

Use the setGeometry() method to position it in the desired location. Other useful QPushButton methods are:

  • setText() – Set the display text
  • setIcon() – Set the icon image
  • setEnabled() – Disable/enable the button
  • setCursor() – Change mouse cursor when hovering

Adding Input Boxes with QLineEdit

QLineEdit provides an editable one line text input box:

self.input = QLineEdit()
self.input.setPlaceholderText("Enter your name")

Useful methods:

  • setText()/text() – Set/get text
  • setEchoMode() – Normal, password, hide input
  • setClearButtonEnabled() – Show clear button
  • setMaxLength() – Limit input length

We can get notified on text change by connecting to its textChanged signal.

Displaying Text with QLabel

The QLabel widget displays read-only text and images:

label = QLabel("Hello World!")

Use setText() to change the display text. We can style the text using the setStyleSheet() method:

label.setStyleSheet("font-size: 25px; font-weight: bold;")  

Some parameters that can be styled: font family/size/weight/style, foreground/background color, margins/padding, borders etc.

Laying Out UI Elements

PyQt5 has various layout classes to handle positioning of widgets in the window. Some common ones are:

  • QHBoxLayout and QVBoxLayout: Horizontal and vertical box layouts
  • QGridLayout: Grid based layout with rows and columns

For example, to lay out a label and input box horizontally:

hbox = QHBoxLayout()
hbox.addWidget(label) 
hbox.addWidget(input)

self.setLayout(hbox)  

And to align them vertically instead:

vbox = QVBoxLayout() 
vbox.addWidget(label)
vbox.addWidget(input)

self.setLayout(vbox)   

Layouts greatly simplify handling of sizes and positions across different window sizes.

PyQt5 Architecture

Before going deeper, let‘s understand a bit about how PyQt5 works under the hood.

PyQt5 is a set of Python bindings for Qt – a popular C++ GUI framework. The architecture looks like this:

The key components are:

Qt Core – Base non-GUI classes used by other modules like network access, JSON handling, threading etc.

Qt GUI Modules – Widgets, graphics drawing etc.

Qt Bindings – auto-generated bindings to expose Qt APIs to other languages like Python.

So PyQt5 gives us a generated Python interface allowing Python code to leverage all Qt functionality.

The key benefits PyQt5 provides over raw Qt usage are:

  • Don‘t need to write C++ code
  • Automatic type conversions
  • Support for Python native types
  • Integrates well with other Python packages

Building and Distributing PyQt5 Apps

When our application coding is complete, we need to package it into an executable file before giving to end users. Here are some options:

PyInstaller

PyInstaller bundles Python apps into stand-alone executables easily.

pip install pyinstaller
pyinstaller myscript.spec

CX Freeze

Converts Python scripts into executables in a very customizable way.

fman build system

fman‘s build system focuses on reliability and stability. It integrates well with PyQt5.

The executable can then be distributed on Linux, Mac and Windows platforms.

Designing UI Forms with Qt Designer

While we can create simple UIs directly in code, Qt Designer is invaluable for building complex interfaces.

Steps to use Qt Designer:

  1. Design UI visually by dragging and arranging widgets
  2. Save design as .ui file
  3. Convert to .py file
  4. Import generated file

For example:

pyuic5 myform.ui -o myform.py 

from myform import Ui_MyForm   

class MyForm(QWidget):
    def __init__(self):
        super().__init__()  
        self.ui = Ui_MyForm()
        self.ui.setupUi(self)

Now all UI elements created in designer are available in self.ui.

This separates presentation layer (in .ui file) from logic layer (in Python code).

In addition to dialogs and main window forms, Qt Designer also allows visually building:

  • Custom widgets that can be reused
  • Toolbars, dock widgets
  • Model-View based forms

This accelerates development by letting you focus on behavior rather than presentation.

Databases with PyQt5

PyQt5 provides good integration with the SQLite database which is serverless. This allows building applications that use local data without needing to setup a separate database server process.

Here is an example showing a database enabled application with PyQt5 that displays and graphs sensor data:

import sqlite3
import datetime 

from PyQt5.QtCharts import QtCharts
from PyQt5.QtWidgets import QApplication, QMainWindow

# Subclass QMainWindow to customize main application window  
class MainWindow(QMainWindow):

    def __init__(self):
        super().__init__()

        self.database = sqlite3.connect("sensors.db")  

        ...

        # Read data from database 
        results = self.database.execute("SELECT * FROM readings")

        # Plot data read from database
        for row in results:
            self.plot.add_datapoint(row[0], row[1])  

        ...

app = QApplication(sys.argv)  

window = MainWindow()  
window.show()  

app.exec()

The data and structure can be initialized easily through SQL queries. This helps avoid having to setup a full-fledged client-server style database architecture.

Data Visualization

For plotting and visualizing data, PyQt5 integrates well with both Matplotlib and Qt‘s own charting library – Qt Charts.

Matplotlib

Matplotlib can render plots, histograms, power spectra, bar charts and many other types of data graphics.

The FigureCanvas widget can be used to embed matplotlib plots into PyQt5 windows.

Qt Charts

Qt Charts provides easy APIs for some common chart types like line, spline, area, bar, pie and scatter plots.

The QtCharts module contains charting widgets that can be added to PyQt5 applications directly.

So with PyQt5, developers have the flexibility to use either Matplotlib or Qt Charts depending on their specific visualization needs.

Multithreading with PyQt5

Similar to the original Qt framework, PyQt5 provides strong support for multithreaded applications. Multithreading allows long running tasks to be moved to background threads so they do not block the main UI.

Here is an example:

import threading
import time

from PyQt5.QtCore import QThread, pyqtSignal

class LongTask(QThread):  
    task_finished = pyqtSignal(str) 

    def run(self):
        time.sleep(10) # Simulate long task
        self.task_finished.emit("Task completed!") 

class MainWindow(QMainWindow):

    def __init__(self):
        ...

        thread = LongTask()  
        thread.task_finished.connect(self.onTaskFinished) 
        thread.start()  

    def onTaskFinished(self, message): 
        print("Completed background task:", message)

The key points are:

  • Subclass QThread and override its run() method for background task logic
  • Create thread instance and call start() to run
  • Communicate back to main thread using signals

This keeps the GUI responsive even with long TCP operations, blocking IO calls etc.

Packaging PyQt5 Apps

Once application coding is complete, we need to package the Python code into an executable file for distribution to end users.

Here are some handy options for converting .py to .exe:

Tool Description
PyInstaller Bundle app and dependencies into one .exe file
CX Freeze Customizable exe builder with many options
fbs pyinstaller Tailored specifically for freezing PyQt5 apps
Briefcase Builds mobile and desktop apps from Python code

For web deployment, the app code can be compiled to JavaScript using tools like PyScript, Pyodide and Transcrypt.

Once packaged, the executables can run standalone on Windows, Mac and Linux without needing Python preinstalled.

Deploying PyQt5 Applications

The major platforms supported for deployment are:

Windows

Windows .exe generated by tools like PyInstaller runs without any other dependencies needed.

MacOS

Mac .app bundles can be generated. Or user installs Python + PyQt5 on their system.

Linux

Providing self-contained AppImages or .deb/.rpm packages avoids external dependencies.

Mobile

Buildozer and Kivy can compile to Android APKs. For iOS, Qt framework should be used instead of PyQt5.

So there are good options available for deploying PyQt5 applications across desktop, server and mobile platforms.

Conclusion

In this guide, we looked at:

  • Getting started with PyQt5
  • Using basic widgets like buttons, input boxes and labels
  • Layout managers for aligning UI elements
  • Signals and slots for communication between objects in PyQt5
  • Architecture of how PyQt5 interfaces with Qt
  • Options for building installable executables for distribution
  • Using Qt Designer visual editor to design dialogs and window forms
  • SQLite database integration example
  • Data visualization integrating matplotlib and Qt charts
  • Multithreading techniques to keep UI responsive
  • Packaging options for Linux, Mac and Windows

There is still too much about PyQt5 we didn‘t cover – 3D graphics, multimedia, QtQuick, SVG, OpenGL integration, web integration, accessibility and internationalization.

I hope this overview gives you a good starting point for leveraging PyQt5 to build modern, scalable cross-platform desktop applications with Python! Let me know if you have any other questions.

Similar Posts