0

我正在尝试创建一个包含任务列表的应用程序,并且每次都有截止日期,现在我想在达到截止日期后执行一个功能(显示一个弹出窗口)。

我有这个:

#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 完美运行(经过测试)

我认为错误在连接中,但我不确定......

4

2 回答 2

2

简短的回答:

改变:

now.currentDateTime();

now = QDateTime::currentDateTime();

冗长的答案:

currentDateTime()是一个静态函数,它实际上不会更改现有对象,而是返回一个新QDataTime对象。尽管您将其作为成员函数调用,但它仍被称为静态函数,并且您的对象完好无损,这仍然是无效的。

您稍后secsTo()对无效数据时间的调用可能会给您一个负数或非常大的数字,该数字要么已经过去(永远不会触发),要么在未来很晚。

于 2012-08-17T00:37:04.113 回答
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);

享受。

于 2013-01-03T18:07:47.400 回答