Как обнаружить неактивность пользователя в Qt?

Как я могу обнаружить неактивность пользователя в Qt QMainWindow? Моя идея до сих пор состоит в том, чтобы иметь QTimer, который увеличивает счетчик, который, если передается определенное значение, блокирует приложение. Любое взаимодействие с мышью или клавишей должно установить таймер обратно на 0. Однако мне нужно знать, как правильно обрабатывать события ввода, которые сбрасываются; Я могу повторно реализовать:

virtual void keyPressEvent(QKeyEvent *event)
virtual void keyReleaseEvent(QKeyEvent *event)
virtual void mouseDoubleClickEvent(QMouseEvent *event)
virtual void mouseMoveEvent(QMouseEvent *event)
virtual void mousePressEvent(QMouseEvent *event)
virtual void mouseReleaseEvent(QMouseEvent *event)

... но не будут ли обработчики событий всех виджетов в QMainWindow предотвращать события, происходящие в этих элементах управления, до достижения QMainWindow? Есть ли лучшая архитектура для определения активности пользователей?

3 ответа

Решение

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

class MyEventFilter : public QObject
{
  Q_OBJECT
protected:
  bool eventFilter(QObject *obj, QEvent *ev)
  {
    if(ev->type() == QEvent::KeyPress || 
       ev->type() == QEvent::MouseMove)
         // now reset your timer, for example
         resetMyTimer();

    return QObject::eventFilter(obj, ev);
  }
}

Тогда используйте что-то вроде

MyApplication app(argc, argv);
MyEventFilter filter;
app.installEventFilter(&filter);
app.exec();

Это определенно работает (я попробовал это сам).

РЕДАКТИРОВАТЬ: И большое спасибо ereOn за указание, что мое предыдущее решение было не очень полезным.

Один из лучших подходов - поймать сигнал xidle, а не поймать столько событий от пользователя. Здесь нужно также захватить событие QEvent:MouseMove

Самый чистый способ - переопределитьeventFilterфункцию вашего виджета главного окна и установите ее как фильтр событий для вашего объекта приложения.

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

      class MainWindow: public QWidget {
public:
    MainWindow() {
        QApplication::instance()->installEventFilter(this);
    }

protected:
    bool eventFilter(QObject* target, QEvent* event) override {
        if(dynamic_cast<QInputEvent*>(event)){
            // detected user interaction
        }

        return QWidget::eventFilter(target, event);
    }
};

Вы можете заменить базовый класс любым классом, производным от . (ВключаяQMainWindow.) Обратите внимание, чтоeventфункция должна передать событие базовому классу и вернуть его возвращаемое значение.

Если у вас более одного окна, вы также можете проверить, является ли целевой объект события вашим окном или одним из его окон.QWidgetдети.

      class MainWindow: public QWidget {
public:
    MainWindow() {
        QApplication::instance()->installEventFilter(this);
    }

protected:
    bool eventFilter(QObject* target, QEvent* event) override {
        if(dynamic_cast<QInputEvent*>(event) && (
            target == this ||
            findChildren<QWidget*>().contains(target))
        ){
            // detected user interaction
        }

        return QWidget::eventFilter(target, event);
    }
};
Другие вопросы по тегам