Руководство по pyqt6

К старту курса по разработке на Python делимся детальным руководством по работе с современным PyQt. Чтобы читать было удобнее, мы объединили несколько статей в одну:

  1. Первое приложение

  2. Слоты и сигналы

  3. Виджеты

За подробностями приглашаем под кат.


Простое приложение Hello World! на Python и Qt6

PyQt — это библиотека Python для создания приложений с графическим интерфейсом с помощью инструментария Qt. Созданная в Riverbank Computing, PyQt является свободным ПО (по лицензии GPL) и разрабатывается с 1999 года. Последняя версия PyQt6 — на основе Qt 6 — выпущена в 2021 году, и библиотека продолжает обновляться. Это руководство можно также использовать для PySide2, PySide6 и PyQt5.

Сегодня используются две основные версии: PyQt5 на основе Qt5 и PyQt6 на основе Qt6. Обе почти полностью совместимы, за исключением импорта и отсутствия поддержки некоторых продвинутых модулей из Qt6. В PyQt6 вносятся изменения в работу пространств имён и флагов, но ими легко управлять. В этом руководстве мы узнаем, как использовать PyQt6 для создания настольных приложений.

Сначала создадим несколько простых окон на рабочем столе, чтобы убедиться, что PyQt работает, и разберём базовые понятия. Затем кратко изучим цикл событий и то, как он связан с программированием графического интерфейса на Python. В заключение поговорим о QMainWindow с полезными элементами интерфейса, такими как панели инструментов и меню. Подробно я расскажу о них в следующих руководствах.

Создание приложения

Установка PyQt:

pip install pyqt6
# и на будущее
pip install pyqt-tools

Сначала создадим новый файл Python с любым названием (например app.py) и сохраним его. Исходный код приложения показан ниже. Введите его полностью и постарайтесь не ошибиться. Если что-то напутаете, Python укажет, что именно:

from PyQt6.QtWidgets import QApplication, QWidget

import sys # Только для доступа к аргументам командной строки

# Приложению нужен один (и только один) экземпляр QApplication.
# Передаём sys.argv, чтобы разрешить аргументы командной строки для приложения.
# Если не будете использовать аргументы командной строки, QApplication([]) тоже работает
app = QApplication(sys.argv)

# Создаём виджет Qt — окно.
window = QWidget()
window.show()  # Важно: окно по умолчанию скрыто.

# Запускаем цикл событий.
app.exec()


# Приложение не доберётся сюда, пока вы не выйдете и цикл
# событий не остановится.

Запускаем приложение из командной строки, как и любой скрипт Python:

python3 app.py

Выполнив его, мы увидим окно. В Qt автоматически создаётся окно с обычным оформлением, возможностью его перетаскивать и менять размер. То, что вы увидите, зависит от платформы, где этот пример выполняется. Вот как отображается это окно на Windows, macOS и Linux (Ubuntu):

Окно на Windows, macOS и Linux

Окно на Windows, macOS и Linux

Разбор кода

Пройдём код построчно, чтобы понять, что именно происходит. Сначала мы импортируем классы PyQt для приложения: здесь это обработчик приложения QApplication и базовый пустой виджет графического интерфейса QWidget (оба из модуля QtWidgets):

from PyQt6.QtWidgets import QApplication, QWidget

Основные модули для Qt: QtWidgets, QtGui и QtCore.

Возможен ещё from import *, но этот вид импорта обычно не приветствуется в Python. Дальше создаём экземпляр QApplication и передаём sys.arg (список Python с аргументами командной строки, передаваемыми приложению):

app = QApplication(sys.argv)

Если не будете использовать аргументы командной строки для управления Qt, передайте пустой список:

app = QApplication([])

Затем создаём экземпляр QWidget, используя имя переменной window:

window = QWidget()
window.show()

В Qt все виджеты верхнего уровня — окна, то есть у них нет родительского элемента и они не вложены в другой виджет или макет. В принципе, окно можно создать, используя любой виджет.

Виджеты без родительского элемента по умолчанию невидимы. Поэтому после создания объекта window необходимо всегда вызывать функцию .show(), чтобы сделать его видимым. .show() можно удалить, но тогда, запустив приложение, вы не сможете выйти из него!

В окне находится пользовательский интерфейс приложения. У каждого приложения он как минимум один. Приложение (по умолчанию) завершает работу при закрытии последнего окна.

Наконец, вызываем app.exec(), чтобы запустить цикл события.

Что такое «цикл событий»?

Прежде чем вывести окно на экран, разберём ключевые понятия, касающиеся организации приложений в мире Qt. Если вам уже знакомы циклы событий, можете пропустить эту часть статьи.

Основной элемент всех приложений в Qt — класс QApplication. Для работы каждому приложению нужен один — и только один — объект QApplication, который содержит цикл событий приложения. Это основной цикл, управляющий всем взаимодействием пользователя с графическим интерфейсом:

При каждом взаимодействии с приложением — будь то нажатие клавиши, щелчок или движение мыши — генерируется событие, которое помещается в очередь событий. В цикле событий очередь проверяется на каждой итерации: если найдено ожидающее событие, оно вместе с управлением передаётся определённому обработчику этого события. Последний обрабатывает его, затем возвращает управление в цикл событий и ждёт новых событий. Для каждого приложения выполняется только один цикл событий.

Класс QApplication содержит цикл событий Qt (нужен один экземпляр QApplication). Приложение ждёт в цикле событий новое событие, которое будет сгенерировано при выполнении действия. Всегда выполняется только один цикл событий.

QMainWindow

Итак, в Qt любые виджеты могут быть окнами. Например, если заменить QtWidget на QPushButton. В этом примере получается окно с одной нажимаемой кнопкой:

import sys
from PyQt6.QtWidgets import QApplication, QPushButton

app = QApplication(sys.argv)

window = QPushButton("Push Me")
window.show()

app.exec()

Классно, но не очень полезно на самом деле: редко когда нужен пользовательский интерфейс, состоящий только из одного элемента управления. Зато возможность с помощью макетов вкладывать одни виджеты в другие позволяет создавать сложные пользовательские интерфейсы внутри пустого QWidget.

В Qt уже есть решение для окна — виджет QMainWindow, имеющий стандартные функции окна для использования в приложениях, который содержит панели инструментов, меню, строку состояния, закрепляемые виджеты и многое другое. Рассмотрим эти расширенные функции позже, а пока добавим в приложение простой, пустой QMainWindow:

import sys
from PyQt6.QtWidgets import QApplication, QMainWindow

app = QApplication(sys.argv)

window = QMainWindow()
window.show()

# Запускаем цикл событий.
app.exec()

Запускаем и видим главное окно. Точно такое же, как и раньше.

QMainWindow пока не очень интересный. Добавим контент. Чтобы сделать настраиваемое окно, лучше создать подкласс QMainWindow, а затем настроить окно в блоке __init__. Так окно станет независимым в плане поведения. Итак, добавляем подкласс QMainWindow — MainWindow:

import sys

from PyQt6.QtCore import QSize, Qt
from PyQt6.QtWidgets import QApplication, QMainWindow, QPushButton


# Подкласс QMainWindow для настройки главного окна приложения
class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        self.setWindowTitle("My App")
        button = QPushButton("Press Me!")

        # Устанавливаем центральный виджет Window.
        self.setCentralWidget(button)


app = QApplication(sys.argv)

window = MainWindow()
window.show()

app.exec()

Для этого демо используем QPushButton. Основные виджеты Qt всегда импортируются из пространства имён QtWidgets, как и классы QMainWindow и QApplication. При использовании QMainWindow задействуем .setCentralWidget для размещения виджета (здесь виджет — QPushButton) в QMainWindow, по умолчанию он занимает всё окно. Как добавлять в окна несколько виджетов? Об этом поговорим рассмотрим в руководстве по макетам.

При создании подкласса из класса Qt, чтобы разрешить Qt настраивать объект, всегда нужно вызывать функцию super __init__.

В блоке __init__ сначала используем .setWindowTitle(), чтобы поменять заголовок главного окна. Затем добавляем первый виджет — QPushButton — в середину окна. Это один из основных виджетов Qt. При создании кнопки можно ввести текст, который будет на ней отображаться. Вызываем .setCentralWidget() в окне. Это специальная функция QMainWindow, которая позволяет установить виджет на середину окна.

Запускаем и снова видим окно, но на этот раз с виджетом QPushButton в центре. Нажатие кнопки ничего не даст — с этим мы разберёмся после:

QMainWindow с одной кнопкой QPushButton на Windows, macOS и Linux

QMainWindow с одной кнопкой QPushButton на Windows, macOS и Linux

Скоро мы подробно рассмотрим другие виджеты, но, если вам не терпится и хочется забежать вперёд, можете заглянуть в документацию QWidget. Попробуйте добавить различные виджеты в окно.

Изменение размеров окон и виджетов

Сейчас размер окна можно свободно поменять: щёлкните мышью на любой угол и перетаскивайте, меняя таким образом размер. Можно дать возможность пользователям самим менять размер приложений, а можно установить ограничения на минимальные или максимальные размеры или фиксированный размер окна.

В Qt размеры определяются с помощью объекта QSize. Он принимает параметры ширины и высоты. Например, так создаётся окно фиксированного размера 400 x 300 пикселей:

import sys

from PyQt6.QtCore import QSize, Qt
from PyQt6.QtWidgets import QApplication, QMainWindow, QPushButton


# Подкласс QMainWindow для настройки главного окна приложения
class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        self.setWindowTitle("My App")

        button = QPushButton("Press Me!")

        self.setFixedSize(QSize(400, 300))

        # Устанавливаем центральный виджет Window.
        self.setCentralWidget(button)


app = QApplication(sys.argv)

window = MainWindow()
window.show()

app.exec()

Запускаем и видим окно фиксированного размера. Поменять его размер не получится.

Окно фиксированного размера

Окно фиксированного размера

Элемент управления maximize отключён на Windows и Linux. На macOS можно развернуть приложение на весь экран, но размер центрального виджета не изменится.

Кроме .setFixedSize() можно также вызвать .setMinimumSize() и .setMaximumSize(), чтобы установить минимальный и максимальный размеры соответственно. Попробуйте сами! Эти методы регулирования размеров работают в любом виджете. Продолжить изучение Python вы сможете на наших курсах:

  • Курс Python-разработчик

  • Профессия Fullstack-разработчик на Python

  • Курс «Python для веб-разработки»

А ещё вы можете приобрести книгу автора этих уроков или продолжить чтение.


Слоты и сигналы

Ранее мы рассмотрели классы QApplication и QMainWindow, цикл событий и добавили в окно простой виджет. А теперь изучим механизмы Qt для взаимодействия виджетов и окон друг с другом. В статью внесены изменения, связанные с PyQt6.

Мы создали окно и добавили в него простой виджет push button, но кнопка пока бесполезна. Нужно связать действие нажатия кнопки с происходящим. В Qt это делается с помощью сигналов и слотов или событий.

Сигналы — это уведомления, отправляемые виджетами, когда что-то происходит. Этим «чем-то» может быть что угодно — нажатие кнопки, изменение текста в поле ввода или изменение текста в окне. Многие сигналы инициируются в ответ на действия пользователя, но не только: в сигналах могут отправляться данные с дополнительным контекстом произошедшего.

Можно также писать собственные сигналы, их мы рассмотрим позже.

Слоты в Qt — это приёмники сигналов. Слотом в приложении на Python можно сделать любую функцию (или метод), просто подключив к нему сигнал. Принимающая функция получает данные, отправляемые ей в сигнале. У многих виджетов Qt есть встроенные слоты, а значит, виджеты можно подключать друг к другу напрямую.

Рассмотрим основные сигналы Qt и их использование для подключения виджетов в приложениях. Сохраните эту заготовку приложения в файле app.py:

import sys
from PyQt6.QtWidgets import QApplication, QMainWindow, QPushButton

class MainWindow(QMainWindow):

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

        self.setWindowTitle("My App")


app = QApplication(sys.argv)

window = MainWindow()
window.show()

app.exec()

Сигналы QPushButton

Сейчас у нас есть QMainWindow с центральным виджетом QPushButton. Подключим эту кнопку к пользовательскому методу Python. Создадим простой настраиваемый слот the_button_was_clicked, принимающий сигнал clicked от QPushButton:

import sys
from PyQt6.QtWidgets import QApplication, QMainWindow, QPushButton


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        self.setWindowTitle("My App")

        button = QPushButton("Press Me!")
        button.setCheckable(True)
        button.clicked.connect(self.the_button_was_clicked)

        # Устанавливаем центральный виджет Window.
        self.setCentralWidget(button)

    def the_button_was_clicked(self):
        print("Clicked!")


app = QApplication(sys.argv)

window = MainWindow()
window.show()

app.exec()

Запускаем. Если нажать на кнопку, в консоли появится текст Clicked! («Нажата!»):

Clicked!
Clicked!
Clicked!
Clicked!

Получение данных

В сигналах может отправляться дополнительная информация о произошедшем. И сигнал .clicked — не исключение: с его помощью сообщается о нажатом (или переключенном) состоянии кнопки. Для обычных кнопок это значение всегда False, поэтому первый слот проигнорировал эти данные. Включим возможность нажатия кнопки, чтобы увидеть этот эффект. Ниже добавляется второй слот и выводится состояние нажатия:

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        self.setWindowTitle("My App")

        button = QPushButton("Press Me!")
        button.setCheckable(True)
        button.clicked.connect(self.the_button_was_clicked)
        button.clicked.connect(self.the_button_was_toggled)

        self.setCentralWidget(button)

    def the_button_was_clicked(self):
        print("Clicked!")

    def the_button_was_toggled(self, checked):
        print("Checked?", checked)

Запускаем! Если нажать на кнопку, она подсветится и станет checked («Нажатой»). Чтобы отключить её, нажимаем ещё раз. Найдите состояние нажатия в консоли:

Clicked!
Checked? True
Clicked!
Checked? False
Clicked!
Checked? True
Clicked!
Checked? False
Clicked!
Checked? True

К сигналу подключается сколько угодно слотов, в которых можно реагировать сразу на несколько версий сигналов.

Хранение данных

Текущее состояние виджета на Python часто хранят в переменной, что позволяет работать со значениями без доступа к исходному виджету. Причём для их хранения используются отдельные переменные или словарь. В следующем примере сохраняем значение кнопки checked («Нажата») в переменной button_is_checked в self:

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        self.button_is_checked = True

        self.setWindowTitle("My App")

        button = QPushButton("Press Me!")
        button.setCheckable(True)
        button.clicked.connect(self.the_button_was_toggled)
        button.setChecked(self.button_is_checked)

        self.setCentralWidget(button)

    def the_button_was_toggled(self, checked):
        self.button_is_checked = checked

        print(self.button_is_checked)

Сначала устанавливаем переменной значение по умолчанию True, а затем используем это значение, чтобы установить исходное состояние виджета. Когда состояние виджета меняется, получаем сигнал и соответственно обновляем переменную.

Эта же схема применима к любым виджетам PyQt. Если в виджете нет сигнала, которым отправляется текущее состояние, нужно получить значение из виджета прямо в обработчике. Например, здесь мы проверяем состояние checked («Нажата») в нажатом обработчике:

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        self.button_is_checked = True

        self.setWindowTitle("My App")

        self.button = QPushButton("Press Me!")
        self.button.setCheckable(True)
        self.button.released.connect(self.the_button_was_released)
        self.button.setChecked(self.button_is_checked)

        self.setCentralWidget(self.button)

    def the_button_was_released(self):
        self.button_is_checked = self.button.isChecked()

        print(self.button_is_checked)

Сохраним ссылку на кнопку в self, чтобы получить к ней доступ в слоте.

Сигнал released срабатывает, когда кнопка отпускается, при этом состояние нажатия не отправляется. Его получают из кнопки в обработчике, используя .isChecked().

Изменение интерфейса

Мы уже видели, как принимаются сигналы и выводятся на консоль результаты. Но что происходит с интерфейсом, когда нажимают на кнопку? Обновим метод слота, чтобы изменить кнопку, поменяв текст, отключив её и сделав её недоступной. И отключим пока состояние, допускающее нажатие:

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        self.setWindowTitle("My App")

        self.button = QPushButton("Press Me!")
        self.button.clicked.connect(self.the_button_was_clicked)

        self.setCentralWidget(self.button)

    def the_button_was_clicked(self):
        self.button.setText("You already clicked me.")
        self.button.setEnabled(False)

        # Также меняем заголовок окна.
        self.setWindowTitle("My Oneshot App")

