简体   繁体   English

如何检测 Qt 中的用户不活动?

[英]How to detect user inactivity in Qt?

How can I detect user inactivity in a Qt QMainWindow?如何检测 Qt QMainWindow 中的用户不活动? My idea so far is to have a QTimer that increments a counter, which, if a certain value is passed, locks the application.到目前为止,我的想法是拥有一个递增计数器的 QTimer,如果传递了某个值,它将锁定应用程序。 Any mouse or key interaction should set the timer back to 0. However I need to know how to properly handle input events which reset;任何鼠标或键交互都应将计时器设置回 0。但是我需要知道如何正确处理重置的输入事件; I can re-implement:我可以重新实现:

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)

...but won't the event handlers of all the widgets in the QMainWindow prevent events occurring in those controls from reaching the QMainWindow's? ...但是 QMainWindow 中所有小部件的事件处理程序不会阻止这些控件中发生的事件到达 QMainWindow 吗? Is there a better architecture for detecting user activity as it is?是否有更好的架构来检测用户活动?

You could use a custom event filter to process all keyboard and mouse events received by your application before they are passed on to the child widgets. 您可以使用自定义事件过滤器来处理应用程序在将其传递给子窗口小部件之前接收的所有键盘和鼠标事件。

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);
  }
}

Then use something like 然后用类似的东西

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

This definitely works (I've tried it myself). 这肯定有效(我自己尝试过)。

EDIT: And many thanks to ereOn for pointing out that my earlier solution was not very useful. 编辑:非常感谢ereOn指出我早期的解决方案不是很有用。

One of better approach will be to catch xidle signal rather then catching so many events from user. 更好的方法之一是捕获xidle信号,而不是从用户捕获这么多事件。 Here one need to capture QEvent:MouseMove event also 这里需要捕获QEvent:MouseMove事件

The cleanest way is to override the eventFilter function of your main window widget and set it as event filter on your application object.最干净的方法是覆盖主 window 小部件的eventFilter function 并将其设置为应用程序 object 上的事件过滤器。

Inside the filter you can use dynamic_cast to check if the event is a QInputEvent .在过滤器中,您可以使用dynamic_cast检查事件是否为QInputEvent All events with user interaction are derived from QInputEvent and are recognized this way.所有与用户交互的事件都派生自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);
    }
};

You can replace the base class QWidget with any class derived from QWidget .您可以将基础 class QWidget替换为派生自QWidget的任何 class 。 (Including QMainWindow .) Note that the event function must pass the event to the base class, and return its return value. (包括QMainWindow 。)请注意, event function 必须将事件传递给基础 class,并返回其返回值。

If you have more then one window, you might also want to check, that the event target object is your window or one of its QWidget children.如果您有多个 window,您可能还想检查事件目标 object 是您的 window 或其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);
    }
};

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM