2012-08-16 140 views
0

我想创建一个应用程序,它包含一个任务列表,并且每次都有一个截止日期,现在我想要在满足最后期限时执行一个函数(显示一个弹出窗口)。QT C++等待具体时间来执行功能

我有这样的:

#ifndef TIMER_H 
#define TIMER_H 
#include <QWidget> 
#include <QTimer> 
#include <QtGui> 
#include <QObject> 

class Timer : public QWidget 
{ 
    Q_OBJECT 
public: 
    Timer(QWidget * parent = 0); 
    void setTimer(QString title, QString description, QDate date, QTime reminderTime); 
public slots: 
    void showWarning() {QString show = tit; 
         QPushButton * thanks = new QPushButton(QObject::tr("Thank you for reminding me!")); 
         show.append("\n"); 
         show.append(des); 
         QMessageBox popup; 
         popup.setText(show); 
         popup.setWindowTitle("Calendar : Reminder"); 
         popup.setDefaultButton(thanks); 
         popup.exec(); 
         } 
private: 
    QString tit; 
    QString des; 
    QDateTime now; 
    QDateTime timeoftheaction; 
    QTimer *timer; 
}; 

CPP文件:

#endif // TIMER_H 
#include "timer.h" 
#include <iostream> 
using namespace std; 

Timer::Timer(QWidget * parent) 
    : QWidget(parent) 
{ 
} 

void Timer::setTimer(QString title, QString description, QDate date, QTime reminderTime) 
{ 
    now.currentDateTime(); 
    timer = new QTimer; 
    tit = title; 
    des = description; 
    timeoftheaction.setDate(date); 
    timeoftheaction.setTime(reminderTime); 
    connect(timer, SIGNAL(timeout()),this,SLOT(showWarning())); 
    timer->start(now.secsTo(timeoftheaction)*1000); 
} 

但功能showWarning从不被称为...... 没有编译错误,功能showWarning完美的作品(测试)

我认为错误是在连接,但我不知道...

+1

你是否检查过'now.secsTo(timeoftheaction)* 1000'实际上给你你认为它是什么? – enderland 2012-08-16 23:22:18

+0

如果将计时器设置为:'timer-> start(1)',它会立即启动吗?如果是这样,那么@恩德兰的建议是正确的 – jdi 2012-08-17 00:14:18

+0

这也可能是一个解决方案: http://stackoverflow.com/questions/11996706/qt-c-wait-till-specific-time-to-executefunction/14144614#14144614 – formiaczek 2013-01-03 18:14:53

回答

2

简短的回答:

变化:

now.currentDateTime(); 

now = QDateTime::currentDateTime(); 

稍长的答案:

currentDateTime()是静态函数的这不是改变现有的对象,实际上返回一个新的QDataTime o bject。尽管您将它作为成员函数调用,但它仍被称为静态对象,并保持对象完好无损。

您以后在无效数据时间呼叫secsTo()可能会让您得到一个负值或真的很大的数字,这个数字已经过去了(从未触发过)或者将来真的很晚。

0

这是一些可能是更通用的解决方案。

#include <QThread> 
#include <QTimer> 
#include <QObject> 

#include <map> 


/** 
* Singleton to implement simple 'relative' timer. 
* Implements busy wait and also timeout-notifications (useful to monitor operations that could hang, etc). 
* 
* If the whole application is stalled (e.g. when a new device is connected), and we only want to 
* wait for a period during which application was 'really' working (not just hanging waiting for OS) 
* - then ticks will be missed too. This way - it's should be possible to avoid unnecessary timeouts 
*  that could happen if global time was measured (especially annoying on WINdows platforms) 
*/ 
class RelativeTimer : public QObject 
{ 
    Q_OBJECT 

    typedef std::multimap <unsigned int, std::pair <QObject*, QString> > Notifications; 

public: 

    /** 
    * Call to busy-wait for number of ticks. 
    */ 
    static void wait_num_of_ticks(unsigned int num_of_ticks_to_wait) 
    { 
     if(self.timer_id == 0) 
     { 
      qDebug("timer not initialised, call 'RelativeTimer::Init()'"); 
      return; 
     } 

     if(num_of_ticks_to_wait > 0) 
     { 
      unsigned long until = self.tick_counter + num_of_ticks_to_wait; // it's ok if it wraps around.. 
      while(self.tick_counter != until) 
      { 
       QCoreApplication::processEvents(); // let others to their job.. 
       // or comment above out and just busy wait.. 
      } 
     } 
    } 

    /** 
    * Call to busy-wait until ms_to_wait have elapsed. 
    * If ms_to_wait is < tick period 
    * Interval will define 'tick' frequency (and accuracy). 
    */ 
    static void wait_ms(unsigned int ms_to_wait) 
    { 
     wait_num_of_ticks(num_of_ticks_to_wait(ms_to_wait)); 
    } 


    /** 
    * Call to schedule a notification after a given timeout. 
    * returns notification_id that can be used to cancel this notification. 
    */ 
    static unsigned long notify_timeout_ms(unsigned int ms_to_wait, 
              QObject *receiver, 
              const char* method_name) 
    { 
     unsigned long ticks_to_wait = 0; 
     if(receiver && method_name) 
     { 
      ticks_to_wait = num_of_ticks_to_wait(ms_to_wait); 
      if(ticks_to_wait > 1) 
      { 
       ticks_to_wait += self.tick_counter; 
       if(ticks_to_wait == 0) // avoid 0 - make it one tick more (to alow to see if successfully added this notif) 
       { 
        ticks_to_wait = 1; 
       } 
       self.notifications.insert(std::make_pair(ticks_to_wait, 
                 std::make_pair(receiver, method_name))); 
       qDebug("added delayed call.."); 
      } 
      else 
      { 
       QMetaObject::invokeMethod(receiver, method_name, Qt::QueuedConnection); 
       ticks_to_wait = 0; 
      } 
     } 
     return ticks_to_wait; 
    } 


    /** 
    * Call to cancel a notification with a given id. 
    * Specify name if there were more notification with the same id (scheduled for the same tick). 
    * returns true on successfull cancellation, false otherwise. 
    */ 
    static bool cancel_timeout_notification(unsigned long notification_id, QString notification_name="") 
    { 
     bool cancelled = false; 
     if(self.notifications.size()) 
     { 
      std::pair<Notifications::iterator, Notifications::iterator> to_cancel = self.notifications.equal_range(notification_id); 
      Notifications::iterator n = to_cancel.first; 
      for(;n != to_cancel.second; ++n) 
      { 
       if(notification_name.size()== 0 || n->second.second == notification_name) 
       { 
        self.notifications.erase(n); 
        cancelled = true; 
        break; 
       } 
      } 
     } 
     return cancelled; 
    } 

    static const unsigned int default_tick_period_ms = 100; 

    /** 
    * Call this method after event loop is created- to initiate (re-start) timer. 
    * tick period defines 'tick' frequency (and accuracy of the timer) 
    * (note on Windows that there's no point to go down below 100ms). 
    */ 
    static void Init(unsigned int tick_period_ms = default_tick_period_ms) 
    { 
     self.moveToThread(&self.thread); 
     self.thread.start(); 

     while(!self.thread.isRunning()); 

     self.current_interval = tick_period_ms; 

     // InitMe() should execute in the thread context.. 
     QMetaObject::invokeMethod(&self, "InitMe", Qt::QueuedConnection); 
    } 

private: 

    /** 
    * Internal method to convert ms to number of ticks. 
    */ 
    static unsigned int num_of_ticks_to_wait(unsigned int ms_to_wait) 
    { 
     if(ms_to_wait > self.current_interval) 
     { 
      if(ms_to_wait % self.current_interval) 
      { 
       // average it.. 
       ms_to_wait = ms_to_wait + self.current_interval/2; 
      } 
      ms_to_wait /= self.current_interval; 
     } 
     else 
     { 
      ms_to_wait = 0; 
     } 

     return ms_to_wait; 
    } 


    /** 
    * Internal method to handle tick. Increments counter and invokes notifications. 
    */ 
    void timerEvent (QTimerEvent* /*event*/) 
    { 
     tick_counter++; 

     if(notifications.size()) 
     { 
      std::pair<Notifications::iterator, Notifications::iterator> to_notify = notifications.equal_range(tick_counter); 
      Notifications::iterator n = to_notify.first; 
      for(;n != to_notify.second; ++n) 
      { 
       QMetaObject::invokeMethod(n->second.first, 
              n->second.second.toStdString().c_str(), 
              Qt::QueuedConnection); 
      } 
      notifications.erase(to_notify.first, to_notify.second); 
     } 
    } 

private slots: 
    /** 
    * Internal slot to initialize the timer. Should be called in this->timer context. 
    */ 
    void InitMe() 
    { 
     if(timer_id != 0) 
     { 
      killTimer(timer_id); 
      timer_id = 0; 
     } 

     tick_counter = 0; 
     timer_id = self.startTimer(self.current_interval); 
    } 

private: 
    RelativeTimer() 
    { 
    } 

    ~RelativeTimer() 
    { 
     thread.quit(); 
     thread.wait(); 
    } 

    QThread thread; 
    Notifications notifications; 
    int timer_id; 
    unsigned int current_interval; 
    unsigned long tick_counter; 

    static RelativeTimer self; // implement it as a signleton.. Define it in your C file, e.g.: 
           // RelativeTimer RelativeTimer::self; 
}; 

可以使用,如:

CurrQObjectClass::OnTimeout() 
{ 
// ... 
} 

CurrQObjectClass::SomeMethod() 
{ 

RelativeTimer::notify_timeout_ms(5000, this, "OnTimeout"); 
} 

也为忙碌的等待:

RelativeTimer::wait_ms(2000); 

享受。