Python 3, Qt Designer, PyQt и pyinstaller: компилируем GUI-программу, написанную на Python

Это раньше нужно было писать на чистом C со вставками на Ассемблере, чтобы программы выполнялись быстро и точно, потребляли как можно меньше оперативной памяти и занимали немного места на диске. Сейчас мощности процессоров, объёмы памяти и другие параметры компьютеров таковы, что можно ради "Hello, world!" запускать виртуальную машину на виртуальной машине внутри виртуальной машины, поднимать там Chrome и писать на JavaScript. Хотя, мне больше Python нравится... Вот на нём мы сейчас и напишем небольшую программу с графическим интерфейсом, которую затем скомпилируем в исполняемый файл (а вы же помните, что Python, так-то, язык интерпретируемый?)

Для остроты ощущений всё будем делать на Windows 10 и компилировать, соответственно, exe-шничек. Но замечу, что всё то же самое можно сделать практически так же в любой другой ОС, поддерживающей Qt и Python. Итак, алгоритм действий.

1. Установите Python 3. На Windows достаточно скачать установочный дистрибутив с официального сайта и запустить его. На момент написания статьи последняя версия Python 3.9.0. Самое важное - не забудьте во время установки выбрать галочку "Add Python to environment variables" или "Add Python 3.9 to PATH" (что, в общем-то, одно и то же и зависит от того, какие настройки при установке вы выбрали - расширенные или по-умолчанию).

2. Теперь запустите командную строку (не обязательно с правами администратора) и введите там следующие команды:
pip3 install pyqt5
pip3 install pyqt5-tools
Так мы установили все необходимые пакеты для связки Qt и Python. Кстати, подразумевается, что Qt у нас уже установлен. Если нет - то установите. Вообще, потребуется только Qt Designer, его можно поставить через онлайн-установщик Qt.

3. Вот теперь откройте Qt Designer (именно Designer! Не Creator!) и создайте в нём нужную форму. Я просто кинул на форму кнопку pushButton и текстовое поле lineEdit. Сохраняем эту форму (Файл - Сохранить как...) с расширением *.ui в папку с проектом. Ну, пусть будет form.ui.

4. Вернитесь в командную строку и выполните следующую команду:
pyuic5 c:/path/to/form.ui -o c:/path/to/form.py
Так мы преобразовали файл формы в формат, с которым Python будет удобно работать.

5. Настало время написать какой-нибудь код. Создайте в той же папке с проектом, на одном уровне с файлами form.ui и form.py, новый файл, допустим, program.py. Пишем код:
import sys
from PyQt5 import QtWidgets
import form # это наш form.py, созданный из form.ui

class MyApp(QtWidgets.QMainWindow, main.Ui_MainWindow): # а это - основной класс, вся логика программы должна располагаться в нём; что-то вроде MainWindow.cpp
def __init__(self): # ничего особенного, для тех, кто писал в Qt на C++: инициализация, setupUI, вот это всё
super().__init__()
self.setupUi(self)
self.pushButton.clicked.connect(self.doit) # соединяем сигнал clicked кнопки pushButton со слотом doit, который должен быть описан в этом же классе

def doit(self): # а вот и слот, который выполняет какую-то работу
self.lineEdit.setText("text") # например, записывает текст в текстовое поле lineEdit

def main(): # кто помнит main.cpp - это оно
app = QtWidgets.QApplication(sys.argv)
window = MyApp() # наш рабочий класс
window.show()
app.exec_()

if __name__ == '__main__': # ну и запускаем всё это
main()
Вот такая простенькая программа. При нажатии на кнопку будет выводить текст в текстовое поле.

6. Откройте командную строку снова. Нам надо установить инструменты для компиляции:
pip3 install pywin32
pip3 install pyinstaller
Мы же в Windows, поэтому нам надо ещё поставить пакет для взаимодействия питона с Win32 API - отсюда и pywin32. В UNIX этот пакет не понадобится, я думаю ;)

7. Теперь переходим в командной строке в папку с проектом
cd c:/path/to/

8. И... компилируем!
pyinstaller --onefile --icon=icon.ico --noconsole program.py
Вот и всё! Рядом с вашими файлами появится папочка dist, а в ней - заветный exe-шничек. Опции:
--onefile - создаёт один исполняемый файл, в который помещается всё необходимое - библиотеки и прочее. Очень удобно для переносимости exe-шничка между машинами.
--icon=icon.ico - иконка программы. Файл *.ico должен лежать там же, где и все остальные файлы проекта, на одном с ними уровне.
--noconsole - без этой опции при открытии полученного exe-шника у вас будет сначала запускаться консоль, а уже из неё - форма. Некрасиво, поэтому добавим эту опцию. Теперь при клике на иконку программы будет сразу открываться форма.

Вот так всё просто, оказывается. Ну да, размер файла программы у меня получился 35 Мб, а оперативной памяти при запуске она съедает 12 Мб. Но это всё же лучше, чем Electron, который с собой в exe-шнике таскает Chrome и запускает его со всем виртуальным окружением каждый раз при открытии исполняемого файла.
2020-11-25