Статья [Python] — #1 Создание окна на PyQt5
PyQt5 — Это библиотека Python, которое служит для создание оконных приложений, котором написан на Qt. В PyQt5 вы сможете создавать разные виджеты, например надписи, кнопки, поле ввода и т.д. В общем, PyQt5 позволяет вам разрабатывать приложении с графическими интерфейсами.
[ УЗНАТЬ ПОДРОБНО О PYQT ВЫ СМОЖЕТЕ ЗДЕСЬ —
Ссылка скрыта от гостей
Установка PyQt
Чтобы установить PyQt, вы просто открываете терминал и вводите вот такую команду:
$ pip install PyQt5
Примечание: Если у вас не получилось установить PyQt5, то в pip добавляем цифру 3(pip3 install PyQt5)
Создаём окно
Теперь, вы узнали о PyQt5 и как установить его. Давайте создадим простое окно на PyQt5, и в этой окно. Создаем простой файл, у меня он будет называть main.py.
Подключаем библиотеку PyQt5:
import sys from PyQt5.QtWidgets import QApplication, QWidget
Здесь мы делаем необходимые импорты. Основные виджеты расположены в PyQt5.QtWidgets.
Настраиваем окно:
if __name__ == '__main__': app = QApplication(sys.argv) mywindow = QWidget() mywindow.resize(250, 150) mywindow.setWindowTitle('My Window') mywindow.show() sys.exit(app.exec_())
Мы создали объект приложения с помощью QApplication и передали мы ему список аргументов sys. После этого мы создали главную переменную mywindow Дальше мы указываем размер окна, с помощью resize. Так же, мы даем заголовок нашего окна с помощью SetWindowTitle. Потом мы выходим из программы точнее с App, с помощью sys.exit(app.exec_())
Скомпилируем весь код:
import sys from PyQt5.QtWidgets import QApplication, QWidget if __name__ == '__main__': app = QApplication(sys.argv) mywindow = QWidget() mywindow.resize(250, 150) mywindow.setWindowTitle('My Window') mywindow.show() sys.exit(app.exec_())
Создание окна Pyqt5
В принципе, нормально получилось. Дальше мы будем создавать еще круче, добавлять несколько виджетов(надписи, кнопки и т.д). Надеюсь, данный статья была полезна для вас.
[ Буду благодарен, если найдете ошибки в тексте. ]
PyQt4 — Введение

PyQt4 это тулкит для разработки GUI приложений. Он представляет из себя смесь языка программирование Пайтон (Питон) и библиотеки Qt. Qt – одна из наиболее мощных библиотек на этой планете. Если не самая мощная. Официальный сайт PyQt www.riverbankcomputing.co.uk разработан Филом Томпсоном.
PyQt4 представляет из себя набор модулей Пайтон. Она содержит более 300 классов и почти 6000 функций и методов. Это мультиплатформенный тулкит. Он работает на всех основных операционных системах, включая Unix, Windows и MacOS.
Начиная с версии PyQt4 GPL доступна для всех поддерживаемых платформ.
Так как тулкит содержит большое количество классов, они распределены в несколько модулей.
Модуль QtCore содержит ядро не-gui функциональности. Этот модуль используется для работы со временем, файлами и папками, различными типами даных, потоками, адресами URL, mime типами, потоками процессов. Модуль QtGui содержит графические компоненты и связанные классы. Сюда включены, например, кнопки, окна, строки состояния, панели инструментов, полосы прокрутки, изображения (bitmap), цвета, шрифты и др. Модуль QtNetwork содержит классы для сетевого программирования. Эти классы позволяют писать TCP/IP и UDP клиенты и серверы. Они делают сетевое программирование легче и более доступным. Модуль QtXml содержит классы для работы с xml файлами. Он предоставляет реализации API SAX и DOM. Модуль QtSvg предоставляет классы для отображения содержимого SVG файлов. Масштабируемая векторная графика (SVG) – это язык описания двумерной графики и графических приложений на языке XML. Модуль QtOpenGL используется для построения 3D и 2D графики с помощью библиотеки OpenGL. Модуль дает возможность бесшовной интеграции библиотек QtGui и OpenGL. Модуль QtSql содержит классы для работы с базами данных.
Простой пример
Код данного примера очень краток. Он лишь отображает небольшое окошко. Однако мы сможем сделать с ним многое. Мы сможем изменить его размеры. Распахнуть на весь экран. Минимизировать. Это требует достаточно большого кода. Кто-то уже написал эту функциональность. Потому что она повторяется в большинстве приложений, нет необходимости писать этот код опять. Таким образом это скрыто от программиста. PyQt высокоуровневый тулкит. Если бы мы писали для низкоуровневого тулкита, то следующий пример был бы намного больше.
#!/usr/bin/python
# simple.py
import sys
from PyQt4 import QtGui
widget = QtGui.QWidget()
widget.resize(250, 150)
widget.setWindowTitle(‘simple’)
widget.show()

import sys
from PyQt4 import QtGui
Подключаем необходимые модули. Основные GUI виджеты находятся в библиотеке QtGui.
app = QtGui.QApplication(sys.argv)
Каждое приложение PyQt4 должно создать объект Qapplication. Этот объект находится в модуле QtGui. Параметр sys.argv это список аргументов командной строки. Скрипты на Пайтон могут быть запущены из консоли, и с помощью аргументов мы можем контролировать запуск приложения.
widget = QtGui.QWidget()
Qwidget это базовый класс для всех объектов интерфейса пользователя для PyQt4. Мы используем стандартный конструктор для Qwidget, который не имеет родителя. Виджет у которого нет родительского является окном.
widget.resize(250, 150)
Метод resize() изменяет размеры виджета. В данном случае 250 пикселей по ширине и 150 по высоте.
widget.setWindowTitle(‘simple’)
Здесь мы устанавлиаем заголовок окна на simple.
widget.show()
Метод show() отображает окно на экране.
sys.exit(app.exec())
В конце мы запускаем основной цикл приложения. Отсюда начинается обработка событий. Приложение получает события от оконной системы и распределяет их по виджетам. Когда цикл заканчивается, и если мы вызовем метод exit(), то наше окно (главный виджет) будет уничтожено. Метод sys.exit() гарантирует чистый выход. Окружение будет проинформировано о том, как приложение завершилось.
Вы удивлены почему метод exec_() записан с подчеркиваение? Это сделано потому, что exec – ключевое слово в пайтон.
Иконка приложения
Иконка программы это просто маленькое изображение, которое обычно отображаетяс в левом верхнем углу заголовка. В следующем примере мы покажем как сделать это на PyQt4. Мы также представим некоторые новые методы.
#!/usr/bin/python
# icon.py
import sys
from PyQt4 import QtGui
class Icon(QtGui.QWidget):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.setGeometry(300, 300, 250, 150)
self.setWindowTitle(‘Icon’)
self.setWindowIcon(QtGui.QIcon(‘icons/web.png’))

app = QtGui.QApplication(sys.argv)
icon = Icon()
icon.show()
sys.exit(app.exec_())
В предыдущем примере код был процедурным. Пайтон поддерживает как процедурный, так и объекто-ориентированные стили программирования. Программирование на PyQt4 предполагает ООП программирование.
class Icon(QtGui.QWidget):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
Три наиболее важные вещи в объекто-ориентированном программировании это классы, данные и методы. Здесь мы создаем новый класс Icon. Класс Icon наследован от класса QtGui.QWidget. Это значит, что мы должны вызвать два конструктора: во-первых, для класса Icon и, во-вторых, для наследованного класса.
self.setGeometry(300, 300, 250, 150)
self.setWindowTitle(‘Icon’)
self.setWindowIcon(QtGui.QIcon(‘icons/web.png’))
Все три класса наследованы от класса QtGui.QWidget. Метод setGeometry() делает две вещи: он определяет положение окна и его размеры. Первые два параметра это координаты по оси X и Y соответственно. Третий задает ширину окна, а четвёртый высоту. Последний метод setWindowIcon() устанавливает иконку программы. Чтобы сделать это, мы создаём объект QIcon. В качестве параметра передаётся путь до файла иконки.
Всплывающая подсказка
Мы можем создать всплывающую подсказку для любого виджета.
#!/usr/bin/python
# tooltip.py
import sys
from PyQt4 import QtGui
from PyQt4 import QtCore
class Tooltip(QtGui.QWidget):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.setGeometry(300, 300, 250, 150)
self.setWindowTitle(‘Tooltip’)
self.setToolTip(‘This is a QWidget widget’)
QtGui.QToolTip.setFont(QtGui.QFont(‘OldEnglish’, 10))

app = QtGui.QApplication(sys.argv)
tooltip = Tooltip()
tooltip.show()
app.exec_()
В этом примере, мы показываем подсказку для виджета Qwidget.
self.setToolTip(‘This is a QWidget widget’)
Для создания подсказки вызываем метод setToolTip(). Можно использовать html тэги для форматирования.
QtGui.QToolTip.setFont(QtGui.QFont(‘OldEnglish’, 10))
Потому как обычный QtoolTip выглядит не лучшим образом, мы изменили его.
Закрытие окна
Самый очевидный путь закрытия окна, это щелкнуть на кнопке закрытия в заголовке окна. В следующем примере мы покажем как можно программно закрыть окно. Для этого мы кратко коснёмся сигналов и слотов.
QPushButton(string text, QWidget parent = None)
Это конструктор QPushButton, который мы будем использовать в нашем примере. Параметр text – это текст, который будет отображаться на кнопке, parent – тот виджет, на который мы поместим кнопку. В нашем случае это Qwidget.
#!/usr/bin/python
# quitbutton.py
import sys
from PyQt4 import QtGui, QtCore
class QuitButton(QtGui.QWidget):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.setGeometry(300, 300, 250, 150)
self.setWindowTitle(‘Icon’)
quit = QtGui.QPushButton(‘Close’, self)
quit.setGeometry(10, 10, 60, 35)
self.connect(quit, QtCore.SIGNAL(‘clicked()’),
QtGui.qApp, QtCore.SLOT(‘quit()’))

app = QtGui.QApplication(sys.argv)
qb = QuitButton()
qb.show()
sys.exit(app.exec_())
quit = QtGui.QPushButton(‘Close’, self)
quit.setGeometry(10, 10, 60, 35)
Мы создаём кнопку и распологаем её на виджете также, как мы размещали виджет на экране.
self.connect(quit, QtCore.SIGNAL(‘clicked()’),
QtGui.qApp, QtCore.SLOT(‘quit()’))
Система обработки событий в PyQt4 построена на механизме сигналов и слотов. Если мы щёлкнем на кнопке, то будет послан сигнал clicked(). Слот может быть как слотом PyQt4 так и любым возможным для языка Пайтон. Метод QtCore.QObject.connect() соединяет сигнал и слот. В нашем случае слот является предопределённым слотов PyQt4.
Окно сообщений
Обычно, при щелчке на кнопке закрытия в заголовке окна виджет закрывается. Иногда нам нужно изменить это действие. Например, если у нас открыт файл в редакторе с которым мы сделали какие-то изменения. В этом случае мы показываем пользователю сообщение для подтверждения выбранного действия.
#!/usr/bin/python
# messagebox.py
import sys
from PyQt4 import QtGui
class MessageBox(QtGui.QWidget):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.setGeometry(300, 300, 250, 150)
self.setWindowTitle(‘message box’)
def closeEvent(self, event):
reply = QtGui.QMessageBox.question(self, ‘Message’,
«Are you sure to quit?», QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)
if reply == QtGui.QMessageBox.Yes:
event.accept()
else:
event.ignore()

app = QtGui.QApplication(sys.argv)
qb = MessageBox()
qb.show()
sys.exit(app.exec_())
Когда мы закрываем виджет, генерируется событие QCloseEvent. Для изменения поведения виджета нам нужно изменить обработчик события QCloseEvent.
reply = QtGui.QMessageBox.question(self, ‘Message’,
«Are you sure to quit?», QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)
Мы выводим сообщение с двумя кнопками “Да” и “Нет”. Первая строка (‘Message’) выводится в заголовке окна, вторая – текст сообщения. Возвращаемое значение хранится в переменной reply.
if reply == QtGui.QMessageBox.Yes:
event.accept()
else:
event.ignore()
Здесь мы проверяем возвращаемое значение: если щелкнули по кнопке “yes”, то мы принимаем стандартный обработчик, иначе – игнорируем закрытие.
P. S.: Продолжение следует…
Python GUI: создаём простое приложение с PyQt и Qt Designer
Помимо всего прочего, на Python можно создавать десктопные приложения с графическим интерфейсом (Python GUI). Это можно сделать с помощью PyQt и Qt Designer, с которыми мы сегодня познакомимся.
Эта статья предназначена для тех, кто только начинает своё знакомство с созданием приложений с графическим интерфейсом (GUI) на Python. В ней мы рассмотрим основы использования PyQt в связке с Qt Designer. Шаг за шагом мы создадим простое Python GUI приложение, которое будет отображать содержимое выбранной директории.
Что нам потребуется
Нам понадобятся PyQt и Qt Designer, ну и Python, само собой.
В этой статье используется PyQt5 с Python 3, но особых различий между PyQt и PySide или их версиями для Python 2 нет.
Windows: PyQt можно скачать здесь. В комплекте с ним идёт Qt Designer.
macOS: Вы можете установить PyQt с помощью Homebrew:
$ brew install pyqt5
Скачать пакет с большинством компонентов и инструментов Qt, который содержит Qt Designer, можно по этой ссылке.
Linux: Всё нужное, вероятно, есть в репозиториях вашего дистрибутива. Qt Designer можно установить из Центра Приложений, но PyQt придётся устанавливать через терминал. Установить всё, что нам понадобится, одной командой можно, например, так:
# для Fedora: $ sudo dnf install python3-qt5 qt-creator # для Debian/Ubuntu: $ sudo apt install python3-qt5 pyqt5-dev-tools qtcreator
После того как вы закончили с приготовлениями, откройте командную строку/терминал и убедитесь, что вы можете использовать команду pyuic5 . Вы должны увидеть следующее:
$ pyuic5 Error: one input ui-file must be specified
Если вы видите сообщение, что такой команды нет или что-то в таком роде, попробуйте загуглить решение проблемы для вашей операционной системы и версии PyQt.
Если вы используете Windows, то, скорее всего, путь C:\Python36\Scripts (измените 36 на вашу версию Python) не прописан в вашем PATH . Загляните в этот тред на Stack Overflow, чтобы узнать, как решить проблему.
Дизайн
Основы
Теперь, когда у нас всё готово к работе, давайте начнём с простого дизайна.
Откройте Qt Designer, где вы увидите диалог новой формы, выберите Main Window и нажмите Create.
После этого у вас должна появиться форма — шаблон для окна, размер которого можно менять и куда можно вставлять объекты из окна виджетов и т.д. Ознакомьтесь с интерфейсом, он довольно простой.
Теперь давайте немного изменим размер нашего главного окна, т.к. нам не нужно, чтобы оно было таким большим. А ещё давайте уберём автоматически добавленное меню и строку состояния, поскольку в нашем приложении они не пригодятся.
Все элементы формы и их иерархия по умолчанию отображаются в правой части окна Qt Designer под названием Object Inspector. Вы с лёгкостью можете удалять объекты, кликая по ним правой кнопкой мыши в этом окне. Или же вы можете выбрать их в основной форме и нажать клавишу DEL на клавиатуре.
В итоге мы имеем почти пустую форму. Единственный оставшийся объект — centralwidget , но он нам понадобится, поэтому с ним мы ничего не будем делать.
Теперь перетащите куда-нибудь в основную форму List Widget (не List View) и Push Button из Widget Box.
Макеты
Вместо использования фиксированных позиций и размеров элементов в приложении лучше использовать макеты. Фиксированные позиции и размеры у вас будут выглядеть хорошо (пока вы не измените размер окна), но вы никогда не можете быть уверены, что всё будет точно так же на других машинах и/или операционных системах.
Макеты представляют собой контейнеры для виджетов, которые будут удерживать их на определённой позиции относительно других элементов. Поэтому при изменении размера окна размер виджетов тоже будет меняться.
Давайте создадим нашу первую форму без использования макетов. Перетащите список и кнопку в форме и измените их размер, чтобы вышло вот так:
Теперь в меню Qt Designer нажмите Form, затем выберите Preview и увидите что-то похожее на скриншот выше. Выглядит хорошо, не так ли? Но вот что случится, когда мы изменим размер окна:
Наши объекты остались на тех же местах и сохранили свои размеры, несмотря на то что размер основного окна изменился и кнопку почти не видно. Вот поэтому в большинстве случаев стоит использовать макеты. Конечно, бывают случаи, когда вам, например, нужна фиксированная или минимальная/максимальная ширина объекта. Но вообще при разработке приложения лучше использовать макеты.
Основное окно уже поддерживает макеты, поэтому нам ничего не нужно добавлять в нашу форму. Просто кликните правой кнопкой мыши по Main Window в Object Inspector и выберите Lay out → Lay out vertically. Также вы можете кликнуть правой кнопкой по пустой области в форме и выбрать те же опции:
Ваши элементы должны быть в том же порядке, что и до внесённых изменений, но если это не так, то просто перетащите их на нужное место.
Так как мы использовали вертикальное размещение, все элементы, которые мы добавим, будут располагаться вертикально. Можно комбинировать размещения для получения желаемого результата. Например, горизонтальное размещение двух кнопок в вертикальном будет выглядеть так:
Если у вас не получается переместить элемент в главном окне, вы можете сделать это в окне Object Inspector.
Последние штрихи
Теперь, благодаря вертикальному размещению, наши элементы выровнены правильно. Единственное, что осталось сделать (но не обязательно), — изменить имя элементов и их текст.
В простом приложении вроде этого с одним лишь списком и кнопкой изменение имён не обязательно, так как им в любом случае просто пользоваться. Тем не менее правильное именование элементов — то, к чему стоит привыкать с самого начала.
Свойства элементов можно изменить в разделе Property Editor.
Подсказка: вы можете менять размер, передвигать или добавлять часто используемые элементы в интерфейс Qt Designer для ускорения рабочего процесса. Вы можете добавлять скрытые/закрытые части интерфейса через пункт меню View.
Нажмите на кнопку, которую вы добавили в форму. Теперь в Property Editor вы должны видеть все свойства этого элемента. В данный момент нас интересуют objectName и text в разделе QAbstractButton . Вы можете сворачивать разделы в Property Editor нажатием по названию раздела.
Измените значение objectName на btnBrowse и text на Выберите папку.
Должно получиться так:
Именем объекта списка является listWidget , что вполне подходит в данном случае.
Сохраните дизайн как design.ui в папке проекта.
Превращаем дизайн в код
Конечно, можно использовать .ui -файлы напрямую из Python-кода, однако есть и другой путь, который может показаться легче. Можно конвертировать код .ui -файла в Python-файл, который мы потом сможем импортировать и использовать. Для этого мы используем команду pyuic5 из терминала/командной строки.
Чтобы конвертировать .ui -файл в Python-файл с названием design.py , используйте следующую команду:
$ pyuic5 path/to/design.ui -o output/path/to/design.py
Пишем код
Теперь у нас есть файл design.py с нужной частью дизайна нашего приложения и мы начинать работу над созданием его логики.
Создайте файл main.py в папке, где находится design.py .
Используем дизайн
Для Python GUI приложения понадобятся следующие модули:
import sys # sys нужен для передачи argv в QApplication from PyQt5 import QtWidgets
Также нам нужен код дизайна, который мы создали ранее, поэтому его мы тоже импортируем:
import design # Это наш конвертированный файл дизайна
Так как файл с дизайном будет полностью перезаписываться каждый раз при изменении дизайна, мы не будем изменять его. Вместо этого мы создадим новый класс ExampleApp , который объединим с кодом дизайна для использования всех его функций:
class ExampleApp(QtWidgets.QMainWindow, design.Ui_MainWindow): def __init__(self): # Это здесь нужно для доступа к переменным, методам # и т.д. в файле design.py super().__init__() self.setupUi(self) # Это нужно для инициализации нашего дизайна
В этом классе мы будем взаимодействовать с элементами интерфейса, добавлять соединения и всё остальное, что нам потребуется. Но для начала нам нужно инициализировать класс при запуске кода. С этим мы разберёмся в функции main() :
def main(): app = QtWidgets.QApplication(sys.argv) # Новый экземпляр QApplication window = ExampleApp() # Создаём объект класса ExampleApp window.show() # Показываем окно app.exec_() # и запускаем приложение
И чтобы выполнить эту функцию, мы воспользуемся привычной конструкцией:
if __name__ == '__main__': # Если мы запускаем файл напрямую, а не импортируем main() # то запускаем функцию main()
В итоге main.py выглядит таким образом:
import sys # sys нужен для передачи argv в QApplication from PyQt5 import QtWidgets import design # Это наш конвертированный файл дизайна class ExampleApp(QtWidgets.QMainWindow, design.Ui_MainWindow): def __init__(self): # Это здесь нужно для доступа к переменным, методам # и т.д. в файле design.py super().__init__() self.setupUi(self) # Это нужно для инициализации нашего дизайна def main(): app = QtWidgets.QApplication(sys.argv) # Новый экземпляр QApplication window = ExampleApp() # Создаём объект класса ExampleApp window.show() # Показываем окно app.exec_() # и запускаем приложение if __name__ == '__main__': # Если мы запускаем файл напрямую, а не импортируем main() # то запускаем функцию main()
Если запустить этот код: $ python3 main.py , то наше приложение запустится!
Но нажатие на кнопку ничего не даёт, поэтому нам придётся с этим разобраться.
Добавляем функциональность в наше Python GUI приложение
Примечание Весь дальнейший код пишется внутри класса ExampleApp .
Начнём с кнопки Выберите папку. Привязать к функции событие вроде нажатия на кнопку можно следующим образом:
self.btnBrowse.clicked.connect(self.browse_folder)
Добавьте эту строку в метод __init__ класса ExampleApp , чтобы выполнить привязку при запуске приложения. А теперь взглянем на неё поближе:
- self.btnBrowse : здесь btnBrowse — имя объекта, который мы определили в Qt Designer. self говорит само за себя и означает принадлежность к текущему классу;
- clicked — событие, которое мы хотим привязать. У разных элементов разные события, например, у виджетов списка есть itemSelectionChanged и т.д.;
- connect() — метод, который привязывает событие к вызову переданной функции;
- self.browse_folder — просто функция (метод), которую мы описали в классе ExampleApp .
Для открытия диалога выбора папки мы можем использовать встроенный метод QtWidgets.QFileDialog.getExistingDirectory :
directory = QtWidgets.QFileDialog.getExistingDirectory(self, "Выберите папку")
Если пользователь выберет директорию, переменной directory присвоится абсолютный путь к выбранной директории, в противном случае она будет равна None . Чтобы не выполнять код дальше, если пользователь закроет диалог, мы используем команду if directory: .
Для отображения содержимого директории нам нужно импортировать os :
import os
И получить список содержимого следующим образом:
os.listdir(path)
Для добавления элементов в listWidget мы используем метод addItem() , а для удаления всех элементов у нас есть self.listWidget.clear() .
В итоге функция browse_folder должна выглядеть так:
def browse_folder(self): self.listWidget.clear() # На случай, если в списке уже есть элементы directory = QtWidgets.QFileDialog.getExistingDirectory(self, "Выберите папку") # открыть диалог выбора директории и установить значение переменной # равной пути к выбранной директории if directory: # не продолжать выполнение, если пользователь не выбрал директорию for file_name in os.listdir(directory): # для каждого файла в директории self.listWidget.addItem(file_name) # добавить файл в listWidget
Теперь, если запустить приложение, нажать на кнопку и выбрать директорию, мы увидим:
Так выглядит весь код нашего Python GUI приложения:
import sys # sys нужен для передачи argv в QApplication import os # Отсюда нам понадобятся методы для отображения содержимого директорий from PyQt5 import QtWidgets import design # Это наш конвертированный файл дизайна class ExampleApp(QtWidgets.QMainWindow, design.Ui_MainWindow): def __init__(self): # Это здесь нужно для доступа к переменным, методам # и т.д. в файле design.py super().__init__() self.setupUi(self) # Это нужно для инициализации нашего дизайна self.btnBrowse.clicked.connect(self.browse_folder) # Выполнить функцию browse_folder # при нажатии кнопки def browse_folder(self): self.listWidget.clear() # На случай, если в списке уже есть элементы directory = QtWidgets.QFileDialog.getExistingDirectory(self, "Выберите папку") # открыть диалог выбора директории и установить значение переменной # равной пути к выбранной директории if directory: # не продолжать выполнение, если пользователь не выбрал директорию for file_name in os.listdir(directory): # для каждого файла в директории self.listWidget.addItem(file_name) # добавить файл в listWidget def main(): app = QtWidgets.QApplication(sys.argv) # Новый экземпляр QApplication window = ExampleApp() # Создаём объект класса ExampleApp window.show() # Показываем окно app.exec_() # и запускаем приложение if __name__ == '__main__': # Если мы запускаем файл напрямую, а не импортируем main() # то запускаем функцию main()
Это были основы использования Qt Designer и PyQt для разработки Python GUI приложения. Теперь вы можете спокойно изменять дизайн приложения и использовать команду pyuic5 без страха потерять написанный код.
PyQt6 — полное руководство для новичков

К старту курса по разработке на Python делимся детальным руководством по работе с современным PyQt. Чтобы читать было удобнее, мы объединили несколько статей в одну:
За подробностями приглашаем под кат.
Простое приложение 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 с полезными элементами интерфейса, такими как панели инструментов и меню. Подробно я расскажу о них в следующих руководствах.
Создание приложения
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):

