Первые программы на PyQt5 [Урок 2]
Изучение PyQt5 PyQt, PyQt5, QApplication, QIcon, QPushButton, QtCore, QWidget, изучить PyQt5, примеры PyQt
В этой части руководства PyQt5
мы изучим некоторую базовую функциональность.
Этот простой пример выводит маленькое окно. Мы можем делать множество вещей с этим окном. Мы можем менять его размер, раскрывать на весь экран или свернуть в панель задач. Это потребовало бы много программного кода. Кто-то уже запрограммировал эту функциональность. Поскольку это повторяется в большинстве приложений, нет необходимости программировать это с самого начала. PyQt5 – это инструментарий высокого уровня. Если бы мы писали с помощью инструментов более низкого уровня, нижеследующий пример кода мог бы с лёгкостью содержать сотни строк.
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import sys
from PyQt5.QtWidgets import QApplication, QWidget
if __name__ == '__main__':
app = QApplication(sys.argv)
w = QWidget()
w.resize(250, 150)
w.move(300, 300)
w.setWindowTitle('Simple')
w.show()
sys.exit(app.exec_())
Пример кода выше выводит маленькое окно на экране.
import sys
from PyQt5.QtWidgets import QApplication, QWidget
Здесь мы обеспечили необходимый импорт модулей. Основные виджеты расположены в модуле PyQt5.QtWidgets.
app = QApplication(sys.argv)
Каждое приложение PyQt5 должно создать объект приложения. Параметр sys.argv - это список аргументов из командной строки. Скрипты Python могут быть запущены из программной оболочки. Это один из способов, как мы можем контролировать запуск наших скриптов.
w = QWidget()
Виджет QWidget – это основной класс всех объектов пользовательского интерфейса в PyQt5. Мы обеспечиваем конструктор по умолчанию для QWidget. Конструктор по умолчанию не имеет родителя. Виджет без родителя называется окном.
w.resize(250, 150)
Метод resize() изменяет размер виджета. Здесь задана ширина 250px и высота 150px.
w.move(300, 300)
Метод move() перемещает виджет на позицию с координатами x=300 и y=300 на экране.
w.setWindowTitle('Simple')
Здесь мы устанавливаем название нашего окна. Оно показывается в строке заголовка.
w.show()
Метод show() отображает виджет на экране. Виджет сначала создаётся в памяти и позже показывается на экране.
sys.exit(app.exec_())
Наконец, мы входим в главный цикл приложения. Обработка событий начинается в этой точке. Главный цикл получает события из системы и отправляет их виджетам приложения. Цикл завершается, если мы вызываем метод exit() или главное окно было закрыто. Метод sys.exit() гарантирует чистый выход. Среда будет проинформирована, когда приложение завершится.
Метод exec_() содержит нижнее подчеркивание, потому что exec – уже используемое имя в Python. И, соответственно, имя exec_() было использовано взамен.
Рисунок: Окно Simple
Иконка приложения
Иконка приложения – это маленькое изображение, которое обычно отображается в верхнем левом углу строки заголовка. В следующем примере мы увидим, как сделать её в PyQt5. Мы также познакомимся с несколькими новыми методами.
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import sys
from PyQt5.QtWidgets import QApplication, QWidget
from PyQt5.QtGui import QIcon
class Example(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setGeometry(300, 300, 300, 220)
self.setWindowTitle('Icon')
self.setWindowIcon(QIcon('web.png'))
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
Предыдущий пример был написан в процедурном стиле. Язык программирования Python поддерживает и процедурный, и объектно-ориентированный стиль программирования. Программирование в PyQt5 означает объектно-ориентированное программирование (ООП).
class Example(QWidget):
def __init__(self):
super().__init__()
...
Есть три важных вещи в объектно-ориентированном программировании – это классы, данные и методы. Здесь мы создаём новый класс с именем Example. Класс Example наследуется из класса QWidget. Это значит, что мы вызываем два конструктора: первый для класса Example и второй для унаследованного класса. Метод super() возвращает объект родителя класса Example и мы вызываем его конструктор. Метод __init__() – это конструктор класса в языке Python.
self.initUI()
Создание GUI поручено методу initUI().
self.setGeometry(300, 300, 300, 220)
self.setWindowTitle('Icon')
self.setWindowIcon(QIcon('web.png'))
Все три метода были унаследованы из класса QWidget. setGeometry делает две вещи: он определяет место окна на экране и устанавливает его размер. Первые два параметра – позиции x и y нашего окна. Третий – ширина, и четвёртый – высота окна. Фактически, setGeometry сочетает методы resize() и move() в одном. Последний метод устанавливает иконку приложения. Чтобы сделать это, мы создали объект QIcon. QIcon принимает путь к нашей иконке для её отображения.
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
Приложение и объекты примера созданы. Главный цикл запущен.
Рисунок: Окно с иконкой
Показ всплывающих подсказок
Мы можем обеспечить любой из наших виджетов всплывающей подсказкой.
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import sys
from PyQt5.QtWidgets import (QWidget, QToolTip, QPushButton, QApplication)
from PyQt5.QtGui import QFont
class Example(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
QToolTip.setFont(QFont('SansSerif', 10))
self.setToolTip('This is a <b>QWidget</b> widget')
btn = QPushButton('Button', self)
btn.setToolTip('This is a <b>QPushButton</b> widget')
btn.resize(btn.sizeHint())
btn.move(50, 50)
self.setGeometry(300, 300, 300, 200)
self.setWindowTitle('Tooltips')
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
В этом примере, мы показываем подсказку для двух PyQt5 виджетов.
QToolTip.setFont(QFont('SansSerif', 10))
Этот статический метод устанавливает шрифт, используемый для показа всплывающих подсказок. Мы используем шрифт 10px SansSerif.
self.setToolTip('This is a <b>QWidget</b> widget')
Чтобы создать подсказку, мы вызываем метод setTooltip(). Мы можем использовать HTML форматирование текста.
btn = QPushButton('Button', self)
btn.setToolTip('This is a <b>QPushButton</b> widget')
Мы создаём виджет кнопки и устанавливаем всплывающую подсказку для неё.
btn.resize(btn.sizeHint())
btn.move(50, 50)
Меняем размер у кнопки, перемещаем её в окно. Метод sizeHint() даёт рекомендуемый размер для кнопки.
Рисунок: Всплывающие подсказки
Закрытие окна
Очевидный способ закрыть окно – это кликнуть на знаке «X» в строке заголовка. В следующем примере, мы покажем, как мы можем программно закрыть наше окно. Мы кратко коснёмся темы сигналов и слотов.
Ниже следует конструктор виджета QPushButton, который мы используем в нашем примере.
QPushButton(string_text, QWidget parent = None)
Параметр string_text – это текст, который будет отображён на кнопке. Parent – это виджет, на котором мы разместим нашу кнопку. В этом случае это будет QWidget.
Виджеты имеют иерархическую форму. В этой иерархии большинство виджетов имеют родителей. Виджеты без родителей – это окна верхнего уровня.
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import sys
from PyQt5.QtWidgets import QWidget, QPushButton, QApplication
from PyQt5.QtCore import QCoreApplication
class Example(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
qbtn = QPushButton('Quit', self)
qbtn.clicked.connect(QCoreApplication.instance().quit)
qbtn.resize(qbtn.sizeHint())
qbtn.move(50, 50)
self.setGeometry(300, 300, 250, 150)
self.setWindowTitle('Quit button')
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
В этом примере, мы создали кнопку выхода. После нажатия на кнопку, приложение завершается.
from PyQt5.QtCore import QCoreApplication
Нам необходим объект из модуля QtCore.
qbtn = QPushButton('Quit', self)
Мы создали кнопку. Кнопка является образцом класса QPushButton. Первый параметр конструктора – это метка кнопки. Второй параметр – родительский виджет. Виджет родителя – это Example, который наследуется из QWidget.
qbtn.clicked.connect(QCoreApplication.instance().quit)
Система обработки событий в PyQt5 построена на механизме сигналов и слотов. Если мы кликаем по кнопке, выдаётся сигнал clicked. Слот может быть слотом Qt или любым слотом, вызываемым из Python. QCoreApplication содержит цикл главного события; он обрабатывает и выполняет все события. Метод instance даёт нам его текущий экземпляр. Заметим, что QCoreApplication создаётся с QApplication. Кликнутый сигнал соединяется с методом quit(), который и завершает приложение. Взаимосвязь сделана между двумя объектами: отправителем и получателем. Отправитель – нажатие кнопки, получатель – объект приложения.
Рисунок: Кнопка выхода
Диалоговое окно
По умолчанию, если вы кликаете по кнопке «X» в строке заголовка, QWidget закрывается. Иногда мы хотим изменить это стандартное поведение. К примеру, если у нас есть открытый в редакторе файл, в котором мы сделали некоторые изменения, мы показываем сообщение для подтверждения выхода.
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import sys
from PyQt5.QtWidgets import QWidget, QMessageBox, QApplication
class Example(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setGeometry(300, 300, 250, 150)
self.setWindowTitle('Message box')
self.show()
def closeEvent(self, event):
reply = QMessageBox.question(self, 'Message', "Are you sure to quit?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
if reply == QMessageBox.Yes:
event.accept()
else:
event.ignore()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
Если мы закрываем QWidget, вызывается QCloseEvent. Чтобы изменить поведение виджета, нам необходимо переопределить обработчик событий closeEvent().
reply = QMessageBox.question(self, 'Message', "Are you sure to quit?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
Мы показываем сообщение с двумя кнопками: «Yes» и «No». Первая строка появляется в строке заголовка. Вторая строка – это текст сообщения, отображаемый с помощью диалогового окна. Третий аргумент указывает комбинацию кнопок, появляющихся в диалоге. Последний параметр – кнопка по умолчанию. Это кнопка, которая первоначально имеет на себе указатель клавиатуры. Возвращаемое значение хранится в переменной reply.
if reply == QtGui.QMessageBox.Yes:
event.accept()
else:
event.ignore()
Здесь мы проверяем возвращаемое значение. Если мы кликаем кнопку «Yes», мы принимаем событие, которое ведёт к закрытию виджета и завершению приложения. В противном случае, мы игнорируем закрывающее событие.
Рисунок: Диалоговое окно
Центрирование окна на экране
Нижеследующий скрипт показывает, как мы можем центрировать окно экране.
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import sys
from PyQt5.QtWidgets import QWidget, QDesktopWidget, QApplication
class Example(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.resize(250, 150)
self.center()
self.setWindowTitle('Center')
self.show()
def center(self):
qr = self.frameGeometry()
cp = QDesktopWidget().availableGeometry().center()
qr.moveCenter(cp)
self.move(qr.topLeft())
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
Класс QtGui.QDesktopWidget предоставляет информацию о пользовательском рабочем столе, включая размер экрана.
self.center()
Код, который будет центрировать окно, размещён в специальном методе center().
qr = self.frameGeometry()
Мы получаем прямоугольник, точно определяющий форму главного окна.
cp = QDesktopWidget().availableGeometry().center()
Мы выясняем разрешение экрана нашего монитора. Из этого разрешения, мы получаем центральную точку.
qr.moveCenter(cp)
Наш прямоугольник уже имеет высоту и ширину. Теперь мы устанавливаем центр прямоугольника в центр экрана. Размер прямоугольника не изменяется.
self.move(qr.topLeft())
Мы перемещаем верхнюю левую точку окна приложения в верхнюю левую точку прямоугольника qr, таким образом центрируя окно на нашем экране.
В этой части руководства PyQt5, мы успели изучить некоторые основы...
Коллеги!
В примере по изменению иконки окна (приложения) ни чего не происходит.
Я так понимаю у вас в примере использовались встроенные значки? или файл
из текущего каталога? в любом случае метод QIcon создает объект даже при
не правильном имени, и значек окна приложения не меняется.
Как понять в чем дело? Буду рад подсказке.
Привет Игорь.
Следующая строка:
self.setWindowIcon(QIcon('web.png'))
отвечает за внедрение иконки. Картинка web.png должна находиться в той же папке где находится исполняемый Python скрипт.
У вас Linux или Windows? У мена на Ubuntu работает, только что проверил.
Archy, спасибо что откликнулся!
У меня Ubunu 16.04, самое смешное, что проверил в Windows все работает, на Linux нет. Причем проблема не в QIcon, как я думал в начале, а в setWindowIcon. Icon на кнопку (Button) вывести смог. а вот на окне - засада. И не работает пример с меню (MenuBar), при чем проверил в Windows все работает.
QIcon в Ubuntu16.04 как и у предыдущего автора не внедряет иконку. Как исправить? Просто и в следующем уроке QIcon не вставляет картинку (для кнопки выхода в панели инструментов)
Такой же конфуз как и у остальных. Добавил файл в папку с нужным файлом, но все как было, так и осталось.
Программа с кнопкой выключения не работает....
Все запускается, кнопка создается, а вот работать кнопка не хочет....
Дружище, делай что-то с сайтом. Именно эта страница грузится у меня более 10 секунд!!!
Ждал, так как инфа полезная... но другие могут и уйти. Удачи!
Почему в примере про закрытие окна:
qbtn.clicked.connect(QCoreApplication.instance().quit)
а не:
qbtn.clicked.connect(QApplication.instance().quit)
У меня работают оба варианта. В чём смысл?
У кого не показывает иконку окна, откопала ответ (https://stackoverflow.com/questions/35864177/why-using-pyqt5-on-mac-can-not-add-a-icon):
нужно переместить setWindowIcon(QIcon('web.png')) из класса в main:
import os
......
импорт и класс, как в примере, но без setWindowIcon
......
if __name__ == '__main__':
app = QApplication(sys.argv) #sys.argv -- командная строка
path = os.path.join(os.path.dirname(sys.modules[__name__].__file__), 'web.png') #путь такой же, как у кода - для этого нужен import os
app.setWindowIcon(QIcon(path)) #идет с QApplication, а не QWidget
ex = Example() #без родителя -- окно
sys.exit(app.exec_()) #цикл + чистый выход
в последующих уроках иногда опускается импорт QWidget, хотя уроки как бы для начинающих.пишите все и полностью,пожалуйста
В примере на закрытие окна по кнопке, в строке "qbtn.clicked.connect(QCoreApplication.instance().quit)" если не срабатывает программа, надо написать "qbtn.clicked.connect(self.close)". Или привязать ивент. Подробнее можно посмотреть тут: https://stackoverflow.com/questions/36555153/pyqt5-closing-terminating-application
При запуске примера выходит ошибка, хелп
Warning: QT_DEVICE_PIXEL_RATIO is deprecated. Instead use:
QT_AUTO_SCREEN_SCALE_FACTOR to enable platform plugin controlled per-screen factors.
QT_SCREEN_SCALE_FACTORS to set per-screen factors.
QT_SCALE_FACTOR to set the application global scale factor.