Быстрый в изучении - мощный в программировании
>> Telegram ЧАТ для Python Программистов

Свободное общение и помощь советом и решением проблем с кодом! Заходите в наш TELEGRAM ЧАТ!

>> Python Форум Помощи!

Мы создали форум где отвечаем на все вопросы связанные с языком программирования Python. Ждем вас там!

>> Python Канал в Telegram

Обучающие статьи, видео и новости из мира Python. Подпишитесь на наш TELEGRAM КАНАЛ!

Первые программы на PyQt5 [Урок 2]

programmy-na-pyqt5.png

В этой части руководства 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

Рисунок: Окно 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, мы успели изучить некоторые основы...

Продолжение: Меню и панели инструментов в PyQt5 [Урок №3]

Прошлый урок: Введение в PyQt5 [Урок 1]

Комментариев: 12
  1. Коллеги!

    В примере по изменению иконки окна (приложения) ни чего не происходит.

    Я так понимаю у вас в примере использовались встроенные значки? или файл

    из текущего каталога? в любом случае метод QIcon создает объект даже при

    не правильном имени, и значек окна приложения не меняется.

    Как понять в чем дело? Буду рад подсказке.

  2. Привет Игорь.

    Следующая строка:

    self.setWindowIcon(QIcon('web.png'))

    отвечает за внедрение иконки. Картинка web.png должна находиться в той же папке где находится исполняемый Python скрипт.

    У вас Linux или Windows? У мена на Ubuntu работает, только что проверил.

  3. Archy, спасибо что откликнулся!

    У меня Ubunu 16.04, самое смешное, что проверил в Windows все работает, на Linux нет. Причем проблема не в QIcon, как я думал в начале, а в setWindowIcon. Icon на кнопку (Button) вывести смог. а вот на окне - засада. И не работает пример с меню (MenuBar), при чем проверил в Windows все работает.

  4. QIcon в Ubuntu16.04 как и у предыдущего автора не внедряет иконку. Как исправить? Просто и в следующем уроке QIcon не вставляет картинку (для кнопки выхода в панели инструментов)

  5. Такой же конфуз как и у остальных. Добавил файл в папку с нужным файлом, но все как было, так и осталось.

  6. Комментатор | 2017-02-23 в 14:55:25

    Программа с кнопкой выключения не работает....

    Все запускается, кнопка создается, а вот работать кнопка не хочет....

  7. Дмитрий | 2017-09-08 в 13:26:38

    Дружище, делай что-то с сайтом. Именно эта страница грузится у меня более 10 секунд!!!

    Ждал, так как инфа полезная... но другие могут и уйти. Удачи!

  8. Почему в примере про закрытие окна:

    qbtn.clicked.connect(QCoreApplication.instance().quit)

    а не:

    qbtn.clicked.connect(QApplication.instance().quit)

    У меня работают оба варианта. В чём смысл?

  9. У кого не показывает иконку окна, откопала ответ (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_()) #цикл + чистый выход

  10. Аноним | 2018-05-13 в 18:50:29

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

  11. В примере на закрытие окна по кнопке, в строке "qbtn.clicked.connect(QCoreApplication.instance().quit)" если не срабатывает программа, надо написать "qbtn.clicked.connect(self.close)". Или привязать ивент. Подробнее можно посмотреть тут: https://stackoverflow.com/questions/36555153/pyqt5-closing-terminating-application

  12. При запуске примера выходит ошибка, хелп

    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.