Frontend Development 19 min read

Comprehensive PyQt5 Tutorial: Environment Setup, Basic Code Structure, Events, Signals & Slots, and QWidget Usage

This article provides a step‑by‑step guide to using PyQt5 for Python GUI development, covering installation, designer integration, converting .ui files to Python code, basic window structure, QObject concepts, event handling, signal‑slot mechanisms, common widget methods, and practical examples with full code snippets.

Python Programming Learning Circle
Python Programming Learning Circle
Python Programming Learning Circle
Comprehensive PyQt5 Tutorial: Environment Setup, Basic Code Structure, Events, Signals & Slots, and QWidget Usage

PyQt5 is a Python binding for the Qt GUI framework; mastering it helps testers and developers quickly build graphical tools and understand front‑end and back‑end integration.

1. Environment Setup

Install the required libraries using the following commands:

<code>pip install pyqt5 -i pypi.douban.com/simple</code>
<code>pip install PySide2 -i pypi.douban.com/simple/ --trusted-host pypi.douban.com</code>

Configure PyCharm to associate Qt Designer with the project and locate the pyuic5.exe conversion tool.

2. Basic Code Structure

The goal is to separate UI code from logic. Create a widget in Designer and save it as a .ui file, then convert it to Python:

<code>pyuic5 -o MyForm_UI.py MyForm.ui</code>

Example of a runnable script for a widget:

<code>if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)
    Window = QtWidgets.QWidget()
    ui = Ui_Form()
    ui.setupUi(Window)
    Window.show()
    sys.exit(app.exec_())</code>

For a main window, inherit from QtWidgets.QMainWindow and use the generated UI class similarly.

3. QObject

All Qt objects inherit from QObject . Each object has a unique objectName that can be set in Designer. You can query or set dynamic properties:

<code>obj.objectName()
obj.setProperty('level1', 'first')
obj.property('level1')
obj.dynamicPropertyNames()</code>

Objects can be deleted with obj.deleteLater() , which emits the destroyed signal.

4. Events, Signals, and Slots

4.1 Events

Widgets receive events such as mouse clicks, double‑clicks, key presses, and context‑menu requests. Overriding the event method allows custom handling before the default signal emission.

<code>class Btn(QPushButton):
    def event(self, evt):
        print(evt, "any signal passes through event")
        return super().event(evt)

    def mousePressEvent(self, evt):
        print("mouse press")
        return super().mousePressEvent(evt)

    def mouseDoubleClickEvent(self, evt):
        print("double click")
        return super().mouseDoubleClickEvent(evt)</code>

4.2 Signals

Signals can be emitted with or without parameters. Built‑in signals (e.g., clicked , valueChanged ) may carry data such as bool , int , or str . Custom signals are declared with pyqtSignal :

<code>class Btn(QPushButton):
    rightSignal = pyqtSignal()
    def mousePressEvent(self, evt):
        super().mousePressEvent(evt)
        if evt.button() == Qt.RightButton:
            print('right button pressed')
            self.rightSignal.emit()</code>

Connecting signals to slots:

<code>btn.rightSignal.connect(custom_handler)
self.qsb.valueChanged[int].connect(lambda v: print(type(v)))
self.qsb.valueChanged[str].connect(lambda v: print(type(v)))</code>

4.3 Slots

Slot functions must accept the same parameters as the signal they are connected to:

<code>def get_msg(a, b):
    pass

def get_msg2(a):
    pass

obj.sendmsged[str, int].connect(get_msg)
obj.sendmsged[str].connect(get_msg2)</code>

5. QWidget Usage

Common widget events include showEvent , closeEvent , resizeEvent , mouse events ( mousePressEvent , mouseReleaseEvent , mouseMoveEvent ), and keyboard events ( keyPressEvent , keyReleaseEvent ). Example of mouse‑enter/leave handling:

<code>class Window(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle('Mouse Enter/Leave Demo')
        self.resize(600, 500)

    def enterEvent(self, event):
        print('mouse entered')
        self.setStyleSheet('background-color:red;')

    def leaveEvent(self, event):
        print('mouse left')
        self.setStyleSheet('background-color:green;')
</code>

Keyboard handling example:

<code>def keyPressEvent(self, event):
    if event.key() == Qt.Key_5:
        print('pressed 5')
    if event.modifiers() == Qt.ControlModifier and event.key() == Qt.Key_C:
        print('ctrl + C')
    if event.modifiers() == Qt.ControlModifier | Qt.ShiftModifier and event.key() == Qt.Key_C:
        print('ctrl + shift + C')
    print('any other key')

def keyReleaseEvent(self, event):
    print('key released')
</code>

6. Common Widget Methods

Resize constraints, geometry, margins, stacking order, visibility, focus policy, and window flags can be controlled programmatically:

<code>widget.setMinimumSize(200, 200)
widget.setMaximumSize(500, 600)
widget.setGeometry(50, 200, 60, 30)
widget.setContentsMargins(50, 50, 10, 0)
label.lower()
label.raise_()
label.stackUnder(other_label)
widget.setWindowFlags(Qt.FramelessWindowHint)
widget.setWindowOpacity(0.7)
widget.setFocusPolicy(Qt.ClickFocus)
widget.setFocus()
</code>

7. Custom Title Bar and Dragging

When using a frameless window, you can create custom close, maximize, and minimize buttons and implement mouse‑drag moving:

<code>class Window(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowFlags(Qt.FramelessWindowHint)
        self.setWindowOpacity(0.7)
        self.init_buttons()
        self.mouse_press = False

    def init_buttons(self):
        self.close_btn = QPushButton('Close', self)
        self.max_btn = QPushButton('Maximize', self)
        self.min_btn = QPushButton('Minimize', self)
        self.close_btn.pressed.connect(self.close)
        self.max_btn.pressed.connect(self.toggle_max)
        self.min_btn.pressed.connect(self.showMinimized)

    def toggle_max(self):
        if self.isMaximized():
            self.showNormal()
            self.max_btn.setText('Maximize')
        else:
            self.showMaximized()
            self.max_btn.setText('Restore')

    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.mouse_press = True
            self.win_x, self.win_y = self.x(), self.y()
            self.m_x, self.m_y = event.globalX(), event.globalY()

    def mouseMoveEvent(self, event):
        if self.mouse_press:
            dx = event.globalX() - self.m_x
            dy = event.globalY() - self.m_y
            self.move(self.win_x + dx, self.win_y + dy)

    def mouseReleaseEvent(self, event):
        self.mouse_press = False
</code>

The article concludes with a reminder that the author will continue updating the tutorial series.

GUIPythonWidgetQtEvent HandlingPyQt5signals and slots
Python Programming Learning Circle
Written by

Python Programming Learning Circle

A global community of Chinese Python developers offering technical articles, columns, original video tutorials, and problem sets. Topics include web full‑stack development, web scraping, data analysis, natural language processing, image processing, machine learning, automated testing, DevOps automation, and big data.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.