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

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


Скачать 7.92 Mb.
НазваниеНиколай Прохоренок Владимир Дронов
Дата05.05.2023
Размер7.92 Mb.
Формат файлаpdf
Имя файлаПрохоренок_Н_А__Дронов_В_А_Python_3_и_PyQt_5_Разработка_приложен.pdf
ТипДокументы
#1111379
страница40 из 83
1   ...   36   37   38   39   40   41   42   43   ...   83
)
— устанавливает текстовые данные в формате HTML (MIME-тип text/html
): data.setHtml("Перетаскиваемый HTML-текст")
 html()
— возвращает текстовые данные в формате HTML;
 hasHtml()
— возвращает значение
True
, если объект содержит текстовые данные в фор- мате HTML, и
False
— в противном случае;
 setUrls(<Список URI-адресов>)
— устанавливает список URI-адресов (MIME-тип text/uri-list
). В качестве значения указывается список с экземплярами класса
QUrl
С помощью этого MIME-типа можно обработать перетаскивание файлов: data.setUrls([QtCore.QUrl("https://www.google.ru/")])
 urls()
— возвращает список URI-адресов: uri = e.mimeData().urls()[0].toString()
 hasUrls()
— возвращает значение
True
, если объект содержит список URI-адресов, и
False
— в противном случае;
 setImageData(<Объект изображения>)
— устанавливает изображение (MIME-тип application/x-qt-image
). В качестве значения можно указать, например, экземпляр класса
QImage или
QPixmap
: data.setImageData(QtGui.QImage("pixmap.png")) data.setImageData(QtGui.QPixmap("pixmap.png"))
 imageData()
— возвращает объект изображения (тип возвращаемого объекта зависит от типа объекта, указанного в методе setImageData()
);
 hasImage()
— возвращает значение
True
, если объект содержит изображение, и
False
— в противном случае;
 setData(, <Данные>)
— позволяет установить данные произвольного MIME- типа. В первом параметре указывается MIME-тип в виде строки, а во втором парамет- ре — экземпляр класса
QByteArray с данными. Метод можно вызвать несколько раз с различными MIME-типами. Вот пример передачи текстовых данных: data.setData("text/plain",
QtCore.QByteArray(bytes("Данные", "utf-8")))
 data()
— возвращает экземпляр класса
QByteArray с данными, соответст- вующими указанному MIME-типу;
 hasFormat()
— возвращает значение
True
, если объект содержит данные ука- занного MIME-типа, и
False
— в противном случае;
 formats()
— возвращает список с поддерживаемыми объектом MIME-типами;
 removeFormat()
— удаляет данные, соответствующие указанному MIME-типу;
 clear()
— удаляет все данные.
Если необходимо перетаскивать данные какого-либо специфического типа, нужно наследо- вать класс
QMimeData и переопределить в нем методы retrieveData()
и formats()
. За под- робной информацией по этому вопросу обращайтесь к документации.

Глава 19. Обработка сигналов и событий
429 19.10.3. Обработка сброса
Прежде чем обрабатывать перетаскивание и сбрасывание объекта, необходимо сообщить системе, что компонент может обрабатывать эти события. Для этого внутри конструктора компонента следует вызвать метод setAcceptDrops()
, унаследованный от класса
QWidget
, и передать этому методу
True
: self.setAcceptDrops(True)
Обработка перетаскивания и сброса объекта выполняется следующим образом:
1.
Внутри метода dragEnterEvent()
компонента проверяется MIME-тип перетаскиваемых данных и действие. Если компонент способен обработать сброс этих данных и соглаша- ется с предложенным действием, необходимо вызвать метод acceptProposedAction()
объекта события. Если нужно изменить действие, методу setDropAction()
объекта собы- тия передается новое действие, а затем у того же объекта вызывается метод accept()
вместо acceptProposedAction()
2.
Если необходимо ограничить область сброса некоторым участком компонента, следует дополнительно определить в нем метод dragMoveEvent()
. Этот метод будет постоянно вызываться при перетаскивании внутри области компонента. При достижении указате- лем мыши нужного участка компонента следует вызвать метод accept()
и передать ему экземпляр класса
QRect с координатами и размером этого участка. В этом случае при перетаскивании внутри участка метод dragMoveEvent()
повторно вызываться не будет.
3.
Внутри метода dropEvent()
компонента производится обработка сброса.
Обработать события, возникающие в процессе перетаскивания и сбрасывания, позволяют следующие методы класса
QWidget
:
 dragEnterEvent(self, )
— вызывается, когда перетаскиваемый объект входит в область компонента. Через параметр

доступен экземпляр класса
QDragEnterEvent
;
 dragLeaveEvent(self, )
— вызывается, когда перетаскиваемый объект покидает область компонента. Через параметр

доступен экземпляр класса
QDragLeaveEvent
;
 dragMoveEvent(self, )
— вызывается при перетаскивании объекта внутри об- ласти компонента. Через параметр

доступен экземпляр класса
QDragMoveEvent
;
 dropEvent(self, )
— вызывается при сбрасывании объекта в области компонен- та. Через параметр

доступен экземпляр класса
QDropEvent
Класс
QDragLeaveEvent наследует класс
QEvent и не несет никакой дополнительной инфор- мации. Достаточно просто знать, что перетаскиваемый объект покинул область компонента.
Цепочка наследования остальных классов выглядит так:
QEvent — QDropEvent — QDragMoveEvent — QDragEnterEvent
Класс
QDragEnterEvent не содержит собственных методов, но наследует все методы классов
QDropEvent и
QDragMoveEvent
Класс
QDropEvent поддерживает следующие методы:
 mimeData()
— возвращает экземпляр класса
QMimeData с перемещаемыми данными и ин- формацией о MIME-типе;
 pos()
— возвращает экземпляр класса
QPoint с целочисленными координатами сбрасы- вания объекта;

430
Часть II. Библиотека PyQt 5
 posF()
— возвращает экземпляр класса
QPointF
с вещественными координатами сбрасы- вания объекта;
 possibleActions()
— возвращает комбинацию возможных действий при сбрасывании.
Вот пример определения значений: if e.possibleActions() & QtCore.Qt.MoveAction: print("MoveAction") if e.possibleActions() & QtCore.Qt.CopyAction: print("CopyAction")
 proposedAction()
— возвращает действие по умолчанию при сбрасывании;
 acceptProposedAction()
— сообщает о готовности принять переносимые данные и согласии с действием, возвращаемым методом proposedAction()
. Метод acceptProposedAction()
(или метод accept()
, поддерживаемый классом
QDragMoveEvent
) необходимо вызвать внутри метода dragEnterEvent()
, иначе метод dropEvent()
вызван не будет;
 setDropAction(<Действие>)
— позволяет указать другое действие при сбрасывании. По- сле изменения действия следует вызвать метод accept()
, а не acceptProposedAction()
;
 dropAction()
— возвращает действие, которое должно быть выполнено при сбрасыва- нии. Оно может не совпадать со значением, возвращаемым методом proposedAction()
, если действие было изменено с помощью метода setDropAction()
;
 keyboardModifiers()
позволяет определить, какие клавиши-модификаторы (,
, и др.) были нажаты вместе с кнопкой мыши. Возможные значения мы уже рассматривали в разд. 19.8.3;
 mouseButtons()
— позволяет определить кнопки мыши, которые были нажаты в процес- се переноса данных;
 source()
— возвращает ссылку на компонент внутри приложения, являющийся источ- ником события, или значение
None
, если данные переносятся из другого приложения.
Теперь рассмотрим методы класса
QDragMoveEvent
:
 accept([])
— сообщает о согласии с дальнейшей обработкой события. В качест- ве параметра можно указать экземпляр класса
QRect с координатами и размерами прямо- угольной области, в которой будет доступно сбрасывание;
 ignore([])
— отменяет операцию переноса данных. В качестве параметра можно указать экземпляр класса
QRect с координатами и размерами прямоугольной области, в которой сбрасывание запрещено;
 answerRect()
— возвращает экземпляр класса
QRect с координатами и размерами прямо- угольной области, в которой произойдет сбрасывание, если событие будет принято.
Некоторые компоненты в PyQt уже поддерживают технологию drag & drop — так, в одно- строчное текстовое поле можно перетащить текст из другого приложения. Поэтому, прежде чем изобретать свой «велосипед», убедитесь, что поддержка технологии в компоненте не реализована.
19.11. Работа с буфером обмена
Помимо технологии drag & drop, для обмена данными между приложениями используется буфер обмена — одно приложение помещает данные в буфер обмена, а второе приложение

Глава 19. Обработка сигналов и событий
431
(или то же самое) может их извлечь. Получить ссылку на глобальный объект буфера обмена позволяет статический метод clipboard()
класса
QApplication
: clipboard = QtWidgets.QApplication.clipboard()
Класс
QClipboard поддерживает следующие методы:
 setText(<Текст>)
— заносит текст в буфер обмена: clipboard.setText("Текст")
 text()
— возвращает из буфера обмена текст или пустую строку;
 text(<Тип>)
— возвращает кортеж из двух строк: первая хранит текст из буфера обмена, вторая — название типа. В параметре
<Тип>
могут быть указаны значения "plain"
(про- стой текст),
"html"
(HTML-код) или пустая строка (любой тип);
 setImage()
— заносит в буфер обмена изображение, представленное экземпля- ром класса
QImage
: clipboard.setImage(QtGui.QImage("image.jpg"))
 image()
— возвращает из буфера обмена изображение, представленное экземпляром класса
QImage
, или пустой экземпляр этого класса;
 setPixmap()
— заносит в буфер обмена изображение, представленное экземп- ляром класса
QPixmap
: clipboard.setPixmap(QtGui.QPixmap("image.jpg"))
 pixmap()
— возвращает из буфера обмена изображение, представленное экземпляром класса
QPixmap
, или пустой экземпляр этого класса;
 setMimeData()
— позволяет сохранить в буфере данные любого типа, пред- ставленные экземпляром класса
QMimeData
(см. разд. 19.10.2);
 mimeData([<Режим>])
— возвращает данные, представленные экземпляром класса
QMimeData
;
 clear()
— очищает буфер обмена.
Отследить изменение состояния буфера обмена позволяет сигнал dataChanged
. Назначить обработчик этого сигнала можно так:
QtWidgets.qApp.clipboard().dataChanged.connect(on_change_clipboard)
19.12. Фильтрация событий
События можно перехватывать еще до того, как они будут переданы компоненту. Для этого необходимо создать класс, который является наследником класса
QObject
, и переопределить в нем метод eventFilter(self, <Объект>, )
. Через параметр
<Объект>
доступна ссылка на компонент, а через параметр

— на объект с дополнительной информаци- ей о событии. Этот объект различен для разных типов событий — так, для события
MouseButtonPress объект будет экземпляром класса
QMouseEvent
, а для события
KeyPress
— экземпляром класса
QKeyEvent
. Из метода eventFilter()
следует вернуть значение
True
, если событие не должно быть передано дальше, и
False
— в противном случае. Вот пример такого класса-фильтра, перехватывающего нажатие клавиши : class MyFilter(QtCore.QObject): def __init__(self, parent=None):
QtCore.QObject.__init__(self, parent)

432
Часть II. Библиотека PyQt 5 def eventFilter(self, obj, e): if e.type() == QtCore.QEvent.KeyPress: if e.key() == QtCore.Qt.Key_B: print("Событие от клавиши не дойдет до компонента") return True return QtCore.QObject.eventFilter(self, obj, e)
Далее следует создать экземпляр этого класса, передав в конструктор ссылку на компонент, а затем вызвать у того же компонента метод installEventFilter()
, передав в качестве единственного параметра ссылку на объект фильтра. Вот пример установки фильтра для надписи: self.label.installEventFilter(MyFilter(self.label))
Метод installEventFilter()
можно вызвать несколько раз, передавая ссылку на разные объекты фильтров. В этом случае первым будет вызван фильтр, который был добавлен по- следним. Кроме того, один фильтр можно установить сразу в нескольких компонентах.
Ссылка на компонент, который является источником события, доступна через второй пара- метр метода eventFilter()
Удалить фильтр позволяет метод removeEventFilter(<Фильтр>)
, вызываемый у компонента, для которого был назначен этот фильтр. Если таковой не был установлен, при вызове мето- да ничего не произойдет.
19.13. Искусственные события
Для создания искусственных событий применяются следующие статические методы из класса
QCoreApplication
:
 sendEvent(, )
— немедленно посылает событие компоненту и воз- вращает результат выполнения обработчика;
 postEvent(, [, priority=NormalEventPriority])
— добавляет собы- тие в очередь. Параметром priority можно передать приоритет события, использовав один из следующих атрибутов класса
QtCore.Qt
:
HighEventPriority
(
1
, высокий прио- ритет),
NormalEventPriority
(
0
, обычный приоритет — значение по умолчанию) и
LowEventPriority
(
-1
, низкий приоритет). Этот метод является потокобезопасным, сле- довательно, его можно использовать в многопоточных приложениях для обмена собы- тиями между потоками.
В параметре

указывается ссылка на объект, которому посылается событие, а в параметре

