Pyqt руководство на русском

К старту курса по разработке на 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 для веб-разработки»

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

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

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

Еще одна замечательная особенность, которая вдохновляет разработчиков пользоваться PyQt5 – это PyQt5 Designer, благодаря которому можно создавать сложные GUI приложения достаточно быстро. Вам нужно только перетаскивать свои виджеты для создания собственной формы. У нас есть готовый сборник 54 уроков по другому фреймворку wxPython.

  • Создаем простой калькулятор в PyQt5
  • Создаем игру Сапёр на PyQt5
  • История курса рубля на PyQt5 + XML от ЦБ РФ

Другие фреймворки

  • wxPython
  • Tkinter
  • PyCairo

В данном руководстве по PyQt5, я буду использовать Python 3.6 на Ubuntu и предположение, что вы уже имеете базовое представление о Python.

Есть вопросы по Python?

На нашем форуме вы можете задать любой вопрос и получить ответ от всего нашего сообщества!

Telegram Чат & Канал

Вступите в наш дружный чат по Python и начните общение с единомышленниками! Станьте частью большого сообщества!

Паблик VK

Одно из самых больших сообществ по Python в социальной сети ВК. Видео уроки и книги для вас!

Звучит замечательно! Начнем с установки PyQt5, и затем перейдем к тому, как разрабатывать GUI приложение с примерами.

Краткое содержание

  • 1 Установка PyQt5
  • 1.1 Установка PyQt5 через pip
  • 1.2 Установка PyQt5 из исходников на Linux
  • 1.3 Установка PyQt5 из исходников на Windows
  • 2 Устанавливаем PyQt5 Designer
  • 2.1 Где находится дизайнер PyQt5?
  • 3 Как использовать дизайнер PyQt5
  • 4 Разница между QDialog, QMainWindow, и QWidget
  • 5 Загрузка .ui против конвертации .ui в .py
  • 5.1 Загрузка файла .ui в ваш код Python
  • 5.2 Конвертация файла .ui в .py file при помощи pyuic5
  • 6 Виджет QLabel
  • 6.1 Меняем шрифт QLabel
  • 6.2 Меняем размер QLabel
  • 6.3 Меняем текст в QLabel
  • 7 Виджет QLineEdit
  • 7.1 Метод setStyleSheet()
  • 8 Виджет QPushButton
  • 9 Визуальный редактор signal/slot
  • 10 Как испускать сигналы в PyQt5
  • 10.1 Как использовать сигнал в PyQt5
  • 10.2 Переопределение сигнала (события) в PyQt5
  • 11 Виджет QComboBox
  • 11.1 Получаем все элементы из QComboBox
  • 11.2 Выбор одного элемента из QCombobox
  • 12 QTableWidget
  • 12.1 Очистка содержимого QTableWidget
  • 12.2 Заполнение QTableWidget из кода
  • 12.3 Делаем QTableWidget нередактируемым (только для чтения)
  • 12.4 Заголовок для столбцов в QTableWidget
  • 12.5 Как сортировать QTableWidget
  • 12.6 Добавляем QComboBox в QTableWidget
  • 12.7 QProgressBar в QTableWidget
  • 13 Компиляция Python приложения

Установка PyQt5

Существует две версии PyQt5: коммерческая и бесплатная версия GPL, которой мы будем пользоваться в этом руководстве.

Есть два способа установки PyQt5:

  • Установка PyQt5 через pip
  • Установка PyQt5 из исходников на Linux

Установка PyQt5 через pip

Чтобы установить PyQt5 при помощи pip, выполните следующую команду:

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

Если не возникло ни одной ошибки, это значит, что вы успешно установили PyQt5. В случае, если ошибки возникли, возможно это связанно с тем, что вы используете версию Python, которая не поддерживается.

Установка PyQt5 из исходников на Linux

Для установки PyQt5 из исходника, вам нужно сделать следующее:

  1. Установить SIP;
  2. Скачать исходник PyQt5;
  3. Настроить и установить.

Как вы возможно знаете, PyQt5 связывает Python с популярной библиотекой Qt, которая написана на С++.

Инструмент, который создает эту связь, называется SIP. Так что для установки PyQt5 из исходника, вам для начала нужно установить SIP.

Для установки SIP, запустите следующую команду:

sudo pip3 install pyqt5sip

Теперь вы можете загрузить и установить исходник PyQt5.

Исходники

Скачать исходник PyQt5 можно отсюда: https://www.riverbankcomputing.com/software/pyqt/download5

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

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

wget https://sourceforge.net/projects/pyqt/files/PyQt5/PyQt5.11.3/PyQt5_gpl5.11.3.tar.gz

tar xvzf PyQt5_gpl5.11.3.tar.gz

cd PyQt5_gpl5.11.3

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

sudo python3 configure.py

sudo make

sudo make install

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

Установка PyQt5 из исходников на Windows

Скачивайте и распакуйте архив с сайта которого мы указали выше.

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

Так как SIP требует компилятор GCC, вам нужно установить MinGW, который является портом Windows для компилятора Linux, GCC.

Единственное, что нужно поменять — это момент конфигурации. Вам нужно сообщить Python о платформе.

Это можно выполнить следующим образом:

python configure.py platform win32g++

make

make install

Поздравляем! Вы успешно установили PyQt5 из исходника.

Установка PyQt5 Designer

Есть два способа создания GUI приложений при помощи PyQt5:

  1. Дизайн виджетов при помощи кода;
  2. Использование PyQt5 Designer.

В этом руководстве мы используем PyQt5 Designer, который упрощает процесс на столько, что вы можете выполнить большой объем работы за секунды.

Недорого заказать услуги SMM продвижения более чем в 9 социальных сетях можно на https://doctorsmm.com/. С помощью этого сервиса можно раскрутить свою группу, страницу, сообщество или канал и набрать нужное количество подписчиков, лайков, репостов и других соцсигналов.

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

$ pip3 install pyqt5tools

Где находится дизайнер PyQt5?

После удачной установки, вы можете найти дизайнер PyQt5 здесь:

C:Program FilesPython36Libsitepackagespyqt5tools

Кстати, если вы установили только для своего текущего пользовательского аккаунта, вы найдете дизайнер PyQt5 вот здесь:

C:UsersPythonUserAppDataLocalProgramsPythonPython3632Libsitepackages pyqt5tools

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

Как использовать дизайнер PyQt5

Откройте designer.exe и увидите диалоговое окно, спрашивающее о том, какую форму шаблона вы предпочитаете.

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

Существует пять видов доступных шаблонов:

  • Диалоговое окно с кнопками внизу (Dialog with Buttons Bottom): создает форму с кнопками ОК и Cancel в правом нижнем углу формы.
  • Диалоговое окно с кнопками справа (Dialog with Buttons Right): создает форму с кнопками OK и Cancel в верхнем правом углу формы.
  • Диалоговое окно без кнопок (Dialog without Buttons): создает пустую форму;
  • Главное окно (Main Window): создает окно с панелью меню и набором инструментов. Унаследовано из QmainWindow;
  • Виджет (Widget): создает виджет, наследуемый из класса Qwidget. Отличается от диалоговых шаблонов тем, что они наследуются из класса QВialog

Итак, у нас есть три типа шаблонов. В чем между ними разница?

Разница между QDialog, QMainWindow, и Qwidget

  • QWidget – это базовый класс для всех GUI Элементов в PyQt5;
  • QDialog используется при запросе чего-либо у пользователя, например, запросы о принятии или отклонении чего-нибудь. Основан на Qwidget.
  • QMainWindow – самый большой шаблон, где вы можете разместить вашу панель инструментов, меню, статус и другие виджеты. Не имеет встроенных кнопок разрешения, таких как в QDialog.

Загрузка .ui против конвертации .ui в .py

В данном руководстве мы используем PyQt5 Designer, но перед тем, как мы пойдем дальше, давайте рассмотрим, как еще мы можем использовать сгенерированный файл из PyQt5 Designer.

Нам нужно открыть PyQt5 Designer, выбрать шаблон Main Window и нажать кнопку create.

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

Далее в файловом меню (File), нажимаем сохранить. PyQt5 Designer экспортирует вашу форму в XML с расширением .ui.

Для использования этого дизайна, у вас есть два способа:

  • Загрузить файл .ui в ваш код Python;
  • Конвертировать файл .ui в файл .py при помощи pyuic5;

Загрузка .ui файла в ваш код Python

Чтобы загрузить файл .ui в ваш код Python, вы можете использовать функцию loadUI() из uic вот так:

from PyQt5 import QtWidgets, uic

import sys

app = QtWidgets.QApplication([])

win = uic.loadUi(«mydesign.ui») # расположение вашего файла .ui

win.show()

sys.exit(app.exec())

Если вы запустите код, вы увидите окно, в котором есть только ярлык.

Это значит, что ui файл успешно загрузился!

Мы используем sys.exit(app.exec()) вместо использования app.exec() напрямую, чтобы выслать правильный код статуса, родительский процесс, или процесс вызова.

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

Конвертация файла .ui в файл .py при помощи pyuic5

Давайте попробуем еще один способ и конвертируем файл .ui в код Python:

$ pyuic5 mydesign.ui o mydesign.py

Да! Был создан новый файл под названием mydesign.py. Теперь, импортируем этот файл, чтобы показать его в окне.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

from PyQt5 import QtWidgets

from mydesign import Ui_MainWindow  # импорт нашего сгенерированного файла

import sys

class mywindow(QtWidgets.QMainWindow):

    def __init__(self):

        super(mywindow, self).__init__()

        self.ui = Ui_MainWindow()

        self.ui.setupUi(self)

app = QtWidgets.QApplication([])

application = mywindow()

application.show()

sys.exit(app.exec())

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

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

Еще одно преимущество использования второго метода. Скорость: вам не нужен парсинг XML для загрузки UI.

Так что мы можем сказать, что конвертация файла .ui в файл .py – безопаснее для кодинга и быстрее для загрузки.

Настало время закатить рукава и поиграть с виджетами PyQt5.

Для внесение виджета QLabel в вашу форму, выполните следующее:

  • Откройте PyQt5 Designer и выберите шаблон Main Window;
  • Перетяните виджет ярлыка из бокса слева;

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

Сохраните дизайн в файл как qlabel.ui и конвертируйте его в файл qlabel.py. Теперь поработаем с ярлыком виджета при помощи кода.

pyuic5 qlabel.ui o qlabel.py

Результат:
Руководство по PyQt5

Меняем шрифт QLabel

Чтобы поменять шрифт QLabel, используйте метод setFont() и передайте ему QFont следующим образом:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

from PyQt5 import QtWidgets, QtGui

from mydesign import Ui_MainWindow

import sys

class mywindow(QtWidgets.QMainWindow):

    def __init__(self):

        super(mywindow, self).__init__()

        self.ui = Ui_MainWindow()

        self.ui.setupUi(self)

        self.ui.label.setFont(

            QtGui.QFont(‘SansSerif’, 30)

        ) # Изменение шрифта и размера

app = QtWidgets.QApplication([])

application = mywindow()

application.show()

sys.exit(app.exec())

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

Меняем размер QLabel

Чтобы поменять размер QLabel, вам нужно указать его геометрию при помощи метода setGeometry(), вот так:

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

from PyQt5 import QtWidgets, QtGui,QtCore

from mydesign import Ui_MainWindow

import sys

class mywindow(QtWidgets.QMainWindow):

    def __init__(self):

        super(mywindow, self).__init__()

        self.ui = Ui_MainWindow()

        self.ui.setupUi(self)

        self.ui.label.setFont(

            QtGui.QFont(‘SansSerif’, 30)

        )

        self.ui.label.setGeometry(

            QtCore.QRect(10, 10, 200, 200)

        ) # изменить геометрию ярлыка

app = QtWidgets.QApplication([])

application = mywindow()

application.show()

sys.exit(app.exec())

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

Меняем текст в QLabel

Чтобы изменить текст в QLabel, вы можете использовать метод setText(), вот так:

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

from PyQt5 import QtWidgets, QtGui,QtCore

from qlabel import Ui_MainWindow

import sys

class mywindow(QtWidgets.QMainWindow):

    def __init__(self):

        super(mywindow, self).__init__()

        self.ui = Ui_MainWindow()

        self.ui.setupUi(self)

        self.ui.label.setFont(

            QtGui.QFont(‘SansSerif’, 30)

        )

        self.ui.label.setGeometry(

            QtCore.QRect(10, 10, 200, 200)

        )

        self.ui.label.setText(«PyScripts») # Меняем текст

app = QtWidgets.QApplication([])

application = mywindow()

application.show()

sys.exit(app.exec())

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

Именно на столько все просто! Давайте рассмотрим другие виджеты.

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

QLineEdit PyQt5 Designer

Я создам новый дизайн qline.ui, используя дизайнер PyQt5 и внесу шесть виджетов QLineEdit и экспортирую его в файл qline.py.

pyuic5 qline.ui o qline.py

Cодержимое файла qline.py после конвертации:

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

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file ‘qline.ui’

#

# Created by: PyQt5 UI code generator 5.11.3

#

# WARNING! All changes made in this file will be lost!

from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_MainWindow(object):

    def setupUi(self, MainWindow):

        MainWindow.setObjectName(«MainWindow»)

        MainWindow.resize(785, 600)

        self.centralwidget = QtWidgets.QWidget(MainWindow)

        self.centralwidget.setObjectName(«centralwidget»)

        self.lineEdit = QtWidgets.QLineEdit(self.centralwidget)

        self.lineEdit.setGeometry(QtCore.QRect(10, 10, 291, 31))

        self.lineEdit.setObjectName(«lineEdit»)

        self.lineEdit_2 = QtWidgets.QLineEdit(self.centralwidget)

        self.lineEdit_2.setGeometry(QtCore.QRect(10, 50, 291, 31))

        self.lineEdit_2.setObjectName(«lineEdit_2»)

        self.lineEdit_3 = QtWidgets.QLineEdit(self.centralwidget)

        self.lineEdit_3.setGeometry(QtCore.QRect(10, 90, 291, 31))

        self.lineEdit_3.setObjectName(«lineEdit_3»)

        self.lineEdit_4 = QtWidgets.QLineEdit(self.centralwidget)

        self.lineEdit_4.setGeometry(QtCore.QRect(10, 130, 291, 31))

        self.lineEdit_4.setObjectName(«lineEdit_4»)

        self.lineEdit_5 = QtWidgets.QLineEdit(self.centralwidget)

        self.lineEdit_5.setGeometry(QtCore.QRect(10, 170, 291, 31))

        self.lineEdit_5.setObjectName(«lineEdit_5»)

        self.lineEdit_6 = QtWidgets.QLineEdit(self.centralwidget)

        self.lineEdit_6.setGeometry(QtCore.QRect(10, 210, 291, 31))

        self.lineEdit_6.setObjectName(«lineEdit_6»)

        MainWindow.setCentralWidget(self.centralwidget)

        self.menubar = QtWidgets.QMenuBar(MainWindow)

        self.menubar.setGeometry(QtCore.QRect(0, 0, 785, 25))

        self.menubar.setObjectName(«menubar»)

        MainWindow.setMenuBar(self.menubar)

        self.statusbar = QtWidgets.QStatusBar(MainWindow)

        self.statusbar.setObjectName(«statusbar»)

        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)

        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):

        _translate = QtCore.QCoreApplication.translate

        MainWindow.setWindowTitle(_translate(«MainWindow», «MainWindow»))

Давайте познакомимся с методами QLineEdit:

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

from PyQt5 import QtWidgets, QtCore

# Импортируем наш файл

from qline import Ui_MainWindow

import sys

class mywindow(QtWidgets.QMainWindow):

    def __init__(self):

        super(mywindow, self).__init__()

        self.ui = Ui_MainWindow()

        self.ui.setupUi(self)

        # Меняем текст

        self.ui.lineEdit.setText(«Добро пожаловать на PythonScripts»)

        # указать максимальную длину

        self.ui.lineEdit_2.setMaxLength(10)

        # ввод пароля

        self.ui.lineEdit_3.setEchoMode(QtWidgets.QLineEdit.Password)

        # только чтение без изменения содержимого.

        self.ui.lineEdit_4.setReadOnly(True)

        # меняем цвет вводимого текста

        self.ui.lineEdit_5.setStyleSheet(«color: rgb(28, 43, 255);»)

        # изменение цвета фона QLineEdit

        self.ui.lineEdit_6.setStyleSheet(«background-color: rgb(28, 43, 255);»)

app = QtWidgets.QApplication([])

application = mywindow()

application.show()

sys.exit(app.exec())

Результат:

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

  • Для 1-го QLineEdit, мы изменили текст, при помощи метода setText().
  • Для 2-го QLineEdit, мы установили максимум доступных 10-и символов, так что более 10-и приниматься не будут.
  • Для 3-го QLineEdit, мы установили режим пароля, так ваши введенные данные отображаются как звездочки;
  • Для 4-го QLineEdit, мы установили режим «только для чтения», так что редактировать контент не представляется возможным.
  • Для 5-го QLineEdit мы изменили цвет шрифта при помощи метода setStyleSheet() и указали нужный цвет с помощью CSS (как и для обычной веб страницы).
  • Для 6-го QLineEdit мы изменили цвет фона при помощи метода setStyleSheet() и CSS.

Метод setStyleSheet()

Метод setStyleSheet() может быть использован с виджетами PyQt5 для изменения стилей.

Вы можете изменить следующие параметры, пользуясь методом setStyleSheet():

  • Размер и тип шрифта;
  • Цвет текста;
  • Цвет заднего фона;
  • Цвет верхней границы;
  • Цвет нижней границы;
  • Цвет левой границы;
  • Цвет правой границы;
  • Цвет выделения;
  • Цвет выделения заднего фона.

Это наиболее важные значения, которые можно передать методу setStyleSheet().

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

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

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

Событие клика в PyQt5 называется сигналом, и метод, который будет выполняться, называется слот.

Так что при нажатии на QPushButton, сигнал издается. Названием сигнала в данном случае, является clicked().

Чтобы связать сигнал со слотом, вам нужно использовать метод connect(), что вы сейчас и увидите.

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

Давайте создадим форму myform.ui при помощи QLabel и QPushButton и экспортируем её в файл myform.py.

QLabel QPushButton

Экспортируем myform.ui в myform.py

pyuic5 myform.ui o myform.py

Сейчас, мы подключим сигнал clicked() к слоту при помощи метода connect(), вот так:

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

Здесь, btnClicked – это слот, или функция, которая будет выполнена после того, как вы кликните на QPushButton.

Итак, ваш код будет выглядеть следующим образом:

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

from PyQt5 import QtWidgets

# Импортируем наш шаблон.

from myform import Ui_MainWindow

import sys

class mywindow(QtWidgets.QMainWindow):

    def __init__(self):

        super(mywindow, self).__init__()

        self.ui = Ui_MainWindow()

        self.ui.setupUi(self)

        # подключение клик-сигнал к слоту btnClicked

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

    def btnClicked(self):

        self.ui.label.setText(«Вы нажали на кнопку!»)

        # Если не использовать, то часть текста исчезнет.

        self.ui.label.adjustSize()

app = QtWidgets.QApplication([])

application = mywindow()

application.show()

sys.exit(app.exec())

Результат:

QPushButton

Замечательно!

Визуальный редактор слота/сигнала

Мы видели, как подключать сигнал виджета к слоту при помощи метода connect(), но это не единственный способ.

На самом деле, для каждого виджета есть предопределенные слоты. Вы можете связать сигнал с любым предопределенным слотом, без необходимости кодить в дизайнере PyQt5.

Перетяните QPushButton и QLineEdit в вашу форму.

Нажмите F4 и перетяните курсор из QPushButton и отпустите его в верхней части QLineEdit. Чтобы вернуться в обычный режим, нажмите на F3.

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

Благодаря этому появится редактор сигнала/слота.

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

Слева находятся предопределенные сигналы, справа — предопределенные слоты. Скажем, нам нужно подключить сигнал clicked() с слотом «очистки содержимого«.

Выберите сигнал clicked слева и выберите clear слот справа и нажмите OK.

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

После выполнения подключений ваших сигналов и слотов, вы можете выйти из этого режима, нажав ESC, или F3.

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

Сохраните форму как signaledit.ui и конвертируем её в signaledit.py:

pyuic5 signaledit.ui o signaledit.py

Полученный файл импортируем в наш код:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

from PyQt5 import QtWidgets

# Импортируем наш шаблон.

from signaledit import Ui_MainWindow

import sys

class mywindow(QtWidgets.QMainWindow):

    def __init__(self):

        super(mywindow, self).__init__()

        self.ui = Ui_MainWindow()

        self.ui.setupUi(self)

app = QtWidgets.QApplication([])

application = mywindow()

application.show()

sys.exit(app.exec())

Результат:

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

Как выпускать сигналы в PyQt5

Мы увидели, как работают сигналы и слоты. Все сигналы, с которыми мы работали, являются предопределенными для нас.

