QTimer 的非空闲替代项,用于定期调用函数

Non-idle alternative to QTimer for periodically called function

本文关键字:用于 函数 调用 QTimer      更新时间:2023-10-16

我在一个小部件中有一个简单的 3D 渲染框架,其中包含负责渲染每一帧的update()方法。目前,我正在使用QTimer每秒触发更新60次,这似乎工作正常:

void RenderingWidget::init()
{
    // ...
    QTimer* timer = new QTimer(this);
    connect(timer, SIGNAL(timeout()), this, SLOT(update()));
    timer->start(16);
}

此解决方案的问题在于,无论渲染速度如何,帧之间都可能有 16 毫秒的空闲时间。在本机 Windows 应用程序中,如果没有其他事件要处理,我可以实现自己的消息循环并连续呈现帧。我可以在Qt中做类似的事情吗?

这是我考虑过的事情,它似乎也可以正常工作,但是我读到这可能是一个不好的做法(即使用QApplication::processEvents()):

void RenderingWidget::run()
{
    running = true;
   while(running)
   {
        update();
        QApplication::processEvents();
    }
}

我终于想通了!虽然Qt中没有直接访问消息循环,但有一个QObject::event()方法,其作用类似于Windows API中的WndProc()

实现

问题中提到的一种方法是重新实现此方法,方法是对QWidgetQApplication进行子类化,然后通过调用 update() 方法处理QEvent::UpdateRequest事件,或者在任何其他情况下,将事件传递给默认处理程序将处理它的基类(类似于 win API 中的默认窗口过程)。执行更新后,将另一个更新请求添加到队列中,除非中间有其他事件,否则控件将返回到update(),依此类推。

下面是一个示例实现:

class RenderingWidget : public QWidget
{
    Q_OBJECT
public:
    explicit RenderingWidget(QWidget *parent = 0);
    virtual ~RenderingWidget();
public slots:   
    void update() 
    { 
        // do all rendering work
        updateLater();    // queue another update
    }
    void updateLater()
    {
        if (!m_updatePending)
        {
            m_updatePending = true;
            QCoreApplication::postEvent(this, new QEvent(QEvent::UpdateRequest);
        }
    }
protected:        
    bool m_updatePending;    
    bool event(QEvent* event)
    { 
        if (event == QEvent::UpdateRequest)
        {
            m_updagePending = false;
            update();
            return true;
        }
        else
        {
            return QWidget::event(event);
        }
    }
};