Главная страница

ээдд. Прохоренок_Н_А__Дронов_В_А_Python_3_и_PyQt_5_Разработка_приложен. Николай Прохоренок Владимир Дронов


Скачать 7.92 Mb.
НазваниеНиколай Прохоренок Владимир Дронов
Дата05.05.2023
Размер7.92 Mb.
Формат файлаpdf
Имя файлаПрохоренок_Н_А__Дронов_В_А_Python_3_и_PyQt_5_Разработка_приложен.pdf
ТипДокументы
#1111379
страница38 из 83
1   ...   34   35   36   37   38   39   40   41   ...   83
= <Объект>.startTimer(<Интервал>[, timerType=<Тип таймера>])
Параметр
<Интервал>
задает промежуток времени в миллисекундах, по истечении которого выполняется метод timerEvent()
. Минимальное значение интервала зависит от операцион- ной системы. Если в параметре
<Интервал>
указать значение
0
, таймер будет срабатывать много раз при отсутствии других необработанных событий.
Необязательный параметр timerType позволяет указать тип таймера в виде одного из атри- бутов класса
QtCore.Qt
:

PreciseTimer
— точный таймер, обеспечивающий точность до миллисекунд;

CoarseTimer
— таймер, обеспечивающий точность в пределах 5% от заданного интерва- ла (значение по умолчанию);

VeryCoarseTimer
— «приблизительный» таймер, обеспечивающий точность до секунд.
Метод startTimer()
возвращает идентификатор таймера, с помощью которого впоследст- вии можно остановить таймер.
Формат метода timerEvent()
: timerEvent(self, <Объект класса QTimerEvent>)
Внутри него можно получить идентификатор таймера с помощью метода timerId()
объекта класса
QTimerEvent
Чтобы остановить таймер, необходимо воспользоваться методом killTimer()
класса
QObject
. Формат метода:
<Объект>.killTimer()
В качестве параметра указывается идентификатор, возвращаемый методом startTimer()
Создадим в окне часы, которые будут отображать текущее системное время с точностью до секунды, и добавим возможность запуска и остановки часов с помощью соответствующих кнопок (листинг 19.6).

Глава 19. Обработка сигналов и событий
405
Листинг 19.6. Вывод времени в окне с точностью до секунды
# -*- coding: utf-8 -*- from PyQt5 import QtCore, QtWidgets import time class MyWindow(QtWidgets.QWidget): def __init__(self, parent=None):
QtWidgets.QWidget.__init__(self, parent) self.setWindowTitle("Часы в окне") self.resize(200, 100) self.timer_id = 0 self.label = QtWidgets.QLabel("") self.label.setAlignment(QtCore.Qt.AlignHCenter) self.button1 = QtWidgets.QPushButton("Запустить") self.button2 = QtWidgets.QPushButton("Остановить") self.button2.setEnabled(False) vbox = QtWidgets.QVBoxLayout() vbox.addWidget(self.label) vbox.addWidget(self.button1) vbox.addWidget(self.button2) self.setLayout(vbox) self.button1.clicked.connect(self.on_clicked_button1) self.button2.clicked.connect(self.on_clicked_button2) def on_clicked_button1(self):
# Задаем интервал в 1 секунду и "приближенный" таймер self.timer_id = self.startTimer(1000, timerType = QtCore.Qt.VeryCoarseTimer) self.button1.setEnabled(False) self.button2.setEnabled(True) def on_clicked_button2(self): if self.timer_id: self.killTimer(self.timer_id) self.timer_id = 0 self.button1.setEnabled(True) self.button2.setEnabled(False) def timerEvent(self, event): self.label.setText(time.strftime("%H:%M:%S")) if __name__ == "__main__": import sys app = QtWidgets.QApplication(sys.argv) window = MyWindow() window.show() sys.exit(app.exec_())
Вместо методов startTimer()
и killTimer()
класса
QObject можно воспользоваться классом
QTimer из модуля
QtCore
. Конструктор класса имеет следующий формат:
<Объект> = QTimer([parent=None])

406
Часть II. Библиотека PyQt 5
Методы класса:
 setInterval(<Интервал>)
— задает промежуток времени в миллисекундах, по истечении которого генерируется сигнал timeout
. Минимальное значение интервала зависит от операционной системы. Если в параметре
<Интервал>
указать значение
0
, таймер будет срабатывать много раз при отсутствии других необработанных сигналов;
 start([<Интервал>])
— запускает таймер. В необязательном параметре можно указать промежуток времени в миллисекундах. Если параметр не указан, используется значение, заданное в вызове метода setInterval()
;
 stop()
— останавливает таймер;
 isActive()
— возвращает значение
True
, если таймер запущен, и
False
— в противном случае;
 timerId()
— возвращает идентификатор таймера, если он запущен, и значение
-1
— в противном случае;
 remainingTime()
— возвращает время, оставшееся до очередного срабатывания таймера, в миллисекундах;
 interval()
— возвращает установленный интервал;
 setSingleShot(<Флаг>)
— если в параметре указано значение
True
, таймер сработает только один раз, в противном случае — будет срабатывать многократно;
 isSingleShot()
— возвращает значение
True
, если таймер будет срабатывать только один раз, и
False
— в противном случае;
 setTimerType(<Тип таймера>)
— задает тип таймера, который указывается в том же виде, что и в случае вызова метода startTimer()
;
 timerType()
— возвращает тип таймера.
Переделаем предыдущий пример и используем класс
QTimer вместо методов startTimer()
и killTimer()
(листинг 19.7).
Листинг 19.7. Использование класса
QTimer
# -*- coding: utf-8 -*- from PyQt5 import QtCore, QtWidgets import time class MyWindow(QtWidgets.QWidget): def __init__(self, parent=None):
QtWidgets.QWidget.__init__(self, parent) self.setWindowTitle("Использование класса QTimer") self.resize(200, 100) self.label = QtWidgets.QLabel("") self.label.setAlignment(QtCore.Qt.AlignHCenter) self.button1 = QtWidgets.QPushButton("Запустить") self.button2 = QtWidgets.QPushButton("Остановить") self.button2.setEnabled(False) vbox = QtWidgets.QVBoxLayout() vbox.addWidget(self.label) vbox.addWidget(self.button1)

Глава 19. Обработка сигналов и событий
407 vbox.addWidget(self.button2) self.setLayout(vbox) self.button1.clicked.connect(self.on_clicked_button1) self.button2.clicked.connect(self.on_clicked_button2) self.timer = QtCore.QTimer() self.timer.timeout.connect(self.on_timeout); def on_clicked_button1(self): self.timer.start(1000) # 1 секунда self.button1.setEnabled(False) self.button2.setEnabled(True) def on_clicked_button2(self): self.timer.stop() self.button1.setEnabled(True) self.button2.setEnabled(False) def on_timeout(self): self.label.setText(time.strftime("%H:%M:%S")) if __name__ == "__main__": import sys app = QtWidgets.QApplication(sys.argv) window = MyWindow() window.show() sys.exit(app.exec_())
Статический метод singleShot()
класса
QTimer запускает таймер, настраивает его для одно- кратного срабатывания и указывает функцию или метод, который будет вызван по истече- нии заданного интервала. Формат вызова этого метода следующий: singleShot(<Интервал>[, <Тип таймера>], <Функция или метод>)
Примеры использования этого статического метода:
QtCore.QTimer.singleShot(1000, self.on_timeout)
QtCore.QTimer.singleShot(1000, QtWidgets.qApp.quit)
19.6. Перехват всех событий
В предыдущих разделах мы рассмотрели обработку сигналов, которые позволяют обмени- ваться сообщениями между компонентами. Обработка внешних событий — например, на- жатий клавиш, — осуществляется несколько иначе. Чтобы обработать событие, необходимо наследовать класс и переопределить в нем метод со специальным названием, — так, чтобы обработать нажатие клавиши, следует переопределить метод keyPressEvent()
. Специальные методы принимают объект, содержащий детальную информацию о событии, — например, код нажатой клавиши. Все эти объекты являются наследниками класса
QEvent и наследуют следующие методы:
 accept()
— устанавливает флаг, разрешающий дальнейшую обработку события. Ска- жем, если в методе closeEvent()
вызвать метод accept()
через объект события, окно будет закрыто. Этот флаг обычно установлен по умолчанию;
 ignore()
— сбрасывает флаг, разрешающий дальнейшую обработку события. Так, если в методе closeEvent()
вызвать метод ignore()
через объект события, окно закрыто не будет;

408
Часть II. Библиотека PyQt 5
 setAccepted(<Флаг>)
— если в качестве параметра указано значение
True
, флаг, разре- шающий дальнейшую обработку события, будет установлен (аналогично вызову метода accept()
), а если
False
— сброшен (аналогично вызову метода ignore()
);
 isAccepted()
