在 QML 中测量经过的时间
Measuring elapsed time in QML
让我们考虑以下示例:我们有一个 Qt Quick Controls Button
。用户在 5 秒内点击它两次。第一次按下 Button
后,这 5 秒 QML Timer
为 运行。我们想要测量两次点击之间经过的时间,精确到毫秒。
不幸的是,QML Timer
无法向我们显示经过的时间。
正如 BlackBerry 论坛上的建议,可以比较日期。不过,这不是很方便,因为第一次点击可能发生在 31 Dec 2015, 23:59:55
上,第二次点击可能发生在 1 Jan 2016, 00:00:05
上,并且检查必须很复杂。
还有更好的选择吗?
不幸的是,QML Timer
没有提供 属性 来检查经过的时间。但是您可以用 C++ 编写自定义 Timer 并将其公开给 QML:
MyTimer.h
#include <QObject>
#include <QElapsedTimer>
class MyTimer : public QObject
{
Q_OBJECT
Q_PROPERTY(int elapsed MEMBER m_elapsed NOTIFY elapsedChanged)
Q_PROPERTY(bool running MEMBER m_running NOTIFY runningChanged)
private:
QElapsedTimer m_timer;
int m_elapsed;
bool m_running;
public slots:
void start() {
this->m_elapsed = 0;
this->m_running = true;
m_timer.start();
emit runningChanged();
}
void stop() {
this->m_elapsed = m_timer.elapsed();
this->m_running = false;
emit elapsedChanged();
emit runningChanged();
}
signals:
void runningChanged();
void elapsedChanged();
};
通过 qmlRegisterType<MyTimer>("MyStuff", 1, 0, "MyTimer")
注册后,它在 QML 中可用:
Window.qml
import QtQuick 2.4
import QtQuick.Controls 1.3
import MyStuff 1.0
ApplicationWindow {
width: 800
height: 600
visible: true
Button {
id: button
anchors.centerIn: parent
text: timer.running ? "stop" : "start"
checkable: true
onClicked: {
if (timer.running) {
timer.stop()
label.text = timer.elapsed + "ms"
} else {
timer.start()
}
}
MyTimer {
id: timer
}
}
Text {
id: label
anchors.left: button.right
anchors.verticalCenter: button.verticalCenter
text: "0ms"
visible: !timer.running
}
}
希望对您有所帮助!
如评论中所述,QML Timer
不适合您的特定需求,因为它与动画计时器同步(更多详细信息 here),因此其分辨率取决于动画计时器还有。
@qCring 解决方案肯定令人满意,如果需要更高的精度或更好的性能,我更喜欢这种方法(另请参阅 this answer 和底部有趣的 link提高精度)。
但是,根据您的要求,纯 QML/JS 方法是完全可行的。在这种情况下,您可以利用 JavaScript Date
,因为它 easy to calculate elapsed time, using getTime()
, but also because QML fully supports JS Date
and also extends 具有一些有用的功能。
这是一个简单的例子:
import QtQuick 2.4
import QtQuick.Window 2.2
import QtQuick.Layouts 1.1
import QtQuick.Controls 1.3
ApplicationWindow {
width: 300
height: 300
visible: true
property double startTime: 0
ColumnLayout {
anchors.fill: parent
Text {
id: time
font.pixelSize: 30
text: "--"
Layout.alignment: Qt.AlignCenter
}
Button {
text: "Click me!"
Layout.alignment: Qt.AlignCenter
onClicked: {
if(startTime == 0){
time.text = "click again..."
startTime = new Date().getTime()
} else {
time.text = new Date().getTime() - startTime + " ms"
startTime = 0
}
}
}
}
}
您没有在问题中提及测量的时间是否仅用于调试目的,或者是否需要用于其他计算。因为如果不是,QML 提供了一个 very simple way 来调试使用 console.time("id string")
和 console.timeEnd("id string")
进行各种操作所花费的时间。
使用 Button
的示例如下所示:
Button {
text: "click here"
property bool measuring: false
onClicked: {
if(!measuring){
console.time("button")
measuring=true
} else {
console.timeEnd("button")
measuring=false
}
}
}
这会将以毫秒为单位的时间打印到控制台,对于测量在 QML 中执行一些长操作所需的时间非常有用。
让我们考虑以下示例:我们有一个 Qt Quick Controls Button
。用户在 5 秒内点击它两次。第一次按下 Button
后,这 5 秒 QML Timer
为 运行。我们想要测量两次点击之间经过的时间,精确到毫秒。
不幸的是,QML Timer
无法向我们显示经过的时间。
正如 BlackBerry 论坛上的建议,可以比较日期。不过,这不是很方便,因为第一次点击可能发生在 31 Dec 2015, 23:59:55
上,第二次点击可能发生在 1 Jan 2016, 00:00:05
上,并且检查必须很复杂。
还有更好的选择吗?
不幸的是,QML Timer
没有提供 属性 来检查经过的时间。但是您可以用 C++ 编写自定义 Timer 并将其公开给 QML:
MyTimer.h
#include <QObject>
#include <QElapsedTimer>
class MyTimer : public QObject
{
Q_OBJECT
Q_PROPERTY(int elapsed MEMBER m_elapsed NOTIFY elapsedChanged)
Q_PROPERTY(bool running MEMBER m_running NOTIFY runningChanged)
private:
QElapsedTimer m_timer;
int m_elapsed;
bool m_running;
public slots:
void start() {
this->m_elapsed = 0;
this->m_running = true;
m_timer.start();
emit runningChanged();
}
void stop() {
this->m_elapsed = m_timer.elapsed();
this->m_running = false;
emit elapsedChanged();
emit runningChanged();
}
signals:
void runningChanged();
void elapsedChanged();
};
通过 qmlRegisterType<MyTimer>("MyStuff", 1, 0, "MyTimer")
注册后,它在 QML 中可用:
Window.qml
import QtQuick 2.4
import QtQuick.Controls 1.3
import MyStuff 1.0
ApplicationWindow {
width: 800
height: 600
visible: true
Button {
id: button
anchors.centerIn: parent
text: timer.running ? "stop" : "start"
checkable: true
onClicked: {
if (timer.running) {
timer.stop()
label.text = timer.elapsed + "ms"
} else {
timer.start()
}
}
MyTimer {
id: timer
}
}
Text {
id: label
anchors.left: button.right
anchors.verticalCenter: button.verticalCenter
text: "0ms"
visible: !timer.running
}
}
希望对您有所帮助!
如评论中所述,QML Timer
不适合您的特定需求,因为它与动画计时器同步(更多详细信息 here),因此其分辨率取决于动画计时器还有。
@qCring 解决方案肯定令人满意,如果需要更高的精度或更好的性能,我更喜欢这种方法(另请参阅 this answer 和底部有趣的 link提高精度)。
但是,根据您的要求,纯 QML/JS 方法是完全可行的。在这种情况下,您可以利用 JavaScript Date
,因为它 easy to calculate elapsed time, using getTime()
, but also because QML fully supports JS Date
and also extends 具有一些有用的功能。
这是一个简单的例子:
import QtQuick 2.4
import QtQuick.Window 2.2
import QtQuick.Layouts 1.1
import QtQuick.Controls 1.3
ApplicationWindow {
width: 300
height: 300
visible: true
property double startTime: 0
ColumnLayout {
anchors.fill: parent
Text {
id: time
font.pixelSize: 30
text: "--"
Layout.alignment: Qt.AlignCenter
}
Button {
text: "Click me!"
Layout.alignment: Qt.AlignCenter
onClicked: {
if(startTime == 0){
time.text = "click again..."
startTime = new Date().getTime()
} else {
time.text = new Date().getTime() - startTime + " ms"
startTime = 0
}
}
}
}
}
您没有在问题中提及测量的时间是否仅用于调试目的,或者是否需要用于其他计算。因为如果不是,QML 提供了一个 very simple way 来调试使用 console.time("id string")
和 console.timeEnd("id string")
进行各种操作所花费的时间。
使用 Button
的示例如下所示:
Button {
text: "click here"
property bool measuring: false
onClicked: {
if(!measuring){
console.time("button")
measuring=true
} else {
console.timeEnd("button")
measuring=false
}
}
}
这会将以毫秒为单位的时间打印到控制台,对于测量在 QML 中执行一些长操作所需的时间非常有用。