2014-02-07 18 views
1

我有一個簡單的3D渲染框架內的小部件與update()方法負責渲染每一幀。目前我使用的是QTimer觸發更新每秒60次,這似乎是確定的工作:非空閒替代QTimer的定期調用功能

void RenderingWidget::init() 
{ 
    // ... 

    QTimer* timer = new QTimer(this); 
    connect(timer, SIGNAL(timeout()), this, SLOT(update())); 
    timer->start(16); 
} 

這種解決方案的問題是,有可能是16個之間的空閒時間ms不管它們渲染的速度有多快。在本地Windows應用程序中,如果沒有其他事件需要處理,我可以實現自己的消息循環並持續渲染幀。 Qt中可以做類似的事情嗎?

這裏的東西我想過,也出現好的工作,但是我讀過,它可能是一個不好的做法(即使用QApplication::processEvents()):

void RenderingWidget::run() 
{ 
    running = true; 

    while(running) 
    { 
     update(); 
     QApplication::processEvents(); 
    } 
} 
+1

我想'的QApplication :: processEvents'你的情況確定。你也可以在widget的paintEvent函數中實現渲染,並使用repaint()立即調用它。您可以使用'QElapsedTimer'手動限制幀速率。 –

回答

1

我終於想通了!雖然沒有直接訪問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); 
     } 
    } 
};