Разбор кода
Пройдём код построчно, чтобы понять, что именно происходит. Сначала мы импортируем классы 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 в центре. Нажатие кнопки ничего не даст — с этим мы разберёмся после:

Скоро мы подробно рассмотрим другие виджеты, но, если вам не терпится и хочется забежать вперёд, можете заглянуть в документацию 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. В этом примере стоит обратить внимание вот на что:
- Сигнал windowTitleChanged при установке заголовка окна выдаётся не всегда. Он срабатывает, только если новый заголовок отличается от предыдущего: если один и тот же заголовок устанавливается несколько раз, сигнал срабатывает только в первый раз. Чтобы избежать неожиданностей, важно перепроверять условия срабатывания сигналов при их использовании в приложении.
- С помощью сигналов создаются цепочки. Одно событие — нажатие кнопки — может привести к тому, что поочерёдно произойдут другие. Эти последующие эффекты отделены от того, что их вызвало. Они возникают согласно простым правилам. И это отделение эффектов от их триггеров — один из ключевых принципов, которые учитываются при создании приложений с графическим интерфейсом. Возвращаться к этому будем на протяжении всего курса.
Мы рассмотрели сигналы и слоты, показали простые сигналы и их использование для передачи данных и состояния в приложении. Теперь переходим к виджетам 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 создаются для каждого отдельного нажатия кнопки мыши и её перемещения в виджете. Вот обработчики событий мыши: