修改控件时回调的速率限制

时间:2017-02-16 20:39:17

标签: c++ qt qml

假设我有一个滑块控件,我的用户可以快速地来回滑动。

是否可以限制QML调用“新值可用”C ++回调的速率?

2 个答案:

答案 0 :(得分:1)

如果要在拖动滑块时完全避免更新值,可以使用Qt Quick Controls 1中的updateValueWhileDragging属性和Qt Quick Controls 2中的live属性。< / p>

在Qt Quick Controls 2中,滑块控件具有valueAt()功能,可以随时调用该功能来检查值。

如果您在QML中编写自己的滑块,则可以使用Timer限制更改信号发射,例如:

property int value

readonly property int actualValue: // some calculation...

Timer {
    running: slider.pressed
    interval: 200
    repeat: true
    onTriggered: slider.value = slider.actualValue
}

答案 1 :(得分:0)

这是一个适用于任何QObject的通用C ++端解决方案:

// https://github.com/KubaO/stackoverflown/tree/master/questions/qml-rate-limter-42284163
#include <QtCore>

class PropertyRateLimiter : public QObject {
   Q_OBJECT
   qint64 msecsPeriod{500};
   const QByteArray property;
   bool dirty{};
   QVariant value;
   QElapsedTimer time;
   QBasicTimer timer;
   QMetaMethod slot = metaObject()->method(metaObject()->indexOfSlot("onChange()"));
   void signal() {
      if (time.isValid()) time.restart(); else time.start();
      if (dirty)
         emit valueChanged(value, parent(), property);
      else
         timer.stop();
      dirty = false;
   }
   Q_SLOT void onChange() {
      dirty = true;
      value = parent()->property(property);
      auto elapsed = time.isValid() ? time.elapsed() : 0;
      if (!time.isValid() || elapsed >= msecsPeriod)
         signal();
      else
         if (!timer.isActive())
            timer.start(msecsPeriod - elapsed, this);
   }
   void timerEvent(QTimerEvent *event) override {
      if (timer.timerId() == event->timerId())
         signal();
   }
public:
   PropertyRateLimiter(const char * propertyName, QObject * parent) :
      QObject{parent}, property{propertyName}
   {
      auto mo = parent->metaObject();
      auto property = mo->property(mo->indexOfProperty(this->property));
      if (!property.hasNotifySignal())
         return;
      connect(parent, property.notifySignal(), this, slot);
   }
   void setPeriod(int period) { msecsPeriod = period; }
   Q_SIGNAL void valueChanged(const QVariant &, QObject *, const QByteArray & name);
};
#include "main.moc"

它的测试工具:

#include <QtQuick>

const char qmlData[] =
R"__end(
import QtQuick 2.6
import QtQuick.Controls 2.0

ApplicationWindow {
   minimumWidth: 300
   minimumHeight: 250
   visible: true

   Column {
      anchors.fill: parent
      Slider { objectName: "slider" }
      Label { objectName: "label" }
   }
}
)__end";

int main(int argc, char ** argv) {
    QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    QGuiApplication app{argc, argv};
    QQmlApplicationEngine engine;
    engine.loadData(QByteArray::fromRawData(qmlData, sizeof(qmlData)-1));
    auto window = engine.rootObjects().first();
    auto slider = window->findChild<QObject*>("slider");
    auto label = window->findChild<QObject*>("label");
    PropertyRateLimiter limiter("position", slider);
    QObject::connect(&limiter, &PropertyRateLimiter::valueChanged, [&](const QVariant & val){
       label->setProperty("text", val);
    });
    return app.exec();
}