В данном примере рассмотрена реализация перемещаемых виджетов через установку фильтра событий.

Для успешной сборки проекта необходимо добавить в подключения следующие классы:

# Core
QEvent
QPoint

# Gui
QMouseEvent

# PlastiQ
PQEventFilter

Основной алгоритм работы фильтра выглядит так:

  1. Отслеживаем нажатие кнопки мыши при помощи события QEvent:: MouseButtonPress.
  2. При нажатии - запоминаем координаты клика на виджете.
  3. Далее отслеживаем движение мыши событием QEvent::MouseMove и передвигаем переносимый виджет на новые координаты.
  4. При отпускании кнопки мыши, то есть наступлении события 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();
comments powered by HyperComments