【问题标题】:QTimer doesn't fire on second callQTimer 在第二次调用时不会触发
【发布时间】:2013-01-16 15:37:57
【问题描述】:

我已经在 qt 中实现了状态模式。
在我的 EnterIdleState 函数中,我连接了一个单次计时器来开始工作。在第一次调用时这工作正常,在第二次尝试时计时器没有触发,尽管连接像以前一样:

代码流是这样的:

SetNewState(newIdleState());
IdleState::doWork();
SetNewState(new WorkState());
WorkdState::doWork();
SetNewState(newIdleState());

SetNewState 如下所示:

void IridiumProcessor::SetNewState(State* pNewState)
{
    if (m_pCurrentState)
    {             
        m_pCurrentState->LeaveState();
        delete m_pCurrentState;
    }    
    m_pCurrentState = pNewState;
    if (m_pCurrentState)
        m_pCurrentState->EnterState();
}

在进入 IdleState 时,我连接了单次计时器:

void IdleState::EnterState()
{
    QTimer::singleShot(1000,this,SLOT(OnTimeout())); 
}
void IdleState::OnTimeout()
{
    qDebug() << "IdleState OnTimeout";
}

当我使用 QTimer membervar 而不是静态 singleShot 调用时,也会发生同样的事情。

【问题讨论】:

  • 当我试图重现这个问题时,出现了一个问题:你在哪里调用 SetNewState() 和 doWork()?它是单线程应用程序吗?会不会是你用一些冗长的操作阻塞了事件线程?

标签: qt


【解决方案1】:

我认为这种情况发生的可能原因很少,除了内存损坏等真正的核心错误。

可能是您在超时到期之前调用了 EnterState() 方法。第二个调用取消了前一个调用,并且一次又一次地重复。为了对此进行调试,您应该向 EnterState() 方法添加一个调试输出,最好是随着时间的推移,看看它是否真的发生了。如果没有,那就说明我错了。

也可能是您在发出信号之前破坏了接收器,正如 chalup 所建议的那样。

另一种可能性是您通过一些冗长的操作阻塞了事件线程。在控件返回到计时器所在线程的 Qt 事件循环之前,计时器不会触发。对于单线程应用程序,它是主事件循环。

【讨论】:

  • 嗯,我的日志显示没有异常 - IdleState 被构造,状态被输入,定时器触发,IdleState 被破坏,然后再次构造,定时器被再次设置但从未触发。
  • @zeroc8,在再次设置 QTimer 后,不再为同一个对象调用 IdleState::EnterState() 吗?你检查了吗?顺便问一下,您使用的是哪个版本的 Qt,在哪个平台上使用?
  • 我在 Xubuntu 10.10 上使用 4.7.0、32 位
  • @zeroc8,我不认为地址是这里的问题。并不是说 Qt 会记住并“列入黑名单”所有在某个时间存在然后被销毁的对象的地址。我会进一步调查。
  • 我检查了构造函数和内存地址,这里一切正常。
【解决方案2】:

我会将日志添加到 IdleState 析构函数:也许您在 QTimer 超时之前在 IridiumProcessor::SetNewState 中销毁它们?

还可以考虑使用QStateMachine,而不是编写自己的解决方案。

【讨论】:

  • 已经这样做了。该对象在该时间点是活动的。我确实考虑过 QStateMachine,但选择了手写状态模式。
猜你喜欢
  • 1970-01-01
  • 2013-08-20
  • 1970-01-01
  • 2010-10-31
  • 1970-01-01
  • 1970-01-01
  • 2015-09-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多