Но что на счет выпуска собственного сигнала?

Это очень просто! Вы можете сделать это, просто использовав класс pyqtSignal, как показано ниже:

  • Определите ваше событие типом pyqtSignal;
  • Вызовите метод emit() в том месте, где вы хотите, чтобы произошло событие.

Скажем, у нас есть класс nut, и мы хотим, чтобы сигнал cracked был выпущен.

from PyQt5.QtCore import pyqtSignal, QObject

class nut(QObject):

    cracked = pyqtSignal()

    def __init__(self):

        QObject.__init__(self)

    def crack(self):

        self.cracked.emit()

Как использовать сигнал

Сейчас мы сделаем наш пример более практичным, создаем экземпляр класса nut и выпуская сигнал cracked:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

from PyQt5.QtCore import pyqtSignal, QObject

class nut(QObject):

    cracked = pyqtSignal()

    def __init__(self):

        QObject.__init__(self)

    def crack(self):

        self.cracked.emit()

def crackit():

    print(«hazelnut cracked!»)

hazelnut = nut()

# подключение сигнала cracked к слоту crackit

hazelnut.cracked.connect(crackit)

hazelnut.crack()

Сигнал cracked успешно выпущен.

Переопределение сигнала (события) в PyQt5

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

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

def keyPressEvent(self, e):

    if e.key() == Qt.Key_F12:

        self.close()

Теперь, если пользователь нажмет клавишу F12, главное окно будет закрыто.

Здесь мы переопределили основной сигнал нажатия в главном окне и закрыли это окно.

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

Давайте перетянем QComboBox в нашу форму и взглянем на её методы.

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

Сохраняем файл как combobox.ui и конвертируем его в combobox.py:

pyuic5 combobox.ui o combobox.py

Если вы запустите приложение сейчас, обратите внимание на то, что QComboBox — пустой. Чтобы вносить объекты в QComboBox, используйте метод addItem():

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

from PyQt5 import QtWidgets

from combobox import Ui_MainWindow

import sys

class mywindow(QtWidgets.QMainWindow):

    def __init__(self):

        super(mywindow, self).__init__()

        self.ui = Ui_MainWindow()

        self.ui.setupUi(self)

        # Добавляем новые значения

        self.ui.comboBox.addItem(«Программист»)

        self.ui.comboBox.addItem(«Дизайнер»)

app = QtWidgets.QApplication([])

application = mywindow()

application.show()

sys.exit(app.exec())

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

Получаем все элементы из QComboBox

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

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

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

Выбор одного элемента из QCombobox

Чтобы выбрать элемент из QComboBox, у вас есть два метода:

# по индексу, который начинается с нуля

self.ui.comboBox.setCurrentIndex(1)

#выбор по тексту

self.ui.comboBox.setCurrentText(«Second item»)

Обратите внимание на то, что при выборе элемента по тексту, следует убедиться в том, что вы вводите правильный текст. В противном случае, QComboBox останется на первом элементе.

Если вы хотите просмотреть вашу базу данных в формате таблицы, в PyQt5 предоставляется QTableWidget как раз для этой цели.

QTableWidget состоит из клеток, каждая клетка — экземпляр класса QTableWidgetItem.

Давайте создадим форму, которая содержит QTableWidget и QPushButton.

QTableWidget

Перетяните QTableWidget и QPushButton из PyQt5 Designer. После этого, сохраните форму как qtable.ui и конвертируйте дизайн в qtable.py.

pyuic5 qtable.ui o qtable.py

Чтобы добавлять ряды в QTableWidget, вы можете использовать метод setRowCount().

Для внесения столбцов в QTableWidget, воспользуйтесь методом setColumnCount().

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

from PyQt5 import QtWidgets

# Импортируем нашу форму.

from qtable import Ui_MainWindow

import sys

class mywindow(QtWidgets.QMainWindow):

    def __init__(self):

        super(mywindow, self).__init__()

        self.ui = Ui_MainWindow()

        self.ui.setupUi(self)

        self.ui.tableWidget.setColumnCount(2)

        self.ui.tableWidget.setRowCount(4)

app = QtWidgets.QApplication([])

application = mywindow()

application.show()

sys.exit(app.exec())

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

Теперь вы можете писать текст вручную внутри клеток QTableWidget.

Очистка содержимого QTableWidget

Чтобы очистить содержимое QTableWidget, вы можете использовать метод clear, вот так:

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

from PyQt5 import QtWidgets

# Импортируем нашу форму.

from qtable import Ui_MainWindow

import sys

class mywindow(QtWidgets.QMainWindow):

    def __init__(self):

        super(mywindow, self).__init__()

        self.ui = Ui_MainWindow()

        self.ui.setupUi(self)

        self.ui.tableWidget.setColumnCount(2)

        self.ui.tableWidget.setRowCount(4)

        # очистка таблицы при клике на кнопку.

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

    def clear(self):

        self.ui.tableWidget.clear()

app = QtWidgets.QApplication([])

application = mywindow()

application.show()

sys.exit(app.exec())

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

Заполнение QTableWidget из кода

Чтобы заполнить QtableWidget программно, вам нужно использовать метод setItem() для каждого объекта QtableWidgetItem.

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

from PyQt5.QtWidgets import QTableWidgetItem

from qtable import *

import sys

data = []

data.append((‘Заполнить’, ‘QTableWidget’))

data.append((‘с данными’, ‘в Python’))

data.append((‘очень’, ‘просто’))

class mywindow(QtWidgets.QMainWindow):

    def __init__(self):

        super().__init__()

        self.ui = Ui_MainWindow()

        self.ui.setupUi(self)

        self.ui.tableWidget.setRowCount(3)

        self.ui.tableWidget.setColumnCount(2)

        # очистка таблицы при клике на кнопку.

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

        row = 0

        for tup in data:

            col = 0

            for item in tup:

                cellinfo = QTableWidgetItem(item)

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

                col += 1

            row += 1

    def clear(self):

        self.ui.tableWidget.clear()

app = QtWidgets.QApplication([])

win = mywindow()

win.show()

sys.exit(app.exec())

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

  • Сначала мы создали список трех кортежей Python;
  • Внутри конструктора главного окна, мы установили количество столбцов и рядов;
  • Далее мы перебираем список и получаем каждый кортеж в списке, для заполнения клеток таблицы, при помощи метода setItem()
  • Наконец, мы показываем главное окно.

Делаем QTableWidget нередактируемым (только для чтения)

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

Чтобы сделать QTableWidget нередактируемым, вы можете использовать метод setFlags(), чтобы сделать каждый QTableWidgetItem доступным только для чтения.

# Только для чтения

cellinfo.setFlags(

    QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled

)

Вам нужно установить флажки, перед тем как настраивать содержимое вашей клетки.

Таким образом, ваш код будет выглядеть вот так:

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

from PyQt5.QtWidgets import QTableWidgetItem

from qtable import *

import sys

data = []

data.append((‘Заполнить’, ‘QTableWidget’))

data.append((‘с данными’, ‘в Python’))

data.append((‘очень’, ‘просто’))

class mywindow(QtWidgets.QMainWindow):

    def __init__(self):

        super().__init__()

        self.ui = Ui_MainWindow()

        self.ui.setupUi(self)

        self.ui.tableWidget.setRowCount(3)

        self.ui.tableWidget.setColumnCount(2)

        # очистка таблицы при клике на кнопку.

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

        row = 0

        for tup in data:

            col = 0

            for item in tup:

                cellinfo = QTableWidgetItem(item)

                # Только для чтения

                cellinfo.setFlags(

                    QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled

                )

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

                col += 1

            row += 1

    def clear(self):

        self.ui.tableWidget.clear()

app = QtWidgets.QApplication([])

win = mywindow()

win.show()

sys.exit(app.exec())

Теперь, если вы попробуете отредактировать какую-либо клетку — у вас не выйдет, так как QtableWidgetItem теперь нельзя редактировать

До этого момента, названия столбцов QTableWidget были числами. Как на счет того, чтобы поменять названия столбцов на что-нибудь другое?

Чтобы задать текст заголовкам QTableWidget, вы можете использовать метод setHorizontalHeaderLabels(), вот так:

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

from PyQt5.QtWidgets import QTableWidgetItem

from qtable import *

import sys

data = []

data.append((‘BMW’, ‘1991’))

data.append((‘Audi’, ‘2003’))

data.append((‘Volvo’, ‘2010’))

class mywindow(QtWidgets.QMainWindow):

    def __init__(self):

        super().__init__()

        self.ui = Ui_MainWindow()

        self.ui.setupUi(self)

        self.ui.tableWidget.setRowCount(3)

        self.ui.tableWidget.setColumnCount(2)

        # очистка таблицы при клике на кнопку.

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

        # заголовки для столбцов.

        self.ui.tableWidget.setHorizontalHeaderLabels(

            (‘Марка’, ‘Год выпуска’)

        )

        row = 0

        for tup in data:

            col = 0

            for item in tup:

                cellinfo = QTableWidgetItem(item)

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

                col += 1

            row += 1

    def clear(self):

        self.ui.tableWidget.clear()

app = QtWidgets.QApplication([])

win = mywindow()

win.show()

sys.exit(app.exec())

setHorizontalHeaderLabels

Таким же образом, вы можете менять заголовок ряда, при помощи метода setVerticalHeaderLabels():

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

from PyQt5.QtWidgets import QTableWidgetItem

from qtable import *

import sys

data = []

data.append((‘BMW’, ‘1991’))

data.append((‘Audi’, ‘2003’))

data.append((‘Volvo’, ‘2010’))

class mywindow(QtWidgets.QMainWindow):

    def __init__(self):

        super().__init__()

        self.ui = Ui_MainWindow()

        self.ui.setupUi(self)

        self.ui.tableWidget.setRowCount(3)

        self.ui.tableWidget.setColumnCount(2)

        # очистка таблицы при клике на кнопку.

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

        # заголовки для столбцов.

        self.ui.tableWidget.setHorizontalHeaderLabels(

            (‘Марка’, ‘Год выпуска’)

        )

        # названия рядов.

        self.ui.tableWidget.setVerticalHeaderLabels(

            (‘900$’, ‘5000$’, ‘13000$’)

        )

        row = 0

        for tup in data:

            col = 0

            for item in tup:

                cellinfo = QTableWidgetItem(item)

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

                col += 1

            row += 1

    def clear(self):

        self.ui.tableWidget.clear()

app = QtWidgets.QApplication([])

win = mywindow()

win.show()

sys.exit(app.exec())

setVerticalHeaderLabels

Как сортировать QTableWidget

Вы можете сделать ваш QTableWidget сортируемым, при помощи метода setSortingEnabled().

self.ui.tableWidget.setSortingEnabled(True)

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

Вы можете использовать этот метод перед, или до наполнения QTableWidget данными.

Что на счет сортировки в QTableWidget, но только для определенного столбца?

Вы можете использовать метод sortByColumn(), и указать индекс столбца и порядок сортировки, вот так:

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

58

59

60

61

62

63

64

from PyQt5.QtWidgets import QTableWidgetItem

from qtable import *

import sys

data = []

data.append((‘BMW’, ‘2005’))

data.append((‘Audi’, ‘2003’))

data.append((‘Volvo’, ‘1990’))

data.append((‘Toyota’, ‘2018’))

class mywindow(QtWidgets.QMainWindow):

    def __init__(self):

        super().__init__()

        self.ui = Ui_MainWindow()

        self.ui.setupUi(self)

        # Кол-во рядов меняется в зависимости от значений в data.

        self.ui.tableWidget.setRowCount(

            len(data)

        )

        # Кол-во столбцов меняется в зависимости от data.

        self.ui.tableWidget.setColumnCount(

            len(data[0])

        )

        # очистка таблицы при клике на кнопку.

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

        # заголовки для столбцов.

        self.ui.tableWidget.setHorizontalHeaderLabels(

            (‘Марка’, ‘Год выпуска’)

        )

        row = 0

        for tup in data:

            col = 0

            for item in tup:

                cellinfo = QTableWidgetItem(item)

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

                col += 1

            row += 1

        # Сортировка по году выпуска.

        # 0 — Марка

        # 1 — Год выпуска

        self.ui.tableWidget.sortByColumn(

            1, QtCore.Qt.AscendingOrder

        )

    def clear(self):

        self.ui.tableWidget.clear()

app = QtWidgets.QApplication([])

win = mywindow()

win.show()

sys.exit(app.exec())

Кстати, вы можете использовать метод sortItems() для сортировки QTableWidget в возрастающем порядке по умолчанию.

self.ui.tableWidget.sortItems(0)

Или вы можете определить свой порядок сортировки:

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

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

Добавляем QComboBox в QTableWidget

У вас может появится задача, чтобы пользователь выбирал значение внутри QTableWidget, вместо ввода текста.
Как на счет того, чтобы добавить QComboBox в QTableWidgetItem?

Чтобы добавить QComboBox внутрь QTableWidgetItem, вы можете использовать метод setCellWidget():

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

from PyQt5.QtWidgets import QTableWidgetItem

from qtable import *

import sys

data = [‘Python’, ‘PHP’, ‘Java’]

class mywindow(QtWidgets.QMainWindow):

    def __init__(self):

        super().__init__()

        self.ui = Ui_MainWindow()

        self.ui.setupUi(self)

        self.ui.tableWidget.setRowCount(3)

        self.ui.tableWidget.setColumnCount(2)

        row = 0

        for item in data:

            cellinfo = QTableWidgetItem(item)

            combo = QtWidgets.QComboBox()

            combo.addItem(«Изучить»)

            combo.addItem(«Забыть»)

            combo.addItem(«Удалить»)

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

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

            row += 1

app = QtWidgets.QApplication([])

win = mywindow()

win.show()

sys.exit(app.exec())

QComboBox в QTableWidget

Отлично!

Не ограничивайте себя в воображении и попробуйте вставлять различные виджеты, такие как QСheckbox, или даже QProgressBar.

QProgressBar в QTableWidget

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

from PyQt5.QtWidgets import QTableWidgetItem

from qtable import *

import sys

data = (

    (‘Python’, 95.5),

    (‘PHP’, 55.1),

    (‘Java’, 0.29)

)

class mywindow(QtWidgets.QMainWindow):

    def __init__(self):

        super().__init__()

        self.ui = Ui_MainWindow()

        self.ui.setupUi(self)

        self.ui.tableWidget.setRowCount(3)

        self.ui.tableWidget.setColumnCount(2)

        self.ui.tableWidget.setHorizontalHeaderLabels(

            (‘Язык’, ‘Знания’)

        )

        line = 0

        for item in data:

            cellinfo = QTableWidgetItem(item[0])

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

            # Создаем QProgressBar

            progress = QtWidgets.QProgressBar()

            progress.setMinimum(0)

            progress.setMaximum(100)

            # Формат вывода: 10.50%

            progress.setValue(item[1])

            progress.setFormat(‘{0:.2f}%’.format(item[1]))

            # Добавляем виджет в ячейку.

            self.ui.tableWidget.setCellWidget(line, 1, progress)

            line += 1

app = QtWidgets.QApplication([])

win = mywindow()

win.show()

sys.exit(app.exec())

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

Указанный выше код будет таким же, за исключением строки, где вы создаете QСomboBox, здесь вы внесете тот виджет, который вам нужен.

Единственное ограничение — это ваше собственное воображение!

Компиляция Python приложения

Вы можете конвертировать ваши программы Python в бинарные исполняемые, и для этого имеется множество инструментов.

Лично я предпочитаю pyinstaller, который подходит для упаковки кода Python в исполняемый файл под Windows, Mac OS X, Solaris, Linux и FreeBSD. Все это будет поддерживаться 32 и 64-битной архитектурой.

Лучшая в pyinstaller для нас — это наличие полной поддержки для PyQt5.

Отлично! Для начала, установим pyinstaller:

$ pip3 install pyinstaller

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

Ваш исполняемый файл будет создан в папке под названием dist в директории вашей программы Python.

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

Вы можете создать один исполняемый файл. Вот так:

$ pyinstaller onefile test.py

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

Вы можете использовать флажки -w или –noconsole, чтобы спрятать окно консоли:

Эта опция доступна только для Windows и Mac OS X.

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

Я старался сделать все на столько простым, на сколько это возможно. Надеюсь, это руководство оказалось для вас полезным.

Спасибо.

Являюсь администратором нескольких порталов по обучению языков программирования Python, Golang и Kotlin. В составе небольшой команды единомышленников, мы занимаемся популяризацией языков программирования на русскоязычную аудиторию. Большая часть статей была адаптирована нами на русский язык и распространяется бесплатно.

E-mail: vasile.buldumac@ati.utm.md

Образование
Universitatea Tehnică a Moldovei (utm.md)

  • 2014 — 2018 Технический Университет Молдовы, ИТ-Инженер. Тема дипломной работы «Автоматизация покупки и продажи криптовалюты используя технический анализ»
  • 2018 — 2020 Технический Университет Молдовы, Магистр, Магистерская диссертация «Идентификация человека в киберпространстве по фотографии лица»

В этом руководстве по PyQt5 будет показано, как использовать Python 3 и Qt для создания графического интерфейса пользователя в Windows, Mac или Linux. Мы даже расскажем, как самостоятельно написать установщик.

PyQt — это библиотека, которая позволяет использовать фреймворк Qt GUI (GUI — это графический интерфейс пользователя) в Python. Сам Qt, как известно, написан на C++. Используя его в Python, вы можете создавать приложения намного быстрее, не жертвуя при этом значительной частью производительности C++.

PyQt5 это самая последняя, пятая версия Qt. Еще можно найти в интернете случайное упоминание PyQt4, но эта версия устарела и больше не поддерживается.

Новый интересный конкурент PyQt — это Qt for Python. Она обладает практически идентичным API, но в отличие от PyQt имеет лицензию LGPL и, следовательно, может использоваться бесплатно даже в коммерческих проектах. Она поддерживается компанией Qt, а значит, скорее всего, за ней будущее. Здесь мы используем PyQt, потому что она более зрелая. Но, так как их интерфейсы очень похожи, вы всегда можете перейти на Qt for Python позднее.

Установка PyQt

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

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

python3 -m venv venv

Эта команда создаст директорию venv/. Чтобы активировать виртуальную среду в Windows, выполните следующую команду:

call venv/scripts/activate.bat

А для Mac и Linux вот эту:

source venv/bin/activate

То, что виртуальная среда активирована, вы можете увидеть по префиксу (venv) в командной строке:

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

pip install PyQt5==5.9.2

Мы используем версию 5.9.2, потому что не все версии PyQt одинаково стабильны. Данная версия гарантированно будет работать хорошо.

Итак, поздравляем! Вы только что успешно установили PyQt5.

Создание GUI (графического интерфейса пользователя)

Теперь самое время написать ваш первый графический интерфейс! В нашей виртуальной среде запустим Python и выполним следующие команды:

Сначала мы загружаем библиотеку PyQt при помощи оператора import:

from PyQt5.QtWidgets import QApplication, QLabel

Затем мы создаем QApplication при помощи следующей команды:

app = QApplication([])

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

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

Теперь, чтобы реально что-нибудь увидеть, мы создаем следующее сообщение:

label = QLabel('Hello World!')

Затем мы даем команду вывести это на экран:

label.show()

Эта команда покажет небольшое окошко (его вид зависит от вашей операционной системы):

Последний шаг — передача управления библиотеке Qt и указание «запустить приложение, пока пользователь не закроет его». Это делается так:

app.exec_()

Если все это сработало, как ожидалось, тогда супер! Вы только что создали при помощи Python и библиотеки Qt свое первое приложение с графическим интерфейсом.

Виджеты

Все, что вы видите в приложениях PyQt, называется виджетами. Кнопки, сообщения, окна, диалоговые окна, индикаторы выполнения и так далее — все это виджеты. Подобно html элементам, виджеты в Qt зачастую вложены друг в друга. Например, окно может содержать кнопку, а кнопка, в свою очередь, — сообщение.

На следующей картинке показаны наиболее распространенные виджеты Qt:

Они перечислены ниже в порядке сверху вниз и слева направо:

  • QLabel
  • QComboBox
  • QCheckBox
  • QRadioButton
  • QPushButton
  • QTableWidget
  • QLineEdit
  • QSlider
  • QProgressBar

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

Макеты

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

Вот код, создающий интерфейс, изображенный на картинке выше:

from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QVBoxLayout

app = QApplication([])
window = QWidget()
layout = QVBoxLayout()
layout.addWidget(QPushButton('Top'))
layout.addWidget(QPushButton('Bottom'))
window.setLayout(layout)
window.show()
app.exec_() 

Как и ранее, мы создали экземляр класса QApplication. Затем мы создаем само окно (window). Мы используем для него самый простой тип QWidget, так как он просто используется как контейнер, а никакого особого поведения нам задавать не нужно. Затем мы создаем макет (layout) и добавляем к нему две кнопки QPushButton. Наконец, мы говорим окну использовать именно этот макет (и, следовательно, его содержимое). Как и в нашем первом приложении, мы заканчиваем вызовами методов .show () и app.exec_ ().

