В данном примере рассмотрена реализация перемещаемых виджетов через установку фильтра событий.
Для успешной сборки проекта необходимо добавить в подключения следующие классы:
# Core
QEvent
QPoint
# Gui
QMouseEvent
# PlastiQ
PQEventFilter
Основной алгоритм работы фильтра выглядит так:
- Отслеживаем нажатие кнопки мыши при помощи события
QEvent:: MouseButtonPress
. - При нажатии - запоминаем координаты клика на виджете.
- Далее отслеживаем движение мыши событием
QEvent::MouseMove
и передвигаем переносимый виджет на новые координаты. - При отпускании кнопки мыши, то есть наступлении события
QEvent::MouseButtonRelease
- прерываем передачу события, если объект действительно был перемещён. Это нужно для того, чтобы предотвратить генерацию сигналаonClicked()
, который возникает после последовательного нажатия и отпускания кнопки мыши.
MyEventFilter.php
/**
* MyEventFilter
*
* Класс для фильтрации событий
*
* @author WxMaper
* @version 1.0
*/
class MyEventFilter extends PQEventFilter {
private $offset = [0,0];
private $moved = false;
public function __construct($parent = null) {
parent::__construct($parent);
}
public function eventFilter($sender, $event) {
switch($event->type()) {
case QEvent::MouseButtonPress:
// Запоминаем позицию клика на объекте.
$this->offset = [ $event->x(), $event->y() ];
break;
case QEvent::MouseMove:
// Смещаем координаты относительно позиции клика.
$mousePoint = new QPoint($event->x() - $this->offset[0],
$event->y() - $this->offset[1]);
// Переводим текущие координаты курсора в координаты
// перемещаемого объекта для родительского виджета.
$position = $sender->mapToParent($mousePoint);
$sender->move($position);
// Запоминаем, что объект был перемещён.
$this->moved = true;
break;
case QEvent::MouseButtonRelease:
// Небольшая хитрушка для прерывания генерации события клика (нужно только для кнопок):
// если объект был сдвинут, то наверняка событие onClicked() не должно сработать.
// Как известно, клик - это нажатие и отжатие, поэтому прервав передачу одного из этих событий,
// объект не сгенерирует событие onClicked().
if($this->moved) {
$this->moved = false;
// прырваем передачу события MouseButtonRelease
return true;
}
}
}
}
Работать с фильтрами событий очень удобно и самое главное - легко.
С помощью метода addEventType()
нужно добавить типы событий на которые должен срабатывать фильтр.
Так же нужно не забывать, что разные события имеют разные типы с разным набором свойств. Поэтому, если
есть необходимость работать с каким либо свойством события, нужно добавить в список
подключений (Includes) тип этого события. Если этого не сделать, то события будут передаваться с
базовым типом QEvent
, который не имеет никаких дополнительных свойств, харектеризующих событие.
В данном примере используются события QEvent::MouseButtonPress
, QEvent::MouseButtonRelease
и
QEvent::MouseMove
- все они имеют тип QMouseEvent
. Другие события, например, QEvent::KeyPress
и
QEvent::KeyRelease
передаются с типом QKeyEvent
. Узнать в подробностях о том к какому типу относится то
или иное событие, а так же увидеть список всех существующих событий можно в документации Qt:
QEvent::Type
Допускается использование одного экземпляра фильтра для нескольких объектов разного типа.
main.php
require_once("MyEventFilter.php");
$app = new QApplication($argc, $argv);
/**
* MainWindow
*
* Окно программы, пример использования класса MyEventFilter
*
*/
class MainWindow extends QWidget {
public function __construct() {
parent::__construct();
$this->initComponents();
}
private function initComponents() {
// Создаём фильтр и устанавливаем типы фильтруемых событий.
$eventFilter = new MyEventFilter($this);
$eventFilter->addEventType(QEvent::MouseButtonPress);
$eventFilter->addEventType(QEvent::MouseMove);
$eventFilter->addEventType(QEvent::MouseButtonRelease);
// Создаём любой виджет, который хотим двигать и устанавливаем ему фильтр.
// В данном случае это будет кнопка QPushButton.
$button = new QPushButton("Двигай меня полностью!", $this);
$button->installEventFilter($eventFilter);
$label = new QLabel("Двигай меня полностью!", $this);
$label->installEventFilter($eventFilter);
// Тест события клика.
$button->onClicked = function() {
QMessageBox::warning(null, "Click!", "Сработал клик!");
};
}
}
$mainWindow = new MainWindow;
$mainWindow->resize(600,400);
$mainWindow->show();
return $app->exec();