— объект события. Последний может быть экземпляром как стандарт- ного (например,
QMouseEvent
), так и пользовательского класса, являющегося наследником класса
QEvent
. Вот пример отправки события
QEvent.MouseButtonPress компоненту label
: e = QtGui.QMouseEvent(QtCore.QEvent.MouseButtonPress,
QtCore.QPointF(5, 5), QtCore.Qt.LeftButton,
QtCore.Qt.LeftButton, QtCore.Qt.NoModifier)
QtCore.QCoreApplication.sendEvent(self.label, e)
Для отправки пользовательского события необходимо создать класс, наследующий
QEvent
В этом классе следует зарегистрировать пользовательское событие с помощью статического метода registerEventType()
и сохранить идентификатор события в атрибуте класса:

Глава 19. Обработка сигналов и событий
433 class MyEvent(QtCore.QEvent): idType = QtCore.QEvent.registerEventType() def __init__(self, data):
QtCore.QEvent.__init__(self, MyEvent.idType) self.data = data def get_data(self): return self.data
Вот пример отправки события класса
MyEvent компоненту label
:
QtCore.QCoreApplication.sendEvent(self.label, MyEvent("512"))
Обработать пользовательское событие можно с помощью методов event(self, )
или customEvent(self, )
: def customEvent(self, e): if e.type() == MyEvent.idType: self.setText("Получены данные: {0}".format(e.get_data()))

ГЛ А В А
20
Размещение компонентов в окнах
При размещении в окне нескольких компонентов возникает вопрос их взаимного располо- жения и минимальных размеров. Следует помнить, что по умолчанию размеры окна можно изменять, а значит, необходимо перехватывать событие изменения размеров и производить перерасчет позиции и размера каждого компонента. Библиотека PyQt избавляет нас от лиш- них проблем и предоставляет множество компонентов-контейнеров, которые производят такой перерасчет автоматически. Все, что от нас требуется, это выбрать нужный контейнер, добавить в него компоненты в определенном порядке, а затем поместить контейнер в окно или в другой контейнер.
20.1. Абсолютное позиционирование
Прежде чем изучать контейнеры, рассмотрим возможность абсолютного позиционирования компонентов в окне. Итак, если при создании компонента указана ссылка на родительский компонент, то он выводится в позицию с координатами
(0, 0)
. Иными словами, если мы добавим несколько компонентов, то все они отобразятся в одной и той же позиции, нало- жившись друг на друга. Последний добавленный компонент окажется на вершине этой кучи, а остальные компоненты станут видны лишь частично или вообще не видны. Размеры добавляемых компонентов будут соответствовать их содержимому.
Для перемещения компонента можно воспользоваться методом move()
, а для изменения размеров — методом resize()
. Выполнить одновременное изменение позиции и размеров позволяет метод setGeometry()
. Все эти методы, а также множество других, позволяющих изменять позицию и размеры, мы уже рассматривали в разд. 18.3 и 18.4. Если компонент не имеет родителя, эти методы изменяют характеристики окна, а если родительский компо- нент был указан, они изменяют характеристики только самого компонента.
Для примера выведем внутри окна надпись и кнопку, указав позицию и размеры для каждо- го компонента (листинг 20.1).
Листинг 20.1. Абсолютное позиционирование
# -*- coding: utf-8 -*- from PyQt5 import QtWidgets import sys app = QtWidgets.QApplication(sys.argv) window = QtWidgets.QWidget() window.setWindowTitle("Абсолютное позиционирование")

Глава 20. Размещение компонентов в окнах
435 window.resize(300, 120) label = QtWidgets.QLabel("Текст надписи", window) button = QtWidgets.QPushButton("Текст на кнопке", window) label.setGeometry(10, 10, 280, 60) button.resize(280, 30) button.move(10, 80) window.show() sys.exit(app.exec_())
Абсолютное позиционирование имеет следующие недостатки:
 при изменении размеров окна необходимо самостоятельно пересчитывать и изменять характеристики всех компонентов в программном коде;
 при указании фиксированных размеров надписи на компонентах могут выходить за их пределы. Помните, что в разных операционных системах используются разные стили оформления, в том числе и характеристики шрифта. Подогнав размеры в одной опера- ционной системе, можно прийти в ужас при виде приложения в другой операционной системе, где размер шрифта в два раза больше. Поэтому лучше вообще отказаться от указания фиксированных размеров или задавать размер и название шрифта для каждого компонента явно. Кроме того, приложение может поддерживать несколько языков ин- терфейса, а поскольку длина слов в разных языках различается, это также станет причи- ной искажения компонентов.
1   ...   36   37   38   39   40   41   42   43   ...   83


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