Безусловно, существует большое количество разных макетов, например QHBoxLayout для размещения элементов в ряд. Более подробно с ними можно ознакомиться в документации Qt.

Пользовательские стили

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

Встроенные стили

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

Здесь используется стиль под названием Fusion. Если вместо этого использовать стиль Windows, это будет выглядеть следующим образом:

Чтобы применить стиль, нужно использовать метод app.setStyle (…):

from PyQt5.QtWidgets import *
app = QApplication([])
app.setStyle('Fusion')
...

Доступные стили зависят от вашей платформы, но обычно они включают в себя «Fusion», «Windows», «WindowsVista» (только для Windows) и «Macintosh» (только для Mac).

Пользовательские цвета

Если вам нравится стиль, но вы хотите изменить его цвета (например, на темную тему), вы можете использовать QPalette и app.setPalette (...). Например:

from PyQt5.QtCore import Qt
from PyQt5.QtGui import QPalette
from PyQt5.QtWidgets import QApplication, QPushButton

app = QApplication([])
app.setStyle('Fusion')
palette = QPalette()
palette.setColor(QPalette.ButtonText, Qt.red)
app.setPalette(palette)
button = QPushButton('Hello World')
button.show()
app.exec_() 

Это изменит цвет текста в кнопках на красный:

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

Таблицы стилей

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

from PyQt5.QtWidgets import QApplication, QPushButton

app = QApplication([])
app.setStyleSheet("QPushButton { margin: 10ex; }")
button = QPushButton('Hello World')
button.show()
app.exec_() 

Для получения дополнительной информации о таблицах стилей смотрите документацию Qt.

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

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

from PyQt5.QtWidgets import *

app = QApplication([])
button = QPushButton('Click')
def on_button_clicked():
    alert = QMessageBox()
    alert.setText('You clicked the button!')
    alert.exec_()

button.clicked.connect(on_button_clicked)
button.show()
app.exec_() 

Строка button.clicked — это сигнал, метод .connect (...) позволяет нам установить на нем так называемый слот. Это просто функция, которая вызывается при поступлении сигнала. В приведенном выше примере наш слот показывает окно сообщения.

Термин «слот» важен при использовании Qt в C++, потому что в C++ слоты должны быть объявлены особым образом. Однако в Python любая функция может быть слотом — мы видели это выше. Поэтому различие между слотами и обычными функциями не имеет для нас большого значения.

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

Компилируем наше приложение

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

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

В мире Python процесс превращения исходного кода в автономный исполняемый файл называется замораживанием (freezing). Несмотря на наличие множества библиотек, решающих эту проблему, например PyInstaller, py2exe, cx_Freeze, bbfreze, py2app и так далее, замораживание приложений PyQt всегда было на удивление непростой проблемой.

Мы будем использовать новую библиотеку под названием fbs, которая позволяет создавать автономные исполняемые файлы для приложений PyQt. Для ее установки введите команду:

pip install fbs

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

fbs startproject

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

Когда вы введете предложенную команду run, должно открыться пустое окно:

Это приложение PyQt5, такое же, как и те, что мы видели раньше. Его исходный код находится в src/main/python/main.py в вашем текущем каталоге. Но вот что самое интересное: мы можем использовать fbs, чтобы превратить его в отдельный исполняемый файл!

fbs freeze

Эта команда создает и помещает автономный двоичный файл в папку /MyApp/ вашего текущего каталога. Вы можете отправить его своим друзьям (с той же ОС, что и ваша), и они также смогут запустить ваше приложение!

Бонус: создаем установщик

Библиотека fbs также позволяет вам создать установщик для вашего приложения с помощью команды fbs installer:

(Если вы работаете в Windows, вам сначала нужно установить NSIS и поместить путь к нему в свой PATH.)

За дополнительной информацией по использованию библиотеки fbs обратитесь к ее документации.

Итоги

Если вы дошли до этого места — примите наши поздравления. Надеемся, теперь у вас есть хорошее представление о том, как для написания приложений Python можно использовать PyQt (и различные ее части). Мы также узнали, как можно создавать автономные исполняемые файлы и установщики при помощи fbs.

Руководство по работе с библиотекой Qt с использованием Python 3

Установка необходимых компонентов для работы

  1. Установить Python версии не менее 3.5.

    В операционных системах семейства Windows процесс установки сводится к скачиванию установщика с сайта https://www.python.org и его запуска.

    В операционных система семейства Unix процесс установки сводится к запуску пакетного менеджера с выбором необходимого пакета.

    Пример установки Python 3 в Ubuntu:

    sudo apt-get install python3
    

    По умолчанию, путь к интерпретатору Python 3 при установке на любой операционной системе добавляется к переменной среды PATH. В Windows для запуска интепретатора достаточно набрать в консоли:

    В Unix системах, как правило, может быть уже установлена более ранняя версия интерпретатора, поэтому для корректного запуска 3-ей ветки Python рекомендуется выполнить в терминале команду:

  2. В Python установка сторонних библиотек (или пакетов) происходит с помощью пакетного менеджера pip.

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

    В Unix системах установка пакетного менеджера pip происходит отдельно.

    Пример установки pip в Ubuntu:

    sudo apt-get install python3-pip
    

    Установка сторонних пакетов (библиотек) сводится к следующей команде в терминале Unix/консоли Windows:

    pip3 install название_стороннего_пакета
    

    pip автоматически найдет, скачает и установит необходимый пакет из сети интернет.

  3. Для установки библиотеки Qt следует выполнить следующую команду:

Основы работы с Qt

Библиотека Qt является кросплатформенной и предназначена для написания графических приложений. Она инкапсулирует в себе все основные понятия любой из операционных графических систем: окна, фреймы, модальные диалоги, кнопки, текстовые поля, панели и т.д. Ядро библиотеки и всех ее компонентов написаны на языке программирования C++. Библиотека не является монолитной и разбита на несколько основных модулей, которые содержат классы для работы с графикой, сетью, файлами, аудио/видео, потоками ОС и т.д.

Пакет PyQt5 является портом для работы с Qt на языке Python. Ввиду этого, пакет наследует основные названия модулей библиотеки и их классов. Однако, в отличие от процесса работы на C++ под Qt, работа на языке Python с использованием пакета PyQt5 избавляет программиста от низкоуровневых особенностей C++ и ускоряет процесс написания программного кода. В пользу PyQt5 стоит сказать, что скорость понимания абстракций графического интерфейса, написанных на языке Python, бывает более высокой, нежели на C++.

Как правило, процесс ознакомления с PyQt5 тесно связан с чтением документации по тому или иному классу. Однако, стоит заметить, что все описания классов модулей Qt представлены на языке C++. Но такие понятия, как классы, его атрибуты и методы в языке C++ интуитивно легко перекладываются на язык Python. Тем самым, любые описания и примеры использования того или иного атрибута/метода на языке C++ в документации Qt справедливы и для Python, где любые упоминания про указатели и ссылки просто опускаются при работы с PyQt5.

На данный момент библиотека Qt развивается в двух направлениях: Qt Widgets и Qt Quick. Qt Widgets является фундаментальным и базовым направлением библиотеки. Данный модуль существует с момента сущестования платформы и направлен на создания графических приложений в стиле объектно-ориентированного подхода, где любой компонент интерфейса представлен объектом класса, тем самым организуя весть графический интерфейс пользователя в иерархию объектов. Qt Quick является более современным ответвлением платформы Qt. Данное направление вводит новые высокоуровневые абстракции вроде машины конечного автомата и вносит принципы реактивного программирования. Также, Qt Quick предлагает идею декларативного описания пользовательского интерфейса средствами JavaScript подобного языка QML.

В данном руководстве описываются базовые принципы работы с Qt Widgets совместно с пакетом PyQt5.

Ссылка на документацию Qt 5: http://doc.qt.io/qt-5/qtwidgets-index.html

Ссылка на документацию PyQt5: http://pyqt.sourceforge.net/Docs/PyQt5

1. Основной цикл обработки событий

Приложение Qt построено на основе бесконечного цикла, который обратывает события: события операционной системы, события пользоваля приложения (поведение мыши, использование клавиатуры). Для запуска минимального приложения, следует передать циклу контекст, в котором начнут обрабатываться события. Базовым контекстом является понятие Виджет, которое представлено классом QWidget.

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

Минимальное приложение Qt состоит из определения класса наследника QWidget, создания его экземпляра и запуска бесконечного цикла обработки событий.

import sys
from PyQt5.QtWidgets import QWidget, QApplication, QVBoxLayout, QLabel


class MyWidget(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self._initUI()

    def _initUI(self):
        self.label = QLabel('Hello', self)

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

        self.setLayout(self.layout)
        self.setGeometry(0, 0, 100, 100)
        self.show()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    myWidget = MyWidget()
    sys.exit(app.exec_())

2. Виджеты

Как было сказано, виджет представлен классом QWidget. Для создания виджета следует определить класс-наследник QWidget. В конструкторе класса следует добавить последний аргумент по умолчанию parent и вызвать инструкцию:

Параметр parent указывает на родительский виджет описываемого. Если описываемый является корневым, parent = None. Стоит сказать, что создание любого другого дочернего виджета, разметки должно просходить с передачей последним аргументом родительского виджета parent. Наиболее часто, родителем оказывается описываемый виджет self.

Часто, виджетам устанавливают ту или иную разметку, по правилам которой внутри располагаются другие виджеты. Наиболее используемыми классами разметки являются QVBoxLayout (вертикальная разметка) и QHBoxLayout (горизонтальная разметка). Для добавления дочерних виджетов в разметку предназачен метод addWidget(QWidget). Чтобы установить виджету ту или иную разметку используется метод setLayout(QLayout).

Хорошим стилем считается создание всех дочерних разметок/виджетов описываемого в теле контструктора класса. Как правило, создается приватный метод, например _initUI, и вызывается в конструкторе __init__.

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

2.1 Текстовая метка: QLabel

Пример использования:

from PyQt5.QtWidgets import QLabel

...

self.label = QLabel('Text', self)

Часто используемые методы:

  1. text() → string: возвращает текст метки.
  2. setText(string): устанавливает текст метки.

2.2 Текстовое поле: QLineEdit

Пример использования

from PyQt5.QtWidgets import QLineEdit

...

self.edit = QLineEdit('текст в поле ввода', self)

Часто используемые методы:

  1. text() → string: возвращает текст поля ввода.
  2. setText(string): устанавливает текст поля ввода.

2.3 Кнопка: QPushButton

Пример использования

from PyQt5.QtWidgets import QPushButton

...

self.button = QPushButton('Текст на кнопке', self)

Часто используемые методы:

  1. setText(string): устанавливает текст на кнопке.

2.4 Многострочное поле ввода: QTextEdit

Пример использования

from PyQt5.QtWidgets import QTextEdit

...

self.muli_edit = QTextEdit(self)

Часто используемые методы:

  1. setText(string): устанавливает текст в поле ввода.
  2. toPlainText() → string: возвращает обычный текст.
  3. toHtml() → string: возврашает текст в формате HTML.

2.5 Слайдер: QSlider

Пример использования

from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QSlider

...

self.slider = QSlider(Qt.Horizontal, self)

Часто используемые методы:

  1. setTickInterval(int): устанавливает шаг.
  2. tickInterval() → int: возвращает шаг.
  3. setMinimum(int): устанавливает минимальное значение.
  4. setMaximum(int): устанавливает максимальное значение.

2.6 Чек-бокс: QCheckBox

Пример использования

from PyQt5.QtWidgets import QCheckBox

...

self.checkbox = QCheckBox('Метка чек-бокса', self)

Часто используемые методы:

  1. toogle(): ставит/снимает чек-бокс.

3. Взаимодействие с пользователем: введение в сигналы/слоты

В библиотеке Qt любые из классов, которые являются наследниками класса QObject могут участвовать в механизме сигналов/слотов. Практически все классы Qt являются наследниками QObject, в том числе и виджеты.

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

Как правило, дочерние компоненты описываемого виджета генерируют какие-либо сигналы. Например, сигнал клика по кнопке. Для реакции на данное событие создается метод внтури описываемого виджета. Стоит упомянуть, что сигнал может передавать любую порцию информации: число, строка, список и т.д.. Если сигнал отправляет какие-либо данные, то в методе на реакцию данного сигнала должен передаваться аргумент(ы) для обработки передаваемой информации.

Пример использования механизма сигналов/слотов:

import sys
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import (QWidget, QLCDNumber, QSlider,
                             QVBoxLayout, QApplication)


class Example(QWidget):

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

        self.initUI()

    def initUI(self):

        lcd = QLCDNumber(self)
        sld = QSlider(Qt.Horizontal, self)

        vbox = QVBoxLayout()
        vbox.addWidget(lcd)
        vbox.addWidget(sld)

        self.setLayout(vbox)
        sld.valueChanged.connect(lcd.display)

        self.setGeometry(300, 300, 250, 150)
        self.show()


if __name__ == '__main__':

    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

Как видно из примера, виджет sld генерирует сигнал valueChanged, информирующий об изменении позиции слайдера. В свою очередь, данный сигнал связан с методом display виджета lcd. В данном случае, valueChanged является сигналом и отсылает значение типа int, а display является методом-сигналом, в который передается значение типа int. Связывание сигнала и слота происходит с помощью метода сигнала connect, который имеется у любого сигнала Qt.

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

Пример определения слота:

import sys
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import (QWidget, QApplication, QVBoxLayout,
                             QLabel, QPushButton)


class MyWidget(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self._initUI()

    def _initUI(self):
        self.label = QLabel('Push the Button', self)
        self.button = QPushButton('Push', self)
        self.button.clicked.connect(self._handleClickButton)

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

        self.setLayout(self.layout)
        self.show()

    def _handleClickButton(self):
        self.label.setText('Push Done.')

if __name__ == '__main__':
    app = QApplication(sys.argv)
    myWidget = MyWidget()
    sys.exit(app.exec_())

Чтобы определить слот, который реагирует на сигналы, отправляющие какую-либо информацию, следует лишь добавить аргумент(ы).

Пример определения слота на сигнал, передающий значение типа int:

import sys
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import (QWidget, QApplication, QVBoxLayout,
                             QLabel, QSlider)


class MyWidget(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self._initUI()

    def _initUI(self):
        self.label = QLabel('Change Slider', self)
        self.slider = QSlider(Qt.Horizontal, self)
        self.slider.valueChanged.connect(self._handleChangeSlider)

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

        self.setLayout(self.layout)
        self.show()

    def _handleChangeSlider(self, value):
        self.label.setText(str(value))

if __name__ == '__main__':
    app = QApplication(sys.argv)
    myWidget = MyWidget()
    sys.exit(app.exec_())

Виджет slider генерирует сигнал valueChanged при изменении слайдера. В свою очередь, данный сигнал связан с слотом/методом _handleChangeSlider, который принимает аргумент value типа int. При любом изменении слайдера вызывается метод _handleChangeSlider, который устанавливает текст метке label на значение ползунка слайдера. Стоит сказать, что метод метки label.setText принимает строковое значение, поэтому значение, отправляемое сигналом, числового типа int явно приводится к строковому типу str.

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

Введение В этом руководстве мы рассмотрим, как использовать среду 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.

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

Руководство по PyQt: Python GUI Designer

От автора: что такое PyQt? PyQt — это привязка Python с открытым исходным кодом для виджет-инструментария Qt, который также функционирует как кросс-платформенная среда разработки приложений. Qt — это популярная среда C ++ для написания приложений с помощью графического интерфейса для всех основных настольных, мобильных и встраиваемых платформ (поддерживает Linux, Windows, MacOS, Android, iOS, Raspberry Pi и многие другие).

PyQt разрабатывается и поддерживается Riverbank Computing, компанией, базирующейся в Англии, а Qt — финской фирмой The Qt Company.

В этом руководстве по PyQT мы рассмотрим:

Что такое PyQt?

Функции PyQT

Версии PyQt

Как установить PyQt

Основные понятия и программы PyQt

Компоненты и виджеты

Темы

Функци PyQT

PyQt состоит из более чем шести сотен классов, охватывающих ряд функций, таких как:

Графические пользовательские интерфейсы

Базы данных SQL

Веб-инструментарий

Обработка XML

Сети

Эти функции можно комбинировать для создания расширенных пользовательских интерфейсов, а также автономных приложений. Многие крупные компании из различных отраслей используют PyQt: LG, Mercedes, AMD, Panasonic, Harman и т. д.

Версии PyQt

PyQt доступен в двух редакциях: PyQt4 и PyQt5. PyQt4 предоставляет связующий код для привязки версий Qx 4.x и 5.x, в то время как PyQt5 обеспечивает привязку только для версий 5.x. В результате PyQt5 не имеет обратной совместимости с устаревшими модулями более ранней версии. В этом руководстве будет использоваться для демонстрации примеров PyQt5. Помимо этих двух версий, Riverbank Computing также предоставляет PyQt3D — привязки python для инфраструктуры Qt3D. Qt3D — это прикладная среда, используемая для создания систем моделирования в реальном времени с 2D / 3D рендерингом.

Как установить PyQt

Есть два способа установки PyQt.

Использование файлов Wheel

Сборка и установка из исходного кода

Qt (произносится «кьют») — сложная система, а база кода PyQt содержит скомпилированный код C ++ и Python. В результате по сравнению с другими библиотеками Python это сложный процесс для сборки и установки из исходного кода. Тем не менее, вы можете легко установить PyQt5 с помощью Wheel.

Установка с помощью Wheel

Wheel — это новый стандартный формат упаковки и распространения Python. Проще говоря, Wheel — это ZIP-архив со специальным названием и расширение файла. Wheel можно установить с помощью pip (менеджер пакетов Python), который включен по умолчанию в последние версии Python.

Итак, если у вас установлен Python 3.4 или более поздней версии, у вас уже есть pip. Однако, если вы используете более старую версию Python, вам нужно скачать и установить pip, прежде продолжать. Вы можете найти инструкции по установке по этой ссылке: //pypi.org/project/pip/.

Чтобы установить PyQt5:

Шаг 1) Откройте командную строку или PowerShell на компьютере с Windows.

Шаг 2) Введите следующее:

Этот шаг загрузит пакет PyQt5 whl (около 50 МБ) и установит его в вашей системе.

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

Основные понятия и программы PyQt

Теперь, когда вы успешно установили PyQt5 на компьютер, вы готовы писать приложения на python с помощью графического интерфейса. Давайте начнем с простого приложения, которое будет отображать пустое окно на экране. Запустите Python IDLE и введите следующее:

import sys

from PyQt5.QtWidgets import QApplication, QWidget

if __name__ == «__main__»:

    app = QApplication(sys.argv)

    w = QWidget()

    w.resize(300,300)

    w.setWindowTitle(‘Guru99’)

    w.show()

    sys.exit(app.exec_())

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

Здорово! Работает. Это не так много, но достаточно, чтобы понять основы. Теперь давайте рассмотрим подробно, что делает каждая из строк в программе.

from PyQt5.QtWidgets import QApplication, QWidget

Этот оператор импортирует все модули, необходимые для создания GUI, в текущее пространство имен. Модуль QtWidgets содержит все основные виджеты, которые вы будете использовать в этом руководстве.

app = QApplication(sys.argv)

Здесь вы создаете объект класса QApplication. Этот шаг необходим для PyQt5; каждое приложение пользовательского интерфейса должно создавать экземпляр QApplication в качестве своего рода точки входа в приложение. Если вы не создадите его, будут выданы ошибки.

sys.argv — это список параметров командной строки, которые вы можете передать приложению при запуске через оболочку или при автоматизации интерфейса.

В этом примере вы не передали аргументы QApplications. Следовательно, вы также можете заменить его приведенным ниже кодом и даже не импортировать модуль sys.

app = QApplication([])

w = QWidget()

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

Метод resize класса QWidget позволяет устанавливать размеры любого виджета. В этом случае вы изменили размер окна на 300 * 300 пикселей. Здесь вы должны помнить, что виджеты могут быть вложены вместе, внешний виджет (т. е. виджет без родителя) называется окном.

w.setWindowTitle(‘Guru99’)

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

show() просто отображает виджет на экране монитора.

Метод app.exec_() запускает цикл событий Qt / C ++. Как вы знаете, PyQt в основном написан на C ++ и использует механизм цикла событий для реализации параллельного выполнения. app.exec_() передает управление Qt, который выходит из приложения только тогда, когда пользователь закроет его графический интерфейс. Вот почему Ctrl + C не выполняет выход из приложения, как в других программах Python. Поскольку Qt контролирует приложение, события Python не обрабатываются, пока мы не настроим их внутри приложения. Также обратите внимание, что у метода exec есть подчеркивание в имени; это потому, что exec() уже является ключевым словом в python, а подчеркивание разрешает конфликт имен.

Заполнение окон

В предыдущем разделе мы рассмотрели, как в Qt создать базовый виджет. Теперь пришло время сделать несколько более сложных интерфейсов, с которыми пользователи могут по-настоящему взаимодействовать. Снова, запустите IDLE и напишите следующее.

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

import sys

from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QPushButton, QMessageBox

def dialog():

    mbox = QMessageBox()

    mbox.setText(«Your allegiance has been noted»)

    mbox.setDetailedText(«You are now a disciple and subject of the all-knowing Guru»)

    mbox.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)

    mbox.exec_()

if __name__ == «__main__»:

    app = QApplication(sys.argv)

    w = QWidget()

    w.resize(300,300)

    w.setWindowTitle(‘Guru99’)

    label = QLabel(w)

    label.setText(«Behold the Guru, Guru99»)

    label.move(100,130)

    label.show()

    btn = QPushButton(w)

    btn.setText(‘Beheld’)

    btn.move(110,150)

    btn.show()

    btn.clicked.connect(dialog)

    w.show()

    sys.exit(app.exec_())

Сохраните файл как appone.py или как угодно и нажмите F5, чтобы запустить программу. Если вы не допустили ошибок, IDLE откроет новое окно с текстом и кнопкой, как показано ниже.

Как только вы нажмете кнопку в первом окне, откроется новое окно сообщения с текстом, который вы написали. Теперь вы можете нажать кнопку Hide Details/Show Details, чтобы переключить видимость дополнительного текста.

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

from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QPushButton, QMessageBox

Это импортирует еще несколько виджетов, которые вы использовали в этом примере, а именно QLabel, QPushButton и QMessageBox.

def dialog():

    mbox = QMessageBox()

    mbox.setText(«Your allegiance has been noted»)

    mbox.setDetailedText(«You are now a disciple and subject of the all-knowing Guru»)

    mbox.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)

    mbox.exec_()

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

Метод dialog вызывается из основного блока программы, когда кнопка нажимается в определенном виджете (в данном случае, btn PushButton). Событие клика, запущенное этой кнопкой, вызывает выполнение этой функции. Такая функция называется в Qt слотом, вы узнаете больше о сигналах и слотах в следующих разделах.

if __name__ == «__main__»:

    app = QApplication(sys.argv)

    w = QWidget()

    w.resize(300,300)

    w.setWindowTitle(‘Guru99’)

Это основной раздел приложения, и, как и в предыдущем примере, вы начинаете с создания экземпляра QApplication, за которым следует простой виджет, это экземпляр QWidget.

label = QLabel(w)

btn = QPushButton(w)

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

Здесь важно заметить, что при создании объектов label и btn вы передаете объект окна (w) конструкторам QLabel и QPushButton. Вот как работает вложение в PyQt5. Чтобы создать виджет внутри другого виджета, вы передаете ссылку на родительский виджет в конструктор дочернего элемента.

label.move(100,130)

btn.move(110,150)

move() используется для установки позиции виджета относительно его родительского виджета. В первом случае метка будет перемещена на 100 пикселей с левой стороны и на 130 пикселей сверху окна.

Точно так же кнопка будет размещена на 110 пикселей слева и на 150 пикселей сверху окна. Этот пример является грубым способом создания макетов и обычно не используется в производстве; он включен только для учебных целей. Qt поддерживает различные макеты, которые мы детально рассмотрим в следующих разделах этого руководства.

btn.clicked.connect(dialog)

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

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

widget.signal.connect(slot)

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

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

Компоненты и виджеты

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

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

Структура каталогов PyQt5

Это фундаментальные модули, используемые связыванием Qt в Python, в частности в PyQt5.

Qt: Он объединяет все классы / модули, упомянутые ниже, в один модуль. Это значительно увеличивает объем памяти, используемой приложением. Однако управлять инфраструктурой проще, импортируя только один модуль.

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

QtWidgets: Содержит большинство виджетов, доступных в Pyqt5.

QtGui: Содержит компоненты графического интерфейса и расширяет модуль QtCore.

QtNetwork: Содержит классы, используемые для реализации сетевого программирования через Qt. Он поддерживает TCP-серверы, TCP-сокеты, UDP-сокеты, обработку SSL, сетевых сеансов и поиск DNS.

QtMultimedia: Предоставляет низкоуровневый мультимедийный функционал.

QtSql: реализует интеграцию базы данных для баз данных SQL. Поддерживает ODBC, MySQL, Oracle, SQLite и PostgreSQL.

Виджеты PyQt5

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

QLineEdit: Это поле ввода, которое позволяет пользователю вводить одну строку текста.

QRadioButton: Это поле ввода с выбираемой кнопкой, аналогичное переключателям в html.

rad = QRadioButton(«button title»)

rad.setChecked(True)  #to select the button by default.

QComboBox: Используется для отображения выпадающего меню со списком выбираемых элементов.

drop = QComboBox(w)

drop.addItems([«item one», «item two», «item three»])

QCheckBox: Отображает выбираемое квадратное поле перед меткой, которая отмечена, если выбрана, аналогично переключателям.

check = QCheckBox(«button title»)

QMenuBar: Отображает горизонтальную строку меню в верхней части окна. Вы можете добавить в эту панель только объекты класса QMenu. Эти объекты QMenu могут дополнительно содержать строки, объекты QAction или другие объекты QMenu.

QToolBar: Это горизонтальная панель или панель, которую можно перемещать в пределах окна. Может содержать кнопки и другие виджеты.

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

QScrollBar: Используется для создания полос прокрутки, которые позволяют пользователю прокручивать вверх и вниз в пределах окна. Он состоит из подвижного ползунка, дорожки ползунка и двух кнопок для прокрутки ползунка вверх или вниз.

QSplitter: Разделители используются для разделения содержимого окна, чтобы виджеты были сгруппированы правильно и не выглядели нагроможденными. QSplitter является одним из основных обработчиков макетов, доступных в PyQt5, и используется для разделения содержимого как по горизонтали, так и по вертикали.

QDock: виджет-док — это подокно с двумя свойствами: оно может быть перемещено в главное окно и его можно закрепить за пределами родительского окна в другом месте на экране.

Макеты и темы

В предыдущих примерах мы использовали только методы move() и resize() для установки позиций виджетов в графическом интерфейсе.

Тем не менее, PyQt имеет мощный механизм управления компоновкой, который можно использовать для создания расширенных пользовательских интерфейсов приложений. В этом разделе вы узнаете о двух важных классах, которые используются в Qt для создания и управления макетами: QBoxLayout и QGridLayout.

QBoxLayout

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

QHBoxLayout: используется для выравнивания дочерних виджетов по горизонтали.

QVBoxLayout: используется для выравнивания дочерних виджетов по вертикали.

Например, так будут выглядеть три кнопки, выровненные по QHBoxLayout.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

import sys

from PyQt5.QtWidgets import *

if __name__ == «__main__»:

    app = QApplication([])

    w = QWidget()

    w.setWindowTitle(«Musketeers»)

    btn1 = QPushButton(«Athos»)

    btn2 = QPushButton(«Porthos»)

    btn3 = QPushButton(«Aramis»)

    hbox = QHBoxLayout(w)

    hbox.addWidget(btn1)

    hbox.addWidget(btn2)

    hbox.addWidget(btn3)

    w.show()

    sys.exit(app.exec_())

А вот как они будут выглядеть в QVBoxLayout.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

import sys

from PyQt5.QtWidgets import *

if __name__ == «__main__»:

    app = QApplication([])

    w = QWidget()

    w.setWindowTitle(«Musketeers»)

    btn1 = QPushButton(«Athos»)

    btn2 = QPushButton(«Porthos»)

    btn3 = QPushButton(«Aramis»)

    vb = QVBoxLayout(w)

    vb.addWidget(btn1)

    vb.addWidget(btn2)

    vb.addWidget(btn3)

    w.show()

    sys.exit(app.exec_())

Единственная функция, которая нуждается в каком-либо объяснении на данный момент, это метод addWidget(). Он используется для вставки виджетов в макет HBox или VBox. Он также используется в других макетах, где принимает другое количество параметров, как вы увидите в следующем разделе. Виджеты отображаются внутри макета в том порядке, в котором вы их вставляете.

QGridLayout

QGridLayout используется для создания интерфейсов, в которых виджеты расположены в виде сетки (например, матрицы или 2D-массива). Чтобы вставить элементы в сетку, вы можете использовать матричное представление, чтобы определить количество строк и столбцов в сетке, а также положение этих элементов.

Например, чтобы создать сетку 3 * 3 (т.е. сетку с тремя строками и тремя столбцами), вы пишите следующий код:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

import sys

from PyQt5.QtWidgets import *

if __name__ == «__main__»:

    app = QApplication([])

    w = QWidget()

    grid = QGridLayout(w)

    for i in range(3):

        for j in range(3):

            grid.addWidget(QPushButton(«Button»),i,j)

    w.show()

    sys.exit(app.exec_())

Вывод будет следующий:

Метод addWidget() в макете сетки принимает следующие аргументы:

Объект виджета, который вы хотите добавить в сетку

X-координата объекта

Y-координата объекта

Диапазон строк (по умолчанию = 0)

Col-span (по умолчанию = 0)

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

import sys

from PyQt5.QtWidgets import *

if __name__ == «__main__»:

    app = QApplication([])

    w = QWidget()

    grid = QGridLayout(w)

    grid.addWidget(QPushButton(«Button one»),0,0)

    grid.addWidget(QPushButton(«Button two»),0,1)

    grid.addWidget(QPushButton(«Button three»),1,0)

    grid.addWidget(QPushButton(«Button four»),1,1)

    w.show()

    sys.exit(app.exec_())

Вот как будет выглядеть сетка:

Вы также можете передать параметры rowspan и colspan в addWidget(), чтобы охватить более одной строки или столбца.

grid.addWidget(QPushButton(«Button five»),2,0,1,0)

Это создаст кнопку, которая растягивается на оба столбца.

Темы

PyQt5 поставляется с некоторыми встроенными темами, которые вы можете использовать в приложениях. Метод setStyle(), вызываемый в экземпляре QApplication, используется для установки определенной темы для вашего приложения. Например, добавление следующей строки кода изменит тему приложения по умолчанию на Fusion:

Так будет выглядеть предыдущий пример в теме Fusion.

Еще одна полезная функция для создания тем приложений — это метод setPalette(). Вот код для изменения цвета различных виджетов с помощью setPalette().

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

import sys

from PyQt5.QtCore import Qt

from PyQt5.QtWidgets import *

from PyQt5.QtGui import QPalette

if __name__ == «__main__»:

    app = QApplication([])

    app.setStyle(«Fusion»)

    qp = QPalette()

    qp.setColor(QPalette.ButtonText, Qt.black)

    qp.setColor(QPalette.Window, Qt.black)

    qp.setColor(QPalette.Button, Qt.gray)

    app.setPalette(qp)

    w = QWidget()

    grid = QGridLayout(w)

    grid.addWidget(QPushButton(«Button one»),0,0)

    grid.addWidget(QPushButton(«Button two»),0,1)

    grid.addWidget(QPushButton(«Button three»),1,0)

    grid.addWidget(QPushButton(«Button four»),1,1)

    w.show()

    sys.exit(app.exec_())

Вот результат:

Чтобы использовать метод setPalette(), сначала нужно определить палитру. Это делается путем создания объекта класса QPalette.

Обратите внимание, что класс QPalette принадлежит модулю QtGui, и вам нужно будет импортировать его, чтобы это работало. Создав объект QPalette, используйте метод setColor(), чтобы передать имя виджета, цвет которого вы хотите изменить, и цвет, который вы хотите установить.

qp.setColor(QPalette.Window, Qt.black)

Это изменит цвет окна на черный. После того, как вы определили цветовую схему, используйте функцию setPalette(), чтобы применить палитру к приложению.

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

Заключение

PyQt — это привязка Python для инфраструктуры пользовательского интерфейса C ++, Qt.

PyQt4 и PyQt5 — две основные версии, разработанные Riverbank Computing.

Основными модулями платформы PyQt являются: Qt, QtCore, QtWidgets, QtGui, QtSql, QtNetwork

PyQt поддерживает различные виджеты, такие как: Кнопки, Текстовые метки, Текстовые поля, Переключатели и чек-боксы, Панели инструментов и строки меню, Webkit, Вкладки, Доки

В PyQt интерактивность реализована с использованием сигналов и слотов.

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

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

Слот является функцией, которая подключается к сигналу и выполняет при повышении сигнала.

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

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

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

Источник: //www.guru99.com

Редакция: Команда webformyself.


PyQt5 — Introduction

PyQt is a GUI widgets toolkit. It is a Python interface for Qt, one of the most powerful, and popular cross-platform GUI library. PyQt was developed by RiverBank Computing Ltd. The latest version of PyQt can be downloaded from its official website − riverbankcomputing.com

PyQt API is a set of modules containing a large number of classes and functions. While QtCore module contains non-GUI functionality for working with file and directory etc., QtGui module contains all the graphical controls. In addition, there are modules for working with XML (QtXml), SVG (QtSvg), and SQL (QtSql), etc.

A list of frequently used modules is given below −

  • QtCore − Core non-GUI classes used by other modules

  • QtGui − Graphical user interface components

  • QtMultimedia − Classes for low-level multimedia programming

  • QtNetwork − Classes for network programming

  • QtOpenGL − OpenGL support classes

  • QtScript − Classes for evaluating Qt Scripts

  • QtSql − Classes for database integration using SQL

  • QtSvg − Classes for displaying the contents of SVG files

  • QtWebKit − Classes for rendering and editing HTML

  • QtXml − Classes for handling XML

  • QtWidgets − Classes for creating classic desktop-style UIs

  • QtDesigner − Classes for extending Qt Designer

Supporting Environments

PyQt is compatible with all the popular operating systems including Windows, Linux, and Mac OS. It is dual licensed, available under GPL as well as commercial license. The latest stable version is PyQt5-5.13.2.

Windows

Wheels for 32-bit or 64-bit architecture are provided that are compatible with Python version 3.5 or later. The recommended way to install is using PIP utility −

pip3 install PyQt5

To install development tools such as Qt Designer to support PyQt5 wheels, following is the command −

pip3 install pyqt5-tools

You can also build PyQt5 on Linux/macOS from the source code www.riverbankcomputing.com/static/Downloads/PyQt5

PyQt5 — What’s New

PyQt5 API is not automatically compatible with earlier versions. Hence, Python code involving PyQt4 modules should be upgraded manually by making relevant changes. In this chapter, main differences between PyQt4 and PyQt5 have been listed.

PyQt5 is not supported on versions of Python earlier than v2.6.

PyQt5 doesn’t support connect() method of QObject class for connection between signal and slot. Hence the usage can no more be implemented −

QObject.connect(widget, QtCore.SIGNAL(‘signalname’), slot_function)

Only the following syntax is defined −

widget.signal.connect(slot_function)

Classes defined in earlier QtGui module have been distributed in QtGui, QtPrintSupport an QtWidgets modules.

In the new QFileDialog class, The getOpenFileNameAndFilter() method is replaced by getOpenFileName(), getOpenFileNamesAndFilter() by getOpenFileNames() and getSaveFileNameAndFilter() by getSaveFileName(). Older signatures of these methods also have changed.

PyQt5 doesn’t have provision to define a class that is sub-classed from more than one Qt class.

pyuic5 utility (to generates Python code from Designer’s XML file) does not support the —pyqt3-wrapper flag.

pyrcc5 does not support the -py2 and -py3 flags. The output of pyrcc5 is compatible with all versions of Python v2.6 onwards.

PyQt5 always invokes sip.setdestroyonexit() automatically and calls the C++ destructor of all wrapped instances that it owns.

PyQt5 — Hello World

Creating a simple GUI application using PyQt involves the following steps −

  • Import QtCore, QtGui and QtWidgets modules from PyQt5 package.

  • Create an application object of QApplication class.

  • A QWidget object creates top level window. Add QLabel object in it.

  • Set the caption of label as «hello world».

  • Define the size and position of window by setGeometry() method.

  • Enter the mainloop of application by app.exec_() method.

Following is the code to execute Hello World program in PyQt −

import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
def window():
   app = QApplication(sys.argv)
   w = QWidget()
   b = QLabel(w)
   b.setText("Hello World!")
   w.setGeometry(100,100,200,50)
   b.move(50,20)
   w.setWindowTitle("PyQt5")
   w.show()
   sys.exit(app.exec_())
if __name__ == '__main__':
   window()

The above code produces the following output −

Hello World

It is also possible to develop an object oriented solution of the above code.

  • Import QtCore, QtGui and QtWidgets modules from PyQt5 package.

  • Create an application object of QApplication class.

  • Declare window class based on QWidget class

  • Add a QLabel object and set the caption of label as «hello world».

  • Define the size and position of window by setGeometry() method.

  • Enter the mainloop of application by app.exec_() method.

Following is the complete code of the object oriented solution −

import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
class window(QWidget):
   def __init__(self, parent = None):
      super(window, self).__init__(parent)
      self.resize(200,50)
      self.setWindowTitle("PyQt5")
      self.label = QLabel(self)
      self.label.setText("Hello World")
      font = QFont()
      font.setFamily("Arial")
      font.setPointSize(16)
      self.label.setFont(font)
      self.label.move(50,20)
def main():
   app = QApplication(sys.argv)
   ex = window()
   ex.show()
   sys.exit(app.exec_())
if __name__ == '__main__':
   main()

Hello Worlds

PyQt5 — Major Classes

PyQt API is a large collection of classes and methods. These classes are defined in more than 20 modules.

Following are some of the frequently used modules −

Sr.No. Modules & Description
1

QtCore

Core non-GUI classes used by other modules

2

QtGui

Graphical user interface components

3

QtMultimedia

Classes for low-level multimedia programming

4

QtNetwork

Classes for network programming

5

QtOpenGL

OpenGL support classes

6

QtScript

Classes for evaluating Qt Scripts

7

QtSql

Classes for database integration using SQL

8

QtSvg

Classes for displaying the contents of SVG files

9

QtWebKit

Classes for rendering and editing HTML

10

QtXml

Classes for handling XML

11

QtWidgets

Classes for creating classic desktop-style UIs.

12

QtDesigner

Classes for extending Qt Designer

13

QtAssistant

Support for online help

PyQt5 development tools is a collection of useful utilities for Qt development. Following is a select list of such utilities −

Sr.No. Tool Name & Description
1

assistant

Qt Assistant documentation tool

2

pyqt5designer

Qt Designer GUI layout tool

3

linguist

Qt Linguist translation tool

4

lrelease

compile ts files to qm files

5

pylupdate5

extract translation strings and generate or update ts files

6

qmake

Qt software build tool

7

pyqt5qmlscene

QML file viewer

8

pyqmlviewer

QML file viewer

9

pyrcc5

Qt resource file compiler

10

pyuic5

Qt User Interface Compiler for generating code from ui files

11

pyqmltestrunner

running unit tests on QML code

12

qdbus

command-line tool to list D-Bus services

13

QDoc

documentation generator for software projects.

14

Qhelpgenerator

generating and viewing Qt help files.

15

qmlimportscanner

parses and reports on QML imports

PyQt API contains more than 400 classes. The QObject class is at the top of class hierarchy. It is the base class of all Qt objects. Additionally, QPaintDevice class is the base class for all objects that can be painted.

QApplication class manages the main settings and control flow of a GUI application. It contains main event loop inside which events generated by window elements and other sources are processed and dispatched. It also handles system-wide and application-wide settings.

QWidget class, derived from QObject and QPaintDevice classes is the base class for all user interface objects. QDialog and QFrame classes are also derived from QWidget class. They have their own sub-class system.

Here is a select list of frequently used widgets

Sr.No. Widgets & Description
1

QLabel

Used to display text or image

2

QLineEdit

Allows the user to enter one line of text

3

QTextEdit

Allows the user to enter multi-line text

4

QPushButton

A command button to invoke action

5

QRadioButton

Enables to choose one from multiple options

6

QCheckBox

Enables choice of more than one options

7

QSpinBox

Enables to increase/decrease an integer value

8

QScrollBar

Enables to access contents of a widget beyond display aperture

9

QSlider

Enables to change the bound value linearly.

10

QComboBox

Provides a dropdown list of items to select from

11

QMenuBar

Horizontal bar holding QMenu objects

12

QStatusBar

Usually at bottom of QMainWindow, provides status information.

13

QToolBar

Usually at top of QMainWindow or floating. Contains action buttons

14

QListView

Provides a selectable list of items in ListMode or IconMode

15

QPixmap

Off-screen image representation for display on QLabel or QPushButton object

16

QDialog

Modal or modeless window which can return information to parent window

A typical GUI based application’s top level window is created by QMainWindow widget object. Some widgets as listed above take their appointed place in this main window, while others are placed in the central widget area using various layout managers.

The following diagram shows the QMainWindow framework −

QMainWindow

