BlackBerry’s Cascades framework allows developers to add a lot of functionality in QML that would otherwise have to be created in C++. The platform is missing one important component however: a timer! Timers are especially useful when you need to create a workaround in your QML to make life easier. Need to defer a view calculation for just a moment later? Want to wait for layout changes in your app to finish, but aren’t exposed to the necessary signals? Right now, there’re only two options:
- Import the
QTimerclass. Unfortunately, this will break Momentics’ QML previewer. - Call a C++ function, which waits for a
QTimer, and then triggers a QML callback that you created. What a pain!
I’ve constructed a simple workaround made entirely from QML that won’t break the Momentics previewer, but is still easy to maintain and extend.
The trick is simple:
- Piggy back off of the built-in animations framework to provide the needed timing functionality. Use an animation to change the opacity of a control that is not visible to the user.
- Allow the timer owner to set the duration and start the animation countdown without needing to know anything about how time is kept.
- Expose a signal that will be emitted when the animation is finished.
I’ve created a sample app on GitHub demonstrating the whole thing working together. The meat of the code is also included below. I hope this will help you keep more of your UI code in QML where it belongs.
// QmlTimer.qml
import bb.cascades 1.0
Container { id: root
opacity: 0.0
property int duration: 0
property bool timerActive: false
signal triggered
function startTimer() {
if (duration == 0) {
console.log("timer can't start when duration is 0");
return;
}
if (timerActive == true) {
console.log("timer is already active, not starting");
return;
}
opacity = 0;
timerActive = true;
timerAnimation.play();
}
function stopTimer() {
timerActive = false;
timerAnimation.stop();
}
animations: [
FadeTransition { id: timerAnimation
fromOpacity: 0
toOpacity: 1
duration: root.duration
}
]
onOpacityChanged: {
if (timerActive == true && opacity == 1) {
timerActive = false;
root.triggered();
}
}
}