Qt Event监控

最近项目需要对Qt事件耗时进行统计分析,并进行过滤,基于此设计一个事件监控器来进行事件分析。

基本原理

1、Qt事件由QAppliction::exec()进入循环,当发生键盘、鼠标、Tab等事件时,QAppliction会通过QAppliction::notify(QObject * obj, QEvent * event)函数分发到界面中,界面再分发到子类中,最后由某一类完成事件处理后,从当前类的QObject::event(QEvent *event)中像父类进行返回,最后完成一次事件循环。
2、Qt事件循环是在主线程中执行的,不存在多线程,若事件成功返回,必定上一次分发的事件相邻,可以通过记录之间的时间戳来计算事件耗时情况。
3、Qt支持重写QAppliction::notify(QObject * obj, QEvent * event)事件和QObject::event(QEvent *event)

代码

QAppliction中重新实现notify()

bool Myapplication::notify(QObject *obj, QEvent *event)
{
    EventMonitor::instance()->start(obj,event->type());
    return QApplication::notify(obj,event);
}

重新实现界面类中的event(),并添加几个事件做延时进行测试

bool MainWindow::event(QEvent *event){
    bool result = QApplication::event(event);
    EventMonitor::instance()->end(this,event->type());
    return result;
}

void MainWindow::resizeEvent(QResizeEvent *event)
{
    QThread::msleep(500);
    MainWindow::resizeEvent(event);
}

void MainWindow::paintEvent(QPaintEvent *event)
{
    QThread::msleep(300);
    MainWindow::paintEvent(event);
}

void MainWindow::contextMenuEvent(QContextMenuEvent *event)
{
    QThread::msleep(200);
    MainWindow::contextMenuEvent(event);
}

主函数中添加监控事件列表

int main(int argc, char *argv[])
{
    Myapplication a(argc, argv);
    MainWindow w;

    w.show();

    EventMonitor::instance()->addMonitorEventType({ QEvent::Paint ,QEvent::Close /*,QEvent::Resize*/,QEvent::ContextMenu });
    EventMonitor::instance()->setThreshold(250);

    qDebug()  << EventMonitor::instance()->MonitorEventType()
    		  << EventMonitor::instance()->threshold();

    return a.exec();
}

** eventMonitor.h **

class EventMonitor
{
public:
    static EventMonitor* instance(){
        static EventMonitor monitor;
        return &monitor;
    }
    ~EventMonitor();

    void start(QObject *obj,int type);
    void end(QObject *obj,int type);

    //!
    //! \brief 监控的时间阈值
    //! \param us
    //!
    void setThreshold(qreal us);
    qreal threshold() const;

    //!
    //! \brief 监控的事件列表
    //!
    typedef QSet<QEvent::Type> EventTypeSet;
    void addMonitorEventType(QEvent::Type type);
    void addMonitorEventType(EventTypeSet set);
    void addAllMonitorEventType();
    void removeMonitorEventType(QEvent::Type type);
    void removeMonitorEventType(EventTypeSet set);
    void removeAllMonitorEventType();
    EventTypeSet MonitorEventType() const;

private:
    explicit EventMonitor();
    void init();
    void trace();

    timeval m_start,m_end;
    qreal m_threshold;
    EventTypeSet m_set;

    struct EventInfo{
        Qt::HANDLE thread_id;
        QEvent::Type type;
        QString func_name;
        QString obj_name;
        qreal elapsed;
    }info;
    friend inline QDebug operator<<(QDebug debug, const EventInfo &info)
    {
        debug <<info.type
              << " obj[" +info.obj_name + "]"
              << " func[" +info.func_name + "]"
              << QString::number(info.elapsed) + "ms";
        return debug;
    }
};

** eventMonitor.cpp **

EventMonitor::~EventMonitor()
{

}

void EventMonitor::start(QObject *obj, int type)
{
    gettimeofday(&m_start,NULL);
    info.thread_id = QThread::currentThreadId();
    info.type = (QEvent::Type)type;
    info.obj_name = obj->objectName();
    info.func_name = QString::fromUtf8(typeid (*obj).name());
    info.elapsed = 0;

}

void EventMonitor::end(QObject *obj, int type)
{
    gettimeofday(&m_end,NULL);
    if(info.thread_id == QThread::currentThreadId()
            && info.type == (QEvent::Type)type
            && strcmp(typeid (*obj).name(),info.func_name.toStdString().data()) ==0 ){
        QStringList tmp =QString::fromUtf8(typeid (*obj).name()).split(QRegExp("[0-9]+"));
        QString func_name;
        for(int i =0; i < tmp.size() -1;i++){
            if(!tmp.at(i).isEmpty())
                func_name += tmp.at(i) +"::";
        }
        info.func_name = func_name + tmp.last();
        info.elapsed = ((m_end.tv_sec-m_start.tv_sec)*1000000+(m_end.tv_usec-m_start.tv_usec)) /1000;
        if(info.elapsed >= m_threshold){
            trace();
        }
        

    }

}

void EventMonitor::setThreshold(qreal us)
{
    m_threshold = us;
}

qreal EventMonitor::threshold() const
{
    return m_threshold;
}

void EventMonitor::addMonitorEventType(QEvent::Type type)
{
    EventTypeSet set;
    set.insert(type);
    addMonitorEventType(set);
}

void EventMonitor::addMonitorEventType(EventMonitor::EventTypeSet set)
{
    m_set += set;
}

void EventMonitor::addAllMonitorEventType()
{
    EventTypeSet set;
    for(int i =0; i <(int)QEvent::MaxUser;i++){
        if(const char *value = QMetaEnum::fromType<QEvent::Type>().valueToKey(i)){
             set.insert((QEvent::Type)QMetaEnum::fromType<QEvent::Type>().keyToValue(value));
        }
    }
    addMonitorEventType(set);
}

void EventMonitor::removeMonitorEventType(QEvent::Type type)
{
    EventTypeSet set;
    set.insert(type);
    removeMonitorEventType(set);
}

void EventMonitor::removeMonitorEventType(EventMonitor::EventTypeSet set)
{
    m_set -= set;
}

void EventMonitor::removeAllMonitorEventType()
{
    EventTypeSet set;
    for(int i =0; i <(int)QEvent::MaxUser;i++){
        if(const char *value = QMetaEnum::fromType<QEvent::Type>().valueToKey(i)){
             set.insert((QEvent::Type)QMetaEnum::fromType<QEvent::Type>().keyToValue(value));
        }
    }
    removeMonitorEventType(set);
}


EventMonitor::EventTypeSet EventMonitor::MonitorEventType() const
{
    return m_set;
}


EventMonitor::EventMonitor()
{
    init();
}

void EventMonitor::init()
{
    m_threshold =10.0;
}

void EventMonitor::trace()
{
    if(m_set.contains(info.type)){
        qDebug() << info;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值