PyQt5 — Using Qt Designer

The PyQt installer comes with a GUI builder tool called Qt Designer. Using its simple drag and drop interface, a GUI interface can be quickly built without having to write the code. It is however, not an IDE such as Visual Studio. Hence, Qt Designer does not have the facility to debug and build the application.

Start Qt Designer application which is a part of development tools and installed in scripts folder of the virtual environment.

Virtual Environment

Start designing GUI interface by choosing File → New menu.

New Menu

You can then drag and drop required widgets from the widget box on the left pane. You can also assign value to properties of widget laid on the form.

Widget

The designed form is saved as demo.ui. This ui file contains XML representation of widgets and their properties in the design. This design is translated into Python equivalent by using pyuic5 command line utility. This utility is a wrapper for uic module of Qt toolkit. The usage of pyuic5 is as follows −

pyuic5 -x demo.ui -o demo.py

In the above command, -x switch adds a small amount of additional code to the generated Python script (from XML) so that it becomes a self-executable standalone application.

if __name__ == "__main__":
   import sys
   app = QtGui.QApplication(sys.argv)
   Dialog = QtGui.QDialog()
   ui = Ui_Dialog()
   ui.setupUi(Dialog)
   Dialog.show()
   sys.exit(app.exec_())

The resultant python script is executed to show the following dialog box −

python demo.py

Dialog Box

The user can input data in input fields but clicking on Add button will not generate any action as it is not associated with any function. Reacting to user-generated response is called as event handling.

PyQt5 — Signals & Slots

Unlike a console mode application, which is executed in a sequential manner, a GUI based application is event driven. Functions or methods are executed in response to user’s actions like clicking on a button, selecting an item from a collection or a mouse click etc., called events.

Widgets used to build the GUI interface act as the source of such events. Each PyQt widget, which is derived from QObject class, is designed to emit ‘signal’ in response to one or more events. The signal on its own does not perform any action. Instead, it is ‘connected’ to a ‘slot’. The slot can be any callable Python function.

Using Qt Designer’s Signal/Slot Editor

First design a simple form with a LineEdit control and a PushButton.

Slot Editor

It is desired that if button is pressed, contents of text box should be erased. The QLineEdit widget has a clear() method for this purpose. Hence, the button’s clicked signal is to be connected to clear() method of the text box.

To start with, choose Edit signals/slots from Edit menu (or press F4). Then highlight the button with mouse and drag the cursor towards the textbox

Cursor

As the mouse is released, a dialog showing signals of button and methods of slot will be displayed. Select clicked signal and clear() method

Clear Method

The Signal/Slot Editor window at bottom right will show the result −

Editor Window

Save ui and Build and Python code from ui file as shown in the below code −

pyuic5 -x signalslot.ui -o signalslot.py

Generated Python code will have the connection between signal and slot by the following statement −

self.pushButton.clicked.connect(self.lineEdit.clear)

Run signalslot.py and enter some text in the LineEdit. The text will be cleared if the button is pressed.

Building Signal-slot Connection

Instead of using Designer, you can directly establish signal-slot connection by following syntax −

widget.signal.connect(slot_function)

Suppose if a function is to be called when a button is clicked. Here, the clicked signal is to be connected to a callable function. It can be achieved in any of the following technique −

button.clicked.connect(slot_function)

Example

In the following example, two QPushButton objects (b1 and b2) are added in QDialog window. We want to call functions b1_clicked() and b2_clicked() on clicking b1 and b2 respectively.

When b1 is clicked, the clicked() signal is connected to b1_clicked() function −

b1.clicked.connect(b1_clicked())

When b2 is clicked, the clicked() signal is connected to b2_clicked() function.

import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

def window():
   app = QApplication(sys.argv)
   win = QDialog()
   b1 = QPushButton(win)
   b1.setText("Button1")
   b1.move(50,20)
   b1.clicked.connect(b1_clicked)
   
   b2 = QPushButton(win)
   b2.setText("Button2")
   b2.move(50,50)
   b2.clicked.connect(b2_clicked)
   
   win.setGeometry(100,100,200,100)

   win.setWindowTitle("PyQt5")
   win.show()
   sys.exit(app.exec_())

def b1_clicked():
   print ("Button 1 clicked")

def b2_clicked():
   print ("Button 2 clicked")

if __name__ == '__main__':
   window()

The above code produces the following output −

PushButton

Output

Button 1 clicked
Button 2 clicked

PyQt5 — Layout Management

A GUI widget can be placed inside the container window by specifying its absolute coordinates measured in pixels. The coordinates are relative to the dimensions of the window defined by setGeometry() method.

setGeometry() syntax

QWidget.setGeometry(xpos, ypos, width, height)

In the following code snippet, the top level window of 300 by 200 pixels dimensions is displayed at position (10, 10) on the monitor.

import sys
from PyQt4 import QtGui

def window():
   app = QtGui.QApplication(sys.argv)
   w = QtGui.QWidget()
	
   b = QtGui.QPushButton(w)
   b.setText("Hello World!")
   b.move(50,20)
	
   w.setGeometry(10,10,300,200)
   w.setWindowTitle(“PyQt”)
   w.show()
   sys.exit(app.exec_())
	
if __name__ == '__main__':
   window()

A PushButton widget is added in the window and placed at a position 50 pixels towards right and 20 pixels below the top left position of the window.

This Absolute Positioning, however, is not suitable because of following reasons −

  • The position of the widget does not change even if the window is resized.

  • The appearance may not be uniform on different display devices with different resolutions.

  • Modification in the layout is difficult as it may need redesigning the entire form.

Original and Resized Window

PyQt API provides layout classes for more elegant management of positioning of widgets inside the container. The advantages of Layout managers over absolute positioning are −

  • Widgets inside the window are automatically resized.

  • Ensures uniform appearance on display devices with different resolutions.

  • Adding or removing widget dynamically is possible without having to redesign.

Qt toolkit defines various layouts that can be used with Qt Designer utility.

Display Class

Here is the list of Classes which we will discuss one by one in this chapter.

Sr.No. Classes & Description
1 QBoxLayout

QBoxLayout class lines up the widgets vertically or horizontally. Its derived classes are QVBoxLayout (for arranging widgets vertically) and QHBoxLayout (for arranging widgets horizontally).

2 QGridLayout

A GridLayout class object presents with a grid of cells arranged in rows and columns. The class contains addWidget() method. Any widget can be added by specifying the number of rows and columns of the cell.

3 QFormLayout

QFormLayout is a convenient way to create two column form, where each row consists of an input field associated with a label. As a convention, the left column contains the label and the right column contains an input field.

PyQt5 — Basic Widgets

Here is the list of Widgets which we will discuss one by one in this chapter.

Sr.No Widgets & Description
1 QLabel

A QLabel object acts as a placeholder to display non-editable text or image, or a movie of animated GIF. It can also be used as a mnemonic key for other widgets.

2 QLineEdit

QLineEdit object is the most commonly used input field. It provides a box in which one line of text can be entered. In order to enter multi-line text, QTextEdit object is required.

3 QPushButton

In PyQt API, the QPushButton class object presents a button which when clicked can be programmed to invoke a certain function.

4 QRadioButton

A QRadioButton class object presents a selectable button with a text label. The user can select one of many options presented on the form. This class is derived from QAbstractButton class.

5 QCheckBox

A rectangular box before the text label appears when a QCheckBox object is added to the parent window. Just as QRadioButton, it is also a selectable button.

6 QComboBox

A QComboBox object presents a dropdown list of items to select from. It takes minimum screen space on the form required to display only the currently selected item.

7 QSpinBox

A QSpinBox object presents the user with a textbox which displays an integer with up/down button on its right.

8 QSlider Widget & Signal

QSlider class object presents the user with a groove over which a handle can be moved. It is a classic widget to control a bounded value.

9 QMenuBar, QMenu & QAction

A horizontal QMenuBar just below the title bar of a QMainWindow object is reserved for displaying QMenu objects.

10 QToolBar

A QToolBar widget is a movable panel consisting of text buttons, buttons with icons or other widgets.

11 QInputDialog

This is a preconfigured dialog with a text field and two buttons, OK and Cancel. The parent window collects the input in the text box after the user clicks on Ok button or presses Enter.

12 QFontDialog

Another commonly used dialog, a font selector widget is the visual appearance of QDialog class. Result of this dialog is a Qfont object, which can be consumed by the parent window.

13 QFileDialog

This widget is a file selector dialog. It enables the user to navigate through the file system and select a file to open or save. The dialog is invoked either through static functions or by calling exec_() function on the dialog object.

14 QTab

If a form has too many fields to be displayed simultaneously, they can be arranged in different pages placed under each tab of a Tabbed Widget. The QTabWidget provides a tab bar and a page area.

15 QStacked

Functioning of QStackedWidget is similar to QTabWidget. It also helps in the efficient use of window’s client area.

16 QSplitter

This is another advanced layout manager which allows the size of child widgets to be changed dynamically by dragging the boundaries between them. The Splitter control provides a handle that can be dragged to resize the controls.

17 QDock

A dockable window is a subwindow that can remain in floating state or can be attached to the main window at a specified position. Main window object of QMainWindow class has an area reserved for dockable windows.

18 QStatusBar

QMainWindow object reserves a horizontal bar at the bottom as the status bar. It is used to display either permanent or contextual status information.

19 QList

QListWidget class is an item-based interface to add or remove items from a list. Each item in the list is a QListWidgetItem object. ListWidget can be set to be multiselectable.

20 QScrollBar

A scrollbar control enables the user to access parts of the document that is outside the viewable area. It provides visual indicator to the current position.

21 QCalendar

QCalendar widget is a useful date picker control. It provides a month-based view. The user can select the date by the use of the mouse or the keyboard, the default being today’s date.

PyQt5 — QDialog Class

A QDialog widget presents a top level window mostly used to collect response from the user. It can be configured to be Modal (where it blocks its parent window) or Modeless (the dialog window can be bypassed).

PyQt API has a number of preconfigured Dialog widgets such as InputDialog, FileDialog, FontDialog, etc.

Example

In the following example, WindowModality attribute of Dialog window decides whether it is modal or modeless. Any one button on the dialog can be set to be default. The dialog is discarded by QDialog.reject() method when the user presses the Escape key.

A PushButton on a top level QWidget window, when clicked, produces a Dialog window. A Dialog box doesn’t have minimize and maximize controls on its title bar.

The user cannot relegate this dialog box in the background because its WindowModality is set to ApplicationModal.

import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

def window():
   app = QApplication(sys.argv)
   w = QWidget()
   btn = QPushButton(w)
   btn.setText("Hello World!")
   btn.move(100,50)
   btn.clicked.connect(showdialog)
   w.setWindowTitle("PyQt Dialog demo")
   w.show()
   sys.exit(app.exec_())

def showdialog():
   dlg = QDialog()
   b1 = QPushButton("ok",dlg)
   b1.move(50,50)
   dlg.setWindowTitle("Dialog") 9. PyQt5 — QDialog Class
   dlg.setWindowModality(Qt.ApplicationModal)
   dlg.exec_()

if __name__ == '__main__':
   window()

The above code produces the following output. Click on button in main window and dialog box pops up −

QDialog Class Output

PyQt5 — QMessageBox

QMessageBox is a commonly used modal dialog to display some informational message and optionally ask the user to respond by clicking any one of the standard buttons on it. Each standard button has a predefined caption, a role and returns a predefined hexadecimal number.

Important methods and enumerations associated with QMessageBox class are given in the following table −

Sr.No. Methods & Description
1

setIcon()

Displays predefined icon corresponding to severity of the message

  • Question
  • Information
  • Warning
  • Critical
2

setText()

Sets the text of the main message to be displayed

3

setInformativeText()

Displays additional information

4

setDetailText()

Dialog shows a Details button. This text appears on clicking it

5

setTitle()

Displays the custom title of dialog

6

setStandardButtons()

List of standard buttons to be displayed. Each button is associated with

QMessageBox.Ok 0x00000400

QMessageBox.Open 0x00002000

QMessageBox.Save 0x00000800

QMessageBox.Cancel 0x00400000

QMessageBox.Close 0x00200000

QMessageBox.Yes 0x00004000

QMessageBox.No 0x00010000

QMessageBox.Abort 0x00040000

QMessageBox.Retry 0x00080000

QMessageBox.Ignore 0x00100000

7

setDefaultButton()

Sets the button as default. It emits the clicked signal if Enter is pressed

8

setEscapeButton()

Sets the button to be treated as clicked if the escape key is pressed

Example

In the following example, click signal of the button on the top level window, the connected function displays the messagebox dialog.

msg = QMessageBox()
msg.setIcon(QMessageBox.Information)
msg.setText("This is a message box")
msg.setInformativeText("This is additional information")
msg.setWindowTitle("MessageBox demo")
msg.setDetailedText("The details are as follows:")

setStandardButton() function displays desired buttons.

msg.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)

buttonClicked() signal is connected to a slot function, which identifies the caption of source of the signal.

msg.buttonClicked.connect(msgbtn)

The complete code for the example is as follows −

import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

def window():
   app = QApplication(sys.argv)
   w = QWidget()
   b = QPushButton(w)
   b.setText("Show message!")
   
   b.move(100,50)
   b.clicked.connect(showdialog)
   w.setWindowTitle("PyQt MessageBox demo")
   w.show()
   sys.exit(app.exec_())

def showdialog():
   msg = QMessageBox()
   msg.setIcon(QMessageBox.Information)
   
   msg.setText("This is a message box")
   msg.setInformativeText("This is additional information")
   msg.setWindowTitle("MessageBox demo")
   msg.setDetailedText("The details are as follows:")
   msg.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
   msg.buttonClicked.connect(msgbtn)

   retval = msg.exec_()

def msgbtn(i):
   print ("Button pressed is:",i.text())

if __name__ == '__main__':
   window()

The above code produces the following output. Message Box pops up when main windows’ button is clicked −

QMessageBox Output

If you click on Ok or Cancel button on MessageBox, the following output is produced on the console −

Button pressed is: OK
Button pressed is: Cancel

PyQt5 — Multiple Document Interface

A typical GUI application may have multiple windows. Tabbed and stacked widgets allow to activate one such window at a time. However, many a times this approach may not be useful as view of other windows is hidden.

One way to display multiple windows simultaneously is to create them as independent windows. This is called as SDI (single Document Interface). This requires more memory resources as each window may have its own menu system, toolbar, etc.

MDI (Multiple Document Interface) applications consume lesser memory resources. The sub windows are laid down inside main container with relation to each other. The container widget is called QMdiArea.

QMdiArea widget generally occupies the central widget of QMainWondow object. Child windows in this area are instances of QMdiSubWindow class. It is possible to set any QWidget as the internal widget of subWindow object. Sub-windows in the MDI area can be arranged in cascaded or tile fashion.

The following table lists important methods of QMdiArea class and QMdiSubWindow class −

Sr.No. Methods & Description
1

addSubWindow()

Adds a widget as a new subwindow in MDI area

2

removeSubWindow()

Removes a widget that is internal widget of a subwindow

3

setActiveSubWindow()

Activates a subwindow

4

cascadeSubWindows()

Arranges subwindows in MDiArea in a cascaded fashion

5

tileSubWindows()

Arranges subwindows in MDiArea in a tiled fashion

6

closeActiveSubWindow()

Closes the active subwindow

7

subWindowList()

Returns the list of subwindows in MDI Area

8

setWidget()

Sets a QWidget as an internal widget of a QMdiSubwindow instance

QMdiArea object emits subWindowActivated() signal whereas windowStateChanged() signal is emitted by QMdisubWindow object.

Example

In the following example, top level window comprising of QMainWindow has a menu and MdiArea.

self.mdi = QMdiArea()
self.setCentralWidget(self.mdi)
bar = self.menuBar()
file = bar.addMenu("File")

file.addAction("New")
file.addAction("cascade")
file.addAction("Tiled")

Triggered() signal of the menu is connected to windowaction() function.

file.triggered[QAction].connect(self.windowaction)

The new action of menu adds a subwindow in MDI area with a title having an incremental number to it.

MainWindow.count = MainWindow.count+1
sub = QMdiSubWindow()
sub.setWidget(QTextEdit())
sub.setWindowTitle("subwindow"+str(MainWindow.count))
self.mdi.addSubWindow(sub)
sub.show()

Cascaded and tiled buttons of the menu arrange currently displayed subwindows in cascaded and tiled fashion respectively.

The complete code is as follows −

import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

class MainWindow(QMainWindow):
   count = 0

   def __init__(self, parent = None):
      super(MainWindow, self).__init__(parent)
      self.mdi = QMdiArea()
      self.setCentralWidget(self.mdi)
      bar = self.menuBar()

      file = bar.addMenu("File")
      file.addAction("New")
      file.addAction("cascade")
      file.addAction("Tiled")
      file.triggered[QAction].connect(self.windowaction)
      self.setWindowTitle("MDI demo")

   def windowaction(self, q):
      print ("triggered")
   
      if q.text() == "New":
         MainWindow.count = MainWindow.count+1
         sub = QMdiSubWindow()
         sub.setWidget(QTextEdit())
         sub.setWindowTitle("subwindow"+str(MainWindow.count))
         self.mdi.addSubWindow(sub)
         sub.show()

      if q.text() == "cascade":
         self.mdi.cascadeSubWindows()

      if q.text() == "Tiled":
         self.mdi.tileSubWindows()

def main():
   app = QApplication(sys.argv)
   ex = MainWindow()
   ex.show()
   sys.exit(app.exec_())

if __name__ == '__main__':
   main()

Run above code and three windows in cascased and tiled formation −

Multiple Document Interface Output1

Multiple Document Interface Output2

Multiple Document Interface Output3

PyQt5 — Drag and Drop

The provision of drag and drop is very intuitive for the user. It is found in many desktop applications where the user can copy or move objects from one window to another.

MIME based drag and drop data transfer is based on QDrag class. QMimeData objects associate the data with their corresponding MIME type. It is stored on clipboard and then used in the drag and drop process.

The following QMimeData class functions allow the MIME type to be detected and used conveniently.

Tester Getter Setter MIME Types
hasText() text() setText() text/plain
hasHtml() html() setHtml() text/html
hasUrls() urls() setUrls() text/uri-list
hasImage() imageData() setImageData() image/ *
hasColor() colorData() setColorData() application/x-color

Many QWidget objects support the drag and drop activity. Those that allow their data to be dragged have setDragEnabled() which must be set to true. On the other hand, the widgets should respond to the drag and drop events in order to store the data dragged into them.

  • DragEnterEvent provides an event which is sent to the target widget as dragging action enters it.

  • DragMoveEvent is used when the drag and drop action is in progress.

  • DragLeaveEvent is generated as the drag and drop action leaves the widget.

  • DropEvent, on the other hand, occurs when the drop is completed. The event’s proposed action can be accepted or rejected conditionally.

Example

In the following code, the DragEnterEvent verifies whether the MIME data of the event contains text. If yes, the event’s proposed action is accepted and the text is added as a new item in the ComboBox.

import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

class combo(QComboBox):
   def __init__(self, title, parent):
      super(combo, self).__init__( parent)
      self.setAcceptDrops(True)

   def dragEnterEvent(self, e):
      print (e)

      if e.mimeData().hasText():
         e.accept()
      else:
         e.ignore()

   def dropEvent(self, e):
      self.addItem(e.mimeData().text())

class Example(QWidget):
   def __init__(self):
      super(Example, self).__init__()

      self.initUI()

   def initUI(self):
      lo = QFormLayout()
      lo.addRow(QLabel("Type some text in textbox and drag it into combo box"))
   
      edit = QLineEdit()
      edit.setDragEnabled(True)
      com = combo("Button", self)
      lo.addRow(edit,com)
      self.setLayout(lo)
      self.setWindowTitle('Simple drag and drop')
def main():
   app = QApplication(sys.argv)
   ex = Example()
   ex.show()
   app.exec_()

if __name__ == '__main__':
   main()

The above code produces the following output −

Drag and Drop Output

PyQt5 — Database Handling

PyQt5 library contains QtSql module. It is an elaborate class system to communicate with many SQL based databases. Its QSqlDatabase provides access through a Connection object. Following is the list of currently available SQL drivers −

Sr.No. Driver Type & Description
1

QDB2

IBM DB2

2

QIBASE

Borland InterBase Driver

3

QMYSQL

MySQL Driver

4

QOCI

Oracle Call Interface Driver

5

QODBC

ODBC Driver (includes Microsoft SQL Server)

6

QPSQL

PostgreSQL Driver

7

QSQLITE

SQLite version 3 or above

8

QSQLITE2

SQLite version 2

Example

For this chapter, a connection with a SQLite database is established using the static method −

db = QtSql.QSqlDatabase.addDatabase('QSQLITE')
db.setDatabaseName('sports.db')

Other methods of QSqlDatabase class are as follows −

Sr.No. Methods & Description
1

setDatabaseName()

Sets the name of the database with which connection is sought

2

setHostName()

Sets the name of the host on which the database is installed

3

setUserName()

Specifies the user name for connection

4

setPassword()

Sets the connection object’s password if any

5

commit()

Commits the transactions and returns true if successful

6

rollback()

Rolls back the database transaction

7

close()

Closes the connection

QSqlQuery class has the functionality to execute and manipulate SQL commands. Both DDL and DML type of SQL queries can be executed. First step is to create SQlite database using the following statements −

db = QSqlDatabase.addDatabase('QSQLITE')
db.setDatabaseName('sportsdatabase.db')

Next, obtain Query object with QSqlQuery() method and call its most important method exec_(), which takes as an argument a string containing SQL statement to be executed.

query = QtSql.QSqlQuery()
query.exec_("create table sportsmen(id int primary key, " "firstname varchar(20), lastname varchar(20))")

The following script creates a SQLite database sports.db with a table of sportsperson populated with five records.

import sys
from PyQt5.QtSql import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

def createDB():
   db = QSqlDatabase.addDatabase('QSQLITE')
   db.setDatabaseName('sportsdatabase.db')

   if not db.open():
      msg = QMessageBox()
      msg.setIcon(QMessageBox.Critical)
      msg.setText("Error in Database Creation")
      retval = msg.exec_()
      return False
   query = QSqlQuery()

   query.exec_("create table sportsmen(
      id int primary key, ""firstname varchar(20), lastname varchar(20))")

   query.exec_("insert into sportsmen values(101, 'Roger', 'Federer')")
   query.exec_("insert into sportsmen values(102, 'Christiano', 'Ronaldo')")
   query.exec_("insert into sportsmen values(103, 'Ussain', 'Bolt')")
   query.exec_("insert into sportsmen values(104, 'Sachin', 'Tendulkar')")
   query.exec_("insert into sportsmen values(105, 'Saina', 'Nehwal')")
   return True

if __name__ == '__main__':
   app = QApplication(sys.argv)
   createDB()

To confirm that the SQLite database is created with above records added in sportsmen table in it, use a SQLite Gui utility called SQLiteStudio.

Database Handling

QSqlTableModel class in PyQt is a high-level interface that provides editable data model for reading and writing records in a single table. This model is used to populate a QTableView object. It presents to the user a scrollable and editable view that can be put on any top level window.

A QSqlTableModel object is declared in the following manner −

model = QtSql.QSqlTableModel()

Its editing strategy can be set to any of the following −

QSqlTableModel.OnFieldChange All changes will be applied immediately
QSqlTableModel.OnRowChange Changes will be applied when the user selects a different row
QSqlTableModel.OnManualSubmit All changes will be cached until either submitAll() or revertAll() is called

Example

In the following example, sportsperson table is used as a model and the strategy is set as −

model.setTable('sportsmen') 
model.setEditStrategy(QtSql.QSqlTableModel.OnFieldChange)
   model.select()

QTableView class is part of Model/View framework in PyQt. The QTableView object is created as follows −

view = QtGui.QTableView()
view.setModel(model)
view.setWindowTitle(title)
return view

This QTableView object and two QPushButton widgets are added to the top level QDialog window. Clicked() signal of add button is connected to addrow() which performs insertRow() on the model table.

button.clicked.connect(addrow)
def addrow():
   print model.rowCount()
   ret = model.insertRows(model.rowCount(), 1)
   print ret

The Slot associated with the delete button executes a lambda function that deletes a row, which is selected by the user.

btn1.clicked.connect(lambda: model.removeRow(view1.currentIndex().row()))

The complete code is as follows −

import sys
from PyQt5.QtSql import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

def initializeModel(model):
   model.setTable('sportsmen')
   model.setEditStrategy(QSqlTableModel.OnFieldChange)
   model.select()
   model.setHeaderData(0, Qt.Horizontal, "ID")
   model.setHeaderData(1, Qt.Horizontal, "First name")
   model.setHeaderData(2, Qt.Horizontal, "Last name")

def createView(title, model):
   view = QTableView()
   view.setModel(model)
   view.setWindowTitle(title)
   return view

def addrow():
   print (model.rowCount())
   ret = model.insertRows(model.rowCount(), 1)
   print (ret)

def findrow(i):
   delrow = i.row()

if __name__ == '__main__':
   app = QApplication(sys.argv)
   db = QSqlDatabase.addDatabase('QSQLITE')
   db.setDatabaseName('sportsdatabase.db')
   model = QSqlTableModel()
   delrow = -1
   initializeModel(model)

   view1 = createView("Table Model (View 1)", model)
   view1.clicked.connect(findrow)

   dlg = QDialog()
   layout = QVBoxLayout()
   layout.addWidget(view1)

   button = QPushButton("Add a row")
   button.clicked.connect(addrow)
   layout.addWidget(button)

   btn1 = QPushButton("del a row")
   btn1.clicked.connect(lambda: model.removeRow(view1.currentIndex().row()))
   layout.addWidget(btn1)

   dlg.setLayout(layout)
   dlg.setWindowTitle("Database Demo")
   dlg.show()
   sys.exit(app.exec_())

The above code produces the following output −

Database Handling Output

Try adding and deleting a few records and go back to SQLiteStudio to confirm the transactions.

PyQt5 — Drawing API

All the QWidget classes in PyQt are sub classed from QPaintDevice class. A QPaintDevice is an abstraction of two dimensional space that can be drawn upon using a QPainter. Dimensions of paint device are measured in pixels starting from the top-left corner.

QPainter class performs low level painting on widgets and other paintable devices such as printer. Normally, it is used in widget’s paint event. The QPaintEvent occurs whenever the widget’s appearance is updated.

The painter is activated by calling the begin() method, while the end() method deactivates it. In between, the desired pattern is painted by suitable methods as listed in the following table.

Sr.No. Methods & Description
1

begin()

Starts painting on the target device

2

drawArc()

Draws an arc between the starting and the end angle

3

drawEllipse()

Draws an ellipse inside a rectangle

4

drawLine()

Draws a line with endpoint coordinates specified

5

drawPixmap()

Extracts pixmap from the image file and displays it at the specified position

6

drwaPolygon()

Draws a polygon using an array of coordinates

7

drawRect()

Draws a rectangle starting at the top-left coordinate with the given width and height

8

drawText()

Displays the text at given coordinates

9

fillRect()

Fills the rectangle with the QColor parameter

10

setBrush()

Sets a brush style for painting

11

setPen()

Sets the color, size and style of pen to be used for drawing

Example

In the following code, various methods of PyQt’s drawing methods are used.

import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

class Example(QWidget):
   def __init__(self):
      super(Example, self).__init__()
      self.initUI()

   def initUI(self):
      self.text = "hello world"
      self.setGeometry(100,100, 400,300)
      self.setWindowTitle('Draw Demo')
      self.show()

   def paintEvent(self, event):
      qp = QPainter()
      qp.begin(self)
      qp.setPen(QColor(Qt.red))
      qp.setFont(QFont('Arial', 20))
      qp.drawText(10,50, "hello Python")
      qp.setPen(QColor(Qt.blue))
      qp.drawLine(10,100,100,100)
      qp.drawRect(10,150,150,100)
      qp.setPen(QColor(Qt.yellow))
      qp.drawEllipse(100,50,100,50)
      qp.drawPixmap(220,10,QPixmap("pythonlogo.png"))
      qp.fillRect(20,175,130,70,QBrush(Qt.SolidPattern))
      qp.end()

def main():
   app = QApplication(sys.argv)
   ex = Example()
   sys.exit(app.exec_())

if __name__ == '__main__':
   main()

The above code produces the following output −

Database Handling Outputs

PyQt5 — BrushStyle Constants

In this chapter, we shall learn Brush Style Constants.

Brush Style Constants

Given below are the Brush Style Constants −

Qt.NoBrush No brush pattern
Qt.SolidPattern Uniform color
Qt.Dense1Pattern Extremely dense brush pattern
Qt.HorPattern Horizontal lines
Qt.VerPattern Vertical lines
Qt.CrossPattern Crossing horizontal and vertical lines
Qt.BDiagPattern Backward diagonal lines
Qt.FDiagPattern Forward diagonal lines
Qt.DiagCrossPattern Crossing diagonal lines

Predefined QColor Styles

Given below are the Predefined QColor Styles −

Qt.NoBrush No brush pattern
Qt.SolidPattern Uniform color
Qt.Dense1Pattern Extremely dense brush pattern
Qt.HorPattern Horizontal lines
Qt.VerPattern Vertical lines
Qt.CrossPattern Crossing horizontal and vertical lines
Qt.BDiagPattern Backward diagonal lines
Qt.FDiagPattern Forward diagonal lines
Qt.DiagCrossPattern Crossing diagonal lines

Predefined QColor Objects

Given below are the Predefined QColor Objects −

Qt.white
Qt.black
Qt.red
Qt.darkRed
Qt.green
Qt.darkGreen
Qt.blue
Qt.cyan
Qt.magenta
Qt.yellow
Qt.darkYellow
Qt.gray

PyQt5 — QClipboard

The QClipboard class provides access to system-wide clipboard that offers a simple mechanism to copy and paste data between applications. Its action is similar to QDrag class and uses similar data types.

QApplication class has a static method clipboard() which returns reference to clipboard object. Any type of MimeData can be copied to or pasted from the clipboard.

Following are the clipboard class methods that are commonly used −

Sr.No. Methods & Description
1

clear()

Clears clipboard contents

2

setImage()

Copies QImage into clipboard

3

setMimeData()

Sets MIME data into clipboard

4

setPixmap()

Copies Pixmap object in clipboard

5

setText()

Copies QString in clipboard

6

text()

Retrieves text from clipboard

Signal associated with clipboard object is −

Sr.No. Method & Description
1

dataChanged()

Whenever clipboard data changes

Example

In the following example, two TextEdit objects and two Pushbuttons are added to a top level window.

To begin with the clipboard object is instantiated. Copy() method of textedit object copies the data onto the system clipboard. When the Paste button is clicked, it fetches the clipboard data and pastes it in other textedit object.

import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

class Example(QWidget):
   def __init__(self):
      super(Example, self).__init__()

      self.initUI()

   def initUI(self):
      hbox = QVBoxLayout()
      self.edit1=QTextEdit()
      hbox.addWidget(self.edit1)
      self.btn1=QPushButton("Copy")
      hbox.addWidget(self.btn1)
      self.edit2=QTextEdit()
      self.btn2=QPushButton("Paste")
      hbox.addWidget(self.edit2)
      hbox.addWidget(self.btn2)
      self.btn1.clicked.connect(self.copytext)
      self.btn2.clicked.connect(self.pastetext)
      self.setLayout(hbox)
      
      self.setGeometry(300, 300, 300, 200)
      self.setWindowTitle('Clipboard')
      self.show()
      
   def copytext(self):

      #clipboard.setText(self.edit1.copy())
      self.edit1.copy()
      print (clipboard.text())

      msg=QMessageBox()
      msg.setText(clipboard.text()+" copied on clipboard")
      msg.exec_()

   def pastetext(self):
      self.edit2.setText(clipboard.text())

app = QApplication(sys.argv)
clipboard=app.clipboard()
ex = Example()
ex.setWindowTitle("clipboard Example")
sys.exit(app.exec_())

The above code produces the following output −

QClipboard

PyQt5 — QPixmap Class

QPixmap class provides an off-screen representation of an image. It can be used as a QPaintDevice object or can be loaded into another widget, typically a label or button.

Qt API has another similar class QImage, which is optimized for I/O and other pixel manipulations. Pixmap, on the other hand, is optimized for showing it on screen. Both formats are interconvertible.

The types of image files that can be read into a QPixmap object are as follows −

BMP Windows Bitmap
GIF Graphic Interchange Format (optional)
JPG Joint Photographic Experts Group
JPEG Joint Photographic Experts Group
PNG Portable Network Graphics
PBM Portable Bitmap
PGM Portable Graymap
PPM Portable Pixmap
XBM X11 Bitmap
XPM X11 Pixmap

Following methods are useful in handling QPixmap object −

Sr.No. Methods & Description
1

copy()

Copies pixmap data from a QRect object

2

fromImage()

Converts QImage object into QPixmap

3

grabWidget()

Creates a pixmap from the given widget

4

grabWindow()

Create pixmap of data in a window

5

Load()

Loads an image file as pixmap

6

save()

Saves the QPixmap object as a file

7

toImage

Converts a QPixmap to QImage

The most common use of QPixmap is to display image on a label/button.

Example

The following example shows an image displayed on a QLabel by using the setPixmap() method.

The complete code is as follows −

import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

def window():
   app = QApplication(sys.argv)
   win = QWidget()
   l1 = QLabel()
   l1.setPixmap(QPixmap("python.png"))

   vbox = QVBoxLayout()
   vbox.addWidget(l1)
   win.setLayout(vbox)
   win.setWindowTitle("QPixmap Demo")
   win.show()
   sys.exit(app.exec_())

if __name__ == '__main__':
   window()

The above code produces the following output −

QPixmap Class

PyQt – Введение

PyQt – это набор инструментов для графического интерфейса. Это интерфейс Python для Qt , одной из самых мощных и популярных кроссплатформенных библиотек графического интерфейса. PyQt был разработан RiverBank Computing Ltd. Последнюю версию PyQt можно скачать с ее официального сайта – riverbankcomputing.com

PyQt API – это набор модулей, содержащих большое количество классов и функций. В то время как модуль QtCore содержит функции не-GUI для работы с файлами, каталогами и т. Д., Модуль QtGui содержит все графические элементы управления. Кроме того, существуют модули для работы с XML (QtXml) , SVG (QtSvg) , SQL (QtSql) и т. Д.

Поддерживающая среда

PyQt совместим со всеми популярными операционными системами, включая Windows, Linux и Mac OS. Это двойная лицензия, доступная под GPL, а также коммерческая лицензия.

Windows

Вы можете скачать и установить соответствующий установщик по ссылке выше, соответствующей версии Python (2.7 или 3.4) и аппаратной архитектуре (32-битная или 64-битная). Обратите внимание, что есть две версии PyQt, а именно PyQt 4.8 и PyQt 5.5 .

Хотя PyQt4 доступен как для Python 2, так и для Python 3, PyQt5 можно использовать только вместе с Python 3. *.

PyQt4 Windows Binaries

PyQt4-4.11.4-GPL-Py3.4-Qt4.8.7-x64.exe 64-битный установщик Windows
PyQt4-4.11.4-GPL-Py3.4-Qt4.8.7-x32.exe 32-битный установщик Windows
PyQt4-4.11.4-GPL-Py3.4-Qt5.5.0-x64.exe 64-битный установщик Windows
PyQt4-4.11.4-GPL-Py3.4-Qt5.5.0-x32.exe 32-битный установщик Windows
PyQt4-4.11.4-GPL-Py2.7-Qt4.8.7-x64.exe 64-битный установщик Windows
PyQt4-4.11.4-GPL-Py2.7-Qt4.8.7-x32.exe 32-битный установщик Windows

PyQt5 Windows Binaries

PyQt5-5.5-GPL-Py3.4-Qt5.5.0-x64.exe 64-битный установщик Windows
PyQt5-5.5-GPL-Py3.4-Qt5.5.0-x32.exe 32-битный установщик Windows

Linux

Для Ubuntu или любого другого дистрибутива Debian Linux используйте следующую команду для установки PyQt –

sudo apt-get install python-qt4
or 
sudo apt-get install pyqt5-dev-tools

Вы также можете создать исходный код, доступный на странице загрузки.

PyQt-x11-GPL-4.11.4.tar.gz Linux, исходный код UNIX для PyQt4
PyQt-GPL-5.5.tar.gz Linux, UNIX, MacOS / X источник для PyQt5

Mac OS

Проект PyQtX ( http://sourceforge.net/projects/pyqtx/ ) содержит двоичные файлы PyQt для Mac. Используйте установщик Homebrew согласно следующей команде –

brew install pyqt

PyQt – Hello World

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

  • Импортировать модуль QtGui.

  • Создайте объект приложения.

  • Объект QWidget создает окно верхнего уровня. Добавьте в него объект QLabel.

  • Установите заголовок ярлыка «Привет, мир».

  • Определите размер и положение окна методом setGeometry ().

  • Введите основной цикл приложения методом app.exec_ () .

Импортировать модуль QtGui.

Создайте объект приложения.

Объект QWidget создает окно верхнего уровня. Добавьте в него объект QLabel.

Установите заголовок ярлыка «Привет, мир».

Определите размер и положение окна методом setGeometry ().

Введите основной цикл приложения методом app.exec_ () .

import sys
from PyQt4 import QtGui

def window():
   app = QtGui.QApplication(sys.argv)
   w = QtGui.QWidget()
   b = QtGui.QLabel(w)
   b.setText("Hello World!")
   w.setGeometry(100,100,200,50)
   b.move(50,20)
   w.setWindowTitle(“PyQt”)
   w.show()
   sys.exit(app.exec_())
	
if __name__ == '__main__':
   window()

Приведенный выше код производит следующий вывод –

Привет, мир

PyQt – Основные классы

PyQt API – это большая коллекция классов и методов. Эти классы определены в более чем 20 модулях. Ниже приведены некоторые из часто используемых модулей –

Sr.No. Модули и описание
1

QtCore

Основные не-GUI классы, используемые другими модулями

2

QtGui

Компоненты графического интерфейса пользователя

3

QtMultimedia

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

4

QtNetwork

Занятия по сетевому программированию

5

QtOpenGL

Поддержка классов OpenGL

6

QtScript

Классы для оценки Qt Scripts

7

QtSql

Классы для интеграции баз данных с использованием SQL

8

QtSvg

Классы для отображения содержимого файлов SVG

9

QtWebKit

Классы для рендеринга и редактирования HTML

10

QtXml

Классы для обработки XML

11

QtAssistant

Поддержка онлайн-справки

12

QtDesigner

Классы для расширения Qt Designer

QtCore

Основные не-GUI классы, используемые другими модулями

QtGui

Компоненты графического интерфейса пользователя

QtMultimedia

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

QtNetwork

Занятия по сетевому программированию

QtOpenGL

Поддержка классов OpenGL

QtScript

Классы для оценки Qt Scripts

QtSql

Классы для интеграции баз данных с использованием SQL

QtSvg

Классы для отображения содержимого файлов SVG

QtWebKit

Классы для рендеринга и редактирования HTML

QtXml

Классы для обработки XML

QtAssistant

Поддержка онлайн-справки

QtDesigner

Классы для расширения Qt Designer

PyQt API содержит более 400 классов. Класс QObject находится на вершине иерархии классов. Это базовый класс всех объектов Qt. Кроме того, класс QPaintDevice является базовым классом для всех объектов, которые могут быть нарисованы.

Класс QApplication управляет основными настройками и потоком управления приложения с графическим интерфейсом. Он содержит основной цикл событий, внутри которого обрабатываются и отправляются события, генерируемые элементами окна и другими источниками. Он также обрабатывает настройки всей системы и приложения.

Класс QWidget , производный от классов QObject и QPaintDevice, является базовым классом для всех объектов пользовательского интерфейса. Классы QDialog и QFrame также являются производными от класса QWidget. У них есть своя собственная система подклассов.

Следующие диаграммы изображают некоторые важные классы в их иерархии.

иерархияQWidgetQDialogQIODeviceQPaintDevice

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

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

Sr.No. Виджеты и описание
1

QLabel

Используется для отображения текста или изображения

2

QLineEdit

Позволяет пользователю ввести одну строку текста

3

QTextEdit

Позволяет пользователю вводить многострочный текст

4

QPushButton

Командная кнопка для вызова действия

5

QRadioButton

Позволяет выбрать один из нескольких вариантов

6

QCheckBox

Позволяет выбрать более одного варианта

7

QSpinBox

Позволяет увеличить / уменьшить целочисленное значение

8

QScrollBar

Позволяет получить доступ к содержимому виджета за пределами апертуры дисплея

9

QSlider

Позволяет изменять граничное значение линейно.

10

QComboBox

Предоставляет выпадающий список элементов для выбора

11

QMenuBar

Турник, содержащий объекты QMenu

12

QStatusBar

Обычно в нижней части QMainWindow, предоставляет информацию о состоянии.

13

QToolBar

Обычно в верхней части QMainWindow или плавающий. Содержит кнопки действий

14

QListView

Предоставляет выбор списка элементов в ListMode или IconMode

15

QPixmap

Внеэкранное представление изображения для отображения на объекте QLabel или QPushButton

16

QDialog

Модальное или немодальное окно, которое может возвращать информацию в родительское окно

QLabel

Используется для отображения текста или изображения

QLineEdit

Позволяет пользователю ввести одну строку текста

QTextEdit

Позволяет пользователю вводить многострочный текст

QPushButton

Командная кнопка для вызова действия

QRadioButton

Позволяет выбрать один из нескольких вариантов

QCheckBox

Позволяет выбрать более одного варианта

QSpinBox

Позволяет увеличить / уменьшить целочисленное значение

QScrollBar

Позволяет получить доступ к содержимому виджета за пределами апертуры дисплея

QSlider

Позволяет изменять граничное значение линейно.

QComboBox

Предоставляет выпадающий список элементов для выбора

QMenuBar

Турник, содержащий объекты QMenu

QStatusBar

Обычно в нижней части QMainWindow, предоставляет информацию о состоянии.

QToolBar

Обычно в верхней части QMainWindow или плавающий. Содержит кнопки действий

QListView

Предоставляет выбор списка элементов в ListMode или IconMode

QPixmap

Внеэкранное представление изображения для отображения на объекте QLabel или QPushButton

QDialog

Модальное или немодальное окно, которое может возвращать информацию в родительское окно

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

На следующей диаграмме показана структура QMainWindow –

QMainWindow

PyQt – Использование Qt Designer

Установщик PyQt поставляется с инструментом для создания графического интерфейса, который называется Qt Designer . Используя простой интерфейс перетаскивания, можно быстро создать интерфейс GUI без необходимости писать код. Это, однако, не IDE, такие как Visual Studio. Следовательно, Qt Designer не имеет средства для отладки и сборки приложения.

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

Qt Designer1

Затем вы можете перетащить нужные виджеты из поля виджетов на левой панели. Вы также можете присвоить значение свойствам виджета, заложенным в форму.

Qt Designer2

Разработанная форма сохраняется как demo.ui. Этот файл пользовательского интерфейса содержит XML-представление виджетов и их свойств в дизайне. Этот дизайн переведен в эквивалент Python с помощью утилиты командной строки pyuic4. Эта утилита является оберткой для модуля uic. Использование pyuic4 выглядит следующим образом –

pyuic4 –x demo.ui –o demo.py

В приведенной выше команде ключ -x добавляет небольшой объем дополнительного кода к сгенерированному XML, чтобы он стал самостоятельным исполняемым приложением.

if __name__ == "__main__":
   import sys
   app = QtGui.QApplication(sys.argv)
   Dialog = QtGui.QDialog()
   ui = Ui_Dialog()
   ui.setupUi(Dialog)
   Dialog.show()
   sys.exit(app.exec_())

Результирующий скрипт Python выполняется, чтобы показать следующее диалоговое окно –

Диалоговое окно

Пользователь может вводить данные в поля ввода, но нажатие на кнопку «Добавить» не будет генерировать никаких действий, поскольку они не связаны ни с какой функцией. Реакция на сгенерированный пользователем ответ называется обработкой события .

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

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

Виджеты, используемые для создания интерфейса GUI, служат источником таких событий. Каждый виджет PyQt, производный от класса QObject, предназначен для передачи « сигнала » в ответ на одно или несколько событий. Сигнал сам по себе не выполняет никаких действий. Вместо этого он «подключен» к « слоту ». Слот может быть любой вызываемой функцией Python .

В PyQt соединение между сигналом и слотом может быть достигнуто различными способами. Ниже приведены наиболее часто используемые методы –

QtCore.QObject.connect(widget, QtCore.SIGNAL(‘signalname’), slot_function)

Более удобный способ вызова slot_function, когда виджет испускает виджет, заключается в следующем:

widget.signal.connect(slot_function)

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

QtCore.QObject.connect(button, QtCore.SIGNAL(“clicked()”), slot_function)

или же

button.clicked.connect(slot_function)

пример

В следующем примере два объекта QPushButton (b1 и b2) добавляются в окно QDialog. Мы хотим вызвать функции b1_clicked () и b2_clicked () при нажатии b1 и b2 соответственно.

При нажатии кнопки b1 сигнал clicked () подключается к функции b1_clicked ().

b1.clicked.connect(b1_clicked())

При нажатии кнопки b2 сигнал clicked () подключается к функции b2_clicked ().

QObject.connect(b2, SIGNAL("clicked()"), b2_clicked)

пример

import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *

def window():
   app = QApplication(sys.argv)
   win = QDialog()
   b1 = QPushButton(win)
   b1.setText("Button1")
   b1.move(50,20)
   b1.clicked.connect(b1_clicked)

   b2 = QPushButton(win)
   b2.setText("Button2")
   b2.move(50,50)
   QObject.connect(b2,SIGNAL("clicked()"),b2_clicked)

   win.setGeometry(100,100,200,100)
   win.setWindowTitle("PyQt")
   win.show()
   sys.exit(app.exec_())

def b1_clicked():
   print "Button 1 clicked"

def b2_clicked():
   print "Button 2 clicked"

if __name__ == '__main__':
   window()

Приведенный выше код производит следующий вывод –

Вывод сигналов и слотов

Выход

Button 1 clicked
Button 2 clicked

PyQt – Управление раскладкой

GUI-виджет можно разместить внутри окна контейнера, указав его абсолютные координаты, измеренные в пикселях. Координаты указаны относительно размеров окна, определенного методом setGeometry ().

setGeometry () синтаксис

QWidget.setGeometry(xpos, ypos, width, height)

В следующем фрагменте кода окно верхнего уровня размером 300 на 200 пикселей отображается в положении (10, 10) на мониторе.

import sys
from PyQt4 import QtGui

def window():
   app = QtGui.QApplication(sys.argv)
   w = QtGui.QWidget()
	
   b = QtGui.QPushButton(w)
   b.setText("Hello World!")
   b.move(50,20)
	
   w.setGeometry(10,10,300,200)
   w.setWindowTitle(“PyQt”)
   w.show()
   sys.exit(app.exec_())
	
if __name__ == '__main__':
   window()

Виджет PushButton добавляется в окно и размещается в позиции 50 пикселей вправо и на 20 пикселей ниже верхней левой позиции окна.

Это абсолютное позиционирование , однако, не подходит по следующим причинам:

  • Положение виджета не изменяется даже при изменении размера окна.

  • Внешний вид может быть неодинаковым на разных устройствах отображения с разным разрешением.

  • Модификация в макете сложна, так как может потребоваться перепроектирование всей формы.

Положение виджета не изменяется даже при изменении размера окна.

Внешний вид может быть неодинаковым на разных устройствах отображения с разным разрешением.

Модификация в макете сложна, так как может потребоваться перепроектирование всей формы.

Оригинальное и измененное окно

PyQt API предоставляет классы макета для более элегантного управления позиционированием виджетов внутри контейнера. Преимущества менеджеров по расположению над абсолютным позиционированием:

  • Виджеты внутри окна автоматически изменяются.

  • Обеспечивает равномерное отображение на устройствах отображения с различными разрешениями.

  • Динамическое добавление или удаление виджета возможно без изменения дизайна.

Виджеты внутри окна автоматически изменяются.

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

Динамическое добавление или удаление виджета возможно без изменения дизайна.

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

Sr.No. Классы и описание
1 QBoxLayout

Класс QBoxLayout выстраивает виджеты вертикально или горизонтально. Его производными классами являются QVBoxLayout (для размещения виджетов по вертикали) и QHBoxLayout (для размещения виджетов по горизонтали).

2 QGridLayout

Объект класса GridLayout представляет собой сетку ячеек, расположенных в строках и столбцах. Класс содержит метод addWidget (). Любой виджет можно добавить, указав количество строк и столбцов ячейки.

3 QFormLayout

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

Класс QBoxLayout выстраивает виджеты вертикально или горизонтально. Его производными классами являются QVBoxLayout (для размещения виджетов по вертикали) и QHBoxLayout (для размещения виджетов по горизонтали).

Объект класса GridLayout представляет собой сетку ячеек, расположенных в строках и столбцах. Класс содержит метод addWidget (). Любой виджет можно добавить, указав количество строк и столбцов ячейки.

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

PyQt – Основные виджеты

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

Sr.No Виджеты и описание
1 QLabel

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

2 QLineEdit

QLineEdit объект является наиболее часто используемым полем ввода. Он предоставляет поле, в которое можно ввести одну строку текста. Для ввода многострочного текста необходим объект QTextEdit.

3 QPushButton

В PyQt API объект класса QPushButton представляет кнопку, при нажатии которой можно запрограммировать вызов определенной функции.

4 QRadioButton

Объект класса QRadioButton представляет выбираемую кнопку с текстовой меткой. Пользователь может выбрать один из многих вариантов, представленных в форме. Этот класс является производным от класса QAbstractButton.

5 QCheckBox

Прямоугольное поле перед текстовой меткой появляется, когда объект QCheckBox добавляется в родительское окно. Так же, как QRadioButton, это также выбираемая кнопка.

6 QComboBox

Объект QComboBox представляет раскрывающийся список элементов для выбора. Он занимает минимальное место на экране в форме, необходимой для отображения только выбранного в данный момент элемента.

7 QSpinBox

Объект QSpinBox представляет пользователю текстовое поле, которое отображает целое число с кнопкой вверх / вниз справа.

8 QSlider Widget & Signal

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

9 QMenuBar, QMenu & QAction

Горизонтальный QMenuBar чуть ниже строки заголовка объекта QMainWindow зарезервирован для отображения объектов QMenu.

10 QToolBar

Виджет QToolBar – это подвижная панель, состоящая из текстовых кнопок, кнопок с иконками или других виджетов.

11 QInputDialog

Это предварительно настроенный диалог с текстовым полем и двумя кнопками, OK и Отмена. Родительское окно собирает ввод в текстовое поле после того, как пользователь нажимает кнопку Ok или нажимает Enter.

12 QFontDialog

Другой часто используемый диалог, виджет выбора шрифта, – это визуальный вид класса QDialog. Результатом этого диалога является объект Qfont, который может использоваться родительским окном.

13 QFileDialog

Этот виджет является диалоговым окном выбора файлов. Это позволяет пользователю перемещаться по файловой системе и выбирать файл для открытия или сохранения. Диалог вызывается либо через статические функции, либо путем вызова функции exec_ () для объекта диалога.

14 QTab

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

15 QStacked

Функционирование QStackedWidget аналогично QTabWidget. Это также помогает в эффективном использовании клиентской области окна.

16 QSplitter

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

17 QDock

Закрепляемое окно – это подокно, которое может оставаться в плавающем состоянии или может быть прикреплено к главному окну в указанной позиции. Объект главного окна класса QMainWindow имеет область, зарезервированную для закрепляемых окон.

18 QStatusBar

Объект QMainWindow резервирует горизонтальную полосу внизу в качестве строки состояния. Он используется для отображения постоянной или контекстной информации о состоянии.

19 QList

Класс QListWidget – это интерфейс на основе элементов для добавления или удаления элементов из списка. Каждый элемент в списке является объектом QListWidgetItem. ListWidget может быть установлен для множественного выбора.

20 QScrollBar

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

21 QCalendar

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

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

QLineEdit объект является наиболее часто используемым полем ввода. Он предоставляет поле, в которое можно ввести одну строку текста. Для ввода многострочного текста необходим объект QTextEdit.

В PyQt API объект класса QPushButton представляет кнопку, при нажатии которой можно запрограммировать вызов определенной функции.

Объект класса QRadioButton представляет выбираемую кнопку с текстовой меткой. Пользователь может выбрать один из многих вариантов, представленных в форме. Этот класс является производным от класса QAbstractButton.

Прямоугольное поле перед текстовой меткой появляется, когда объект QCheckBox добавляется в родительское окно. Так же, как QRadioButton, это также выбираемая кнопка.

Объект QComboBox представляет раскрывающийся список элементов для выбора. Он занимает минимальное место на экране в форме, необходимой для отображения только выбранного в данный момент элемента.

Объект QSpinBox представляет пользователю текстовое поле, которое отображает целое число с кнопкой вверх / вниз справа.

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

Горизонтальный QMenuBar чуть ниже строки заголовка объекта QMainWindow зарезервирован для отображения объектов QMenu.

Виджет QToolBar – это подвижная панель, состоящая из текстовых кнопок, кнопок с иконками или других виджетов.

Это предварительно настроенный диалог с текстовым полем и двумя кнопками, OK и Отмена. Родительское окно собирает ввод в текстовое поле после того, как пользователь нажимает кнопку Ok или нажимает Enter.

Другой часто используемый диалог, виджет выбора шрифта, – это визуальный вид класса QDialog. Результатом этого диалога является объект Qfont, который может использоваться родительским окном.

Этот виджет является диалоговым окном выбора файлов. Это позволяет пользователю перемещаться по файловой системе и выбирать файл для открытия или сохранения. Диалог вызывается либо через статические функции, либо путем вызова функции exec_ () для объекта диалога.

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

Функционирование QStackedWidget аналогично QTabWidget. Это также помогает в эффективном использовании клиентской области окна.

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

Закрепляемое окно – это подокно, которое может оставаться в плавающем состоянии или может быть прикреплено к главному окну в указанной позиции. Объект главного окна класса QMainWindow имеет область, зарезервированную для закрепляемых окон.

Объект QMainWindow резервирует горизонтальную полосу внизу в качестве строки состояния. Он используется для отображения постоянной или контекстной информации о состоянии.

Класс QListWidget – это интерфейс на основе элементов для добавления или удаления элементов из списка. Каждый элемент в списке является объектом QListWidgetItem. ListWidget может быть установлен для множественного выбора.

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

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

PyQt – класс QDialog

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

PyQt API имеет несколько предварительно настроенных виджетов Dialog, таких как InputDialog, FileDialog, FontDialog и т. Д.

пример

В следующем примере атрибут WindowModality диалогового окна определяет, является ли оно модальным или немодальным. Любая кнопка в диалоговом окне может быть установлена ​​по умолчанию. Диалог закрывается методом QDialog.reject (), когда пользователь нажимает клавишу Escape.

Нажатие кнопки в окне QWidget верхнего уровня при нажатии создает диалоговое окно. Диалоговое окно не имеет минимизировать и максимизировать элементы управления в строке заголовка.

Пользователь не может передать это диалоговое окно в фоновом режиме, поскольку его WindowModality установлен на ApplicationModal.

import sys
from PyQt4.QtGui import *
from PyQt4.QtCore import *

def window():
   app = QApplication(sys.argv)
   w = QWidget()
   b = QPushButton(w)
   b.setText("Hello World!")
   b.move(50,50)
   b.clicked.connect(showdialog)
   w.setWindowTitle("PyQt Dialog demo")
   w.show()
   sys.exit(app.exec_())
	
def showdialog():
   d = QDialog()
   b1 = QPushButton("ok",d)
   b1.move(50,50)
   d.setWindowTitle("Dialog")
   d.setWindowModality(Qt.ApplicationModal)
   d.exec_()
	
if __name__ == '__main__':
   window()

Приведенный выше код производит следующий вывод –

Вывод класса QDialog

PyQt – QMessageBox

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

Важные методы и перечисления, связанные с классом QMessageBox, приведены в следующей таблице:

Sr.No. Методы и описание
1

SetIcon ()

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

Вопрос Вопрос

Информация Информация

Предупреждение Предупреждение

критический критический

2

SetText ()

Устанавливает текст основного сообщения для отображения

3

setInformativeText ()

Отображает дополнительную информацию

4

setDetailText ()

Диалог показывает кнопку Подробности. Этот текст появляется при нажатии на него

5

SetTitle ()

Отображает пользовательский заголовок диалога

6

setStandardButtons ()

Список стандартных кнопок для отображения. Каждая кнопка связана с

QMessageBox.Ok 0x00000400

QMessageBox.Open 0x00002000

QMessageBox.Save 0x00000800

QMessageBox.Cancel 0x00400000

QMessageBox.Close 0x00200000

QMessageBox.Yes 0x00004000

QMessageBox.No 0x00010000

QMessageBox.Abort 0x00040000

QMessageBox.Retry 0x00080000

QMessageBox.Ignore 0x00100000

7

setDefaultButton ()

Устанавливает кнопку по умолчанию. Выдает сигнал нажатия, если нажата Enter

8

setEscapeButton ()

Устанавливает кнопку, которая будет обрабатываться как нажатая, если нажата клавиша выхода

SetIcon ()

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

Вопрос Вопрос

Информация Информация

Предупреждение Предупреждение

критический критический

SetText ()

Устанавливает текст основного сообщения для отображения

setInformativeText ()

Отображает дополнительную информацию

setDetailText ()

Диалог показывает кнопку Подробности. Этот текст появляется при нажатии на него

SetTitle ()

Отображает пользовательский заголовок диалога

setStandardButtons ()

Список стандартных кнопок для отображения. Каждая кнопка связана с

QMessageBox.Ok 0x00000400

QMessageBox.Open 0x00002000

QMessageBox.Save 0x00000800

QMessageBox.Cancel 0x00400000

QMessageBox.Close 0x00200000

QMessageBox.Yes 0x00004000

QMessageBox.No 0x00010000

QMessageBox.Abort 0x00040000

QMessageBox.Retry 0x00080000

QMessageBox.Ignore 0x00100000

setDefaultButton ()

Устанавливает кнопку по умолчанию. Выдает сигнал нажатия, если нажата Enter

setEscapeButton ()

Устанавливает кнопку, которая будет обрабатываться как нажатая, если нажата клавиша выхода

пример

В следующем примере нажмите сигнал кнопки в окне верхнего уровня, подключенная функция отобразит диалоговое окно сообщения.

msg = QMessageBox()
msg.setIcon(QMessageBox.Information)
msg.setText("This is a message box")
msg.setInformativeText("This is additional information")
msg.setWindowTitle("MessageBox demo")
msg.setDetailedText("The details are as follows:")

Функция setStandardButton () отображает нужные кнопки.

msg.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)

Сигнал buttonClicked () подключен к функции слота, которая идентифицирует заголовок источника сигнала.

msg.buttonClicked.connect(msgbtn)

Полный код для примера выглядит следующим образом:

import sys
from PyQt4.QtGui import *
from PyQt4.QtCore import *

def window():
   app = QApplication(sys.argv)
   w = QWidget()
   b = QPushButton(w)
   b.setText("Show message!")

   b.move(50,50)
   b.clicked.connect(showdialog)
   w.setWindowTitle("PyQt Dialog demo")
   w.show()
   sys.exit(app.exec_())
	
def showdialog():
   msg = QMessageBox()
   msg.setIcon(QMessageBox.Information)

   msg.setText("This is a message box")
   msg.setInformativeText("This is additional information")
   msg.setWindowTitle("MessageBox demo")
   msg.setDetailedText("The details are as follows:")
   msg.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
   msg.buttonClicked.connect(msgbtn)
	
   retval = msg.exec_()
   print "value of pressed message box button:", retval
	
def msgbtn(i):
   print "Button pressed is:",i.text()
	
if __name__ == '__main__': 
   window()

Приведенный выше код производит следующий вывод –

QMessageBox Output1QMessageBox Output2

PyQt – многодокументный интерфейс

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

Один из способов одновременного отображения нескольких окон – это создать их как независимые окна. Это называется SDI (интерфейс с одним документом). Это требует больше ресурсов памяти, так как каждое окно может иметь свою собственную систему меню, панель инструментов и т. Д.

Приложения MDI (Multiple Document Interface) потребляют меньше ресурсов памяти. Подокна располагаются внутри основного контейнера относительно друг друга. Контейнерный виджет называется QMdiArea .

Виджет QMdiArea обычно занимает центральный виджет объекта QMainWondow. Дочерние окна в этой области являются экземплярами класса QMdiSubWindow. В качестве внутреннего виджета объекта subWindow можно установить любой QWidget. Подокна в области MDI могут быть расположены каскадно или мозаично.

В следующей таблице перечислены важные методы класса QMdiArea и класса QMdiSubWindow.

Sr.No. Методы и описание
1

addSubWindow ()

Добавляет виджет как новое подокно в области MDI

2

removeSubWindow ()

Удаляет виджет, который является внутренним виджетом подокна

3

setActiveSubWindow ()

Активирует подокно

4

cascadeSubWindows ()

Располагает подокна в MDiArea каскадным способом

5

tileSubWindows ()

Располагает подокна в MDiArea плиточным способом

6

closeActiveSubWindow ()

Закрывает активное подокно

7

subWindowList ()

Возвращает список подокон в MDI Area

8

setWidget ()

Устанавливает QWidget как внутренний виджет экземпляра QMdiSubwindow

addSubWindow ()

Добавляет виджет как новое подокно в области MDI

removeSubWindow ()

Удаляет виджет, который является внутренним виджетом подокна

setActiveSubWindow ()

Активирует подокно

cascadeSubWindows ()

Располагает подокна в MDiArea каскадным способом

tileSubWindows ()

Располагает подокна в MDiArea плиточным способом

closeActiveSubWindow ()

Закрывает активное подокно

subWindowList ()

Возвращает список подокон в MDI Area

setWidget ()

Устанавливает QWidget как внутренний виджет экземпляра QMdiSubwindow

Объект QMdiArea испускает сигнал subWindowActivation (), тогда как сигнал windowStateChanged () испускается объектом QMdisubWindow.

пример

В следующем примере окно верхнего уровня, содержащее QMainWindow, имеет меню и MdiArea.

self.mdi = QMdiArea()
self.setCentralWidget(self.mdi)
bar = self.menuBar()
file = bar.addMenu("File")

file.addAction("New")
file.addAction("cascade")
file.addAction("Tiled")

Триггерный () сигнал меню связан с функцией windowaction ().

file.triggered[QAction].connect(self.windowaction)

Новое действие меню добавляет подокно в области MDI с заголовком, имеющим добавочный номер.

MainWindow.count = MainWindow.count+1
sub = QMdiSubWindow()
sub.setWidget(QTextEdit())
sub.setWindowTitle("subwindow"+str(MainWindow.count))
self.mdi.addSubWindow(sub)
sub.show()

Каскадные и мозаичные кнопки меню располагают отображаемые в данный момент подокна в каскадной и мозаичной форме соответственно.

Полный код выглядит следующим образом –

import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *

class MainWindow(QMainWindow):
   count = 0
	
   def __init__(self, parent = None):
      super(MainWindow, self).__init__(parent)
      self.mdi = QMdiArea()
      self.setCentralWidget(self.mdi)
      bar = self.menuBar()
		
      file = bar.addMenu("File")
      file.addAction("New")
      file.addAction("cascade")
      file.addAction("Tiled")
      file.triggered[QAction].connect(self.windowaction)
      self.setWindowTitle("MDI demo")
		
   def windowaction(self, q):
      print "triggered"
		
   if q.text() == "New":
      MainWindow.count = MainWindow.count+1
      sub = QMdiSubWindow()
      sub.setWidget(QTextEdit())
      sub.setWindowTitle("subwindow"+str(MainWindow.count))
      self.mdi.addSubWindow(sub)
      sub.show()
		
   if q.text() == "cascade":
      self.mdi.cascadeSubWindows()
		
   if q.text() == "Tiled":
      self.mdi.tileSubWindows()
		
   def main():
      app = QApplication(sys.argv)
      ex = MainWindow()
      ex.show()
      sys.exit(app.exec_())
	
   if __name__ == '__main__':
      main()

Приведенный выше код производит следующий вывод –

Многодокументный интерфейс Output1Многодокументный интерфейс Output2Многодокументный интерфейс Output3

PyQt – Drag & Drop

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

Перетаскивание данных на основе MIME основано на классе QDrag. Объекты QMimeData связывают данные с соответствующим им типом MIME. Он сохраняется в буфере обмена, а затем используется в процессе перетаскивания.

Следующие функции класса QMimeData позволяют легко определять тип MIME и использовать его.

тестер добытчик Сеттер MIME Типы
hasText () текст() SetText () текст / обычный
hasHtml () HTML () setHtml () текст / html
hasUrls () URL () setUrls () текст / Ури список
hasImage () ImageData () setImageData () изображение / *
hasColor () colorData () setColorData () применение / х цветов

Многие объекты QWidget поддерживают перетаскивание. Те, которые позволяют перетаскивать их данные, имеют setDragEnabled (), который должен быть установлен в true. С другой стороны, виджеты должны реагировать на события перетаскивания, чтобы сохранить перетаскиваемые в них данные.

  • DragEnterEvent предоставляет событие, которое отправляется целевому виджету при поступлении в него действия перетаскивания.

  • DragMoveEvent используется, когда выполняется действие перетаскивания.

  • DragLeaveEvent генерируется, когда действие перетаскивания покидает виджет.

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

DragEnterEvent предоставляет событие, которое отправляется целевому виджету при поступлении в него действия перетаскивания.

DragMoveEvent используется, когда выполняется действие перетаскивания.

DragLeaveEvent генерируется, когда действие перетаскивания покидает виджет.

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

пример

В следующем коде DragEnterEvent проверяет, содержат ли данные MIME события событие. Если да, предлагаемое действие события принимается, и текст добавляется как новый элемент в ComboBox.

import sys
from PyQt4.QtGui import *
from PyQt4.QtCore import *

class combo(QComboBox):

   def __init__(self, title, parent):
      super(combo, self).__init__( parent)
	
      self.setAcceptDrops(True)
		
   def dragEnterEvent(self, e):
      print e
		
      if e.mimeData().hasText():
         e.accept()
      else:
         e.ignore()
			
   def dropEvent(self, e):
      self.addItem(e.mimeData().text())
		
class Example(QWidget):

   def __init__(self):
      super(Example, self).__init__()
		
      self.initUI()
		
   def initUI(self):
      lo = QFormLayout()
      lo.addRow(QLabel("Type some text in textbox and drag it into combo box"))
		
      edit = QLineEdit()
      edit.setDragEnabled(True)
      com = combo("Button", self)
      lo.addRow(edit,com)
      self.setLayout(lo)
      self.setWindowTitle('Simple drag & drop')
		
def main():
   app = QApplication(sys.argv)
   ex = Example()
   ex.show()
   app.exec_()
	
if __name__ == '__main__':
   main()

Приведенный выше код производит следующий вывод –

Перетаскивание вывода

PyQt – Обработка базы данных

PyQt API содержит сложную систему классов для связи со многими базами данных на основе SQL. Его QSqlDatabase обеспечивает доступ через объект Connection. Ниже приведен список доступных в настоящее время драйверов SQL –

Sr.No. Тип и описание драйвера
1

QDB2

IBM DB2

2

QIBASE

Borland InterBase Driver

3

QMYSQL

MySQL Driver

4

QOCI

Драйвер интерфейса вызова Oracle

5

QODBC

Драйвер ODBC (включает Microsoft SQL Server)

6

QPSQL

PostgreSQL драйвер

7

QSQLITE

SQLite версии 3 или выше

8

QSQLITE2

SQLite версия 2

QDB2

IBM DB2

QIBASE

Borland InterBase Driver

QMYSQL

MySQL Driver

QOCI

Драйвер интерфейса вызова Oracle

QODBC

Драйвер ODBC (включает Microsoft SQL Server)

QPSQL

PostgreSQL драйвер

QSQLITE

SQLite версии 3 или выше

QSQLITE2

SQLite версия 2

пример

Соединение с базой данных SQLite устанавливается статическим методом –

db = QtSql.QSqlDatabase.addDatabase('QSQLITE')
db.setDatabaseName('sports.db')

Другие методы класса QSqlDatabase следующие:

Sr.No. Методы и описание
1

setDatabaseName ()

Устанавливает имя базы данных, с которой ищется соединение

2

setHostName ()

Устанавливает имя хоста, на котором установлена ​​база данных

3

setUserName ()

Определяет имя пользователя для подключения

4

Установка пароля()

Устанавливает пароль объекта подключения, если таковой имеется

5

совершить ()

Подтверждает транзакции и возвращает true в случае успеха

6

откат ()

Откат транзакции базы данных

7

близко()

Закрывает связь

setDatabaseName ()

Устанавливает имя базы данных, с которой ищется соединение

setHostName ()

Устанавливает имя хоста, на котором установлена ​​база данных

setUserName ()

Определяет имя пользователя для подключения

Установка пароля()

Устанавливает пароль объекта подключения, если таковой имеется

совершить ()

Подтверждает транзакции и возвращает true в случае успеха

откат ()

Откат транзакции базы данных

близко()

Закрывает связь

Класс QSqlQuery обладает функциональностью для выполнения команд SQL и управления ими. Могут быть выполнены как SQL-запросы DDL, так и DML-типа. Наиболее важным методом в классе является exec_ (), который принимает в качестве аргумента строку, содержащую инструкцию SQL для выполнения.

query = QtSql.QSqlQuery()
query.exec_("create table sportsmen(id int primary key, 
   " "firstname varchar(20), lastname varchar(20))")

Следующий скрипт создает базу данных SQLite sports.db с таблицей sportsperson, заполненной пятью записями.

from PyQt4 import QtSql, QtGui

def createDB():
   db = QtSql.QSqlDatabase.addDatabase('QSQLITE')
   db.setDatabaseName('sports.db')
	
   if not db.open():
      QtGui.QMessageBox.critical(None, QtGui.qApp.tr("Cannot open database"),
         QtGui.qApp.tr("Unable to establish a database connection.n"
            "This example needs SQLite support. Please read "
            "the Qt SQL driver documentation for information "
            "how to build it.nn" "Click Cancel to exit."),
         QtGui.QMessageBox.Cancel)
			
      return False
		
   query = QtSql.QSqlQuery()
	
   query.exec_("create table sportsmen(id int primary key, "
      "firstname varchar(20), lastname varchar(20))")
		
   query.exec_("insert into sportsmen values(101, 'Roger', 'Federer')")
   query.exec_("insert into sportsmen values(102, 'Christiano', 'Ronaldo')")
   query.exec_("insert into sportsmen values(103, 'Ussain', 'Bolt')")
   query.exec_("insert into sportsmen values(104, 'Sachin', 'Tendulkar')")
   query.exec_("insert into sportsmen values(105, 'Saina', 'Nehwal')")
   return True
	
if __name__ == '__main__':
   import sys
	
   app = QtGui.QApplication(sys.argv)
   createDB()

Класс QSqlTableModel в PyQt – это высокоуровневый интерфейс, который предоставляет редактируемую модель данных для чтения и записи записей в одной таблице. Эта модель используется для заполнения объекта QTableView. Он предоставляет пользователю прокручиваемый и редактируемый вид, который можно поместить в любое окно верхнего уровня.

Объект QTableModel объявляется следующим образом:

model = QtSql.QSqlTableModel()

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

QSqlTableModel.OnFieldChange Все изменения будут применены немедленно
QSqlTableModel.OnRowChange Изменения будут применены, когда пользователь выберет другую строку
QSqlTableModel.OnManualSubmit Все изменения будут кэшироваться до тех пор, пока не будет вызвана submitAll () или revertAll ()

пример

В следующем примере таблица спортсмена используется в качестве модели, а стратегия задается как –

model.setTable('sportsmen') 
model.setEditStrategy(QtSql.QSqlTableModel.OnFieldChange)

   model.select()

Класс QTableView является частью инфраструктуры Model / View в PyQt. Объект QTableView создается следующим образом:

view = QtGui.QTableView()
view.setModel(model)
view.setWindowTitle(title)
return view

Этот объект QTableView и два виджета QPushButton добавляются в окно QDialog верхнего уровня. Сигнал clicked () кнопки add связан с addrow (), который выполняет insertRow () для таблицы модели.

button.clicked.connect(addrow)
def addrow():
   print model.rowCount()
   ret = model.insertRows(model.rowCount(), 1)
   print ret

Слот, связанный с кнопкой удаления, выполняет лямбда-функцию, которая удаляет строку, выбранную пользователем.

btn1.clicked.connect(lambda: model.removeRow(view1.currentIndex().row()))

Полный код выглядит следующим образом –

import sys
from PyQt4 import QtCore, QtGui, QtSql
import sportsconnection

def initializeModel(model):
   model.setTable('sportsmen')
   model.setEditStrategy(QtSql.QSqlTableModel.OnFieldChange)
   model.select()
   model.setHeaderData(0, QtCore.Qt.Horizontal, "ID")
   model.setHeaderData(1, QtCore.Qt.Horizontal, "First name")
   model.setHeaderData(2, QtCore.Qt.Horizontal, "Last name")
	
def createView(title, model):
   view = QtGui.QTableView()
   view.setModel(model)
   view.setWindowTitle(title)
   return view
	
def addrow():
   print model.rowCount()
   ret = model.insertRows(model.rowCount(), 1)
   print ret
	
def findrow(i):
   delrow = i.row()
	
if __name__ == '__main__':

   app = QtGui.QApplication(sys.argv)
   db = QtSql.QSqlDatabase.addDatabase('QSQLITE')
   db.setDatabaseName('sports.db')
   model = QtSql.QSqlTableModel()
   delrow = -1
   initializeModel(model)
	
   view1 = createView("Table Model (View 1)", model)
   view1.clicked.connect(findrow)
	
   dlg = QtGui.QDialog()
   layout = QtGui.QVBoxLayout()
   layout.addWidget(view1)
	
   button = QtGui.QPushButton("Add a row")
   button.clicked.connect(addrow)
   layout.addWidget(button)
	
   btn1 = QtGui.QPushButton("del a row")
   btn1.clicked.connect(lambda: model.removeRow(view1.currentIndex().row()))
   layout.addWidget(btn1)
	
   dlg.setLayout(layout)
   dlg.setWindowTitle("Database Demo")
   dlg.show()
   sys.exit(app.exec_())

Приведенный выше код производит следующий вывод –

Вывод обработки базы данных

PyQt – API рисования

Все классы QWidget в PyQt подклассифицированы из класса QPaintDevice. QPaintDevice – это абстракция двумерного пространства, которая может быть нарисована при использовании QPainter. Размеры устройства рисования измеряются в пикселях, начиная с верхнего левого угла.

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

Художник активируется путем вызова метода begin (), а метод end () деактивирует его. Между ними желаемый рисунок раскрашивается подходящими методами, перечисленными в следующей таблице.

Sr.No. Методы и описание
1

начать()

Начинает рисовать на целевом устройстве

2

drawArc ()

Рисует дугу между начальным и конечным углом

3

drawEllipse ()

Рисует эллипс внутри прямоугольника

4

DrawLine ()

Рисует линию с указанием координат конечной точки

5

drawPixmap ()

Извлекает растровое изображение из файла изображения и отображает его в указанной позиции

6

drwaPolygon ()

Рисует многоугольник, используя массив координат

7

DrawRect ()

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

8

DrawText ()

Отображает текст в заданных координатах

9

FillRect ()

Заполняет прямоугольник параметром QColor

10

setBrush ()

Устанавливает стиль кисти для рисования

11

setPen ()

Устанавливает цвет, размер и стиль пера, который будет использоваться для рисования

начать()

Начинает рисовать на целевом устройстве

drawArc ()

Рисует дугу между начальным и конечным углом

drawEllipse ()

Рисует эллипс внутри прямоугольника

DrawLine ()

Рисует линию с указанием координат конечной точки

drawPixmap ()

Извлекает растровое изображение из файла изображения и отображает его в указанной позиции

drwaPolygon ()

Рисует многоугольник, используя массив координат

DrawRect ()

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

DrawText ()

Отображает текст в заданных координатах

FillRect ()

Заполняет прямоугольник параметром QColor

setBrush ()

Устанавливает стиль кисти для рисования

setPen ()

Устанавливает цвет, размер и стиль пера, который будет использоваться для рисования

PyQt – константы BrushStyle

Предопределенные стили QColor

Qt.NoBrush Без кисти
Qt.SolidPattern Равномерный цвет
Qt.Dense1Pattern Чрезвычайно плотный рисунок кисти
Qt.HorPattern Горизонтальные линии
Qt.VerPattern Вертикальные линии
Qt.CrossPattern Пересечение горизонтальных и вертикальных линий
Qt.BDiagPattern Обратные диагональные линии
Qt.FDiagPattern Передние диагональные линии
Qt.DiagCrossPattern Пересечение диагональных линий

Предопределенные объекты QColor

Qt.white
Qt.black
Qt.red
Qt.darkRed
Qt.green
Qt.darkGreen
Qt.blue
Qt.cyan
Qt.magenta
Qt.yellow
Qt.darkYellow
Qt.gray

Пользовательский цвет можно выбрать, указав значения RGB или CMYK или HSV.

пример

В следующем примере реализованы некоторые из этих методов.

import sys
from PyQt4.QtGui import *
from PyQt4.QtCore import *

class Example(QWidget):

   def __init__(self):
      super(Example, self).__init__()
      self.initUI()
		
   def initUI(self):
      self.text = "hello world"
      self.setGeometry(100,100, 400,300)
      self.setWindowTitle('Draw Demo')
      self.show()
		
   def paintEvent(self, event):
      qp = QPainter()
      qp.begin(self)
      qp.setPen(QColor(Qt.red))
      qp.setFont(QFont('Arial', 20))
		
      qp.drawText(10,50, "hello Pyth
		on")
      qp.setPen(QColor(Qt.blue))
      qp.drawLine(10,100,100,100)
      qp.drawRect(10,150,150,100)
		
      qp.setPen(QColor(Qt.yellow))
      qp.drawEllipse(100,50,100,50)
      qp.drawPixmap(220,10,QPixmap("python.jpg"))
      qp.fillRect(200,175,150,100,QBrush(Qt.SolidPattern))
      qp.end()
		
def main():
   app = QApplication(sys.argv)
   ex = Example()
   sys.exit(app.exec_())
	
if __name__ == '__main__':
   main()

Приведенный выше код производит следующий вывод –

Вывод констант BrushStyle

PyQt – QClipboard

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

Класс QApplication имеет статический метод clipboard (), который возвращает ссылку на объект буфера обмена. Любой тип MimeData может быть скопирован или вставлен из буфера обмена.

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

Sr.No. Методы и описание
1

Чисто()

Очищает содержимое буфера обмена

2

setImage ()

Копирует QImage в буфер обмена

3

setMimeData ()

Устанавливает данные MIME в буфер обмена

4

setPixmap ()

Копирует объект Pixmap в буфер обмена

5

SetText ()

Копирует QString в буфер обмена

6

текст()

Получает текст из буфера обмена

Чисто()

Очищает содержимое буфера обмена

setImage ()

Копирует QImage в буфер обмена

setMimeData ()

Устанавливает данные MIME в буфер обмена

setPixmap ()

Копирует объект Pixmap в буфер обмена

SetText ()

Копирует QString в буфер обмена

текст()

Получает текст из буфера обмена

Сигнал, связанный с объектом буфера обмена, –

Sr.No. Метод и описание
1

dataChanged ()

Всякий раз, когда данные буфера обмена изменяются

dataChanged ()

Всякий раз, когда данные буфера обмена изменяются

пример

В следующем примере два объекта TextEdit и две кнопки добавляются в окно верхнего уровня.

Для начала создается объект буфера обмена. Метод Copy () объекта textedit копирует данные в системный буфер обмена. При нажатии кнопки «Вставить» он выбирает данные буфера обмена и вставляет их в другой объект textedit.

QClipboard Output1QClipboard Output2QClipboard Output3

PyQt – класс QPixmap

Класс QPixmap обеспечивает представление изображения вне экрана. Он может использоваться как объект QPaintDevice или может быть загружен в другой виджет, обычно метку или кнопку.

У Qt API есть другой аналогичный класс QImage, который оптимизирован для ввода-вывода и других пиксельных манипуляций. Pixmap, с другой стороны, оптимизирован для отображения на экране. Оба формата являются взаимозаменяемыми.

Типы файлов изображений, которые могут быть прочитаны в объект QPixmap, следующие:

BMP Битовая карта Windows
GIF Формат обмена графическими данными (необязательно)
JPG Объединенная группа экспертов по фотографии
JPEG Объединенная группа экспертов по фотографии
PNG Портативная сетевая графика
PBM Portable Bitmap
PGM Портативная серая карта
PPM Портативный Pixmap
XBM X11 Bitmap
XPM X11 Pixmap

Следующие методы полезны при обработке объекта QPixmap –

Sr.No. Методы и описание
1

копия ()

Копирует данные растрового изображения из объекта QRect

2

fromImage ()

Преобразует объект QImage в QPixmap

3

grabWidget ()

Создает растровое изображение из данного виджета

4

grabWindow ()

Создать растровое изображение данных в окне

5

Нагрузка ()

Загружает файл изображения как растровое изображение

6

спасти()

Сохраняет объект QPixmap в виде файла

7

изображать

Преобразует QPixmap в QImage

копия ()

Копирует данные растрового изображения из объекта QRect

fromImage ()

Преобразует объект QImage в QPixmap

grabWidget ()

Создает растровое изображение из данного виджета

grabWindow ()

Создать растровое изображение данных в окне

Нагрузка ()

Загружает файл изображения как растровое изображение

спасти()

Сохраняет объект QPixmap в виде файла

изображать

Преобразует QPixmap в QImage

Наиболее распространенное использование QPixmap – это отображение изображения на ярлыке / кнопке.

пример

В следующем примере показано изображение, отображаемое в QLabel с помощью метода setPixmap (). Полный код выглядит следующим образом –

import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *

def window():
   app = QApplication(sys.argv)
   win = QWidget()
   l1 = QLabel()
   l1.setPixmap(QPixmap("python.jpg"))
	
   vbox = QVBoxLayout()
   vbox.addWidget(l1)
   win.setLayout(vbox)
   win.setWindowTitle("QPixmap Demo")
   win.show()
   sys.exit(app.exec_())
	
if __name__ == '__main__':
   window()

Приведенный выше код производит следующий вывод –

Понравилась статья? Поделить с друзьями:
  • Руководство по эксплуатации мыла
  • Стронгхолд для кошек инструкция по применению от ушного клеща
  • Руководство по ремонту ниссан тиида 2007 2014
  • Митсубиси галант 8 мануал на русском
  • Капли фенистил инструкция по применению при аллергии взрослым