如何使用Qtimer添加1秒延迟

17

我目前有一个如下所述的方法

void SomeMethod(int a)
{

     //Delay for one sec.
     timer->start(1000);

     //After one sec
     SomeOtherFunction(a);
}

这个方法实际上是一个附加到信号的槽。我想使用Qtimer添加一秒的延迟,但我不确定如何完成。由于计时器在完成时会触发一个信号,并且该信号需要附加到另一个不带任何参数的方法上,因此我无法确定如何完成此任务。有关如何完成此任务的建议吗?

更新: 该信号将在一秒内多次调用,延迟为一秒钟。我的问题在于将参数传递给定时器的timeout()信号所附加的槽。我的最后一个尝试是将值存储在类的成员变量中,然后使用互斥锁来保护它在使用变量时不被更改。但是我正在寻找更简单的方法。


你是否预计会更频繁地处理信号而不是延迟周期? - Linville
@Linville 是的,我的延迟将是一秒钟,信号可能会在一秒钟内被多次调用。 - Rajeshwar
4个回答

54

实际上,对于你的问题有更加优雅的解决方案,不需要成员变量或队列。在Qt 5.4和C++11中,你可以直接从QTimer::singleShot(..)方法运行Lambda表达式!如果你使用的是Qt 5.0 - 5.3,你可以使用connect方法将QTimer的超时信号连接到一个Lambda表达式,该表达式将使用适当的参数调用需要延迟执行的方法。

编辑:随着Qt 5.4的发布,只需要一行代码!

Qt 5.4(及更高版本)

void MyClass::SomeMethod(int a) {
  QTimer::singleShot(1000, []() { SomeOtherFunction(a); } );
}

Qt 5.0 - 5.3

void MyClass::SomeMethod(int a) {
  QTimer *timer = new QTimer(this);
  timer->setSingleShot(true);

  connect(timer, &QTimer::timeout, [=]() {
    SomeOtherFunction(a);
    timer->deleteLater();
  } );

  timer->start(1000);
}

这很不错。可惜你不能在静态的 QTimer::singleShot() 中使用 lambda 表达式。 - user362638
@Roku,同意!这是QTBUG-26406。希望他们能尽快解决它! - Linville
1
我也没有使用C++11。 - Rajeshwar
2
Qt 5.4将支持QTimer::singleShot()和lambdas - Linville

1
如果您每秒钟调用SomeMethod多次且延迟始终是恒定的,您可以将参数a放入QQueue中,并创建一个单次触发器来调用SomeOtherFunction,该函数从QQueue中获取参数。
void SomeClass::SomeMethod(int a)
{
    queue.enqueue(a);
    QTimer::singleShot(1000, this, SLOT(SomeOtherFunction()));
}

void SomeClass::SomeOtherFunction()
{
    int a = queue.dequeue();
    // do something with a
}

1

我对你提出问题的方式感到有些困惑,但是如果你想知道如何使计时器的timeout()信号调用带有参数的函数,那么你可以创建一个单独的插槽来接收timeout并调用你想要的函数。类似于这样:

class MyClass : public QObject
{
    Q_OBJECT
public:
    MyClass(QObject *parent);

public slots:

    void TimerHandlerFunction();
    void SomeMethod(int a);

private:
    int m_a;
    QTimer m_timer;
};

实现:-

MyClass::MyClass(QObject *parent) : QObject(parent)
{
    // Connect the timer's timeout to our TimerHandlerFunction()
    connect(&m_timer, SIGNAL(timeout()), this, SLOT(TimerHandlerFunction()));
}

void MyClass::SomeMethod(int a)
{
    m_a = a; // Store the value to pass later

    m_timer.setSingleShot(true); // If you only want it to fire once
    m_timer.start(1000);
}

void MyClass::TimerHandlerFunction()
{
    SomeOtherFunction(m_a);
}

请注意,QObject类实际上有一个定时器,您可以通过调用startTimer()来使用它,因此您实际上不需要在这里使用单独的QTimer对象。它包含在这里是为了尝试使示例代码与问题保持接近。

我看到你正在使用类的成员变量并存储参数。然而,这将是多线程的。那么这种方式安全吗? - Rajeshwar
我不想在这种情况下使用互斥锁。有没有简单的机制可以替代? - Rajeshwar
你不使用QMutex的原因是什么?你所要做的就是创建一个QMutex对象,在设置值之前调用mutex.lock,之后再调用mutex.unlock。这就是最简单的方法了! - TheDarkKnight
@Rajeshwar的回答很好,除此之外,我很想知道是什么让你确认这个答案是好的,即使你留下了许多未回答的问题?我认为你误解了QTimer作为多线程的概念。如果我错了,请谅解并纠正我。 - Ashif
1
@ashif 看起来Qtimer要么需要在变量周围包装互斥锁,要么需要使用排队连接。我现在只是简单地使用一个线程直接传递值。无论哪种方式,答案都提供了我所拥有的选项。谢谢。 - Rajeshwar
显示剩余4条评论

0

那样不起作用,因为QTimer::start是非阻塞的。

你应该使用QTimer::singleShot来启动计时器,并将其连接到一个槽函数,在QTimer超时后执行。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接