— возвращает текущее состояние флага, разрешающего дальнейшую об- работку события;
 spontaneous()
— возвращает
True
, если событие сгенерировано системой, и
False
— если внутри программы;
 type()
— возвращает тип события. Приведем основные типы событий (полный их спи- сок содержится в документации по классу
QEvent на странице https://doc.qt.io/qt-
5/qevent.html):

0
— нет события;

1

Timer
— событие таймера;

2

MouseButtonPress
— нажата кнопка мыши;

3

MouseButtonRelease
— отпущена кнопка мыши;

4

MouseButtonDblClick
— двойной щелчок мышью;

5

MouseMove
— перемещение мыши;

6

KeyPress
— клавиша на клавиатуре нажата;

7

KeyRelease
— клавиша на клавиатуре отпущена;

8

FocusIn
— получен фокус ввода с клавиатуры;

9

FocusOut
— потерян фокус ввода с клавиатуры;

10

Enter
— указатель мыши входит в область компонента;

11

Leave
— указатель мыши покидает область компонента;

12

Paint
— перерисовка компонента;

13

Move
— позиция компонента изменилась;

14

Resize
— изменился размер компонента;

17

Show
— компонент отображен;

18

Hide
— компонент скрыт;

19

Close
— окно закрыто;

24

WindowActivate
— окно стало активным;

25

WindowDeactivate
— окно стало неактивным;

26

ShowToParent
дочерний компонент отображен;

27

HideToParent
— дочерний компонент скрыт;

31

Wheel
— прокручено колесико мыши;

40

Clipboard
— содержимое буфера обмена изменено;

60

DragEnter
— указатель мыши входит в область компонента при операции пере- таскивания;

61

DragMove
— производится операция перетаскивания;

62

DragLeave
— указатель мыши покидает область компонента при операции пере- таскивания;

Глава 19. Обработка сигналов и событий
409

63

Drop
— операция перетаскивания завершена;

68

ChildAdded
— добавлен дочерний компонент;

69

ChildPolished
— производится настройка дочернего компонента;

71

ChildRemoved
— удален дочерний компонент;

74

PolishRequest
— компонент настроен;

75

Polish
— производится настройка компонента;

82

ContextMenu
— событие контекстного меню;

99

ActivationChange
— изменился статус активности окна верхнего уровня;

103

WindowBlocked
— окно блокировано модальным окном;

104

WindowUnblocked
— текущее окно разблокировано после закрытия модального окна;

105

WindowStateChange
— статус окна изменился;

121

ApplicationActivate
— приложение стало доступно пользователю;

122

ApplicationDeactivate
— приложение стало недоступно пользователю;

1000

User
— пользовательское событие;

65535

MaxUser
— максимальный идентификатор пользовательского события.
Статический метод registerEventType([<Число>])
позволяет зарегистрировать пользова- тельский тип события, возвращая идентификатор зарегистрированного события. В качестве параметра можно указать значение в пределах от
QEvent.User
(
1000
) до
QEvent.MaxUser
(
65535
).
Перехват всех событий осуществляется с помощью метода с предопределенным названием event(self, )
. Через параметр

доступен объект с дополнительной инфор- мацией о событии. Этот объект различен для разных типов событий — например, для собы- тия
MouseButtonPress объект будет экземпляром класса
QMouseEvent
, а для события
KeyPress
— экземпляром класса
QKeyEvent
. Методы, поддерживаемые всеми этими класса- ми, мы рассмотрим в следующих разделах.
Из метода event()
следует вернуть в качестве результата значение
True
, если событие было обработано, и
False
— в противном случае. Если возвращается значение
True
, то родитель- ский компонент не получит событие. Чтобы продолжить распространение события, необхо- димо вызвать метод event()
базового класса и передать ему текущий объект события.
Обычно это делается так: return QtWidgets.QWidget.event(self, e)
В этом случае пользовательский класс является наследником класса
QWidget и переопреде- ляет метод event()
. Если вы наследуете другой класс, следует вызывать метод именно этого класса. Например, при наследовании класса
QLabel инструкция будет выглядеть так: return QtWidgets.QLabel.event(self, e)
Пример перехвата нажатия клавиши, щелчка мышью и закрытия окна показан в листин- ге 19.8.
Листинг 19.8. Перехват всех событий
# -*- coding: utf-8 -*- from PyQt5 import QtCore, QtWidgets

410
Часть II. Библиотека PyQt 5 class MyWindow(QtWidgets.QWidget): def __init__(self, parent=None):
QtWidgets.QWidget.__init__(self, parent) self.resize(300, 100) def event(self, e): if e.type() == QtCore.QEvent.KeyPress: print("Нажата клавиша на клавиатуре") print("Код:", e.key(), ", текст:", e.text()) elif e.type() == QtCore.QEvent.Close: print("Окно закрыто") elif e.type() == QtCore.QEvent.MouseButtonPress: print("Щелчок мышью. Координаты:", e.x(), e.y()) return QtWidgets.QWidget.event(self, e) # Отправляем дальше if __name__ == "__main__": import sys app = QtWidgets.QApplication(sys.argv) window = MyWindow() window.show() sys.exit(app.exec_())
19.7. События окна
Перехватывать все события следует только в самом крайнем случае. В обычных ситуациях нужно использовать методы, предназначенные для обработки определенного события, — например, чтобы обработать закрытие окна, достаточно переопределить метод closeEvent()
. Методы, которые требуется переопределять для обработки событий окна, мы сейчас и рассмотрим.
19.7.1. Изменение состояния окна
Отследить изменение состояния окна (сворачивание, разворачивание, скрытие и отображе- ние) позволяют следующие методы:
 changeEvent(self, )
— вызывается при изменении состояния окна, приложения или компонента, заголовка окна, его палитры, статуса активности окна верхнего уров- ня, языка, локали и др. (полный список смотрите в документации). При обработке со- бытия
WindowStateChange через параметр

доступен экземпляр класса
QWindowStateChangeEvent
. Этот класс поддерживает только метод oldState()
, с по- мощью которого можно получить предыдущее состояние окна;
 showEvent(self, )
— вызывается при отображении компонента. Через параметр

доступен экземпляр класса
QShowEvent
;
 hideEvent(self, )
— вызывается при скрытии компонента. Через параметр

доступен экземпляр класса
QHideEvent
Для примера выведем в консоль текущее состояние окна при его сворачивании, разворачи- вании, скрытии и отображении (листинг 19.9).

Глава 19. Обработка сигналов и событий
411
Листинг 19.9. Отслеживание состояния окна
# -*- coding: utf-8 -*- from PyQt5 import QtCore, QtWidgets class MyWindow(QtWidgets.QWidget): def __init__(self, parent=None):
QtWidgets.QWidget.__init__(self, parent) self.resize(300, 100) def changeEvent(self, e): if e.type() == QtCore.QEvent.WindowStateChange: if self.isMinimized(): print("Окно свернуто") elif self.isMaximized(): print("Окно раскрыто до максимальных размеров") elif self.isFullScreen(): print("Полноэкранный режим") elif self.isActiveWindow(): print("Окно находится в фокусе ввода")
QtWidgets.QWidget.changeEvent(self, e) # Отправляем дальше def showEvent(self, e): print("Окно отображено")
QtWidgets.QWidget.showEvent(self, e) # Отправляем дальше def hideEvent(self, e): print("Окно скрыто")
QtWidgets.QWidget.hideEvent(self, e) # Отправляем дальше if __name__ == "__main__": import sys app = QtWidgets.QApplication(sys.argv) window = MyWindow() window.show() sys.exit(app.exec_())
19.7.2. Изменение положения и размеров окна
При перемещении и изменении размеров окна вызываются следующие методы:
 moveEvent(self, )
— непрерывно вызывается при перемещении окна. Через параметр

доступен экземпляр класса
QMoveEvent
. Получить координаты окна по- зволяют следующие методы этого класса:
• pos()
— возвращает экземпляр класса
QPoint с текущими координатами;
• oldPos()
— возвращает экземпляр класса
QPoint с предыдущими координатами;
 resizeEvent(self, )
— непрерывно вызывается при изменении размеров окна.
Через параметр

доступен экземпляр класса
QResizeEvent
. Получить размеры ок- на позволяют следующие методы этого класса:
• size()
— возвращает экземпляр класса
QSize с текущими размерами;
• oldSize()
— возвращает экземпляр класса
QSize с предыдущими размерами.