Снова нужен доступ к кнопке в методе the_button_was_clicked, поэтому сохраняем ссылку на неё в self. Чтобы поменять текст кнопки, передаём str в .setText(). Чтобы отключить кнопку, вызываем .setEnabled() с аргументом False. И запускаем программу. Если нажать на кнопку, текст изменится и кнопка станет недоступной.

В методах слота можно не только менять кнопку, которая активирует сигнал, но и делать всё что угодно. Например, поменять заголовок окна, добавив в метод the_button_was_clicked эту строку:

self.setWindowTitle("A new window title")

Большинство виджетов, в том числе QMainWindow, имеют свои сигналы. В следующем, более сложном примере подключим сигнал .windowTitleChanged в QMainWindow к пользовательскому методу слота. А также сделаем для этого слота новый заголовок окна:

from PyQt6.QtWidgets import QApplication, QMainWindow, QPushButton

import sys
from random import choice

window_titles = [
    'My App',
    'My App',
    'Still My App',
    'Still My App',
    'What on earth',
    'What on earth',
    'This is surprising',
    'This is surprising',
    'Something went wrong'
]


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        self.n_times_clicked = 0

        self.setWindowTitle("My App")

        self.button = QPushButton("Press Me!")
        self.button.clicked.connect(self.the_button_was_clicked)

        self.windowTitleChanged.connect(self.the_window_title_changed)

        # Устанавливаем центральный виджет Window.
        self.setCentralWidget(self.button)

    def the_button_was_clicked(self):
        print("Clicked.")
        new_window_title = choice(window_titles)
        print("Setting title:  %s" % new_window_title)
        self.setWindowTitle(new_window_title)

    def the_window_title_changed(self, window_title):
        print("Window title changed: %s" % window_title)

        if window_title == 'Something went wrong':
            self.button.setDisabled(True)


app = QApplication(sys.argv)

window = MainWindow()
window.show()

app.exec()

Сначала создаём список заголовков окна и выбираем один из них наугад, используя встроенную функцию Python random.choice(). Подключаем пользовательский метод слота the_window_title_changed к сигналу окна .windowTitleChanged.

При нажатии на кнопку заголовок окна случайным образом изменится. Если новый заголовок окна изменится на Something went wrong («Что-то пошло не так»), кнопка отключится.

Запускаем! Нажимайте на кнопку, пока заголовок не изменится на Something went wrong. В этом примере стоит обратить внимание вот на что:

  1. Сигнал windowTitleChanged при установке заголовка окна выдаётся не всегда. Он срабатывает, только если новый заголовок отличается от предыдущего: если один и тот же заголовок устанавливается несколько раз, сигнал срабатывает только в первый раз. Чтобы избежать неожиданностей, важно перепроверять условия срабатывания сигналов при их использовании в приложении.

  2. С помощью сигналов создаются цепочки. Одно событие — нажатие кнопки — может привести к тому, что поочерёдно произойдут другие. Эти последующие эффекты отделены от того, что их вызвало. Они возникают согласно простым правилам. И это отделение эффектов от их триггеров — один из ключевых принципов, которые учитываются при создании приложений с графическим интерфейсом. Возвращаться к этому будем на протяжении всего курса.

Мы рассмотрели сигналы и слоты, показали простые сигналы и их использование для передачи данных и состояния в приложении. Теперь переходим к виджетам Qt, которые будут использоваться в приложениях вместе с сигналами.

Подключение виджетов друг к другу напрямую

Мы уже видели примеры подключения сигналов виджетов к методам Python. Когда сигнал из виджета срабатывает, вызывается метод Python, из сигнала он получает данные. Но для обработки сигналов не всегда нужна функция Python — можно подключать виджеты друг к другу напрямую.

Добавим в окно виджеты QLineEdit и QLabel. В __init__ для окна и подключим сигнал редактирования строки .textChanged к методу .setText в QLabel. Когда в QLineEdit меняется текст, он сразу будет поступать в QLabel (в метод .setText):

from PyQt6.QtWidgets import QApplication, QMainWindow, QLabel, QLineEdit, QVBoxLayout, QWidget

import sys


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        self.setWindowTitle("My App")

        self.label = QLabel()

        self.input = QLineEdit()
        self.input.textChanged.connect(self.label.setText)

        layout = QVBoxLayout()
        layout.addWidget(self.input)
        layout.addWidget(self.label)

        container = QWidget()
        container.setLayout(layout)

        # Устанавливаем центральный виджет Window.
        self.setCentralWidget(container)


app = QApplication(sys.argv)

window = MainWindow()
window.show()

app.exec()

Внимание: чтобы подключить входные данные к метке, нужно определить и эти данные, и метку. В этом коде в макет добавляются два виджета и устанавливаются в окне. Подробно рассмотрим макеты позже, а пока не обращайте на них внимания.

Запускаем программу:

Введите текст в верхнем поле — он сразу появится в виде метки.

У большинства виджетов Qt есть доступные слоты, к которым подключается любой сигнал, возврощающий тот же тип, что он принимает. В документации по виджетам, в разделе Public Slots («Общедоступные слоты»), имеются слоты для каждого виджета. Посмотрите документацию для QLabel.

События

Любое взаимодействие пользователя с приложением Qt — это событие. Есть много типов событий, каждое из которых — это отдельный тип взаимодействия. В Qt события представлены объектами событий, в которые упакована информация о произошедшем. События передаются определённым обработчикам событий в виджете, где произошло взаимодействие.

Определяя пользовательские или расширенные обработчики событий, можно менять способ реагирования виджетов на них. Обработчики событий определяются так же, как и любой другой метод, но название обработчика зависит от типа обрабатываемого события.

QMouseEvent — одно из основных событий, получаемых виджетами. События QMouseEvent создаются для каждого отдельного нажатия кнопки мыши и её перемещения в виджете. Вот обработчики событий мыши:

Обработчик

Событие

mouseMoveEvent

Мышь переместилась

mousePressEvent

Кнопка мыши нажата

mouseReleaseEvent

Кнопка мыши отпущена

mouseDoubleClickEvent

Обнаружен двойной клик

Например, нажатие на виджет приведёт к отправке QMouseEvent в обработчик событий .mousePressEvent в этом виджете.

События можно перехватывать, создав подкласс и переопределив метод обработчика в этом классе. Их можно фильтровать, менять или игнорировать, передавая обычному обработчику путём вызова функции суперкласса методом super(). Они добавляются в класс главного окна следующим образом (в каждом случае в e будет получено входящее событие):

import sys

from PyQt6.QtCore import Qt
from PyQt6.QtWidgets import QApplication, QLabel, QMainWindow, QTextEdit


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.label = QLabel("Click in this window")
        self.setCentralWidget(self.label)

    def mouseMoveEvent(self, e):
        self.label.setText("mouseMoveEvent")

    def mousePressEvent(self, e):
        self.label.setText("mousePressEvent")

    def mouseReleaseEvent(self, e):
        self.label.setText("mouseReleaseEvent")

    def mouseDoubleClickEvent(self, e):
        self.label.setText("mouseDoubleClickEvent")


app = QApplication(sys.argv)

window = MainWindow()
window.show()

app.exec()

Запускаем! В окне переместите мышь и нажмите на кнопку, затем дважды нажмите на кнопку и посмотрите, какие появляются события.

События перемещения мыши регистрируются только при нажатой кнопке. Чтобы это изменить, вызовите в окне self.setMouseTracking(True). События press («Нажатие кнопки»), click («Клика») и double-click («Двойного клика») срабатывают при нажатии кнопки. Событие release («Отпускание») срабатывает, только когда кнопка отпускается. Клик пользователя регистрируется обычно при нажатии кнопки мыши и её отпускании.

Внутри обработчиков события есть доступ к объекту этого события. Он содержит информацию о событии и используется, чтобы реагировать по-разному в зависимости от того, что произошло. Рассмотрим объекты событий управления мышью.

События управления мышью

В Qt все события управления мышью отслеживаются с помощью объекта QMouseEvent. При этом информация о событии считывается из следующих методов событий:

Метод

Возвращает

.button()

Конкретную кнопку, вызвавшую данное событие

.buttons()

Состояние всех кнопок мыши (флаги OR)

.position()

Относительную позицию виджета в виде целого QPoint .

Эти методы используются в обработчике событий, чтобы на разные события реагировать по-разному или полностью их игнорировать. Через методы позиционирования в виде объектов QPoint предоставляется глобальная и локальная (касающаяся виджета) информация о местоположении. Сведения о кнопках поступают с использованием типов кнопок мыши из пространства имён Qt. Например, в этом коде показаны разные реакции на нажатие левой, правой или средней кнопки мыши в окне:

    def mousePressEvent(self, e):
        if e.button() == Qt.LeftButton:
            # здесь обрабатываем нажатие левой кнопки
            self.label.setText("mousePressEvent LEFT")

        elif e.button() == Qt.MiddleButton:
            # здесь обрабатываем нажатие средней кнопки.
            self.label.setText("mousePressEvent MIDDLE")

        elif e.button() == Qt.RightButton:
            # здесь обрабатываем нажатие правой кнопки.
            self.label.setText("mousePressEvent RIGHT")

    def mouseReleaseEvent(self, e):
        if e.button() == Qt.LeftButton:
            self.label.setText("mouseReleaseEvent LEFT")

        elif e.button() == Qt.MiddleButton:
            self.label.setText("mouseReleaseEvent MIDDLE")

        elif e.button() == Qt.RightButton:
            self.label.setText("mouseReleaseEvent RIGHT")

    def mouseDoubleClickEvent(self, e):
        if e.button() == Qt.LeftButton:
            self.label.setText("mouseDoubleClickEvent LEFT")

        elif e.button() == Qt.MiddleButton:
            self.label.setText("mouseDoubleClickEvent MIDDLE")

        elif e.button() == Qt.RightButton:
            self.label.setText("mouseDoubleClickEvent RIGHT")

Идентификаторы кнопок определяются в пространстве имён Qt:

Код

Бинарное значение

Описание

Qt.NoButton

0 (000)

Кнопка не нажата, или событие не связано с нажатием кнопки

Qt.LeftButton

1 (001)

Левая кнопка нажата

Qt.RightButton

2 (010)

Правая кнопка нажата

Qt.MiddleButton

4 (100)

Средняя кнопка [обычно это колёсико мыши] нажата

В мышках для правшей положения левой и правой кнопок меняются местами, то есть при нажатии правой кнопки вернётся Qt.LeftButton. Иными словами, учитывать ориентацию мыши не нужно.

Контекстные меню

Контекстные меню — это небольшие контекстно-зависимые меню, которые обычно появляются в окне при нажатии правой кнопкои мыши. В Qt у виджетов есть определённое событие для активации таких меню.

В примере ниже мы будем перехватывать событие .contextMenuEvent в QMainWindow. Это событие запускается всякий раз перед самым появлением контекстного меню, а передаётся событие с одним значением типа QContextMenuEvent.

Чтобы перехватить событие, просто переопределяем метод объекта с помощью нового метода с тем же именем. В нашем случае создаём метод в подклассе MainWindow с именем contextMenuEvent, и он будет получать все события этого типа:

import sys

from PyQt6.QtCore import Qt
from PyQt6.QtGui import QAction
from PyQt6.QtWidgets import QApplication, QLabel, QMainWindow, QMenu


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

    def contextMenuEvent(self, e):
        context = QMenu(self)
        context.addAction(QAction("test 1", self))
        context.addAction(QAction("test 2", self))
        context.addAction(QAction("test 3", self))
        context.exec(e.globalPos())


app = QApplication(sys.argv)

window = MainWindow()
window.show()

app.exec()

Если запустить этот код и нажать правой кнопкой в окне, появится контекстное меню. В действиях меню можно настроить слоты .triggered как обычные (и повторно использовать действия, определённые для меню и панелей инструментов).

При передаче исходного положения в функцию exec оно должно соответствовать родительскому элементу, переданному при определении. В нашем случае в качестве родительского элемента передаётся self, поэтому используем глобальное положение. Для полноты картины нужно сказать, что создавать контекстные меню можно и при помощи сигналов:

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.show()

        self.setContextMenuPolicy(Qt.CustomContextMenu)
        self.customContextMenuRequested.connect(self.on_context_menu)

    def on_context_menu(self, pos):
        context = QMenu(self)
        context.addAction(QAction("test 1", self))
        context.addAction(QAction("test 2", self))
        context.addAction(QAction("test 3", self))
        context.exec(self.mapToGlobal(pos))

Что выбрать — решать только вам.

Иерархия событий

В PyQt каждый виджет — это часть двух различных иерархий: иерархии объектов в Python и иерархии макета в Qt. Реакция на события или их игнорирование влияет на поведение пользовательского интерфейса.

Перенаправление наследования Python

Часто бывает нужно перехватить событие, что-то с ним сделать, запустив при этом поведение обработки событий по умолчанию. Если объект унаследован от стандартного виджета, у него наверняка будет поведение по умолчанию. Запустить его можно, методом super() вызвав реализацию из суперкласса. Будет вызван именно суперкласс в Python, а не .parent() из PyQt:

def mousePressEvent(self, event):
    print("Mouse pressed!")
    super(self, MainWindow).contextMenuEvent(event)

Интерфейс ведёт себя как раньше, при этом мы добавили новое поведение, которое не вмешивается в прежнее.

Передача вверх по иерархии макета

Когда в приложение добавляется виджет, он также получает из макета другой родительский элемент. Чтобы найти родительский элемент виджета, надо вызвать функцию .parent(). Иногда эти родительские элементы указываются вручную (и часто автоматически), например для QMenu или QDialog. Когда в главное окно добавляется виджет, оно становится родительским элементом виджета.

Когда события создаются для взаимодействия пользователя с пользовательским интерфейсом, они передаются в его самый верхний виджет. Если в окне есть кнопка и вы нажмёте её, она получит событие первой.

Если первый виджет не может обработать событие, оно перейдёт к следующему по очереди родительскому виджету. Эта передача вверх по иерархии вложенных виджетов продолжится, пока событие не будет обработано или не достигнет главного окна. В обработчиках событий событие помечают как обработанное через вызов .accept():

    class CustomButton(QPushButton)
        def mousePressEvent(self, e):
            e.accept()

Вызвав в объекте события .ignore(), помечают его как необработанное. В этом случае событие будет передаваться по иерархии вверх:

    class CustomButton(QPushButton)
        def event(self, e):
            e.ignore()

Чтобы виджет пропускал события, вы можете спокойно игнорировать те, на которые каким-то образом реагировали. Аналогично вы можете отреагировать на одни события, заглушая другие. А продолжить изучение Python вы сможете на наших курсах:

  • Курс Python-разработчик

  • Профессия Fullstack-разработчик на Python

  • Курс «Python для веб-разработки»

Напомним также о книге автора этих уроков.


Виджеты

В большинстве пользовательских интерфейсов и в Qt «виджет» — это компонент, с которым взаимодействует пользователь. Пользовательские интерфейсы состоят из нескольких виджетов, расположенных внутри окна. В Qt большой выбор виджетов и можно создать собственные виджеты.

Краткое демо

Посмотрим на самые распространённые виджеты PyQt. Они создаются и добавляются в макет окна с помощью этого кода (работу макетов в Qt рассмотрим в следующем руководстве):

import sys

from PyQt6.QtCore import Qt
from PyQt6.QtWidgets import (
    QApplication,
    QCheckBox,
    QComboBox,
    QDateEdit,
    QDateTimeEdit,
    QDial,
    QDoubleSpinBox,
    QFontComboBox,
    QLabel,
    QLCDNumber,
    QLineEdit,
    QMainWindow,
    QProgressBar,
    QPushButton,
    QRadioButton,
    QSlider,
    QSpinBox,
    QTimeEdit,
    QVBoxLayout,
    QWidget,
)


# Подкласс QMainWindow для настройки основного окна приложения
class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        self.setWindowTitle("Widgets App")

        layout = QVBoxLayout()
        widgets = [
            QCheckBox,
            QComboBox,
            QDateEdit,
            QDateTimeEdit,
            QDial,
            QDoubleSpinBox,
            QFontComboBox,
            QLCDNumber,
            QLabel,
            QLineEdit,
            QProgressBar,
            QPushButton,
            QRadioButton,
            QSlider,
            QSpinBox,
            QTimeEdit,
        ]

        for w in widgets:
            layout.addWidget(w())

        widget = QWidget()
        widget.setLayout(layout)

        # Устанавливаем центральный виджет окна. Виджет будет расширяться по умолчанию,
        # заполняя всё пространство окна.
        self.setCentralWidget(widget)


app = QApplication(sys.argv)
window = MainWindow()
window.show()

app.exec()

Запускаем! Появится окно со всеми созданными виджетами:

Виджеты на Windows, Mac и Ubuntu Linux

Виджеты на Windows, Mac и Ubuntu Linux

Посмотрим внимательно на все эти виджеты:

Класс виджета

Описание виджета

QCheckbox

Чекбокс

QComboBox

Окно выпадающего списка

QDateEdit

Для редактирования даты и времени

QDateTimeEdit

Для редактирования даты и времени

QDial

Поворотный циферблат

QDoubleSpinbox

Спиннер для чисел с плавающей точкой

QFontComboBox

Список шрифтов

QLCDNumber

Довольно неприятный дисплей LCD

QLabel

Просто метка, не интерактивная

QLineEdit

Поле ввода со строкой

QProgressBar

Индикатор выполнения

QPushButton

Кнопка

QRadioButton

Переключаемый набор, в котором активен только один элемент

QSlider

Слайдер

QSpinBox

Спиннер для целых чисел

QTimeEdit

Поле редактирования времени

Их гораздо больше, но они не поместятся в статью. Полный список есть в документации Qt.

Разберём подробно самые используемые виджеты и поэкспериментируем с ними в простом приложении. Сохраните следующий код в файле app.py и, запустив его, убедитесь, что он работает:

import sys
from PyQt6.QtWidgets import (
    QMainWindow, QApplication,
    QLabel, QCheckBox, QComboBox, QListBox, QLineEdit,
    QLineEdit, QSpinBox, QDoubleSpinBox, QSlider
)
from PyQt6.QtCore import Qt

class MainWindow(QMainWindow):

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

        self.setWindowTitle("My App")


app = QApplication(sys.argv)
w = MainWindow()
w.show()
app.exec()

Выше мы импортировали несколько виджетов Qt. Разберём каждый по очереди. Добавим их в приложение и посмотрим, как они себя ведут.

QLabel

Начнём с QLabel, одного из простейших виджетов в Qt. Он состоит из строчки текста и устанавливается в приложении. Текст задаётся аргументом QLabel:

widget = QLabel("Hello")

Или с помощью метода .setText():

widget = QLabel("1")  # Создана метка с текстом 1.
widget.setText("2")   # Создана метка с текстом 2.

Параметры шрифта, например его размер или выравнивание в виджете, настраиваются так:

class MainWindow(QMainWindow):

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

        self.setWindowTitle("My App")

        widget = QLabel("Hello")
        font = widget.font()
        font.setPointSize(30)
        widget.setFont(font)
        widget.setAlignment(Qt.AlignmentFlag.AlignHCenter | Qt.AlignmentFlag.AlignVCenter)

        self.setCentralWidget(widget)

QLabel на Windows, Mac и Ubuntu Linux

QLabel на Windows, Mac и Ubuntu Linux

Рекомендация по шрифту: чтобы изменить свойства шрифта виджета, лучше получить текущий шрифт, обновить его и применить снова. Так начертание шрифта будет соответствовать ограничениям рабочего стола. Выравнивание указывается с помощью флага из пространства имён Qt. Вот флаги для горизонтального выравнивания:

Флаг PyQt6 (полный код)

Поведение

Qt.AlignmentFlag.AlignLeft

Выравнивает по левому краю

Qt.AlignmentFlag.AlignRight

Выравнивает по правому краю

Qt.AlignmentFlag.AlignHCenter

Центрирует по горизонтали в доступном пространстве

Qt.AlignmentFlag.AlignJustify

Выравнивает текст в доступном пространстве

Флаги используются вместе с помощью каналов (|), но флаги вертикального и горизонтального выравнивания не применяются одновременно:

Флаг PyQt6 (полный код)

Поведение

Qt.AlignmentFlag.AlignTop

Выравнивается по верху

Qt.AlignmentFlag.AlignBottom

Выравнивается по низу

Qt.AlignmentFlag.AlignVCenter

Центрирует вертикально в доступном пространстве

align_top_left = Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignTop

При этом для совместного применения двух флагов (не A & B) используется канал | с операцией логического «ИЛИ». Эти флаги — неперекрывающиеся битовые маски. Например, у Qt.AlignmentFlag.AlignLeft шестнадцатеричное значение 0x0001, а у Qt.AlignmentFlag.AlignBottom — 0x0040. С помощью операции логического «ИЛИ» получаем значение «внизу слева» — 0x0041. Этот принцип применим и ко всем остальным парам флагов Qt. Если вам что-то здесь непонятно, смело пропускайте эту часть и переходите к следующей. Только не забывайте использовать |. Наконец, есть флаг, с помощью которого выполняется выравнивание по центру в обоих направлениях одновременно:

Флаг PyQt6

Поведение

Qt.AlignmentFlag.AlignCenter

Центрирует горизонтально и вертикально.

Как ни странно, QLabel используется и для показа изображения с помощью .setPixmap(). Этот метод принимает QPixmap, создаваемый передачей имени файла изображения в QPixmap. Среди примеров из этой книги есть файл otje.jpg, который отображается в окне так:

widget.setPixmap(QPixmap('otje.jpg'))

Кот Отье

Кот Отье

Какая мордочка! По умолчанию изображение масштабируется, сохраняя соотношение ширины и высоты. Если нужно растянуть и подогнать его по размерам окна, установите .setScaledContents(True) в QLabel:

widget.setScaledContents(True)

QCheckBox

А этот виджет, как следует из названия, предоставляет пользователю чекбокс с флажками. Как и во всех виджетах Qt, здесь есть настраиваемые параметры, изменяющие его поведение:

class MainWindow(QMainWindow):

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

        self.setWindowTitle("My App")

        widget = QCheckBox()
        widget.setCheckState(Qt.CheckState.Checked)

        # Включение трёх состояний: widget.setCheckState(Qt.PartiallyChecked)
        # Или: widget.setTriState(True)
        widget.stateChanged.connect(self.show_state)

        self.setCentralWidget(widget)


    def show_state(self, s):
        print(s == Qt.CheckState.Checked)
        print(s)

QCheckBox на Windows, Mac & Ubuntu Linux

QCheckBox на Windows, Mac & Ubuntu Linux

Состояние чекбокса устанавливается программно с помощью .setChecked или .setCheckState. Первый принимает True или False, то есть чекбокс с галочкой или без неё соответственно. В случае с .setCheckState с помощью флага пространства имён Qt также указывается конкретное состояние чекбокса:

Флаг PyQt6 (Полный код)

Состояние

Qt.CheckState.Unchecked

Элемент не отмечен

Qt.CheckState.PartiallyChecked

Элемент отмечен частично

Qt.CheckState.Checked

Элемент отмечен

Чекбокс, поддерживающий состояние частичной отмеченности (Qt.CheckState.PartiallyChecked) галочками, обычно называют «имеющим третье состояние», т. е. он и отмечен, и не отмечен. Чекбокс в этом состоянии часто отображается в виде серого флажка и используется в иерархических структурах чекбоксов, где дочерние чекбоксы связаны с родительскими.

Установив значение Qt.CheckState.PartiallyChecked, вы переведёте чекбокс в третье состояние. То же самое, но без перевода текущего состояния в состояние частичной отмеченности галочками, делается с помощью .setTriState(True).

При запуске скрипта номер текущего состояния отображается в виде значения целочисленного типа int. Причём состоянию, отмеченному галочками, соответствует 2, не отмеченному — 0, а состоянию частичной отмеченности — 1. Запоминать эти значения не нужно: К примеру, переменная пространства имён Qt.Checked равна 2. Это значение соответствующих флагов состояния. То есть вы можете проверить состояние с помощью state == Qt.Checked.

QComboBox

QComboBox — это выпадающий список, закрытый по умолчанию, с кнопкой, чтобы открыть его. Можно выбрать один элемент из списка, при этом выбранный в данный момент элемент отображается в виджете в виде метки. Поле со списком подходит для выбора варианта из длинного списка вариантов. Такое поле используется при выборе начертания или размера шрифта в текстовых редакторах. В Qt для выбора шрифта есть специальное поле со списком шрифтов — QFontComboBox.

В QComboBox можно добавлять элементы, передавая список строк в .addItems(). Элементы добавляются в порядке расположения соответствующих элементам строк кода.

class MainWindow(QMainWindow):

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

        self.setWindowTitle("My App")

        widget = QComboBox()
        widget.addItems(["One", "Two", "Three"])

        # Отправляет текущий индекс (позицию) выбранного элемента.
        widget.currentIndexChanged.connect( self.index_changed )

        # Есть альтернативный сигнал отправки текста.
        widget.textChanged.connect( self.text_changed )

        self.setCentralWidget(widget)


    def index_changed(self, i): # i — это int
        print(i)

    def text_changed(self, s): # s — это str
        print(s)

QComboBox на Windows, Mac и Ubuntu Linux

QComboBox на Windows, Mac и Ubuntu Linux

Сигнал .currentIndexChanged срабатывает при обновлении выбранного в данный момент элемента, индекс которого в списке передаётся по умолчанию. Кроме того, есть сигнал .currentTextChanged, при срабатывании которого вместо индекса предоставляется метка выбранного в данный момент элемента. Это часто оказывается полезнее.

Также QComboBox можно редактировать, вводя значения, которых в данный момент нет в списке, — вставлять их или просто использовать как значения. Поле делается редактируемым так:

widget.setEditable(True)

Чтобы определить, как обрабатываются вставляемые значения, устанавливается флаг. Флаги хранятся в самом классе QComboBox. Вот их список:

Флаг PyQt6 (полный код)

Поведение

QComboBox.InsertPolicy.NoInsert

Не вставлять

QComboBox.InsertPolicy.InsertAtTop

Вставить как первый элемент

QComboBox.InsertPolicy.InsertAtCurrent

Заменить текущий выбранный элемент

QComboBox.InsertPolicy.InsertAtBottom

Вставить после последнего элемента

QComboBox.InsertPolicy.InsertAfterCurrent

Вставить после текущего элемента

QComboBox.InsertPolicy.InsertBeforeCurrent

Вставить перед текущим элементом

QComboBox.InsertPolicy.InsertAlphabetically

Вставить в алфавитном порядке

Чтобы использовать их, применяется флаг:

widget.setInsertPolicy(QComboBox.InsertPolicy.InsertAlphabetically)

Кроме того, можно ограничить количество элементов поля, например при помощи .setMaxCount:

widget.setMaxCount(10)

Подробнее о QComboBox рассказывается здесь.

QListWidget

Этот виджет похож на QComboBox, но варианты здесь представлены в виде прокручиваемого списка элементов и возможен выбор нескольких элементов одновременно. В QListWidget есть сигнал currentItemChanged для отправки QListItem (элемента виджета списка) и сигнал currentTextChanged для отправки текста текущего элемента:

class MainWindow(QMainWindow):

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

        self.setWindowTitle("My App")

        widget = QListWidget()
        widget.addItems(["One", "Two", "Three"])

        widget.currentItemChanged.connect(self.index_changed)
        widget.currentTextChanged.connect(self.text_changed)

        self.setCentralWidget(widget)


    def index_changed(self, i); # i — не индекс, а сам QList
        print(i.text())

    def text_changed(self, s): # s — это строка
        print(s)

QListWidget на Windows, Mac и Ubuntu Linux

QListWidget на Windows, Mac и Ubuntu Linux

QLineEdit

Виджет QLineEdit — это простое однострочное текстовое поле для редактирования вводимых пользователями данных. Он используется для полей, где нет ограничений на входные данные. Например, при вводе адреса электронной почты или имени компьютера:

class MainWindow(QMainWindow):

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

        self.setWindowTitle("My App")

        widget = QLineEdit()
        widget.setMaxLength(10)
        widget.setPlaceholderText("Enter your text")

        #widget.setReadOnly(True) # раскомментируйте, чтобы сделать доступным только для чтения

        widget.returnPressed.connect(self.return_pressed)
        widget.selectionChanged.connect(self.selection_changed)
        widget.textChanged.connect(self.text_changed)
        widget.textEdited.connect(self.text_edited)

        self.setCentralWidget(widget)


    def return_pressed(self):
        print("Return pressed!")
        self.centralWidget().setText("BOOM!")

    def selection_changed(self):
        print("Selection changed")
        print(self.centralWidget().selectedText())

    def text_changed(self, s):
        print("Text changed...")
        print(s)

    def text_edited(self, s):
        print("Text edited...")
        print(s)

QLineEdit на Windows, Mac и Ubuntu Linux

QLineEdit на Windows, Mac и Ubuntu Linux

Как показано в этом коде, при однострочном редактировании вы можете установить максимальную длину текста.

В QLineEdit есть ряд сигналов для различных событий редактирования, в том числе при нажатии клавиши return (пользователем), когда пользователь изменил свой выбор. Также есть два сигнала редактирования: один — на случай, когда текст в поле отредактирован, другой — когда он изменён. Здесь различаются два вида изменений: пользовательские и выполненные программой. Сигнал textEdited отправляется только при редактировании текста пользователем.

Кроме того, с помощью маски ввода можно выполнить проверку вводимых данных, чтобы определить, какие символы поддерживаются и где. Применяется к соответствующему полю так:

widget.setInputMask('000.000.000.000;_')

Это позволяет использовать серию трёхзначных чисел, разделённых точками, для проверки адресов IPv4.

QSpinBox и QDoubleSpinBox

QSpinBox — это небольшое поле ввода чисел со стрелками для изменения значения. Оно поддерживает целые числа, а QDoubleSpinBox — числа с плавающей точкой:

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        self.setWindowTitle("My App")

        widget = QSpinBox()
        # Или: widget = QDoubleSpinBox()

        widget.setMinimum(-10)
        widget.setMaximum(3)
        # Или: widget.setRange(-10,3)

        widget.setPrefix("$")
        widget.setSuffix("c")
        widget.setSingleStep(3)  # Или, например, 0.5 в QDoubleSpinBox
        widget.valueChanged.connect(self.value_changed)
        widget.textChanged.connect(self.value_changed_str)

        self.setCentralWidget(widget)

    def value_changed(self, i):
        print(i)

    def value_changed_str(self, s):
        print(s)

Запустив код, вы увидите поле для ввода чисел. Значение в нём показывает префиксные и постфиксные блоки и ограничено диапазоном от +3 до –10:

QSpinBox на Windows, Mac и Ubuntu Linux

QSpinBox на Windows, Mac и Ubuntu Linux

В этом коде показан разнообразный функционал виджета. Чтобы задать диапазон допустимых значений, используются setMinimum и setMaximum. Одновременно они устанавливаются с помощью SetRange. Аннотация типов значений поддерживается префиксами и суффиксами, добавляемыми к числу. Например, для обозначений валюты или денежных единиц используются .setPrefix и .setSuffix соответственно.

Нажав на стрелки «вверх» и «вниз» на виджете, можно увеличить или уменьшить значение на величину, устанавливаемую с помощью .setSingleStep. Но это не повлияет на допустимые для виджета значения.

В QSpinBox и QDoubleSpinBox есть сигнал .valueChanged, срабатывающий при изменении их значений. С помощью необработанного сигнала .valueChanged отправляется числовое значение (целочисленного типа int или типа числа с плавающей точкой float), а с помощью .textChanged — значение в виде строки, включающей символы префикса и суффикса.

QSlider

QSlider — это ползунок, очень схожий по внутреннему функционалу с QDoubleSpinBox. Текущее значение представлено не числами, а в виде маркера ползунка, располагающегося по всей длине виджета. Этот виджет удобен для указания значения в промежутке между максимумом и минимумом, где абсолютная точность не требуется. Чаще всего этот тип виджетов используется при регулировке громкости. Есть и другие сигналы: .sliderMoved срабатывает при перемещении ползунка а .sliderPressed — при нажатии на ползунок:

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        self.setWindowTitle("My App")

        widget = QSlider()

        widget.setMinimum(-10)
        widget.setMaximum(3)
        # Или: widget.setRange(-10,3)

        widget.setSingleStep(3)

        widget.valueChanged.connect(self.value_changed)
        widget.sliderMoved.connect(self.slider_position)
        widget.sliderPressed.connect(self.slider_pressed)
        widget.sliderReleased.connect(self.slider_released)

        self.setCentralWidget(widget)

    def value_changed(self, i):
        print(i)

    def slider_position(self, p):
        print("position", p)

    def slider_pressed(self):
        print("Pressed!")

    def slider_released(self):
        print("Released")

Запустив код, вы увидите ползунок. Переместите его, чтобы изменить значение:

QSlider на Windows, Mac и Ubuntu Linux

QSlider на Windows, Mac и Ubuntu Linux

Также можно сделать вертикальный или горизонтальный ползунок, задав соответствующее расположение при его создании. Флаги расположения определены в пространстве имён Qt, например:

widget.QSlider(Qt.Orientiation.Vertical)

Или так:

widget.QSlider(Qt.Orientiation.Horizontal)

QDial

Наконец, QDial — это круговой виджет, схожий по функционалу с механическим ползунком из реального мира. Красиво, но с точки зрения пользовательского интерфейса не очень удобно. Он часто используется в аудиоприложениях:

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        self.setWindowTitle("My App")

        widget = QDial()
        widget.setRange(-10, 100)
        widget.setSingleStep(0.5)

        widget.valueChanged.connect(self.value_changed)
        widget.sliderMoved.connect(self.slider_position)
        widget.sliderPressed.connect(self.slider_pressed)
        widget.sliderReleased.connect(self.slider_released)

        self.setCentralWidget(widget)

    def value_changed(self, i):
        print(i)

    def slider_position(self, p):
        print("position", p)

    def slider_pressed(self):
        print("Pressed!")

    def slider_released(self):
        print("Released")

Запустив код, вы увидите круговой ползунок. Поверните его, чтобы выбрать число:

QDial на Windows, Mac и Ubuntu Linux

QDial на Windows, Mac и Ubuntu Linux

На сегодня мы заканчиваем, но это далеко не всё. Мы также расскажем о макете в PyQt, о работе с QAction, тулбарами, диалогами и не только. А пока ещё раз напоминаем о книге автора этих уроков и приглашаем на наши курсы:

  • Курс Python-разработчик

  • Профессия Fullstack-разработчик на Python

  • Курс «Python для веб-разработки»

Узнайте подробности здесь.

Профессии и курсы

PyQt is a Python library for creating GUI applications using the Qt toolkit.
Created by Riverbank Computing, PyQt is free software (GPL licensed) and has been in development since 1999. The latest version PyQt6 — based on Qt 6 —
was released in 2021 and the library continues to be updated.

This complete PyQt6 tutorial takes you from first concepts to building fully-functional GUI applications in Python.
It requires some basic Python knowledge, but no previous familiarity with GUI concepts. Everything will be introduced step by by step, using hands-on examples.

PyQt6 is the Qt6-based edition of the Python GUI library PyQt from Riverbank Computing. It was first released in January 2021.

There are two major versions currently in use: PyQt5 based on Qt5 and PyQt6 based on Qt6. Both versions are almost completely compatible aside from imports. PyQt6 also makes some changes to how namespaces and flags work, but these are easily manageable.

Looking for something else? I also have a PyQt5 tutorial, PySide2 tutorial and PySide6 tutorial.

This track consists of 27 tutorials.
Keep checking back as I’m adding new tutorials regularly — last updated 16 March 2023.

Getting started with PyQt6

Take your first steps building apps with Python & Qt6

Like writing any code, building PyQt6 applications is all about approaching it in the right way. In the first part of the course we cover the fundamentals necessary to get you building Python GUIs as quickly as possible. By the end of the first part you’ll have a running QApplication which we can then customize.

1
video

6
tutorials

1:11:03

Creating applications with Qt Designer

Using the drag-drop designer to develop your PyQt6 apps

As your applications get larger or interfaces become more complicated, it can get a bit cumbersome to
define all elements programmatically. The good news is that Qt comes with a graphical editor Qt Designer (or Qt Creator)
which contains a drag-and-drop UI editor — Qt Designer. In this PyQt6 tutorial we’ll cover the basics
of creating Python GUIs with Qt Designer.

Mozzarella Ashbadger

Build your own tabbed web browser with PyQt6

Now we’ve learnt the basics, we’ll put it into practice building a real-life app.
In this course we’ll create a functional web browser using PyQt6 widgets.
Starting with the basics and then gradually extending it to add features like opening and saving pages, help,
printing and tabbed browsing. Follow the tutorial step by step to create
your own app, but feel free to experiment as you go.

This course is not yet ready to take, but I’m working on it.
Check back shortly.

Extended UI features

Extending your apps with complex GUI behaviour

In this PyQt6 tutorial we’ll cover some advanced features of Qt that you can use to improve
your Python GUIs.

Threads & Processes

Run concurrent tasks without impacting your PyQt6 UI

As your applications become more complex you may finding yourself wanting to perform long-running tasks, such as interacting with remote APIs or performing complex calculations. By default any code you write exists in the same thread and process, meaning your long-running code can actually block Qt execution and cause your Python GUI app to «hang». In this PyQt6 tutorial we’ll cover how to avoid this happening and keep your applications running smoothly, no matter the workload.

ModelViews and Databases

Connecting your PyQt6 application to data sources

All but the simplest of apps will usually need to interact with some kind of external data store —
whether that’s a database, a remote API or simple configuration data. The Qt ModelView architecture
simplifies the linking and updating your UI with data in custom formats or from external sources. In
this PyQt6 tutorial we’ll discover how you can use Qt ModelViews to build high performance Python GUIs.

Graphics and Plotting

Vector graphics and plotting using PyQtGraph in PyQt6

Python is one of the most popular languages in the data science and machine learning fields. Effective visualization of data is a key part of building usable interfaces for data science. Matplotlib is the most popular plotting library in Python, and comes with support for PyQt6 built in. In addition, there are PyQt6-specific plotting options available such as PyQtGraph which provide a better interactive experience. In this tutorial we’ll look at these alternatives and build some simple plot interfaces.

QGraphics Framework

Vector graphic interfaces

The PyQt6 Graphics View framework is a scene-based vector graphics API. Using this you can create dynamic interactive interfaces for anything from vector graphics tools, data analysis workflow designers to simple 2D games.
The Graphics View Framework allows you to develop fast & efficient scenes, containing millions of items, each with their own distinct graphic features and behaviors.

Designing your own custom widgets in PyQt6

Widgets in Qt are built on bitmap graphics — drawing pixels on a rectangular canvas to
construct the «widget». To be able to create your own custom widgets you first need to understand
how the QPainter system works and what you can do with it. In this PyQt6 tutorial we’ll go
from basic bitmap graphics to our own entirely custom widget.

Packaging and distribution

Sharing your awesome PyQt6 applications with other people

There comes a point in any app’s development where it needs to leave home — half the fun in writing software is being able to share it with other people. Packaging Python GUI apps can be a little tricky, but in this PyQt6 tutorial we’ll cover how to package up your apps to share, whether commercially or just for fun.

QtQuick & QML

Building modern PyQt6 GUIs with QtQuick & QML

Qt Quick is Qt’s declarative UI design system, using the Qt Modeling Language (QML) to define custom user interfaces. Originally developed for use in mobile applications, it offers dynamic graphical elements and fluid transitions and effects allowing you to replicate the kinds of UIs you find on mobile devices. Qt Quick is supported on all desktop platforms too and is a great choice for building desktop widgets or other interactive tools. Qt Quick is also a great choice for developing UIs for hardware and microcontrollers with PyQt6.

This PyQt tutorial helps you develop beautiful GUI applications from scratch with PyQt6.

PyQt Tutorial

What’ll you learn

  • Create beautiful desktop applications using PyQt6.
  • Understand the core concepts of PyQt6 including the event loop, slots and signal, and widgets.
  • Use the Qt Designer tool.

Who this PyQt tutorial is for

We create this PyQt tutorial for intermediate Python programmers who want to make powerful and beautiful desktop applications. We assume that you have been working with Python and understanding Python object-oriented programming.

Section 1. Getting Started

This section helps you get started with PyQt by developing the first but famous program that shows the Hello World message and helps you understand how PyQt works under the hood.

  • PyQt Hello World – show you how to create a PyQt program that displays the hello world message on a window.
  • Signals & Slots – explain how PyQt uses signals & slots to allow objects to communicate with each other.

Section 2. Basic Widgets

In this section, you’ll learn about the basic widgets including QLabel, QPushButton, and QLineEdit.

  • QLabel – display a text or an image.
  • QPushButton – create a push button or toggle button.
  • QLineEdit – show you how to create a single-line text entry widget.

Section 3. Layout Management

In this section, you’ll learn how to use Qt layout management to place and arrange widgets in the application window.

  • QHBoxLayout – learn how to arrange widgets horizontally from left to right.
  • QVBoxLayout – show you how to arrange widgets vertically from top to bottom.
  • QGridLayout – place widgets in uniform rows and columns.
  • QFormLayout – show you how to arrange widgets on data-entry forms effectively.

Section 4. More PyQt Widgets

In this section, you’ll learn how to use other commonly used PyQt widgets such as checkbox, radio button, combobox, spinner, date edit, time edit, date and time edit, and slider.

  • QCheckbox – create a checkbox.
  • QRadioButton – show you how to create a radio button and radio button group.
  • QCombobox – create a combobox.
  • QSpinBox – learn how to create a spin box that spins through a set of incremental values.
  • QDateEdit – create a widget for editing dates.
  • QTimeEdit – create a widget for editing times.
  • QDateTimeEdit – create a widget for editing both dates and times.
  • QSlider – create a slider that controls a bounded value.
  • QWidget – create a container that holds child widgets.
  • QTabWidget – create a tab widget that groups related widgets into pages.
  • QGroupBox – create a group box with a title that groups related widgets.
  • QTextEdit – create a widget that supports multiline text editing.
  • QProgressBar – create a progress bar widget.

Section 5. Message Boxes & Dialogs

This section introduces to you the message boxes, input dialogs, and file dialogs so that you can create more interactive applications.

  • QMessageBox – show you how to create common message boxes including information, warning, critical, and question.
  • QInputDialog – learn how to create a simple dialog to get input from the user.
  • QFileDialog – guide you on how to create a file dialog that selects one or more files or a directory.

Section 6. Main Window, Menus, Toolbars, and Status Bars

This section shows you how to create the main window and other commonly used widgets like menu bars, toolbars, and status bars. We’ll develop a simple text editor program.

  • QMainWindow – show you how to create the main window that supports the menu bars, toolbars, and status bars.
  • QMenu – show you how to create a menu bar and add menu items to the menu bar.
  • QToolBar – learn how to create a toolbar and add it to the main window.
  • QStatusBar – guide you on how to create a status bar for the main window.
  • QDockWidget – show you how to create a dock widget.

Section 7. List, Table, and Tree Widgets

This section introduces to you the widgets for presenting data including list, table, and tree widgets.

  • QListWidget – show you how to use the list widget.
  • QTableWidget – learn how to use the table widget to display tabular data.
  • QTreeWidget – guide you on how to present hierarchical data on a tree widget.

Section 8. Qt Designer

  • Qt Designer – show you how to design user interfaces using Qt Designer.

Section 9. PyQt & Concurrency

This section shows you how to create a responsive PyQt application using multithreading techniques.

  • QThread – show you how to use QThread class to offload a long-running operation to a worker thread from the main thread.
  • QThreadPool – learn how to use the QThreadPool and QRunnable classes to manage and recycle worker threads automatically.

Section 10. Theming

This section guides you on how to customize the Qt widgets using Qt style sheets, themes, and icons.

  • Qt Style Sheets – show you how to use the Qt Style Sheets (QSS) to customize the appearance of the widgets.

Section 11. PyQt Model/View Pattern

  • Model/view pattern – learn about model/view pattern in PyQt.

Section 12. Package & distribute PyQt apps

  • PyQt to EXE – show you how to convert a PyQt program to an executable file using PyInstaller.

Did you find this tutorial helpful ?

In this PyQt6 Tutorial we are going to talk about Building Python GUI Application with PyQt6. first of all let’s talk about PyQt6 and the installation process.

What is Python PyQt6 ?

PyQt6 is a set of Python bindings for Qt application framework and GUI library. Qt is cross platform application development library and it is widely used for developing software applications with graphical user interfaces. PyQt6 allows developers to write Qt applications in Python and it is popular choice for Python developers who want to create cross platform desktop applications. PyQt6 provides access to all the classes and functions of the Qt framework, and all developers can create rich and interactive graphical user interfaces with features such as drag and drop, internationalization, threading and multimedia support. PyQt6 also includes supports for different platforms like Windows, macOS, Linux and mobile platforms such as Android and iOS, and PyQt6 is the latest version of PyQt, and it supports the latest version of Qt.

First of all we need to install PyQt6 and you can use pip for the installation.

Let’s start by creating  simple PyQt6  GUI application. basically we want to create our basic GUI window with Python PyQt6.

import sys

from PyQt5.QtWidgets import QApplication, QWidget

app = QApplication(sys.argv)

# Create window

window = QWidget()

window.setWindowTitle(‘Geekscoders — Learn PyQt6’)

window.setGeometry(100, 100, 300, 200)

window.show()

# Run event loop

sys.exit(app.exec())

Now let’s talk about above code, now this code will be similar to PyQt5 code if you are familiar with that,  first we have imported sys module and  QApplication and QWidget classes from the PyQt5.QtWidgets module. after that it creates an instance of the QApplication class with the system arguments passed as parameter. this initializes Qt application. after that it creates an instance of the QWidget class and sets its window title to Geekscoders – Learn PyQt6. it also sets the position and size of the window using the setGeometry() method, after that window is shown using the show() method, and finally event loop is started by calling app.exec(). this method runs the application event loop which handles user events and system events until the application is terminated. sys.exit() call ensures that the program exits cleanly when the event loop is terminated.

If you run the code you will see this result

PyQt6 Tutorial - Building Python GUI Applications

PyQt6 Tutorial – Building Python GUI Applications

Now let me give you some more information about the modules that we have used in the above example.

What is PyQt6 QApplication ?

PyQt6 QApplication is class that represents the application object for PyQt6 application. it provides the necessary functionalities to initialize Qt application, handle events and manage application main event loop. when PyQt6 application is launched, QApplication object needs to be created before any other Qt widgets or objects. QApplication constructor takes an optional list of command line arguments which can be used to specify different application settings and options. QApplication class also provides methods to set and retrieve application wide properties such as the application name, organization name and application version number. these properties can be used by other Qt widgets and objects to customize their behavior.

QtWidgets Module in PyQt6 

QtWidgets module in PyQt6 is core module that provides different classes for creating and managing graphical user interfaces (GUIs) in PyQt6 application. this module includes different layout managers and other utility classes that make it easy to build complex and interactive desktop applications, QtWidgets module includes classes for handling input events such as mouse clicks and keyboard input and for displaying 2D graphics such as images and text.

Some of the most commonly used classes in the QtWidgets module include:

QWidget Base class for all user interface objects in PyQt6. It provides basic functionality needed to create and display a window.
QMainWindow Main application window that provides  central area for displaying the application content as well as a menu bar, toolbars and  status bar.
QLabel A widget that can display text and images.
QPushButton A button widget that can be clicked by the user.
QLineEdit Widget that allows the user to enter text.
QTextEdit Widget that allows the user to edit and display multiline text.
QComboBox A widget that provides a dropdown list of items.
QCheckBox A widget that can be checked or unchecked by the user.
QRadioButton A widget that allows the user to select one option from a group of options.
QSpinBox A widget that allows the user to enter an integer value.
QDoubleSpinBox A widget that allows the user to enter a floating point value.
QSlider A widget that allows the user to select a value by moving a slider.
QProgressBar Widget that displays a progress bar.
QTreeView A widget that displays hierarchical data in tree like structure.
QTableWidget A widget that displays tabular data in a grid.
QDockWidget Widget that can be docked and undocked from the main application window.
QSplitter A widget that allows the user to resize two or more widgets by dragging a handle.

These are just some of the most commonly used classes in the QtWidgets module. there are many other classes and tools available in this module that make it possible to create complex and sophisticated graphical user interfaces for desktop applications.

Now let’s talk about PyQt6 layout manager classes that are available in QtWidgets module.

Layout Management in PyQt6 ?

Layout management in PyQt6 is the process of arranging widgets in window or dialog in a way that is both visually appealing and responsive to changes in the window size or content. PyQt6 provides several layout managers that make it easy to create complex and dynamic layouts for desktop applications. layout managers automatically adjust the position and size of widgets in response to changes in the window size or content. they ensure that widgets are spaced evenly and that there is enough room for all the widgets in the window.

These are some of the mostly used layout managers in PyQt6

QHBoxLayout Arranges widgets in a horizontal row.
QVBoxLayout Arranges widgets in a vertical column.
QGridLayout Arranges widgets in a grid of rows and columns.
QFormLayout Arranges widgets in a grid of labels and input fields.
QStackedLayout Allows widgets to be stacked on top of each other, with only one widget visible at a time.

So we have learned that how we can create simple GUI window with PyQt6, now let’s use OOP, and create our Python PyQt6 GUI Application window with OOP.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

import sys

from PyQt5.QtWidgets import QApplication, QWidget

class Window(QWidget):

    def __init__(self):

        super().__init__()

        # Set window properties

        self.setWindowTitle(‘Geekscoders — Learn PyQt6’)

        self.setGeometry(100, 100, 300, 200)

        # Show window

        self.show()

if __name__ == ‘__main__’:

    # Create application object

    app = QApplication(sys.argv)

    # Create window object

    window = Window()

    # Run event loop

    sys.exit(app.exec())

In the above code we have created Window class that inherits from the QWidget class provided by PyQt6. after that we have defined __init__ method to set the window properties and show the window. we have created an instance of the QApplication class and store it in the app variable, and then creates an instance of the Window class and store it in the window variable. and lastly we start the event loop by calling the exec method of the QApplication object and pass control to the event loop until the user closes the window or exits the application, if you run the code you will see the same PyQt6 GUI Application window.

Right now we have just a basic window in Pyyhon PyQt6, now let’s add some widgets to the window and we want to learn about some important widgets in PyQt6.

PyQt6 QLabel

QLabel is a class in PyQt6 that provides text or image display area. it is used to display static text, images or pixmap. QLabel can display text in different formats such as plain text, HTML, and rich text. it also supports alignment, margin and padding properties. QLabel can be used as standalone widget or as a component of a more complex user interface. you can set the text or image to be displayed in the QLabel using the setText() and setPixmap() methods, and you can also set the alignment of the text or image using the setAlignment() method.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

import sys

from PyQt6.QtWidgets import QApplication, QWidget, QLabel, QHBoxLayout, QVBoxLayout

from PyQt6.QtGui import QPixmap

class LabelExample(QWidget):

    def __init__(self):

        super().__init__()

        # Set window properties

        self.setWindowTitle(‘QLabel Example’)

        self.setGeometry(100, 100, 300, 200)

        # Create QLabel and set pixmap

        label = QLabel()

        pixmap = QPixmap(‘pic2.png’)

        label.setPixmap(pixmap)

        label2 = QLabel(«Welcome to Geekscoders.com»)

        # Create horizontal and vertical layouts

        hbox = QHBoxLayout()

        vbox = QVBoxLayout()

        # Add label to horizontal layout

        hbox.addWidget(label)

        hbox.addWidget(label2)

        # Add horizontal layout to vertical layout

        vbox.addLayout(hbox)

        # Set main window layout

        self.setLayout(vbox)

        # Show window

        self.show()

if __name__ == ‘__main__’:

    # Create application object

    app = QApplication(sys.argv)

    # Create window object

    window = LabelExample()

    # Run event loop

    sys.exit(app.exec())

In this example we have created QLabel object and set its pixmap using the setPixmap() method, also we have added a text to the label. after that we creates horizontal layout (and a vertical layout. we  have added QLabel to the horizontal layout using the addWidget() method, and then add the horizontal layout to the vertical layout using the addLayout() method. and finally we set the main window layout to the vertical layout using the setLayout() method.

Run the code and this will be the result

PyQt6 Tutorial - Building Python GUI Application

PyQt6 Tutorial – Building Python GUI Application

PyQt6 QPushButton

QPushButton is a class in PyQt6 that represents push button widget. it is used to create clickable buttons that perform an action when clicked. QPushButton can display text an icon or both.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

import sys

from PyQt6.QtWidgets import QApplication, QWidget, QLabel, QPushButton, QVBoxLayout

from PyQt6.QtGui import QFont

class ButtonExample(QWidget):

    def __init__(self):

        super().__init__()

        # Set window properties

        self.setWindowTitle(‘QPushButton Example’)

        self.setGeometry(100, 100, 300, 200)

        # Creat QLabel and QPushButton

        self.label = QLabel(‘Hello World’, self)

        self.button = QPushButton(‘Click me’, self)

        # Connect button to function

        self.button.clicked.connect(self.on_button_click)

        # Creat vertical layout

        layout = QVBoxLayout()

        layout.addWidget(self.label)

        layout.addWidget(self.button)

        # Set window layout

        self.setLayout(layout)

        # Show window

        self.show()

    def on_button_click(self):

        self.label.setText(‘Welcome to Geekscoders.com’)

        self.label.setFont(QFont(«Times», 15))

        self.label.setStyleSheet(‘color:red’)

if __name__ == ‘__main__’:

    # Create application object

    app = QApplication(sys.argv)

    # Create window object

    window = ButtonExample()

    # Run event loop

    sys.exit(app.exec())

In this example we have created QLabel and QPushButton. we connect the clicked signal of the button to a function on_button_click() that sets the text of the label to Welcome to Geekscoders.com using the setText() method, also changes the text font size with color. we have used vertical layout to organize the widgets and add both the label and button to the layout using addWidget(). and at the end we set the main window layout to the vertical layout using the setLayout() method.

Run the code click on the button and this will be the result

PyQt6 Tutorial - PyQt6 QPushButton

PyQt6 Tutorial – Building Python GUI Application

PyQt6 QLineEdit

QLineEdit is PyQt6 class that provides single line text editor. it allows users to input and edit text and supports different features such as undo/redo, copy/paste and drag and drop.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

import sys

from PyQt6.QtWidgets import QApplication, QWidget, QLineEdit, QLabel, QVBoxLayout

from PyQt6.QtGui import QFont

class LineeditExample(QWidget):

    def __init__(self):

        super().__init__()

        # Set window properties

        self.setWindowTitle(‘QLineEdit Example’)

        self.setGeometry(100, 100, 300, 200)

        # Create QLineEdit and QLabel widgets

        self.line_edit = QLineEdit(self)

        self.label = QLabel(self)

        self.label.setFont(QFont(«Times», 15))

        # Create vertical layout

        layout = QVBoxLayout()

        layout.addWidget(self.line_edit)

        layout.addWidget(self.label)

        # Set window layout

        self.setLayout(layout)

        # Show window

        self.show()

        # Connect signal to slot

        self.line_edit.returnPressed.connect(self.on_return_pressed)

    def on_return_pressed(self):

        # Get text from QLineEdit

        text = self.line_edit.text()

        # Set text of QLabel

        self.label.setText(text)

if __name__ == ‘__main__’:

    # Create application object

    app = QApplication(sys.argv)

    # Create window object

    window = LineeditExample()

    # Run event loop

    sys.exit(app.exec())

In this example we have added QLabel widget to the window and update its text whenever the user presses Enter key in the QLineEdit widget. we achieve this by connecting the returnPressed signal of the QLineEdit to the on_return_pressed() slot function which retrieves the text from the QLineEdit using the text() method and sets the text of the QLabel using the setText() method.

Run the code and this will be the result

PyQt6 Tutorial - Building Python GUI Application

PyQt6 Tutorial – Building Python GUI Application

PyQt6 QTextEdit

QTextEdit is a widget in PyQt6 that provides rich text editing area. it allows users to enter and edit formatted text including images, lists, tables and many more. QTextEdit widget is multiline text box that supports rich text formatting, so it is ideal for creating a text editor,  word processor or note taking application.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

import sys

from PyQt6.QtWidgets import QApplication, QTextEdit, QPushButton, QVBoxLayout, QWidget, QFileDialog

class TextEdit(QWidget):

    def __init__(self):

        super().__init__()

        # Set window properties

        self.setWindowTitle(‘QTextEdit Example’)

        self.setGeometry(100, 100, 500, 400)

        # Create QTextEdit widget

        self.text_edit = QTextEdit()

        # Create QPushButton widget

        self.save_button = QPushButton(‘Save’)

        # Create layout

        layout = QVBoxLayout()

        layout.addWidget(self.text_edit)

        layout.addWidget(self.save_button)

        # Connect signal to slot

        self.save_button.clicked.connect(self.save_text)

        self.setLayout(layout)

    def save_text(self):

        # Open file dialog to select file

        file_name, _ = QFileDialog.getSaveFileName(self, ‘Save File’, », ‘Text Files (*.txt)’)

        if file_name:

            # Open file and write text to it

            with open(file_name, ‘w’) as f:

                f.write(self.text_edit.toPlainText())

if __name__ == ‘__main__’:

    # Create application object

    app = QApplication(sys.argv)

    # Create window object

    window = TextEdit()

    # Show window

    window.show()

    # Run event loop

    sys.exit(app.exec())

In the above example we have created our window with QTextEdit widget and Save button. when the user clicks Save button, we open a file dialog to let the user choose where to save the file. if the user selects a file, we open the file and write the contents of the QTextEdit widget to it using the toPlainText() method. this method returns the plain text contents of the QTextEdit widget as a string.

This will be the result

PyQt6 Tutorial - Building Python GUI Application

PyQt6 Tutorial – Building Python GUI Application

PyQt6 QComboBox

QComboBox is PyQt6 widget that provides drop down list of selectable items. it allows users to select one item from a list of options which can be defined in code or loaded from data source such as a file or database. QComboBox provides several useful methods for adding and removing items, setting the currently selected item and responding to changes in the selected item. it also supports customization of the appearance and behavior of the drop down list including the ability to set the maximum number of visible items and to enable or disable auto completion of the selected item.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

import sys

from PyQt6.QtWidgets import QApplication, QLabel, QComboBox, QVBoxLayout, QWidget

from PyQt6.QtGui import QFont

class ComboExample(QWidget):

    def __init__(self):

        super().__init__()

        # Set window properties

        self.setWindowTitle(‘QComboBox Example’)

        self.setGeometry(100, 100, 400, 200)

        # Create QLabel widget

        self.label = QLabel(‘Select a programming language:’)

        # Create QComboBox widget

        self.combo_box = QComboBox()

        self.combo_box.addItems([‘Python’, ‘Java’, ‘C++’, ‘JavaScript’, ‘Ruby’, ‘PHP’])

        # Create layout

        layout = QVBoxLayout()

        layout.addWidget(self.label)

        layout.addWidget(self.combo_box)

        self.setLayout(layout)

        # Connect signal to slot

        self.combo_box.currentIndexChanged.connect(self.update_label)

    def update_label(self, index):

        self.label.setText(f‘You selected {self.combo_box.itemText(index)}’)

        self.label.setFont(QFont(«Times», 15))

if __name__ == ‘__main__’:

    # Create application object

    app = QApplication(sys.argv)

    # Create window object

    window = ComboExample()

    # Show window

    window.show()

    # Run event loop

    sys.exit(app.exec())

In this example we have created window with QComboBox widget and QLabel widget. QComboBox is populated with a list of programming languages and the selected language is displayed in the QLabel when the user selects an item from the drop down list. currentIndexChanged signal of the QComboBox is connected to a slot that updates the text of the QLabel with the currently selected item.

Run the code and this will be the result

PyQt6 Tutorial QComboBox

PyQt6 Tutorial QComboBox

PyQt6 QCheckBox

QCheckBox is PyQt6 widget that provides checkable box that can be used to select or deselect an option. it can be used to present simple yes/no or true/false choice or to represent binary option in a more complex user interface. QCheckBox provides several useful methods for setting and getting the state of the check box, setting the text label displayed next to the box and responding to changes in the state of the check box. it also supports customization of the appearance and behavior of the check box, including the ability to set the size, font and style of the check box and label.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

import sys

from PyQt6.QtWidgets import QApplication, QLabel, QCheckBox, QVBoxLayout, QWidget

class CheckBoxExample(QWidget):

    def __init__(self):

        super().__init__()

        # Set window properties

        self.setWindowTitle(‘QCheckBox Example’)

        self.setGeometry(100, 100, 400, 200)

        # Create QLabel widget

        self.label = QLabel(‘Select options:’)

        # Create QCheckBox widgets

        self.check_box1 = QCheckBox(‘Option 1’)

        self.check_box2 = QCheckBox(‘Option 2’)

        # Create layout

        layout = QVBoxLayout()

        layout.addWidget(self.label)

        layout.addWidget(self.check_box1)

        layout.addWidget(self.check_box2)

        self.setLayout(layout)

        # Connect signals to slots

        self.check_box1.stateChanged.connect(self.update_label)

        self.check_box2.stateChanged.connect(self.update_label)

    def update_label(self):

        text = f‘Options selected: ‘

        if self.check_box1.isChecked():

            text += f‘{self.check_box1.text()} ‘

        if self.check_box2.isChecked():

            text += f‘{self.check_box2.text()} ‘

        if not self.check_box1.isChecked() and not self.check_box2.isChecked():

            text += ‘none’

        self.label.setText(text)

if __name__ == ‘__main__’:

    # Create application object

    app = QApplication(sys.argv)

    # Create window object

    window = CheckBoxExample()

    # Show window

    window.show()

    # Run event loop

    sys.exit(app.exec())

In the above example we have created a window with two QCheckBox widgets and QLabel widget. state of the check boxes is displayed in the QLabel when the user toggles them. stateChanged signal of each QCheckBox is connected to a slot that updates the text of the QLabel with the currently selected options. if neither check box is selected the label displays none.

Run the code and this is the result

PyQt6 Tutorial QCheckBox

PyQt6 Tutorial QCheckBox

PyQt6 QRadioButton

QRadioButton is PyQt6 widget that allows the user to select one option from a group of options. it is similar to QCheckBox but the user can select only one option at a time. QRadioButton inherits from QAbstractButton class. QRadioButton works by grouping several radio buttons together using a QButtonGroup. QButtonGroup ensures that only one radio button can be selected at a time. when radio button is selected it emits toggled signal. you can connect to this signal to perform some action when the radio button is selected.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

import sys

from PyQt6.QtWidgets import QApplication, QWidget, QLabel,QRadioButton, QVBoxLayout

from PyQt6.QtGui import QFont

class RadioExample(QWidget):

    def __init__(self):

        super().__init__()

        # Set window properties

        self.setWindowTitle(‘QRadioButton Example’)

        self.setGeometry(100, 100, 400, 200)

        # Create QRadioButton widgets

        self.radio_button1 = QRadioButton(‘Python’)

        self.radio_button2 = QRadioButton(‘Java’)

        self.radio_button3 = QRadioButton(‘C++’)

        self.label = QLabel()

        self.label.setFont(QFont(«Times», 15))

        self.label.setStyleSheet(‘color:red’)

        # Create layout

        layout = QVBoxLayout()

        layout.addWidget(self.radio_button1)

        layout.addWidget(self.radio_button2)

        layout.addWidget(self.radio_button3)

        layout.addWidget(self.label)

        # Set layout

        self.setLayout(layout)

        # Connect signals to slots

        self.radio_button1.toggled.connect(self.on_radio_button_toggled)

        self.radio_button2.toggled.connect(self.on_radio_button_toggled)

        self.radio_button3.toggled.connect(self.on_radio_button_toggled)

    def on_radio_button_toggled(self, checked):

        if checked:

            if self.radio_button1.isChecked():

                self.label.setText(«Python is selected»)

            elif self.radio_button2.isChecked():

                self.label.setText(«Java is selected»)

            elif self.radio_button3.isChecked():

                self.label.setText(‘C++ is selected’)

if __name__ == ‘__main__’:

    # Create application object

    app = QApplication(sys.argv)

    # Create window object

    window = RadioExample()

    # Show window

    window.show()

    # Run event loop

    sys.exit(app.exec())

In the above example we have created a window with three QRadioButton widgets. we group radio buttons together implicitly by adding them to the same QVBoxLayout. after that we connect the toggled signal of each radio button to a slot that prints the selected option in the label when the user selects it.

This is the result

Building Python GUI Application

Building Python GUI Application

PyQt6 QSpinBox

QSpinBox is PyQt6 widget that allows the user to select an integer value from a range of values. it is subclass of QAbstractSpinBox class. QSpinBox has spin box and two buttons, one to increment the value and another to decrement it. QSpinBox provides many properties to customize its behavior. for example you can set the minimum and maximum values, step size, and the number of digits to display. you can also set the suffix and prefix for the displayed value. QSpinBox emits valueChanged(int) signal whenever the value changes. you can connect to this signal to perform some action when the value changes.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

import sys

from PyQt6.QtWidgets import QApplication, QWidget, QLabel, QSpinBox, QVBoxLayout

from PyQt6.QtGui import QFont

class SpinExample(QWidget):

    def __init__(self):

        super().__init__()

        # Set window properties

        self.setWindowTitle(‘QSpinBox — Geekscoders.com’)

        self.setGeometry(100, 100, 400, 200)

        # Create QSpinBox widget

        self.spin_box = QSpinBox()

        self.spin_box.setMinimum(1)

        self.spin_box.setMaximum(10)

        self.spin_box.setSingleStep(1)

        self.spin_box.setValue(5)

        # Create QLabel widget

        self.label = QLabel()

        # Create layout

        layout = QVBoxLayout()

        layout.addWidget(self.spin_box)

        layout.addWidget(self.label)

        # Set layout

        self.setLayout(layout)

        # Connect signals to slots

        self.spin_box.valueChanged.connect(self.on_spin_box_value_changed)

    def on_spin_box_value_changed(self, value):

        self.label.setText(f‘Value selected: {value}’)

        self.label.setFont(QFont(«Times», 15))

if __name__ == ‘__main__’:

    # Create application object

    app = QApplication(sys.argv)

    # Create window object

    window = SpinExample()

    # Show window

    window.show()

    # Run event loop

    sys.exit(app.exec())

In the above example we have created window with QSpinBox widget that allows the user to select an integer value from 1 to 10. we have also created QLabel widget to display the selected value. we connect valueChanged signal of the QSpinBox to a slot that updates the label with the selected value whenever the value changes.

This is the result

PyQt6 QSpinBox

PyQt6 QSpinBox

PyQt6 QProgressBar

QProgressBar is PyQt6 widget that shows the progress of  long running operation. it provides graphical representation of the progress, usually as horizontal bar that grows from left to right. QProgressBar can be used to indicate the progress of file downloads, file uploads, installations or any other time-consuming task.

QProgressBar provides many properties to customize its appearance and behavior. for example you can set the minimum and maximum values, current value, and orientation of the progress bar. you can also set the text to be displayed in the progress bar and the alignment of the text. QProgressBar emits the valueChanged(int) signal whenever the value changes. you can connect to this signal to perform some action when the value changes.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

import sys

import time

from PyQt6.QtWidgets import QApplication, QWidget, QProgressBar, QPushButton, QVBoxLayout

class ProgresExample(QWidget):

    def __init__(self):

        super().__init__()

        # Set window properties

        self.setWindowTitle(‘QProgressBar — Geekscoders.com’)

        self.setGeometry(100, 100, 400, 200)

        # Creat QProgressBar widget

        self.progress_bar = QProgressBar()

        self.progress_bar.setMinimum(0)

        self.progress_bar.setMaximum(100)

        self.progress_bar.setValue(0)

        # Create QPushButton widget

        self.button = QPushButton(‘Start’)

        self.button.clicked.connect(self.start_progress)

        # Create layout

        layout = QVBoxLayout()

        layout.addWidget(self.progress_bar)

        layout.addWidget(self.button)

        # Set layout

        self.setLayout(layout)

    def start_progress(self):

        # Start progress

        for i in range(101):

            self.progress_bar.setValue(i)

            time.sleep(0.05)

if __name__ == ‘__main__’:

    # Create application object

    app = QApplication(sys.argv)

    # Create window object

    window = ProgresExample()

    # Show window

    window.show()

    # Run event loop

    sys.exit(app.exec())

In the above example we have created a window with QProgressBar widget that shows the progress of long running operation. we have also created QPushButton widget to start the progress. when the user clicks the button, we start the progress by updating the value of the progress bar in a loop. We use the setValue method of the QProgressBar widget to set the current value of the progress bar. We also use the sleep function from the time module to simulate a delay in the progress. The progress bar grows from left to right, and the text is aligned to the center of the progress bar.

This is the result

PyQt6 QProgressBar

PyQt6 QProgressBar

PyQt6 QTableWidget

QTableWidget is PyQt6 widget that provides table view with rows and columns. it allows you to display and edit tabular data in grid format. you can use QTableWidget to create tables with different numbers of rows and columns, add data to cells and customize the appearance of the table. QTableWidget provides many properties to customize its appearance and behavior. for example you can set the number of rows and columns, size of cells, text alignment of cells and selection mode. you can also set the data of cells using the setItem() method or setCellWidget() method to add widgets to cells.

QTableWidget emits several signals including cellClicked(), itemChanged() and cellDoubleClicked(). you can connect to these signals to perform some action when the user clicks or double clicks a cell or changes the data in a cell.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

import sys

from PyQt6.QtWidgets import QApplication, QWidget, QTableWidget, QTableWidgetItem, QVBoxLayout

class TableExample(QWidget):

    def __init__(self):

        super().__init__()

        # Set window properties

        self.setWindowTitle(‘QTableWidget — Geekscoders.com’)

        self.setGeometry(100, 100, 400, 200)

        # Creat QTableWidget widget

        self.table = QTableWidget()

        self.table.setColumnCount(3)

        self.table.setRowCount(2)

        self.table.setHorizontalHeaderLabels([‘Name’, ‘Age’, ‘Gender’])

        # Set data to cell

        self.table.setItem(0, 0, QTableWidgetItem(‘Geekscoders’))

        self.table.setItem(0, 1, QTableWidgetItem(’25’))

        self.table.setItem(0, 2, QTableWidgetItem(‘Male’))

        self.table.setItem(1, 0, QTableWidgetItem(‘John’))

        self.table.setItem(1, 1, QTableWidgetItem(’30’))

        self.table.setItem(1, 2, QTableWidgetItem(‘Female’))

        # Create layout

        layout = QVBoxLayout()

        layout.addWidget(self.table)

        # Set layout

        self.setLayout(layout)

if __name__ == ‘__main__’:

    # Create application object

    app = QApplication(sys.argv)

    # Create window object

    window = TableExample()

    # Show window

    window.show()

    # Run event loop

    sys.exit(app.exec())

In the above example we have created a window with QTableWidget widget that shows a table with two rows and three columns. we have also set the horizontal header labels to Name, Age and Gender. we use the setItem() method to set the data of cells. we creates  QTableWidgetItem object for each cell and set the text of the object. and at the end we add the table to the window layout.

This will be the result

PyQt6 QTableWidget

PyQt6 QTableWidget

PyQt6 QTreeView

PyQt6 QTreeView is a widget that displays data in hierarchical tree like structure. it allows the user to expand and collapse the nodes to view or hide the child items. QTreeView is used for displaying data that has a hierarchical structure such as file system, directory structure, or  tree data structure. data is displayed in tree like format where each node represents a parent item and its children are displayed as sub nodes. it also allows for the user to interact with the data displayed in the tree view such as editing or deleting items.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

import sys

from PyQt6.QtGui import QStandardItem, QStandardItemModel

from PyQt6.QtWidgets import QApplication, QTreeView, QWidget, QVBoxLayout

class TreeViewExample(QWidget):

    def __init__(self):

        super().__init__()

        # Set up the window

        self.setWindowTitle(«QTreeView Example»)

        self.setGeometry(100, 100, 400, 400)

        # Create the model and set up some data

        self.model = QStandardItemModel()

        self.model.setHorizontalHeaderLabels([«Name», «Age»])

        self.root_node = self.model.invisibleRootItem()

        for name, age in [(«Geekscoders», 25), («Bob», 30), («John», 35)]:

            parent = QStandardItem(name)

            parent.appendRow([QStandardItem(name), QStandardItem(str(age))])

            self.root_node.appendRow(parent)

        # Create the tree view and set the model

        self.tree_view = QTreeView()

        self.tree_view.setModel(self.model)

        self.tree_view.setEditTriggers(QTreeView.EditTrigger.NoEditTriggers)  # Prevent editing of items

        # Set up the layout

        layout = QVBoxLayout()

        layout.addWidget(self.tree_view)

        self.setLayout(layout)

if __name__ == «__main__»:

    app = QApplication(sys.argv)

    window = TreeViewExample()

    window.show()

    sys.exit(app.exec())

This code creates simple window with QTreeView widget that displays some data with  hierarchical structure. data is stored in QStandardItemModel which is then set as the model for QTreeView. each parent item is QStandardItem with name and each child item is a list of QStandardItems with name and an age. when the window is run QTreeView will display the data in tree like format with each parent item displayed as node with expand/collapse button, and its children displayed as sub nodes.

This will be the result

PyQt6 QTreeView

PyQt6 QTreeView

Learn More

  • Python PyQt5 Tutorial
  • Python TKinter Tutorial

Введение В этом руководстве мы рассмотрим, как использовать среду Python PyQT [https://www.riverbankcomputing.com/static/Docs/PyQt6/] для разработки графического интерфейса пользователя (GUI) для настольного приложения в Python. Популярные альтернативы Python для разработки графического интерфейса включают Tkinter [https://docs.python.org/3/library/tkinter.html], Kivy [https://kivy.org/#home], PySimpleGUI [https: // pysimplegui .readthedocs.io / en / latest /] и wxPython [https://www.wxpython.org/]. Примечание: на момент написания

Вступление

В этом руководстве мы рассмотрим, как использовать
среду Python
PyQT для разработки графического интерфейса пользователя (GUI) для
настольного приложения на Python.

Популярные альтернативы Python для разработки графического интерфейса
включают Tkinter ,
Kivy ,
PySimpleGUI
и
wxPython .

Примечание. На момент написания этого руководства PyQt6 — это
последняя и наиболее продвинутая версия инфраструктуры Python PyQT, а
также версия, которую мы будем использовать.

Мы пройдем через процесс установки и познакомимся с ключевыми элементами
PyQT, прежде чем перейти к менеджерам компоновки , виджетам ,
сигналам и слотам, а также к тому, как стилизовать виджеты , а также
взглянем на файлы пользовательского интерфейса, и как создавать
пользовательские интерфейсы с помощью интуитивно понятного интерфейса
перетаскивания, который мы затем можем экспортировать в исполняемые
скрипты Python:

  • Монтаж

  • Введение в PyQt

  • Менеджеры по компоновке

  • Виджеты

    • Этикетки
    • Кнопки
    • Редактирование строки
    • Поля со списком
    • Радио-кнопки
    • Отображение данных с помощью виджета таблицы
    • Отображение данных с помощью виджета в виде дерева
  • Сигналы и слоты

  • Стилизация приложений-виджетов

  • Файлы пользовательского интерфейса

    • qtDesigner
    • Преобразование файлов пользовательского интерфейса в Python
  • Заключение

Монтаж

Чтобы использовать фреймворк
PyQt, нам
сначала нужно установить его с помощью диспетчера пакетов pip.

Если в вашей системе установлен pip, давайте запустим следующую команду,
чтобы установить новейшую версию PyQt:

 $ pip install pyqt6 

Если pip install pyqt6 завершится неудачно, вы можете проверить
наличие изменений при установке
здесь
.

Введение в PyQt

PyQt — это набор инструментов, который является продуктом библиотеки
Qt и языка программирования Python. Поскольку PyQt
является одним из наиболее часто используемых GUI-фреймворков для
Python, существует как тонна хорошо написанной документации, так и
большое сообщество.

Одним из основных классов PyQt является
QWidget

  • реализация виджета . Виджеты — это компоненты графического
    интерфейса и основные строительные блоки пользовательских интерфейсов.
    Виджет может быть меткой, кнопкой, меню, полем со списком, скроллером,
    панелью инструментов, диалоговым окном файла и т. Д.

Есть много виджетов, и чтобы привыкнуть к ним, нужно время. Мы
рассмотрим наиболее часто используемые виджеты, которые по большей части
будут присутствовать почти в каждом приложении PyQt.

Относительный порядок этих виджетов во фрейме приложения диктуется и
управляется менеджером компоновки . Мы также рассмотрим доступные
менеджеры компоновки и их влияние на расположение компонентов
графического интерфейса.

Точкой входа в каждое приложение PyQt является QApplication , который
представляет само приложение. Он обрабатывает всю инициализацию и
«холст», на котором мы рисуем.

Примечание. Всегда существует только один QApplication ,
независимо от количества окон или модальных блоков в вашем приложении.

Давайте сделаем рывок и инициализируем приложение PyQt, а также
инициализируем окно с пустым холстом:

 import sys 
 from PyQt6.QtWidgets import QApplication, QWidget 
 app = QApplication(sys.argv) 
 root = QWidget() 
 root.setWindowTitle('A Simple PyQt6 App') 
 root.setGeometry(100, 100, 280, 80) 
 root.show() 
 sys.exit(app.exec()) 

Запуск этого кода инициализирует простое приложение:

{.ezlazyload}

Давайте рассмотрим эту инициализацию построчно.

Во-первых, мы импортируем встроенный sys который предоставляет нам
функции для управления средой выполнения Python . В нашем случае мы
будем использовать этот модуль для обработки статуса выхода приложения —
когда пользователь нажимает кнопку «X»:

 import sys 

Затем мы можем импортировать QApplication (основу) и QWidget
(компоненты GUI) из модуля PyQt6.QtWidgets

 from PyQt6.QtWidgets import QApplication, QWidget 

Далее, эта строка является требованием QT. Он инициализирует PyQT.
Sys.argv содержит список всех аргументов командной строки, переданных
приложению. Каждое созданное вами приложение с графическим интерфейсом
пользователя должно иметь ровно один экземпляр QApplication.

Теперь, поскольку QApplication отвечает за инициализацию большинства
элементов, участвующих в разработке приложений PyQt, мы хотим сначала
создать его экземпляр. Конструктор принимает sys.argv поскольку вы
также можете передавать аргументы командной
строки :

 app = QApplication(sys.argv) 

Теперь в QApplication фактически нет окон. Запуск приложения без окна
даст нам невидимый результат. Чтобы на самом деле представить окно в
миксе, мы создадим корневой виджет , который также известен как
оконный виджет . В любом случае он представляет собой самый нижний
виджет, в который мы будем добавлять другие компоненты:

 root = QWidget() 

Давайте установим собственный заголовок окна с помощью
setWindowTitle() :

 root.setWindowTitle('A Simple PyQt6 App') 

Метод setGeometry() принимает 4 аргумента: x_coordinate ,
y_coordinate , width и height . x_coordinate и y_coordinate
определяют исходную точку окна при отображении:

 root.setGeometry(100, 100, 280, 80) 

Теперь, чтобы отобразить созданный графический интерфейс на экране, мы
вызываем метод show() в root :

 root.show() 

Наконец, мы выполняем приложение через app.exec() и запускаем основной
цикл приложения, пока пользователь не закроет его:

 sys.exit(app.exec()) 

Менеджеры по компоновке

Менеджеры компоновки PyQt предоставляют нам эффективный способ
упорядочивания виджетов PyQt в графическом интерфейсе. Чем лучше мы
размещаем наши виджеты, тем более изысканным и профессиональным может
выглядеть наше приложение с графическим интерфейсом пользователя.
Неуклюжие, огромные промежутки между кнопками без особого использования
пространства не очень удобны для пользователя. То же самое касается и
наоборот — если мы поместим кнопки слишком близко, их станет неудобно
легко нажимать неправильно.

Самыми популярными классами диспетчера макетов PyQt являются:

  1. QVBoxLayout размещает
    виджеты вертикально.
  2. QHBoxLayout размещает
    виджеты по горизонтали.
  3. QGridLayout размещает
    виджеты в сетке.
  4. QFormLayout размещает
    виджеты в двух столбцах.

При создании приложений с графическим интерфейсом пользователя с PyQt вы
часто будете использовать более одного из четырех менеджеров компоновки
общего назначения, даже в одном приложении, для разных типов окон.

Давайте воспользуемся предыдущим примером и обновим его, добавив
несколько виджетов, таких как QPushButton и управляя ими с помощью
диспетчера макетов.

1. QVBoxLayout

Диспетчер макетов ящиков (как QVBox, так и QHBox) использует все
пространство, которое он получает от родительского макета или виджета, и
делит его на несколько ящиков.

Каждый виджет, управляемый менеджером, заполнит одно поле.

QVBoxLayout позволяет нам расположить наши виджеты вертикально. Макет
добавляет виджеты к себе последовательно сверху вниз. Таким образом,
первый виджет, добавленный в ваш код, будет самым верхним виджетом, а
последний виджет, добавленный в ваш код, будет самым нижним виджетом в
макете.

Давайте добавим несколько кнопок в наше приложение через QVBoxLayout :

 #!/usr/bin/python 
 # Import all needed modules 
 import sys 
 from PyQt6.QtWidgets import QApplication, QPushButton, QVBoxLayout, QWidget 
 
 # Create the Qt Application 
 app = QApplication(sys.argv) 
 
 # Create the root Widget/Window 
 window = QWidget() 
 
 # Create the Vertical Box Layout Manager, setting `window` as parent by passing it in the constructor. 
 layout = QVBoxLayout(window) 
 
 # Create and add the QPushButton Widgets to the `layout` 
 layout.addWidget(QPushButton('One')) 
 layout.addWidget(QPushButton('Two')) 
 layout.addWidget(QPushButton('Three')) 
 layout.addWidget(QPushButton('Four')) 
 layout.addWidget(QPushButton('Five')) 
 
 # Show the parent Widget 
 window.show() 
 
 # Run the main Qt loop and allow safe exiting 
 sys.exit(app.exec()) 

Запустив этот код, мы увидим на экране следующее окно:

QVBoxLayoutПример{.ezlazyload}

Это окно содержит 5 кнопок, расположенных вертикально сверху вниз. Когда
мы нажимаем на них, ничего не происходит, потому что мы еще не добавили
для них никакой логики.

2. QHBoxLayout

QHBoxLayout — это макет блока, который позволяет нам расположить
наши виджеты по горизонтали. Макет добавляет виджеты к себе слева
направо. Таким образом, первый виджет, добавленный в ваш код, будет
самым левым виджетом, а последний виджет, добавленный в ваш код, будет
самым правым виджетом в макете.

Заменим вертикальный прямоугольник на горизонтальный:

 #!/usr/bin/python 
 # Import all needed modules 
 import sys 
 from PyQt6.QtWidgets import QApplication, QPushButton, QHBoxLayout, QWidget 
 
 # Create the Qt Application 
 app = QApplication(sys.argv) 
 
 # Create the parent Widget of the Widgets added to the layout 
 window = QWidget() 
 
 # Create the Horizontal Box Layout Manager, setting `window` as parent by passing it in the constructor 
 layout = QHBoxLayout(window) 
 
 # Create and add the QPushButton Widgets to the `layout` 
 layout.addWidget(QPushButton('One')) 
 layout.addWidget(QPushButton('Two')) 
 layout.addWidget(QPushButton('Three')) 
 layout.addWidget(QPushButton('Four')) 
 layout.addWidget(QPushButton('Five')) 
 
 # Show the parent Widget 
 window.show() 
 
 # Run the main Qt loop 
 sys.exit(app.exec()) 

Запустив этот код, мы увидим на экране следующее окно:

QHBoxLayoutПример{.ezlazyload}

Это окно содержит 5 кнопок, расположенных по горизонтали слева направо.

3. QGridLayout

QGridLayout используется, когда мы хотим расположить виджеты в сетке
из строк и столбцов. В этой сетке, используя координаты, мы можем
определить относительное положение каждого виджета как: (строка,
столбец).

Примечание. И row и column должны быть целыми числами.

QGridLayout также использует все пространство, которое он получает от
своего родительского макета или виджета, и делит его на несколько
блоков. Как и в предыдущих менеджерах компоновки, каждый виджет
помещается в свое собственное поле. Количество ящиков рассчитывается
автоматически в зависимости от количества виджетов и их координат.

Давайте использовать QGridLayout вместо горизонтального прямоугольного
макета:

 #!/usr/bin/python 
 
 # Import all needed modules 
 import sys 
 from PyQt6.QtWidgets import QApplication, QPushButton, QGridLayout, QWidget 
 
 # Create the Qt Application 
 app = QApplication(sys.argv) 
 
 # Create the parent Widget 
 window = QWidget() 
 
 # Create the buttons 
 button1 = QPushButton('One') 
 button2 = QPushButton('Two') 
 button3 = QPushButton('Three') 
 button4 = QPushButton('Four') 
 button5 = QPushButton('Five') 
 
 # Create the QGrid Layout Manager 
 layout = QGridLayout(window) 
 
 # Add button Widgets to the QGridLayout 
 # addWidget([object], [row number], [column number]) 
 layout.addWidget(button1,0,0) 
 layout.addWidget(button2,1,0) 
 layout.addWidget(button3,2,0) 
 layout.addWidget(button4,0,1) 
 layout.addWidget(button5,0,2) 
 
 # Show the parent Widget 
 window.show() 
 
 # Run the main Qt loop 
 sys.exit(app.exec()) 

Запустив этот код, мы увидим на экране следующее окно:

QGridLayoutПример{.ezlazyload}

Это окно содержит 5 кнопок, которые расположены так, как мы указали в
addWidget() . Сам метод принимает 3 аргумента:

  1. Виджет, который нужно разместить в сетке.
  2. Ряд, в который он должен быть помещен.
  3. Столбец, в который он должен быть помещен.

Существует необязательный четвертый аргумент, alignment , который
определяет параметр выравнивания каждого Widget внутри своего поля.
Значение по умолчанию ( Qt.Alignment.AlignCenter ) означает, что
каждый виджет должен заполнять все свое поле от центра кнаружи.
Подробнее о Qt в следующих разделах.

Наконец, есть также columnSpan и rowSpan , которые определяют,
занимает ли виджет несколько строк или столбцов:

 addWidget(Widget, fromRow, fromColumn, rowSpan, columnSpan, Qt.Alignment) 

Qt.Alignment строк и столбцов, а также Qt.Alignment (до PyQt6 это был
бы Qt.AlignLeft ):

 # New import other than the ones already present 
 from PyQt6.QtCore import Qt 
 
 # addWidget([object], [row number], [column number], [columnSpan], [rowSpan], Qt.Alignment) 
 layout.addWidget(button1, 0, 0, 1, 1, Qt.Alignment.AlignLeft) 
 layout.addWidget(button2, 1, 0, 1, 1, Qt.Alignment.AlignLeft) 
 layout.addWidget(button3, 2, 0, 1, 1, Qt.Alignment.AlignLeft) 
 layout.addWidget(button4, 0, 1, 1, 1, Qt.Alignment.AlignLeft) 
 layout.addWidget(button5, 0, 2, 1, 1, Qt.Alignment.AlignLeft) 

Вы можете AlignLeft , AlignTop , AlignBottom , AlignRight и
AlignCenter . Изменив размер окна, мы увидим, что каждая кнопка
выровнена по левому краю своего поля, а не по центру:

{.ezlazyload}

Тогда как, если бы мы использовали AlignCenter или оставили его по
умолчанию:

{.ezlazyload}

4. QFormLayout

QFormLayout упрощает создание макетов форм для настольных приложений.
Он состоит из двух столбцов — для меток и для входов.

Обычно виджет ввода — это QLineEdit , QSpinBox , QComboBox или
аналогичные виджеты ввода. Создадим QFormLayout :

 #!/usr/bin/python 
 
 # Import all needed modules 
 import sys 
 from PyQt6.QtWidgets import QApplication, QWidget, QVBoxLayout, QLabel, QPushButton, QLineEdit 
 
 def addLabel(layout, text): 
 layout.addWidget(QLabel(text)) 
 
 # Create the Qt Application 
 app = QApplication(sys.argv) 
 
 # Create the parent Widget and the QVBoxLayout Layout Manager 
 window = QWidget() 
 layout = QVBoxLayout(window) 
 
 # Create a label Widget and add it to the layout 
 label = QLabel('Enter some text!') 
 layout.addWidget(label) 
 
 line_edit = QLineEdit() 
 layout.addWidget(line_edit) 
 
 # Create a QPushButton object with a caption on it 
 qbtn= QPushButton('Add Label') 
 
 # Add the QPushButton to the layout 
 layout.addWidget(qbtn) 
 
 # Close the application when the button is pressed 
 # Here I am using slots & signals, which I will demonstrate later in this tutorial 
 qbtn.clicked.connect(lambda:addLabel(layout, line_edit.text())) 
 
 # Show the parent Widget 
 window.show() 
 
 # Run the main Qt loop 
 sys.exit(app.exec()) 

Запустив этот код, мы увидим на экране следующее окно:

QFormLayoutПример{.ezlazyload}

Это окно содержит 2 метки и 2 QLineEdit добавленных с помощью
addRow() . addRow() принимает 2 аргумента:

  1. Текст метки (строка)
  2. Виджет ввода ( QWidget )

Метод автоматически создаст и добавит новый QLabel с нашим labelText
в
качестве текста. Кроме того, вы также можете добавить QLabel вместо
строки, которая пропускает автоматическое преобразование:

 layout.addRow(QLabel('Nickname:'), QLineEdit()) 
 layout.addRow(QLabel('Score:'), QLineEdit()) 

Это также приводит к:

{.ezlazyload}

Виджеты

Теперь, когда мы знакомы с менеджерами компоновки, которые предлагает
PyQt, давайте перейдем к тому, чем они управляют. Виджеты — это
ключевая концепция Qt и, как следствие, PyQt.

Виджет отражает графический компонент пользовательского интерфейса.
Пользовательский интерфейс состоит из нескольких виджетов, расположенных
внутри окна. Каждый виджет содержит ряд атрибутов и методов, которые
позволяют нам моделировать их внешний вид и поведение.

PyQt6 в настоящее время предлагает более 40 виджетов, и вы даже можете
создавать свои собственные виджеты.

Начиная с PyQt5, базовые классы были перетасованы в разные модули. PyQt6
использует несколько фундаментальных высокоуровневых модулей, в том
числе:

  • Qt : Все модули, упомянутые ниже, могут быть упакованы вместе в
    один модуль.
  • QtCore : QtCore содержит все основные неграфические модули,
    используемые другими модулями. В этом модуле реализованы сигналы,
    слоты и т. Д.
  • QtWidgets : этот модуль содержит большинство виджетов, доступных
    в PyQt6.
  • QtGui : QtGui расширяет QtCore и содержит компоненты
    графического интерфейса.
  • QtSql : этот модуль реализует интеграцию базы данных для баз
    данных SQL.
  • QtMultimedia : В этом модуле можно найти низкоуровневую
    мультимедийную функциональность.
  • QtNetwork : Классы, используемые для реализации сетевого
    программирования (сокеты, обработка SSL, сетевые сеансы, DNS, …),
    можно найти в этом модуле.

В этом разделе мы сосредоточимся на модуле QtWidgets и предлагаемых им
виджетах.

1. Этикетки

Самый популярный виджет, метка , чаще всего используется для
объяснения цели или использования вашего графического интерфейса,
например, для аннотирования того, для чего предназначено поле.
Мы можем создать метку, вызвав класс QLabel Имейте в виду, что этот
виджет не обеспечивает взаимодействия с пользователем.

Мы можем изменить внешний вид этикетки различными способами:

  • setAlignment() выравнивает заголовок в соответствии с константами
    выравнивания, которые могут быть следующими:

    • Alignment.AlignLeft
    • Alignment.AlignRight
    • Alignment.AlignCenter
    • Alignment.AlignJustify
  • Text() используется для получения заголовка метки.
  • setText() вместо получения заголовка установит заголовок метки.
  • setIndent() установит отступ.
  • setWordWrap() будет заключать слова в метку или нет, в зависимости
    от переданного boolean .

Теперь давайте создадим небольшое приложение PyQt6, используя только
метки, чтобы отображать некоторую информацию о Бельгии:

 #!/usr/bin/python 
 # Import all needed modules 
 import sys 
 from PyQt6.QtWidgets import QApplication, QWidget, QVBoxLayout, QLabel 
 from PyQt6.QtCore import Qt 
 
 # Create the Qt Application 
 app = QApplication(sys.argv) 
 
 # Create the parent Widget and the QVBoxLayout Layout Manager 
 window = QWidget() 
 layout = QVBoxLayout(window) 
 
 # Create a label beforehand 
 firstLabel = QLabel('Countrycode: BE') 
 secondLabel = QLabel('Brussels waffles are the best food ever.') 
 
 # Add labels to layout, creating an anonymous label while adding 
 layout.addWidget(firstLabel) 
 layout.addWidget(secondLabel, alignment = Qt.Alignment.AlignJustify) 
 layout.addWidget(QLabel('The Belgian flag consists of the colors black, yellow and red', wordWrap=True), alignment = Qt.Alignment.AlignLeft) 
 
 # using setText() we can change the caption of a label 
 firstLabel.setText('Belgium is a country located in Europe') 
 firstLabel.setAlignment(Qt.Alignment.AlignRight) 
 
 # Show the parent Widget 
 window.show() 
 
 # Run the main Qt loop 
 sys.exit(app.exec()) 

Вы можете QLabel как с firstLabel . Затем, даже после добавления его
в макет — вы можете манипулировать им и устанавливать текст,
выравнивание и т. Д. С помощью его методов установки. Последние
состояния, установленные установщиками, в конце будут отрисованы в окне.

Если вы не хотите создавать объекты заранее и не вызывать много методов

  • вы можете просто создать виджет и добавить его сразу после, в самом
    addWidget() . Мы установили для аргумента wordWrap QLabel значение
    true, поскольку он немного длиннее двух других, и мы могли бы захотеть
    обернуть слова, если они длиннее, чем может вместить окно.

Примечание. Начиная с PyQt6, Qt является частью PyQt6.QtCore , а
параметры Align_ являются частью Alignment приводит к
Qt.Alignment.Align_ . До PyQt6 Qt был частью PyQtX , а не QtCore
, а параметры Align_ были частью Qt поэтому вызовы были бы больше
похожи на Qt.Align_ вместо этого.

Если мы запустим этот код, мы увидим наши три метки, выровненные в
соответствии с нашими настройками Alignment

ЯрлыкиПример{.ezlazyload}

2. Сигналы и слоты

Сигналы и слоты в PyQt используются для связи между объектами. Этот
механизм является центральной особенностью фреймворка Qt.

Например, если пользователь нажмет кнопку «Удалить» , мы хотим, чтобы
вызывалась функция delete() Для этого 2 виджета должны
взаимодействовать друг с другом.

Событие — это действие, выполняемое пользователем в нашем графическом
интерфейсе.

Когда происходит событие, соответствующий виджет излучает сигнал.
Виджеты, доступные в Qt, имеют много предопределенных сигналов, но вы
всегда можете сделать дополнительные настраиваемые сигналы.

Слот — это функция, которая вызывается в ответ на сигнал . И снова у
виджетов, доступных в Qt, есть много предопределенных слотов, но очень
распространенной практикой является создание собственных.

Наиболее полезные функции сигналов и слотов включают в себя:

  • Сигнал может быть подключен к другому сигналу
  • Сигнал может быть подключен к одному или нескольким слотам
  • Слот может быть подключен к одному или нескольким сигналам

Общий синтаксис подключения сигнала к слоту:

 widget.signal.connect(slot_function) 

Этот код соединит slot_function с Widget.signal , и всякий раз,
когда будет испускаться сигнал, будет вызываться функция
slot_function()

Чтобы избежать неожиданного поведения, важно аннотировать каждую функцию
слота с помощью декоратора @pyqtSlot()

 from PyQt6.QtCore import pyqtSlot 
 
 # Slot function - Note the @pyqtSlot() annotation! 
 @pyqtSlot() 
 def hello_world(): 
 print('Button is clicked, Hello World!') 

Теперь давайте создадим приложение, которое использует механизм сигналов
и слотов, поместив кнопку, которая просто выводит сообщение на консоль:

 #!/usr/bin/python 
 # Import all needed modules 
 import sys 
 from PyQt6.QtWidgets import QApplication, QPushButton 
 from PyQt6.QtCore import pyqtSlot 
 
 @pyqtSlot() 
 def hello_world(): 
 print('You shall not pass!') 
 
 # Create the Qt Application 
 app = QApplication(sys.argv) 
 
 # Create a QPushButton Object 
 button = QPushButton('Click me') 
 
 # Connect the button to the hello_world slot function 
 button.clicked.connect(hello_world) 
 
 # Show the button to the user 
 button.show() 
 
 # Run the main Qt loop 
 sys.exit(app.exec()) 

Запустив этот код, мы увидим на экране следующее окно:

Краткий пример сигналов ислотов{.ezlazyload}

После запуска этого кода и нажатия кнопки на консоль выводится следующий
текст:

 You shall not pass! 

3. Кнопки

Теперь, когда мы можем пометить другие компоненты графического
интерфейса в приложении — давайте взглянем на первый интерактивный
компонент, который мы будем реализовывать — QButton . Кнопки приводят
к результатам — в нашем случае их можно использовать для вызова
определенных функций. Есть несколько предопределенных кнопок по
умолчанию: ОК, Да, Нет, Отмена, Применить и Закрыть , хотя вы также
можете добавить на них собственный текст.

Вы можете прикрепить обработчик событий к кнопке, которая запускает
функцию или любой другой фрагмент кода при нажатии кнопки. Давайте
создадим кнопку, которая позволяет пользователю добавлять QLabel на
экран.

Как только пользователь вводит текст в QLineEdit и было обнаружено
нажатие кнопки, мы собираем данные из QLineEdit и используем этот
текст для установки текста нового QLabel , который затем добавляется в
макет.

Поскольку кнопки ожидают, что вызываемая функция будет передана в
качестве обработчика события щелчка, мы определим новую функцию
add_label() которую можно использовать для добавления любого QLabel
в указанный макет:

 def addLabel(layout, text): 
 layout.addWidget(QLabel(text)) 

Теперь давайте напишем наш графический интерфейс и вызовем эту функцию с
текстом, предоставленным пользователем:

 #!/usr/bin/python 
 # Import all needed modules 
 import sys 
 from PyQt6.QtWidgets import QApplication, QWidget, QVBoxLayout, QLabel, QPushButton, QLineEdit 
 
 def addLabel(layout, text): 
 layout.addWidget(QLabel(text)) 
 
 # Create the Qt Application 
 app = QApplication(sys.argv) 
 
 # Create the parent Widget and the QVBoxLayout Layout Manager 
 window = QWidget() 
 layout = QVBoxLayout(window) 
 
 # Create a Qlabel Widget and add it to the layout 
 label = QLabel('Enter some text!') 
 layout.addWidget(label) 
 
 # Create a QLineEdit to collect user data 
 line_edit = QLineEdit() 
 layout.addWidget(line_edit) 
 
 # Create a QPushButton object with a caption on it 
 qbtn= QPushButton('Add Label') 
 layout.addWidget(qbtn) 
 
 # When clicked, perform a callable function - `addLabel()` 
 qbtn.clicked.connect(lambda:addLabel(layout, line_edit.text())) 
 
 # Show the parent Widget 
 window.show() 
 
 # Run the main Qt loop 
 sys.exit(app.exec()) 

После того, как мы запустим этот код, мы можем написать текст в
QLineEdit , которое добавляется в макет как QLabel когда мы нажимаем
на Add Label :

Примеркнопок{.ezlazyload}

4. Редактирование строк

Мы дважды кратко рассмотрели QLineEdit — давайте посмотрим, что он
предлагает. Как было показано ранее, он позволяет пользователям вводить
строку текста — это элементарный способ сбора пользовательских данных,
будь то для добавления или редактирования уже существующих данных.
Конечно, мы можем выполнять обычные операции, такие как копирование ,
вставка , отмена , повтор, во время написания текста внутри них.

Вот некоторые из распространенных методов, которые вы будете
использовать с ними:

  • setAlignment() снова выровняет заголовок в соответствии с
    константами выравнивания
  • setMaxLength() устанавливает максимальное количество символов,
    которое пользователь не может превзойти
  • text() — извлекает текст в QLineEdit
  • setText() — устанавливает текст в QLineEdit
  • clear() сотрет все содержимое QLineEdit

Давайте перепишем предыдущий пример, но на этот раз уже есть некоторый
предопределенный текст в QLineEdit , изменим уже существующий QLabel
вместо добавления нового — и кратко рассмотрим использование слотов
PyQt
, которые будут рассмотрены более подробно позже. в руководстве.

Мы создадим простейшее приложение для цитат, в котором есть корпус
известных цитат и которое выдает случайные по запросу. Вы можете
расширить этот список, добавив новый и нажав Добавить цитату , которая
затем будет включена в пул котировок, когда вы решите получить новую
случайную цитату с помощью Get Random Quote :

 #!/usr/bin/python 
 # Import all needed modules 
 import sys 
 from PyQt6.QtWidgets import QApplication, QWidget, QVBoxLayout, QLabel, QPushButton, QLineEdit 
 from PyQt6.QtCore import pyqtSlot 
 import random 
 
 # Deifne helper functions as PyQt Slots 
 @pyqtSlot() 
 def randomQuote(): 
 # Set label to random quote from the list 
 quoteLabel.setText(random.choice(quotes)) 
 
 @pyqtSlot() 
 def addQuote(): 
 # Add new quote to the list and clear the input field 
 quotes.append(newQuoteLineEdit.text()) 
 newQuoteLineEdit.clear() 
 
 app = QApplication(sys.argv) 
 window = QWidget() 
 layout = QVBoxLayout(window) 
 
 # Default quote list 
 quotes = ['Do or do not, there is no try.', 'The meaning of life is 42'] 
 
 # Get a random quote for the user 
 quoteLabel = QLabel(random.choice(quotes)) 
 
 # QLineEdit field to collect new quote information, and a button for it 
 newQuoteLineEdit = QLineEdit('Add new quote...') 
 addQuoteButton = QPushButton('Add New Quote') 
 
 # Button to get random quote 
 getQuoteButton = QPushButton('Get Random Quote') 
 
 # Add the previous Widgets to the layout 
 layout.addWidget(newQuoteLineEdit) 
 layout.addWidget(quoteLabel) 
 layout.addWidget(addQuoteButton) 
 layout.addWidget(getQuoteButton) 
 
 # On click - call the slots (functions) 
 getQuoteButton.clicked.connect(randomQuote) 
 addQuoteButton.clicked.connect(addQuote) 
 
 # Show the parent Widget 
 window.show() 
 
 # Run the main Qt loop 
 sys.exit(app.exec()) 

Это приводит к:

{.ezlazyload}

5. Поля со списком

Комбинированные поля позволяют пользователям выбирать из списка опций

  • аналогично <select> в HTML. Это может быть достигнуто с помощью
    виджета QComboBox Базовый QComboBox для чтения, что означает, что
    пользователь должен выбирать исключительно из предопределенного списка и
    не может добавлять свои собственные параметры. Однако они также могут
    быть редактируемыми, что позволяет пользователю добавлять новый
    параметр, если он не соответствует его потребностям.

Ниже приведены наиболее часто используемые методы класса QComboBox:

  • addItem() добавляет строку в коллекцию
  • addItems() добавит каждую из строк в данном списке в коллекцию
  • Clear() используется для удаления всех элементов в коллекции
  • count() используется для получения количества элементов в
    коллекции
  • currentText() используется для получения текста текущего
    выбранного элемента
  • itemText() принимает index и возвращает текст этого элемента
  • currentIndex() возвращает индекс текущего выбранного элемента

Давайте создадим мини-приложение для заказа, в котором пользователь
выбирает элемент из меню и вводит комментарий для ресторана. Затем при
нажатии кнопки пользователю показывается такой порядок:

 #!/usr/bin/python 
 # Import all needed modules 
 import sys 
 from PyQt6.QtWidgets import QApplication, QWidget, QVBoxLayout, QLabel, QPushButton, QLineEdit, QComboBox 
 from PyQt6.QtCore import pyqtSlot 
 
 @pyqtSlot() 
 def placeOrder(): 
 order_format = "Placed order for {} with comment '{}'" 
 layout.addWidget(QLabel(order_format.format(comboBox.currentText(), commentLineEdit.text()))) 
 
 app = QApplication(sys.argv) 
 
 window = QWidget() 
 layout = QVBoxLayout(window) 
 
 label1 = QLabel('Pick one of the following options:') 
 comboBox = QComboBox() 
 comboBox.addItems(['Pasta', 'Pizza', 'Lasagna']) 
 
 layout.addWidget(label1) 
 layout.addWidget(comboBox) 
 
 commentLineEdit = QLineEdit('Comment for the restaurant...') 
 placeOrderButton = QPushButton('Place order') 
 
 layout.addWidget(commentLineEdit) 
 layout.addWidget(placeOrderButton) 
 
 placeOrderButton.clicked.connect(placeOrder) 
 
 window.show() 
 sys.exit(app.exec()) 

Теперь разместим заказ и прикрепим к нему запрос:

Пример полей сосписком{.ezlazyload}

6. Радиокнопки и флажки

Радиокнопки и флажки в основном используются с той же целью — позволяя
кому-то выбрать вариант из нескольких. Единственное отличие состоит в
том, что радиобоксы используются, когда мы хотим ограничить пользователя
выбором одного варианта, а флажки используются, когда мы хотим разрешить
пользователю выбирать несколько опций.

Например, мы можем заставить пользователя выбрать между новым или старым
клиентом (не могут быть оба одновременно), но разрешить ему выбрать
несколько услуг, на которые они хотели бы подписаться.

QCheckBox , они реализованы как QRadioButton и QCheckBox. Мы можем
проверить, отмечены ли они, установить для них отмеченный или снятый
флажок, установить их текст, а также получить текст их меток:

  • setChecked() проверяет переключатель или флажок
  • setText() устанавливает метку, связанную с кнопкой или флажком
  • text() получит метку кнопки / флажка
  • isChecked() проверяет, выбрана ли кнопка / флажок.

Давайте создадим простое приложение, которое позволяет пользователям
выбирать между парой услуг, которые предлагает воображаемая автомойка:

 #!/usr/bin/python 
 # Import all needed modules 
 import sys 
 from PyQt6.QtWidgets import QApplication, QWidget, QVBoxLayout, QLabel, QRadioButton, QCheckBox 
 
 app = QApplication(sys.argv) 
 window = QWidget() 
 layout = QVBoxLayout(window) 
 
 label_customer = QLabel('Pick one of the following options:') 
 
 # Create two radio buttons for the customer, assuming they might be a new customer 
 qradioButton = QRadioButton('Old Customer') 
 qradioButton2 = QRadioButton('New Customer') 
 qradioButton2.setChecked(True) 
 
 layout.addWidget(label_customer) 
 layout.addWidget(qradioButton) 
 layout.addWidget(qradioButton2) 
 
 label_service = QLabel("Pick the services you'd like:") 
 qCheckBox = QCheckBox('Car Wash') 
 qCheckBox2 = QCheckBox('Car Polish') 
 qCheckBox3 = QCheckBox('Vacuuming') 
 
 layout.addWidget(label_service) 
 layout.addWidget(qCheckBox) 
 layout.addWidget(qCheckBox2) 
 layout.addWidget(qCheckBox3) 
 
 window.show() 
 sys.exit(app.exec()) 

Это подсказывает нам приложение, похожее на опрос, которое позволяет нам
выбирать, старый мы или новый клиент, и позволяет нам выбирать между
услугами, которые предлагает автомойка:

Пример радиокнопок{.ezlazyload}

7. Отображение данных с помощью виджета таблицы

QTableWidget — это виджет, который без особой настройки позволяет нам
создавать в PyQt потрясающие таблицы, похожие на Excel, в которых мы
можем отображать данные.

Каждая таблица представляет собой таблицу на основе элементов со
строками и столбцами.

Имейте в виду, что использование QTableWidget — не единственный способ
отображения информации в таблицах. Модели данных также можно создавать и
отображать с помощью виджета QTableView Хотя QTableWidget своей сути
использует QTableView под капотом для фактического создания таблицы,
поэтому мы будем использовать подход более высокого уровня, используя
таблицу с самого начала.

Учитывая столбцовую природу таблиц, мы можем удобно создавать словари
для хранения данных для них или даже списков списков. При создании
таблицы мы захотим установить количество столбцов и строк перед
добавлением в нее каких-либо данных, а затем просто заполнить ее
циклами:

  • setRowCount() устанавливает количество строк
  • setColumnCount() устанавливает количество столбцов
  • setHorizontalHeaderLabels() устанавливает метки горизонтальных
    заголовков

Теперь давайте создадим простое приложение, которое содержит таблицу с
несколькими северными странами и их столицами:

 #!/usr/bin/python 
 # Import all needed modules 
 import sys 
 from PyQt6.QtWidgets import (QApplication, QTableWidget, QTableWidgetItem) 
 from PyQt6.QtGui import QColor 
 
 # Declare our table values 
 nordic_countries = [('Norway', 'Oslo', 'Yes'), 
 ('Iceland', 'Reykjavik', 'Yes'), 
 ('Denmark', 'Copenhagen', 'Yes'), 
 ('Belgium', 'Brussels','No')] 
 
 # Create the Qt Application 
 app = QApplication(sys.argv) 
 table = QTableWidget() 
 
 # Configure QTableWidget to have a number of rows equivalent to the amount of items from the nordic_countries struct 
 table.setRowCount(len(nordic_countries)) 
 
 # Since every country in our 'nordic_countries' variable has the same amount of attributes 
 # we take the amount (3) of the first country and use this as the number of columns 
 table.setColumnCount(len(nordic_countries[0])) 
 
 # Set the Horizontal headers using setHorizontalHeaderLabels() 
 table.setHorizontalHeaderLabels(['Country', 'Capital', 'Scandinavian?']) 
 
 # Loop through every country in our 'nordic_countries' variable 
 for i, (country, capital, scandinavian_bool) in enumerate(nordic_countries): 
 
 # Make a QTableWidgetItem --> acts as an item in a table 
 item_country = QTableWidgetItem(country) 
 item_capital = QTableWidgetItem(capital) 
 item_scandinavian_bool = QTableWidgetItem(scandinavian_bool) 
 
 # Set the items: item, index, QTableWidgetItem 
 table.setItem(i, 0, item_country) 
 table.setItem(i, 1, item_capital) 
 table.setItem(i, 2, item_scandinavian_bool) 
 
 # Finally show the table 
 table.show() 
 
 # Launch the application 
 sys.exit(app.exec()) 

Запустив этот код, мы увидим на экране следующее окно:

Пример таблицыWigdet{.ezlazyload}

8. Отображение данных с помощью виджета в виде дерева.

Деревянные виджеты действительно полезны для отображения древовидных
структур, таких как файловые иерархии или подсписки, относящиеся к
определенным спискам элементов. Чтобы приспособиться к этому типу
виджетов, PyQt предлагает QTreeWidget .

Подобно тому, как QTableWidget построен поверх QTableView
QTreeWidget построен поверх QTreeView .

Дерево состоит из заголовков и элементов . Заголовки — это имена
столбцов. Каждому элементу может быть назначено несколько элементов.
Элемент, например, может быть каталогом, в то время как его собственные
элементы — это файлы в этом каталоге — или элемент может быть задачей, а
его элементы — это люди, назначенные для этой задачи.

Вот некоторые из распространенных методов, которые мы будем использовать
для работы с Tree Widgets:

  • setHeaderLabels() устанавливает имя столбца для виджета дерева
  • clear() чтобы удалить все данные из Дерева
  • editItem() для редактирования определенного элемента в дереве
  • addTopLevelItem() для добавления элемента верхнего уровня
  • addTopLevelItems() для добавления списка элементов верхнего уровня

Каждый элемент может быть назначен родительскому компоненту. Для
элемента верхнего уровня мы можем назначить его самому QTreeWidget , а
для элементов более низкого уровня — мы можем назначить их уже
существующим элементам верхнего уровня. Вы можете пойти в этом
направлении настолько далеко, насколько захотите, однако слишком большое
количество уровней может сбивать с толку пользователя.

Давайте продолжим и составим быстрый список покупок — с Food и
Furniture в качестве предметов верхнего уровня (категории предметов,
которые мы хотели бы купить), а их дети будут фактическими предметами
сами:

 #!/usr/bin/python 
 # Import all needed modules 
 import sys 
 from PyQt6 import QtWidgets 
 
 app = QtWidgets.QApplication(sys.argv) 
 window = QtWidgets.QWidget() 
 layout = QtWidgets.QVBoxLayout(window) 
 
 # Create the QTreeWidget Widget 
 tree_widget = QtWidgets.QTreeWidget() 
 
 # Set the column name for the Tree Widget 
 tree_widget.setHeaderLabels(['Items', 'Total Cost']) 
 
 # Populate first tree with QTreeWidgetItem objects 
 foodList = QtWidgets.QTreeWidgetItem(tree_widget, ['Food', '€ 15']) 
 QtWidgets.QTreeWidgetItem(foodList, ['Apples', '€ 6']) 
 QtWidgets.QTreeWidgetItem(foodList, ['Pears', '€ 4']) 
 QtWidgets.QTreeWidgetItem(foodList, ['Oranges', '€ 5']) 
 
 # Populate second tree with QTreeWidgetItem objects 
 furnitureList = QtWidgets.QTreeWidgetItem(tree_widget, ['Furniture', '€ 225']) 
 QtWidgets.QTreeWidgetItem(furnitureList, ['Table', '€ 150']) 
 QtWidgets.QTreeWidgetItem(furnitureList, ['Chairs', '€ 75']) 
 
 layout.addWidget(tree_widget) 
 
 window.show() 
 sys.exit(app.exec()) 

Запустив этот код, мы увидим на экране следующее окно:

Пример Tree Wigdet

Заключение

В этом руководстве мы перешли к PyQt — оболочке Python для популярной
библиотеки Qt.

Мы рассмотрели некоторые ключевые концепции библиотеки и приступили к
работе с ней через менеджеры компоновки, познакомились с виджетами и
создали несколько действительно простых демонстрационных приложений,
демонстрирующих, как вы можете их использовать.

Понравилась статья? Поделить с друзьями:
  • Иэ 9703б машина заточная инструкция по сборке
  • Какие три раздела должна иметь любая квалификационная характеристика должностная инструкция
  • Убдн 1 инструкция по эксплуатации скачать бесплатно
  • Пустырник триптофан инструкция по применению побочные действия отзывы
  • Мазь розенфельда инструкция по применению в нос взрослым при гайморите