Search code examples
qmlfilteringsignals-slots

How to debounce a signal in QML?


I have a few properties that have change handlers that request a repaint of a canvas. This works fairly well, but I would like to debounce the signal because a user can only see a limited number of refreshes and some of the data items can change quite frequently. This causes far more refreshes than the user can see and reduces how responsive the UI is.

I have looked at debouncing the signal in javascript (there are examples on the web for how to do that) and tie it in to QML, but I haven't figured out how to get QML and javascript to work together in that way yet.

I would love to see something like the following:

function rateLimitedRefresh(){
    // magic to limit to 30 frames per second
    canvas.requestPaint()
}

onValueChanged: {
    rateLimitedRefresh();
}

With the requestPaint method only being called on the canvas a maximum of 30 times per second.

I used a modification of Mertanian's answer. This modification enforces the frame rate limit at a per frame level as opposed to a per second level.

property var limitStartTime: new Date()

function rateLimitedRefresh(){
    // magic to limit to 30 frames per second
    var now = new Date();

    if (now - limitStartTime >= 32) {
        limitStartTime = now
        canvas.requestPaint()
    }
}

Solution

  • How about something like this:

    property var limitStartTime: new Date()
    property int refreshesThisSecond: 0
    
    function rateLimitedRefresh(){ 
        // magic to limit to 30 frames per second
        if ((new Date()) - limitStartTime >= 33) {
            limitStartTime = new Date(limitStartTime.getTime() + 33)
            canvas.requestPaint() 
        }
    }
    
    onValueChanged: { 
        rateLimitedRefresh(); 
    }