412
Часть II. Библиотека PyQt 5
Пример обработки изменения положения окна и его размера показан в листинге 19.10.
Листинг 19.10. Отслеживание смены положения и размеров окна
# -*- coding: utf-8 -*- from PyQt5 import QtWidgets class MyWindow(QtWidgets.QWidget): def __init__(self, parent=None):
QtWidgets.QWidget.__init__(self, parent) self.resize(300, 100) def moveEvent(self, e): print("x = {0}; y = {1}".format(e.pos().x(), e.pos().y()))
QtWidgets.QWidget.moveEvent(self, e) # Отправляем дальше def resizeEvent(self, e): print("w = {0}; h = {1}".format(e.size().width(), e.size().height()))
QtWidgets.QWidget.resizeEvent(self, e) # Отправляем дальше if __name__ == "__main__": import sys app = QtWidgets.QApplication(sys.argv) window = MyWindow() window.show() sys.exit(app.exec_())
19.7.3. Перерисовка окна или его части
Когда компонент (или часть компонента) становится видимым, требуется выполнить его перерисовку. В этом случае вызывается метод с названием paintEvent(self, )
Через параметр

доступен экземпляр класса
QPaintEvent
, который поддерживает следующие методы:
 rect()
— возвращает экземпляр класса
QRect с координатами и размерами прямоуголь- ной области, которую требуется перерисовать;
 region()
— возвращает экземпляр класса
QRegion с регионом, требующим перерисовки.
С помощью этих методов можно получить координаты области, которая, например, была ранее перекрыта другим окном и теперь вновь оказалась в зоне видимости. Перерисовывая только область, а не весь компонент, можно заметно повысить быстродействие приложения.
Следует также заметить, что в целях эффективности последовательность событий перери- совки может быть объединена в одно событие с общей областью перерисовки.
В некоторых случаях перерисовку окна необходимо выполнить вне зависимости от внеш- них действий системы или пользователя — например, при изменении каких-либо значений требуется обновить график. Вызвать событие перерисовки компонента позволяют следую- щие методы класса
QWidget
:
 repaint()
— немедленно вызывает метод paintEvent()
для перерисовки компонента при условии, что таковой не скрыт, и обновление не было запрещено вызовом метода setUpdatesEnabled()
. Форматы метода:

Глава 19. Обработка сигналов и событий
413 repaint() repaint(, , <Ширина>, <Высота>) repaint() repaint()
Первый формат вызова выполняет перерисовку всего компонента, а остальные — только области с указанными координатами;
 update()
— посылает сообщение о необходимости перерисовки компонента при усло- вии, что компонент не скрыт и обновление не запрещено. Событие будет обработано на следующей итерации основного цикла приложения. Если посылаются сразу несколько сообщений, они объединяются в одно, благодаря чему можно избежать неприятного мерцания. Рекомендуется использовать этот метод вместо метода repaint()
. Форматы вызова: update() update(, , <Ширина>, <Высота>) update() update()
19.7.4. Предотвращение закрытия окна
При закрытии окна нажатием кнопки Закрыть в его заголовке или вызовом метода close()
в коде выполняется метод closeEvent(self, )
. Через параметр

доступен экземпляр класса
QCloseEvent
. Чтобы предотвратить закрытие окна, у объекта события сле- дует вызвать метод ignore()
, в противном случае — метод accept()
В качестве примера по нажатию кнопки Закрыть выведем стандартное диалоговое окно с запросом подтверждения закрытия окна (листинг 19.11). Если пользователь нажмет кноп- ку Да, закроем окно, а если щелкнет кнопку Нет или просто закроет диалоговое окно, не будем его закрывать.
Листинг 19.11. Обработка закрытия окна
# -*- coding: utf-8 -*- from PyQt5 import QtWidgets class MyWindow(QtWidgets.QWidget): def __init__(self, parent=None):
QtWidgets.QWidget.__init__(self, parent) self.resize(300, 100) def closeEvent(self, e): result = QtWidgets.QMessageBox.question(self,
"Подтверждение закрытия окна",
"Вы действительно хотите закрыть окно?",
QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No,
QtWidgets.QMessageBox.No) if result == QtWidgets.QMessageBox.Yes: e.accept()
QtWidgets.QWidget.closeEvent(self, e) else: e.ignore()

414
Часть II. Библиотека PyQt 5 if __name__ == "__main__": import sys app = QtWidgets.QApplication(sys.argv) window = MyWindow() window.show() sys.exit(app.exec_())
19.8. События клавиатуры
События клавиатуры обрабатываются очень часто. Например, при нажатии клавиши выводится справочная информация, при нажатии клавиши в однострочном тексто- вом поле фокус ввода переносится на другой компонент, и т. д. Рассмотрим события кла- виатуры подробно.
19.8.1. Установка фокуса ввода
В текущий момент времени только один компонент (или вообще ни одного) может иметь фокус ввода. Для управления фокусом ввода предназначены следующие методы класса
QWidget
:
 setFocus([<Причина>])
— устанавливает фокус ввода, если компонент находится в ак- тивном окне. В параметре
<Причина>
можно указать причину изменения фокуса ввода в виде одного из следующих атрибутов класса
QtCore.Qt
:

MouseFocusReason

0
— фокус изменен с помощью мыши;

TabFocusReason

1
— нажата клавиша ;

BacktabFocusReason

2
— нажата комбинация клавиш +;

ActiveWindowFocusReason

3
— окно стало активным или неактивным;

PopupFocusReason

4
— открыто или закрыто всплывающее окно;

ShortcutFocusReason

5
— нажата комбинация клавиш быстрого доступа;

MenuBarFocusReason

6
— фокус изменился из-за меню;

OtherFocusReason

7
— другая причина;
 clearFocus()
— убирает фокус ввода с компонента;
 hasFocus()
— возвращает значение
True
, если компонент имеет фокус ввода, и
False
— в противном случае;
 focusWidget()
— возвращает ссылку на последний компонент, для которого вызывался метод setFocus()
. Для компонентов верхнего уровня возвращается ссылка на компо- нент, который получит фокус после того, как окно станет активным;
 setFocusProxy()
— позволяет указать ссылку на компонент, который будет получать фокус ввода вместо текущего компонента;
 focusProxy()
— возвращает ссылку на компонент, который обрабатывает фокус ввода вместо текущего компонента. Если такого компонента нет, метод возвращает значение
None
;
 focusNextChild()
— находит следующий компонент, которому можно передать фокус, и передает фокус ему. Фактически работает аналогично нажатию клавиши . Воз- вращает значение
True
, если компонент найден, и
False
— в противном случае;

Глава 19. Обработка сигналов и событий
415
 focusPreviousChild()
— находит предыдущий компонент, которому можно передать фокус, и передает фокус ему. Работает аналогично нажатию комбинации клавиш
+. Возвращает значение
True
, если компонент найден, и
False
— в против- ном случае;
 focusNextPrevChild(<Флаг>)
— если в параметре указано значение
True
, работает ана- логично методу focusNextChild()
, если указано
False
— аналогично методу focusPreviousChild()
. Возвращает значение
True
, если компонент найден, и
False
— в противном случае;
 setTabOrder(<Компонент1>, <Компонент2>)
— позволяет задать последовательность сме- ны фокуса при нажатии клавиши . Метод является статическим. В параметре
<Компонент2>
указывается ссылка на компонент, на который переместится фокус с ком- понента
<Компонент1>
. Если компонентов много, метод вызывается несколько раз. Вот пример указания цепочки перехода widget1 -> widget2 -> widget3 -> widget4
:
QtWidgets.QWidget.setTabOrder(widget1, widget2)
QtWidgets.QWidget.setTabOrder(widget2, widget3)
QtWidgets.QWidget.setTabOrder(widget3, widget4)
 setFocusPolicy(<Способ>)
— задает способ получения фокуса компонентом в виде одного из следующих атрибутов класса
QtCore.Qt
:

NoFocus

0
— компонент не может получать фокус;

TabFocus

1
— получает фокус с помощью клавиши ;

ClickFocus

2
— получает фокус с помощью щелчка мышью;

StrongFocus

11
— получает фокус с помощью клавиши и щелчка мышью;

WheelFocus

15
— получает фокус с помощью клавиши , щелчка мышью и колесика мыши;
 focusPolicy()
— возвращает текущий способ получения фокуса;
 grabKeyboard()
— захватывает ввод с клавиатуры. Другие компоненты не будут полу- чать события клавиатуры, пока не будет вызван метод releaseKeyboard()
;
 releaseKeyboard()
— освобождает захваченный ранее ввод с клавиатуры.
Получить ссылку на компонент, находящийся в фокусе ввода, позволяет статический метод focusWidget()
класса
QApplication
. Если ни один компонент не имеет фокуса ввода, метод возвращает значение
None
. Не путайте этот метод с одноименным методом из класса
QWidget
Обработать получение и потерю фокуса ввода позволяют следующие методы класса
QWidget
:
 focusInEvent(self, )
— вызывается при получении фокуса ввода;
 focusOutEvent(self, )
— вызывается при потере фокуса ввода.
Через параметр

доступен экземпляр класса
QFocusEvent
, который поддерживает следующие методы:
 gotFocus()
— возвращает значение
True
, если тип события
QEvent.FocusIn
(получение фокуса ввода), и
False
— в противном случае;
 lostFocus()
— возвращает значение
True
, если тип события
QEvent.FocusOut
(потеря фокуса ввода), и
False
— в противном случае;

416
Часть II. Библиотека PyQt 5
 reason()
— возвращает причину установки фокуса. Значение аналогично значению па- раметра
<Причина>
в методе setFocus()
Создадим окно с кнопкой и двумя однострочными полями ввода (листинг 19.12). Для полей ввода обработаем получение и потерю фокуса ввода, а по нажатию кнопки установим фокус ввода на второе поле. Кроме того, зададим последовательность перехода при нажатии кла- виши .
Листинг 19.12. Установка фокуса ввода
# -*- coding: utf-8 -*- from PyQt5 import QtWidgets class MyLineEdit(QtWidgets.QLineEdit): def __init__(self, id, parent=None):
QtWidgets.QLineEdit.__init__(self, parent) self.id = id def focusInEvent(self, e): print("Получен фокус полем", self.id)
QtWidgets.QLineEdit.focusInEvent(self, e) def focusOutEvent(self, e): print("Потерян фокус полем", self.id)
QtWidgets.QLineEdit.focusOutEvent(self, e) class MyWindow(QtWidgets.QWidget): def __init__(self, parent=None):
QtWidgets.QWidget.__init__(self, parent) self.resize(300, 100) self.button = QtWidgets.QPushButton("Установить фокус на поле 2") self.line1 = MyLineEdit(1) self.line2 = MyLineEdit(2) self.vbox = QtWidgets.QVBoxLayout() self.vbox.addWidget(self.button) self.vbox.addWidget(self.line1) self.vbox.addWidget(self.line2) self.setLayout(self.vbox) self.button.clicked.connect(self.on_clicked)
# Задаем порядок обхода с помощью клавиши
QtWidgets.QWidget.setTabOrder(self.line1, self.line2)
QtWidgets.QWidget.setTabOrder(self.line2, self.button) def on_clicked(self): self.line2.setFocus() if __name__ == "__main__": import sys app = QtWidgets.QApplication(sys.argv) window = MyWindow() window.show() sys.exit(app.exec_())

Глава 19. Обработка сигналов и событий
417 19.8.2. Назначение клавиш быстрого доступа
Клавиши быстрого доступа (иногда их также называют «горячими» клавишами) позволяют установить фокус ввода с помощью нажатия специальной (например, или ) и какой-либо дополнительной клавиши. Если после нажатия клавиш быстрого доступа в фокусе окажется кнопка (или пункт меню), она будет нажата.
Чтобы задать клавиши быстрого доступа, следует в тексте надписи указать символ
&
перед буквой. В этом случае буква, перед которой указан символ
&
, будет — в качестве подсказки пользователю — подчеркнута. При одновременном нажатии клавиши и подчеркнутой буквы компонент окажется в фокусе ввода. Некоторые компоненты, например текстовое поле, не имеют надписи. Чтобы задать клавиши быстрого доступа для таких компонентов, необходимо отдельно создать надпись и связать ее с компонентом с помощью метода setBuddy(<Компонент>)
класса
QLabel
. Если же создание надписи не представляется воз- можным, можно воспользоваться следующими методами класса
QWidget
:
 grabShortcut(<Клавиши>[, <Контекст>])
— регистрирует клавиши быстрого доступа и возвращает идентификатор, с помощью которого можно управлять ими в дальнейшем.
В параметре
<Клавиши>
указывается экземпляр класса
QKeySequence из модуля
QtGui
Создать экземпляр этого класса для комбинации клавиш + можно, например, так:
QtGui.QKeySequence.mnemonic("&e")
QtGui.QKeySequence("Alt+e")
QtGui.QKeySequence(QtCore.Qt.ALT + QtCore.Qt.Key_E)
В параметре
<Контекст>
можно указать атрибуты
WidgetShortcut
,
WidgetWithChildren-
Shortcut
,
WindowShortcut
(значение по умолчанию) и
ApplicationShortcut класса
QtCore.Qt
;
 releaseShortcut()
— удаляет комбинацию с идентификатором

;
 setShortcutEnabled([, <Флаг>])
— если в качестве параметра
<Флаг>
указано
True
(значение по умолчанию), клавиша быстрого доступа с идентификатором

разреше- на. Значение
False запрещает использование клавиши быстрого доступа.
При нажатии клавиш быстрого доступа генерируется событие
QEvent
Shortcut
, которое можно обработать в методе event(self, )
. Через параметр

