Вопросы:
· Принцип
работы сеточного макета.
· Программирование
сеточного макета.
· Задание
работы программы при изменении размеров её окна.
Итак,
наиболее универсальным макетом графического интерфейса является сеточный макет.
В графической библиотеке PyQt5
он реализован классом QGridLayout из модуля QtWidgets. В отличие
от классов блочного макета, представляющих собой горизонтальный и вертикальный
ряды ячеек, которые заполняются виджетами, объект этого класса представляет
собой целую прямоугольную таблицу таких ячеек. Обратиться к этим ячейкам можно,
указав индексы их строки и столбца. При этом, как и в случае со списками, важно
помнить, что нумерация строк и столбцов начинается с нуля, а не с единицы. Один
виджет в таком макете может занимать одну ячейку или же прямоугольный участок
ячеек, размещающийся сразу в нескольких строках и столбцах. Заполняется
сеточный макет, в отличие от блочных контейнеров, в произвольном порядке. При
добавлении виджета в него, достаточно просто указать, какие ячейки этот виджет
будет занимать. Размерность таблицы ячеек устанавливается объектом
автоматически, в зависимости от того, какие ячейки заполнены.
Рассмотрим
использование сеточного макета, создав интерфейс окна для ввода информации о
пользователе. Подумаем, как должно выглядеть такое окно. Предположим, что
пользователю нужно задать свою фамилию, имя, отчество, а также домашний адрес. В
правой верхней части окна будут находиться три однострочных поля ввода: для
фамилии, имени и отчества пользователя. Ниже этих трёх полей будет располагаться
многострочное поле ввода для домашнего адреса пользователя. Слева от каждого
поля ввода будет находиться метка с текстом, поясняющая, что необходимо задать
в поле ввода. Под нижним полем ввода будет располагаться кнопка «Ввод».
Теперь
рассмотрим, как элементы управления должны вести себя при изменении размеров
окна. При горизонтальном увеличении размеров окна должны расширяться поля ввода
и кнопка под ними. Остальные размеры окна должны оставаться постоянными. При
вертикальном увеличении размеров окна должна увеличиваться высота поля ввода
для домашнего адреса. Все остальные размеры окна должны оставаться постоянными.
Перейдём
к программированию заданного интерфейса. Создав модуль в среде разработки языка
Питон, мы должны описать в нём класс, который будет отвечать за работу окна, а
также инструкции, необходимые для запуска приложения. Сначала загрузим в наш
модуль классы, которые нам понадобятся для запуска приложения и создания
интерфейса. Прежде всего подключим модуль sys.
Далее из модуля QtWidgets библиотеки PyQt5 загрузим все классы. После
чего из модуля QtCore
загрузим класс Qt.
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import Qt
Создадим класс MainWindow, который унаследуем от класса QWidgets. Пока
пропустим его описание. Теперь опишем основную программу. В ней, в переменной a,
создадим объект класса QApplication,
а в качестве параметра зададим методу-конструктору значение переменной argv
из модуля sys. Далее в переменной window
создадим объект класса MainWindow, после чего вызовем у созданного
объекта метод show
без параметров. И, наконец, из модуля sys
вызовем функцию exit,
которой в качестве параметра зададим метод exec,
вызванный у объекта a.
class MainWindow
(QWidget):
pass
a = QApplication (sys.argv)
window = MainWindow ()
window.show ()
sys.exit (a.exec ())
Теперь
перейдём к описанию класса MainWindow.
Создадим его метод-конструктор. В нём вызовем метод-конструктор класса-предка QWidgets.
После чего вызовем методы setupUI
и setForm, которые опишем далее.
def __init__
(self):
super ().__init__ ()
self.setupUI ()
self.setForm ()
Опишем
метод setupUI для настройки окна программы и его элементов управления. В
нём зададим заголовок окна «Ввод пользовательских данных». Далее вызовем у окна
метод move, который
передвинет его в точку экрана с заданными координатами. Зададим точку с
координатами 650 и 250. Таким образом мы создали окно программы и разместили
его на экране, но пока в нём нет элементов управления. Создадим их. Начнём с
поясняющих меток. В поле lblSurname
создадим
объект класса QLabel, то есть это будет поясняющая
метка для поля «Фамилия». При создании сразу зададим текст метки: «Фамилия:».
Точно так же в полях lblName,
lblMiddleName и
lblHomeAddress создадим поясняющие
метки для полей «Имя», «Отчество» и
«Домашний адрес». По умолчанию текст меток всегда выравнивается по левому краю,
нам же нужно выровнять текст по правому краю. Исправим выравнивание в метке lblSurname.
Для этого вызовем у неё метод setAlignment,
которому в качестве параметра зададим горизонтальное выравнивание по правому
краю и вертикальное по центру. Точно так же изменим выравнивание текста в метках
lblName, lblMiddleName
и
lblHomeAddress.
def setupUI (self):
self.setWindowTitle (‘Ввод пользовательских данных’)
self.move (650, 250)
self.lblSurname = QLabel (‘Фамилия:’, self)
self.lblName = QLabel (‘Имя:’, self)
self.lblMiddleName = QLabel (‘Отчество:’, self)
self.lblHomeAddress = QLabel (‘Домашний
адрес:’, self)
self.lblSurname.setAlignment (Qt.AlignRight|Qt.AlignCenter)
self.lblName.setAlignment (Qt.AlignRight|Qt.AlignCenter)
self.lblMiddleName.setAlignment
(Qt.AlignRight|Qt.AlignCenter)
self.lblHomeAddress.setAlignment
(Qt.AlignRight|Qt.AlignCenter)
Далее
создадим поля ввода. Для этого в поле txtSurname
создадим однострочное поле ввода, то есть объект класса QLineEdit.
Создадим под именами txtName
и txtMiddleName
такие же однострочные поля ввода для имени и отчества. Для домашнего адреса нам
нужно многострочное поле ввода. Чтобы его получить, создадим в поле txtHomeAddress
объект класса QTextEdit.
После того, как мы создали метки и поля ввода, нам осталось создать лишь кнопку
«Ввод». Для этого в поле btnInput
создадим объект класса QPushButton.
При создании сразу зададим текст кнопки – «Ввод».
self.txtSurname = QLineEdit (self)
self.txtName = QLineEdit (self)
self.txtMiddleName = QLineEdit (self)
self.txtHomeAddress = QTextEdit (self)
self.btnInput = QPushButton (‘Ввод’, self)
Теперь,
после того, как мы создали все элементы управления, нужно настроить их
расположение на форме. Для этого опишем метод setForm.
В этом методе, в переменной grid,
создадим объект класса QGridLayout. После того, как мы создали контейнер
для макета нашего графического интерфейса, нужно добавить в него элементы
управления. Начнём с меток. Вызовем у объекта grid
метод addWidget,
в котором в качестве параметра зададим метку lblSurName.
В
классе QGridLayout метод addWidget
вызывается иначе, чем у классов блочного макета. Помимо имени виджета, в
качестве параметров он принимает на вход несколько целых чисел. Это могут быть
два целых числа – индексы ячейки, в которой будет располагаться соответствующий
элемент управления, если он будет занимать единственную ячейку. Или же это
могут быть четыре числа в том случае, когда для виджета отводится прямоугольный
промежуток ячеек. Тогда первые два числа – это индексы левой верхней ячейки
промежутка, который будет занят виджетом, а вторые два числа – это,
соответственно, вертикальный и горизонтальный размеры этого промежутка. Они
указываются количеством занимаемых ячеек.
При
размещении метки lblSurname
укажем ячейку из нулевой строки и нулевого столбца. Таким же образом в нулевом
столбце первой, второй и третьей строк разместим соответственно метки lblName,
lblMiddleName и
lblHomeAddress. Теперь разместим поля
ввода: txtName,
txtMiddleName и
txtHomeAddress — в первом столбце, в
нулевой, первой и второй строках соответственно. Теперь нам нужно разместить
многострочное поле ввода txtHomeAddress.
Сделаем так, чтобы оно занимало одну ячейку по горизонтали и две ячейки по
вертикали. Его левая верхняя ячейка будет располагаться в третьей строке и
первом столбце. Поле ввода будет располагаться в двух строках и одном столбце.
Теперь нужно разместить кнопку btnInput
под нижним полем ввода, которое занимает третью и четвёртую строки. То есть
кнопка будет находиться в пятой строке и первом столбце. Добавим между ячейками
макета свободное пространство, вызвав у объекта grid
метод setSpacing.
Сделаем расстояние между ячейками, а также границы в десять пикселей. Теперь
нужно отобразить макет на форме. Для этого у формы вызовем метод setLayout,
в котором зададим объект grid
в качестве параметра.
def setForm
(self):
grid = QGridLayout ()
grid.addWidget (self.lblSurname, 0, 0)
grid.addWidget (self.lblName, 1, 0)
grid.addWidget (self.lblMiddleName, 2, 0)
grid.addWidget (self.lblHomeAddress, 3, 0)
grid.addWidget (self.txtSurname, 0, 1)
grid.addWidget (self.txtName, 1, 1)
grid.addWidget (self.txtMiddleName, 2, 1)
grid.addWidget (self.txtHomeAddress, 3, 1, 2, 1)
grid.addWidget (self.btnInput, 5, 1)
grid.setSpacing (10)
self.setLayout (grid)
Сохраним
модуль и запустим его на выполнение. На экран было выведено окно программы, в
котором размещены элементы управления. При изменении размеров окна все элементы
управления ведут себя так, как и было задумано: на изменение размеров формы
реагируют те элементы управления, которые должны на них реагировать.
Однако,
при изменении размеров формы также можно заметить несколько недостатков. Во-первых,
при минимально возможном размере формы не полностью виден её заголовок.
Чтобы
это исправить, изменим минимальный размер окна. Для этого в методе setupUI
добавим строку кода, которая вызывает у формы метод setMinimumSize.
В этом методе зададим минимальный размер окна 350´250
пикселей.
self.setMinimumSize (350, 250)
Снова
запустим модуль на выполнение. Теперь даже при минимальном размере окна его
заголовок виден полностью. Однако кнопка ввода многим может показаться слишком
узкой. Дело в том, что вертикальный размер кнопки по умолчанию и при изменении размера
её ячейки остаётся постоянным, равным минимальному. Поэтому изменим минимальный
размер кнопки. Сделаем его 100´30. Горизонтальный размер
кнопки не очень важен, так как он зависит от ширины окна программы, а
вертикальный размер кнопки теперь будет равен тридцати пикселям.
self.btnInput.setMinimumSize
(100, 30)
Сохраним
модуль и запустим его на выполнение. Теперь кнопка ввода стала шире. Однако у
нашей формы остался ещё один недостаток: текст метки для домашнего адреса
расположен ниже относительно своего поля ввода по сравнению с остальными
метками, а также при увеличении вертикального размера окна текст этой метки
смещается вниз.
Дело
в политике размеров. Она описывает поведение элементов управления в ячейках
макетов при изменении их размеров и хранится в классе QSizePolicy
модуля QtWidgets.
По умолчанию у каждого класса виджетов она своя. Так, отдельно может быть
установлена политика вертикального и горизонтального размеров. У неё может быть
одно из семи значений: игнорируемый размер – Ignored,
фиксированный размер – Fixed,
предпочтительный размер – Preferred,
минимальный размер – Minimum,
максимальный
размер – Maximum, минимально
расширяемый размер – MinimumExpanding
и расширяемый размер – Expanding.
Так, фиксированный размер элемента управления не изменяется при изменении
размеров окна. При предпочтительном размере элемент управления принимает размер
ячейки, в которой он находится. Вы можете самостоятельно рассмотреть поведение
элементов управления при других значениях политики размеров. Пока важно лишь
то, что значение этой политики мы можем задать самостоятельно.
По
умолчанию у метки установлен предпочтительный вертикальной размер, а
выравнивание текста мы установили по центру. Изменим политику размеров метки lblHomeAddress,
вызвав у неё метод setSizePolicy.
Зададим у неё предпочтительный горизонтальный размер Preferred
и фиксированный вертикальный – Fixed.
Снова запустим модуль на выполнение. На этот раз форма выглядит и ведёт себя
при изменении размеров точно так же, как было задумано изначально. Задача
решена.
self.lblHomeAddress.setSizePolicy (QSizePolicy.Preferred,
QSizePolicy.Fixed)
Помимо
управления размерами и положением виджетов, при изменении размеров окна иногда
требуется делать что-то ещё. Для этого нужно обратиться к событию изменения
размеров окна. Чтобы это сделать в классе, который описывает окно программы,
необходимо переопределить метод resizeEvent,
описанный у его предка QWidgets. Этот метод срабатывает при изменении
размеров окна. Сделаем так, чтобы при изменении размеров окна, его размеры
выводились на экран. Для этого запишем инструкцию print,
которая будет выводить на экран результаты методов width
и height, вызванных у
формы, разделённые точкой с запятой.
def resizeEvent
(self, event):
print (self.width (), ‘; ‘, self.height (), sep = »)
Запустим
модуль на выполнение. И попытаемся изменить размеры окна. При этом его размеры выводятся
на экран.
Мы
узнали:
· Cеточный
макет графического интерфейса реализован классом QGridLayout.
Объект этого класса представляет собой прямоугольную таблицу ячеек, которые
заполняются виджетами. При этом виджет может занимать как одну ячейку таблицы,
так и прямоугольный промежуток ячеек.
· Политика
размеров определяет поведение элементов управления графическим
интерфейсом при изменении размеров ячеек, в которых они находятся.
· Метод
resizeEvent
описывает работу программы при изменении размеров её окна.
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 из исходника, вам нужно сделать следующее:
- Установить SIP;
- Скачать исходник PyQt5;
- Настроить и установить.
Как вы возможно знаете, PyQt5 связывает Python с популярной библиотекой Qt, которая написана на С++.
Инструмент, который создает эту связь, называется SIP. Так что для установки PyQt5 из исходника, вам для начала нужно установить SIP.
Для установки SIP, запустите следующую команду:
|
sudo pip3 install pyqt5—sip |
Теперь вы можете загрузить и установить исходник PyQt5.
Исходники
Скачать исходник PyQt5 можно отсюда: https://www.riverbankcomputing.com/software/pyqt/download5
Внимание: На момент прочтения статьи возможно появилась новая версия которая отличается от той что в скрине. Версия на текущий момент 5.11.3, вы должны самостоятельно скопировать ссылку с сайта и предоставить её в wget. Заметьте, что обновить версию придется во всех ниже предоставленных командах.
|
wget https://sourceforge.net/projects/pyqt/files/PyQt5/PyQt—5.11.3/PyQt5_gpl—5.11.3.tar.gz tar —xvzf PyQt5_gpl—5.11.3.tar.gz cd PyQt5_gpl—5.11.3 |
Мы распаковали сжатый исходник, теперь запустите следующие команды внутри корня папки:
|
sudo python3 configure.py sudo make sudo make install |
Чтобы убедиться в том, что все прошло гладко, попробуйте импортировать модуль PyQt5 так же, как мы делали все раньше. Все должно пройти хорошо.
Установка PyQt5 из исходников на Windows
Скачивайте и распакуйте архив с сайта которого мы указали выше.
Так как SIP требует компилятор GCC, вам нужно установить MinGW, который является портом Windows для компилятора Linux, GCC.
Единственное, что нужно поменять — это момент конфигурации. Вам нужно сообщить Python о платформе.
Это можно выполнить следующим образом:
|
python configure.py —platform win32—g++ make make install |
Поздравляем! Вы успешно установили PyQt5 из исходника.
Установка PyQt5 Designer
Есть два способа создания GUI приложений при помощи PyQt5:
- Дизайн виджетов при помощи кода;
- Использование PyQt5 Designer.
В этом руководстве мы используем PyQt5 Designer, который упрощает процесс на столько, что вы можете выполнить большой объем работы за секунды.
Недорого заказать услуги SMM продвижения более чем в 9 социальных сетях можно на https://doctorsmm.com/. С помощью этого сервиса можно раскрутить свою группу, страницу, сообщество или канал и набрать нужное количество подписчиков, лайков, репостов и других соцсигналов.
Дизайнер PyQt5 поставляется вместе с набором инструментов. Для его установки, вам нужно установить эти инструменты.
|
$ pip3 install pyqt5—tools |
Где находится дизайнер PyQt5?
После удачной установки, вы можете найти дизайнер PyQt5 здесь:
|
C:\Program Files\Python36\Lib\site—packages\pyqt5—tools\ |
Кстати, если вы установили только для своего текущего пользовательского аккаунта, вы найдете дизайнер PyQt5 вот здесь:
|
C:\Users\PythonUser\AppData\Local\Programs\Python\Python36—32\Lib\site—packages\ pyqt5—tools\ |
Вы можете создать короткий путь для него, вместо того, чтобы постоянно переходить к этому расположению для запуска дизайнера PyQt5.
Как использовать дизайнер PyQt5
Откройте designer.exe и увидите диалоговое окно, спрашивающее о том, какую форму шаблона вы предпочитаете.
Существует пять видов доступных шаблонов:
- Диалоговое окно с кнопками внизу (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.
Далее в файловом меню (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;
- Перетяните виджет ярлыка из бокса слева;
Сохраните дизайн в файл как qlabel.ui и конвертируйте его в файл qlabel.py. Теперь поработаем с ярлыком виджета при помощи кода.
|
pyuic5 qlabel.ui —o qlabel.py |
Результат:
Меняем шрифт 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()) |
Меняем текст в 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()) |
Именно на столько все просто! Давайте рассмотрим другие виджеты.
Виджет QLineEdit – это редактируемое поле, где вы можете принимать данные от пользователя. LineEdit содержит множество методов, с которыми можно работать.
Я создам новый дизайн 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()) |
Результат:
- Для 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.
Экспортируем 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()) |
Результат:
Замечательно!
Визуальный редактор слота/сигнала
Мы видели, как подключать сигнал виджета к слоту при помощи метода connect(), но это не единственный способ.
На самом деле, для каждого виджета есть предопределенные слоты. Вы можете связать сигнал с любым предопределенным слотом, без необходимости кодить в дизайнере PyQt5.
Перетяните QPushButton и QLineEdit в вашу форму.
Нажмите F4 и перетяните курсор из QPushButton и отпустите его в верхней части QLineEdit. Чтобы вернуться в обычный режим, нажмите на F3.
Благодаря этому появится редактор сигнала/слота.
Слева находятся предопределенные сигналы, справа — предопределенные слоты. Скажем, нам нужно подключить сигнал clicked() с слотом «очистки содержимого«.
Выберите сигнал clicked слева и выберите clear слот справа и нажмите OK.
После выполнения подключений ваших сигналов и слотов, вы можете выйти из этого режима, нажав 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
Мы увидели, как работают сигналы и слоты. Все сигналы, с которыми мы работали, являются предопределенными для нас.
Но что на счет выпуска собственного сигнала?
Это очень просто! Вы можете сделать это, просто использовав класс 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 в нашу форму и взглянем на её методы.
Сохраняем файл как 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()) |
Получаем все элементы из 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 и 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()) |
Теперь вы можете писать текст вручную внутри клеток 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()) |
Заполнение 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()) |
- Сначала мы создали список трех кортежей 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()) |
Таким же образом, вы можете менять заголовок ряда, при помощи метода 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()) |
Как сортировать 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()) |
Отлично!
Не ограничивайте себя в воображении и попробуйте вставлять различные виджеты, такие как 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()) |
Указанный выше код будет таким же, за исключением строки, где вы создаете 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. Мы даже расскажем, как самостоятельно написать установщик.
Друзья, подписывайтесь на наш телеграм канал Pythonist. Там еще больше туториалов, задач и книг по Python.
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.
In this tutorial, I explain how to import .ui files created using PyQt5’s designer tool in Python and how to connect widgets from the GUI to methods in Python.
- Introduction
- Installing PyQt5
- Generating the UI File
- Importing the UI File In Python
- Getting Widget Object Pointers
- Giving Widgets Unique Names to Find Them With
- Using These Names to Find the Widgets
- Searching For A Pointer
- Connecting Buttons to Methods
- Reading Inputs
- This Seems Like A Lot Of Effort?
Introduction
In my tutorial on Python GUI’s with PyQt, I had many people bring up the fact that when modifying the GUI, as soon as pyuic5 is executed again to rebuild the Python file, all original changes will be lost.
In a sense, this is true. For demonstration proposes, I had put all code into the Python file generated, but a smarter way to add code would be have been to import the generated file so that when it changes (executed pyuic5 again to create an updated .py file), it would only have affected the imported file. This method also allows for separation of the GUI and logic.
In this tutorial, I am going to cover a method that allows you to import the .ui file generated by PyQt Designer directly in Python. Please be aware that there is a lot more effort when importing it this way and it can be a lot harder to find where errors are occurring.
Installing PyQt5
Go to my previous tutorial to learn how to install PyQt5. Generally, you can install it using python -m pip install pyqt5 regarding your environment is set up correctly.
If you haven’t got the designer, you can use python -m pip install pyqt5-tools to install tools that contain the designer. Finding the executable can be a bit tough to find if you don’t know where packages install so I would recommend reading the other post to help you find it.
Generating the UI File
As covered in my original PyQt5 tutorial, install the designer, locate it and use it. When saving the GUI you have created, it will be saved as a .ui. This .ui file is XML that contains the layout of the GUI and other things you may have set in the designer application. Here is a snippet of an example .ui file:
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>367</width>
<height>339</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
contents...
</widget>
</widget>
<resources/>
<connections/>
</ui>
Regarding you know what XML is, this is pretty basic; knowing a little bit of XML is required for this.
Importing the UI File In Python
First we need to import the modules required. We need QtWidgets from PyQt5 for the base widget and uic from PyQt5 also to load the file. We also need sys to access arguments.
from PyQt5 import QtWidgets, uic
import sys
Next we need to create a base class that will load the .ui file in the constructor. It will need to call the __init__ method of the inherited class, load the .ui file into the current object and then show the window.
class Ui(QtWidgets.QMainWindow):
def __init__(self):
super(Ui, self).__init__() # Call the inherited classes __init__ method
uic.loadUi('basic.ui', self) # Load the .ui file
self.show() # Show the GUI
It is very important here to inherit the correct class. In this example I inherit QtWidgets.QMainWindow because I created a new «Main Window» when selecting the form type when first creating the .ui file in PyQt Designer. If you look back to the source of the .ui file, we can actually identify the class we need to inherit.
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
This is a snippet of the XML from before. You can see «MainWindow» is the root widget as all the content is wrapped in the <widget class="QMainWindow" name="MainWindow"> ... </widget> element. This tag has a class attribute; in this example, the value is QMainWindow, which explains why I used QtWidgets.QMainWindow.
Your widget class may be different so be sure to double-check!
After this, we then need to create an instance of this class we just made and execute it.
app = QtWidgets.QApplication(sys.argv) # Create an instance of QtWidgets.QApplication
window = Ui() # Create an instance of our class
app.exec_() # Start the application
Putting this all together, we get:
from PyQt5 import QtWidgets, uic
import sys
class Ui(QtWidgets.QMainWindow):
def __init__(self):
super(Ui, self).__init__()
uic.loadUi('basic.ui', self)
self.show()
app = QtWidgets.QApplication(sys.argv)
window = Ui()
app.exec_()
This assumes that the .ui file is called
basic.ui
Run the script to make sure everything runs, if the GUI that you created appears, congratulations! If not, look back over what you may have missed and READ THE ERROR (I cannot stress this enough).
A small check-list for things that may go wrong:
- PyQt5 isn’t installed
- The .ui file you are importing does not exist (incorrect reference)
- You did not inherit the correct class (found in the XML)
Once you have the GUI being imported, you now need to identify some pointers for the objects you want to use. For this example I am going to use the .ui linked below:
Download: basic.ui
This GUI contains 5 widgets that we can see:
- Text input line
- A button to the right of this saying «Print Content»
- 3 buttons below the input saying «Mode», «Set» and «Clear»
When looking at the XML, we can see that there is a centralwidget inside a QMainWindow and inside the centralwidget are the 5 widgets I created.
Giving Widgets Unique Names to Find Them With
The most important part of getting a pointer to one of these widgets is to give each widget a unique name, preferably something that is friendly to read. Open my .ui file in the Designer or in notepad to see the names I have given each widget. In the XML you can see the 5 widgets I created have friendly name attributes; these names can help us identify the widgets.
To set these names, when clicking on an object in the designer, the property editor on the left provides a field called objectName
Set this to what you want the object to be called and you should see this in the XML when you save the file.
You don’t have to look at the XML, seeing/modifying it in the designer is enough.
Using These Names to Find the Widgets
Now that each widget has a name attribute, we can get pointers of these objects. When I say pointers, I mean a variable that we can use to access this widget and modify it.
When uic.loadUi('basic.ui', self) is called, the names of the widgets will be used to create pointers to the widgets themselves. This means to get our button named «printButton», we can access it using self.printButton within the same class that uic.loadUi('basic.ui', self) was called in after it has been called (technically we can call that on whatever self is).
class Ui(QtWidgets.QMainWindow):
def __init__(self):
super(Ui, self).__init__()
uic.loadUi('basic.ui', self)
# Set the print button text to "Text Changed"
self.printButton.setText('Text Changed')
# This should not throw an error as `uic.loadUi` would have created `self.printButton`
self.show()
Searching For A Pointer
In the case that the method above doesn’t work for some widgets, you can still search for them. To find an object, we can use findChild on any one of its parent objects while supplying the type of widget we are getting and the name.
class Ui(QtWidgets.QMainWindow):
def __init__(self):
super(Ui, self).__init__()
uic.loadUi('basic.ui', self)
# Find the button with the name "printButton"
self.button = self.findChild(QtWidgets.QPushButton, 'printButton')
# We have now created `self.printButton` ourselves (will overwrite whatever was there if something existed already)
self.show()
Alternatively, you can leave the name out to find the first object of the type you provided. You can also call
findChildrento find more than one object.
In the example above, I have searched for a QPushButton object with the name «printButton». To find the object type you need to search for, each widget in the XML will have a class attribute beside the name attribute. If you look at the .ui file I provided and search for «printButton», you will see an attribute class on the same line with a value QPushButton; this is how I knew to use QtWidgets.QPushButton.
<widget class="QWidget" name="centralwidget">
<widget class="QPushButton" name="printButton">
<property name="geometry">
To find the name of this class in the designer, click on a widget and look at the «Object Inspector» window to the right. In the image below you can see that the type of the widget named «input» is QLineEdit; so I would then use QtWidgets.QLineEdit.
The method above simply helps you get a pointer to the object. Now that the hardest part is done, you are free to do what you would normally do after you have located all your widgets you want to use.
Please note, this is not a full tutorial on PyQt5. I am simply demonstrating how to import .ui files
Connecting Buttons to Methods
To connect a button to a method, we need to get a pointer (as shown before) and then connect it like we normally would. Here is a full example:
from PyQt5 import QtWidgets, uic
import sys
class Ui(QtWidgets.QMainWindow):
def __init__(self):
super(Ui, self).__init__()
uic.loadUi('basic.ui', self)
self.button = self.findChild(QtWidgets.QPushButton, 'printButton') # Find the button
self.button.clicked.connect(self.printButtonPressed) # Remember to pass the definition/method, not the return value!
self.show()
def printButtonPressed(self):
# This is executed when the button is pressed
print('printButtonPressed')
app = QtWidgets.QApplication(sys.argv)
window = Ui()
app.exec_()
Reading Inputs
To read inputs, I will use the button method from before to trigger an event and also get another pointer to the input widget.
from PyQt5 import QtWidgets, uic
import sys
class Ui(QtWidgets.QMainWindow):
def __init__(self):
super(Ui, self).__init__()
uic.loadUi('basic.ui', self)
self.button = self.findChild(QtWidgets.QPushButton, 'printButton') # Find the button
self.button.clicked.connect(self.printButtonPressed) # Remember to pass the definition/method, not the return value!
self.input = self.findChild(QtWidgets.QLineEdit, 'input')
self.show()
def printButtonPressed(self):
# This is executed when the button is pressed
print('Input text:' + self.input.text())
app = QtWidgets.QApplication(sys.argv)
window = Ui()
app.exec_()
These are only the basics but are great to build up from.
This Seems Like A Lot Of Effort?
Yes, at first it will be a lot of effort, but once you have set up all the pointers, you no longer need to worry about the GUI changing (regarding you keep the names of widgets the same). This is a small price to pay in ‘overhead’ for more smooth development later.
I have written many codes using PyQt5 and all its powerful layouts and widgets.
But somehow I am missing how to properly import the great amount of modules that I need for my codes.
Everything works fine, I just want to understand the best practice when working with PyQt5.
I read that there is not an exact way, but any suggestion is appreciated.
I read all about here: https://peps.python.org/pep-0008/ but still I find difficult to find a good solution for PyQt5.
What I do up to now is as follows:
from PyQt5.QtWidgets import QApplication, QMainWindow, QStatusBar, QTextEdit, QFileDialog
from PyQt5.QtWidgets import QLabel, QWidget, QHBoxLayout, QPushButton, QLineEdit
from PyQt5.QtWidgets import QRadioButton, QGridLayout, QFormLayout, QAction
from PyQt5.QtCore import Qt
import pyqtgraph as pg
from pyqtgraph.Qt import QtGui
which is quite cumbersome.
I know also that I should not use
from PyQt5.QtWidgets import *
so what is the most neat way?