доступен экзем- пляр класса
QShortcutEvent
, поддерживающий следующие методы:
 shortcutId()
— возвращает идентификатор комбинации клавиш;
 isAmbiguous()
— возвращает значение
True
, если событие отправлено сразу нескольким компонентам, и
False
— в противном случае;
 key()
— возвращает экземпляр класса
QKeySequence
, представляющий нажатую клавишу быстрого доступа.
Создадим окно с надписью, двумя однострочными текстовыми полями и кнопкой (лис- тинг 19.13). Для первого текстового поля назначим комбинацию клавиш +<В> через надпись, а для второго поля — комбинацию +<Е> с помощью метода grabShortcut()
Для кнопки назначим комбинацию клавиш +<У> обычным образом — через надпись на кнопке.
Листинг 19.13. Назначение клавиш быстрого доступа разными способами
# -*- coding: utf-8 -*- from PyQt5 import QtCore, QtGui, QtWidgets

418
Часть II. Библиотека PyQt 5 class MyLineEdit(QtWidgets.QLineEdit): def __init__(self, parent=None):
QtWidgets.QLineEdit.__init__(self, parent) self.id = None def event(self, e): if e.type() == QtCore.QEvent.Shortcut: if self.id == e.shortcutId(): self.setFocus(QtCore.Qt.ShortcutFocusReason) return True return QtWidgets.QLineEdit.event(self, e) class MyWindow(QtWidgets.QWidget): def __init__(self, parent=None):
QtWidgets.QWidget.__init__(self, parent) self.resize(300, 100) self.label = QtWidgets.QLabel("Устано&вить фокус на поле 1") self.lineEdit1 = QtWidgets.QLineEdit() self.label.setBuddy(self.lineEdit1) self.lineEdit2 = MyLineEdit() self.lineEdit2.id = self.lineEdit2.grabShortcut(
QtGui.QKeySequence.mnemonic("&е")) self.button = QtWidgets.QPushButton("&Убрать фокус с поля 1") self.vbox = QtWidgets.QVBoxLayout() self.vbox.addWidget(self.label) self.vbox.addWidget(self.lineEdit1) self.vbox.addWidget(self.lineEdit2) self.vbox.addWidget(self.button) self.setLayout(self.vbox) self.button.clicked.connect(self.on_clicked) def on_clicked(self): self.lineEdit1.clearFocus() if __name__ == "__main__": import sys app = QtWidgets.QApplication(sys.argv) window = MyWindow() window.show() sys.exit(app.exec_())
Помимо рассмотренных способов, для назначения клавиш быстрого доступа можно вос- пользоваться классом
QShortcut из модуля
QtWidgets
. В этом случае назначение клавиш для второго текстового поля будет выглядеть так: self.lineEdit2 = QtWidgets.QLineEdit() self.shc = QtWidgets.QShortcut(QtGui.QKeySequence.mnemonic("&е"), self) self.shc.setContext(QtCore.Qt.WindowShortcut) self.shc.activated.connect(self.lineEdit2.setFocus)
Назначить комбинацию быстрых клавиш также позволяет класс
QAction из модуля
QtWidgets
. Назначение клавиш для второго текстового поля выглядит следующим образом:

Глава 19. Обработка сигналов и событий
419 self.lineEdit2 = QtWidgets.QLineEdit() self.act = QtWidgets.QAction(self) self.act.setShortcut(QtGui.QKeySequence.mnemonic("&е")) self.act.triggered.connect(self.lineEdit2.setFocus) self.addAction(self.act)
19.8.3. Нажатие и отпускание клавиши на клавиатуре
При нажатии и отпускании клавиши вызываются следующие методы:
 keyPressEvent(self, )
— вызывается при нажатии клавиши на клавиатуре. Если клавишу удерживать нажатой, метод будет вызываться многократно, пока клавишу не отпустят;
 keyReleaseEvent(self, )
— вызывается при отпускании нажатой ранее клавиши.
Через параметр

доступен экземпляр класса
QKeyEvent
, хранящий дополнительную информацию о событии. Он поддерживает следующие полезные для нас методы (полный их список приведен в документации по классу
QKeyEvent на странице https://doc.qt.io/ qt-5/qkeyevent.html):
 key()
— возвращает код нажатой клавиши. Пример определения клавиши: if e.key() == QtCore.Qt.Key_B: print("Нажата клавиша
1   ...   34   35   36   37   38   39   40   41   ...   83


написать администратору сайта