(1)本例练习成员函数 void start ( int msec ) :
(2)这里练习直接启用定时器,并绑定槽函数的 singleShot () :
(3)本源码来自于头文件 qtimer . h :
#ifndef QTIMER_H
#define QTIMER_H
#include <QtCore/qglobal.h>
#ifndef QT_NO_QOBJECT
#include <QtCore/qbasictimer.h> // conceptual inheritance
#include <QtCore/qobject.h>
#if __has_include(<chrono>)
# include <chrono>
#endif
QT_BEGIN_NAMESPACE //说明本类定义于 QT 的全局命名空间
class QTimerPrivate;
/*
The QTimer class provides repetitive and single-shot timers.
QTimer类为定时器提供了一个高级编程接口。
要使用它,创建一个QTimer,将其 timeout()信号连接到适当的槽位,并调用start()。
从那时起,它将以恒定的时间间隔发出 timeout()信号。
您可以通过调用setSingleShot(true)来设置计时器,使其仅超时一次。
您还可以使用静态QTimer::singleShot()函数在指定时间间隔后调用槽.
在多线程应用程序中,您可以在任何具有事件循环的线程中使用 QTimer。
要从非 GUI 线程启动事件循环,请使用 QThread::exec()。
Qt使用计时器的线程亲和性来确定哪个线程将发出 timeout()信号。
因此,您必须在计时器的线程中启动和停止计时器;从另一个线程启动计时器是不可能的。
作为特殊情况,超时为0的QTimer将尽快超时,但未指定零计时器和其他事件源之间的顺序。
0定时器可以用来做一些工作,同时仍然提供一个敏捷的用户界面:
QTimer * timer = new QTimer(this);
connect(timer, & QTimer::timeout, this, & Foo::processOneThing);
timer->start();
从那时起,processOneThing()将被反复调用。
它应该以这样一种方式编写,即它总是快速返回(通常在处理一个数据项之后),以便Qt可以将事件传递给用户界面,
并在完成所有工作后立即停止计时器。
这是在GUI应用程序中实现繁重工作的传统方式,但随着多线程在越来越多的平台上的应用,
我们预计零毫秒的QTimer对象将逐渐被QThread所取代。
Accuracy and Timer Resolution
计时器的准确性取决于底层操作系统和硬件。
大多数平台支持1毫秒的分辨率,但在许多实际情况下,计时器的准确性将不会等于此分辨率。
准确性还取决于计时器类型。对于Qt::Precise Timer,QTimer将尝试将准确性保持在1毫秒。
精确计时器也永远不会早于预期超时。
对干 Qt::CoarseTimer和 Qt:VervCoarseTimer类型,QTimer可能会比预期更早地唤醒,
这些类型的范围是:Qt::CoarseTimer的5%间隔和Qt::VeryCoarseTimer的500毫秒。
如果系统繁忙或无法提供请求的准确性,则所有计时器类型都可能比预期时间更长。
在这种情况下即使多个超时已经过期,Qt也只会在超时溢出时发出超时 timeout()一次,然后恢复原始间隔。
Alternatives to QTimer
使用 QTimer 的替代方案是调用 QObject::startTimer()来启动您的对象,
并在您的类中重写QObject:timerEvent()事件处理程序(该类必须继承 Q0bject)。
缺点是timerEvent()不支持单拍定时器或信号等高级功能。
not support such high-level features as single-shot timers or signals.
另一种选择是OBasicTimer。通常,"它比直接使用Q0bject::startTimer()更简单。
请参阅计时器以了解所有三种方法的概述。
-些操作系统限制了可以使用的定时器数量;Qt尝试绕过这些限制。
*/
class Q_CORE_EXPORT QTimer : public QObject
{
Q_OBJECT
//注意:此属性支持 QProperty 绑定。 此属性持有以毫秒为单位的超时间隔。
//此属性的缺省值为 0。
//具有0秒超时时间的 QTimer 将在窗口系统的事件队列中的所有事件都被处理后立即超时。
//设置活动计时器的间隔会更改其timerld()。
Q_PROPERTY(int interval READ interval WRITE setInterval BINDABLE bindableInterval)
//Note: This property supports QProperty bindings.
//This property holds whether the timer is a single-shot timer
//A single-shot timer fires only once,
//non-single-shot timers fire every interval milliseconds.
//The default value for this property is false. //默认的定时器是持续不断的
Q_PROPERTY(bool singleShot
READ isSingleShot WRITE setSingleShot BINDABLE bindableSingleShot)
Q_PROPERTY(Qt::TimerType timerType
READ timerType WRITE setTimerType BINDABLE bindableTimerType)
//Note: This property supports QProperty bindings.
//controls the accuracy of the timer。
//The default value for this property is Qt::CoarseTimer. //默认是此中等精度定时器
//此属性持有剩余时间(以毫秒为单位)。返回计时器在超时前剩余的毫秒数。
//如果计时器不活动,返回的值将为-1。如果计时器超时,返回的值将为 0。
Q_PROPERTY(int remainingTime READ remainingTime)
Q_PROPERTY(bool active READ isActive STORED false BINDABLE bindableActive)
//Note: This property supports QProperty bindings.
//This boolean property is true if the timer is running; otherwise false.
protected:
void timerEvent(QTimerEvent *) override;
private:
Q_DISABLE_COPY(QTimer)
Q_DECLARE_PRIVATE(QTimer)
inline int startTimer(int){ return -1;}
inline void killTimer(int){}
static constexpr
Qt::TimerType defaultTypeFor(int msecs) noexcept
{ return msecs >= 2000 ? Qt::CoarseTimer : Qt::PreciseTimer; }
static //两对重载函数
Qt::TimerType defaultTypeFor(std::chrono::milliseconds interval)
{ return defaultTypeFor(int(interval.count())); }
static void singleShotImpl(int msec, Qt::TimerType timerType,
const QObject * receiver,
QtPrivate::QSlotObjectBase * slotObj);
static void singleShotImpl(std::chrono::milliseconds interval,
Qt::TimerType timerType,
const QObject * receiver ,
QtPrivate::QSlotObjectBase * slotObj)
{
singleShotImpl(int(interval.count()),
timerType, receiver, slotObj);
}
#if __has_include(<chrono>) //此宏是成立的
#endif
public:
//Constructs a timer with the given parent.
explicit QTimer(QObject * parent = nullptr);
~QTimer();
//Q_PROPERTY(int interval
// READ interval
// WRITE setInterval BINDABLE bindableInterval)
int interval() const;
void setInterval(int msec); //单位 ms
QBindable<int> bindableInterval(); //无注释,下同,太好了
//Q_PROPERTY(bool singleShot
// READ isSingleShot
// WRITE setSingleShot BINDABLE bindableSingleShot)
bool isSingleShot() const; //默认重复触发
void setSingleShot(bool singleShot);
QBindable<bool> bindableSingleShot();
//Q_PROPERTY(Qt::TimerType timerType
// READ timerType //默认中等精度
// WRITE setTimerType BINDABLE bindableTimerType)
Qt::TimerType timerType() const;
void setTimerType(Qt::TimerType atype);
QBindable<Qt::TimerType> bindableTimerType();
//enum Qt::TimerType { PreciseTimer, CoarseTimer, VeryCoarseTimer };
//Q_PROPERTY(int remainingTime READ remainingTime)
int remainingTime() const;
//Q_PROPERTY(bool active
// READ isActive STORED false BINDABLE bindableActive)
bool isActive() const;
QBindable<bool> bindableActive();
int timerId() const;
//Returns the ID of the timer if the timer is running; otherwise returns -1.
static void singleShot(int msec, //第 4个形参仍然可以这么提供: & Widget::do_timer_shot
const QObject * receiver, const char * member);
static void singleShot(int msec, Qt::TimerType timerType, //或者 & do_timer_shot
const QObject * receiver, const char * member);
public Q_SLOTS:
//Starts or restarts the timer with the timeout specified in interval.
//If the timer is already running, it will be stopped and restarted.
//If singleShot is true, the timer will be activated only once.
void start(); //会停止上一次未结束的定时器,并重新开始计时
void start(int msec); //本函数启动定时器,并顺便设置了定时时长。
//Starts or restarts the timer with a timeout interval of msec milliseconds.
//If the timer is already running, it will be stopped and restarted.
//If singleShot is true, the timer will be activated only once.
void stop (); //Stops the timer.
Q_SIGNALS: //看老师的写法,不给槽函数带形参,也是可以的。不要此信号函数的实参
void timeout(QPrivateSignal); //void do_timer_timeout();
//This signal is emitted when the timer times out.
//Note: This is a private signal.
//It can be used in signal connections but cannot be emitted by the user.
public :
#ifdef Q_CLANG_QDOC //经验证,无此定义的
template<typename PointerToMemberFunction>
static void singleShot(int msec, const QObject *receiver,
PointerToMemberFunction method);
template<typename PointerToMemberFunction>
static void singleShot(int msec, Qt::TimerType timerType,
const QObject *receiver, PointerToMemberFunction method);
template<typename Functor>
static void singleShot(int msec, Functor functor);
template<typename Functor>
static void singleShot(int msec, Qt::TimerType timerType, Functor functor);
template<typename Functor, int>
static void singleShot(int msec, const QObject *context, Functor functor);
template<typename Functor, int>
static void singleShot(int msec, Qt::TimerType timerType,
const QObject *context, Functor functor);
template <typename Functor>
QMetaObject::Connection callOnTimeout(Functor slot,
Qt::ConnectionType connectionType = Qt::AutoConnection);
template <typename Functor>
QMetaObject::Connection callOnTimeout(const QObject * context, Functor slot,
Qt::ConnectionType connectionType = Qt::AutoConnection);
template <typename MemberFunction>
QMetaObject::Connection callOnTimeout(const QObject * receiver,
MemberFunction * slot,
Qt::ConnectionType connectionType = Qt::AutoConnection);
#else //主要学习 #else部分。看起来是要支持 c++ STL库中的类型作为 singleShot()的参数
// singleShot to a QObject slot
template <typename Duration, typename Func1>
static inline void singleShot(Duration interval,
const typename QtPrivate::FunctionPointer<Func1>::Object * receiver, Func1 slot)
{
singleShot(interval, defaultTypeFor(interval), receiver, slot);
}
template <typename Duration, typename Func1>
static inline void singleShot(Duration interval, Qt::TimerType timerType,
const typename QtPrivate::FunctionPointer<Func1>::Object * receiver, Func1 slot)
{
typedef QtPrivate::FunctionPointer<Func1> SlotType;
//compilation error if the slot has arguments.
static_assert(int(SlotType::ArgumentCount) == 0,
"The slot must not have any arguments.");
singleShotImpl(interval, timerType, receiver,
new QtPrivate::QSlotObject<Func1, typename SlotType::Arguments, void>(slot));
}
// singleShot to a functor or function pointer (without context)
template <typename Duration, typename Func1>
static inline typename std::enable_if<
!QtPrivate::FunctionPointer<Func1>::IsPointerToMemberFunction &&
!std::is_same<const char*, Func1>::value, void>::type
singleShot(Duration interval, Func1 slot)
{
singleShot(interval, defaultTypeFor(interval), nullptr, std::move(slot));
}
template <typename Duration, typename Func1>
static inline typename std::enable_if<
!QtPrivate::FunctionPointer<Func1>::IsPointerToMemberFunction &&
!std::is_same<const char*, Func1>::value, void>::type
singleShot(Duration interval, Qt::TimerType timerType, Func1 slot)
{
singleShot(interval, timerType, nullptr, std::move(slot));
}
// singleShot to a functor or function pointer (with context)
template <typename Duration, typename Func1>
static inline typename std::enable_if<
!QtPrivate::FunctionPointer<Func1>::IsPointerToMemberFunction &&
!std::is_same<const char*, Func1>::value, void>::type
singleShot(Duration interval, const QObject * context, Func1 slot)
{
singleShot(interval, defaultTypeFor(interval), context, std::move(slot));
}
template <typename Duration, typename Func1>
static inline typename std::enable_if<
!QtPrivate::FunctionPointer<Func1>::IsPointerToMemberFunction &&
!std::is_same<const char *, Func1>::value, void>::type
singleShot(Duration interval, Qt::TimerType timerType,
const QObject * context, Func1 slot)
{
//compilation error if the slot has arguments.
typedef QtPrivate::FunctionPointer<Func1> SlotType;
static_assert(int(SlotType::ArgumentCount) <= 0,
"The slot must not have any arguments.");
singleShotImpl(interval, timerType, context,
new QtPrivate::QFunctorSlotObject<Func1, 0,
typename QtPrivate::List_Left<void, 0>::Value, void>(std::move(slot)));
}
template <typename ... Args>
QMetaObject::Connection callOnTimeout(Args && ...args)
{
return QObject::connect(this, &QTimer::timeout, std::forward<Args>(args)... );
}
#endif //主要是用上面的静态函数来关联定时器信号与槽函数
static void singleShot(std::chrono::milliseconds value, //又是要兼容 c++ STL库的源码
const QObject * receiver, const char * member)
{
singleShot(int(value.count()), receiver, member);
}
static void singleShot(std::chrono::milliseconds value, Qt::TimerType timerType,
const QObject * receiver, const char * member)
{
singleShot(int(value.count()), timerType, receiver, member);
}
void setInterval(std::chrono::milliseconds value)
{
setInterval(int(value.count()));
}
std::chrono::milliseconds intervalAsDuration() const
{
return std::chrono::milliseconds(interval());
}
std::chrono::milliseconds remainingTimeAsDuration() const
{
return std::chrono::milliseconds(remainingTime());
}
void start(std::chrono::milliseconds value) //构成了函数重载
{
start(int(value.count()));
}
#if __has_include(<chrono>) || defined(Q_QDOC) //前者成立,后者不成立
#endif
}; //完结 class QTimer : public QObject
QT_END_NAMESPACE
#endif // QT_NO_QOBJECT
#endif // QTIMER_H
(4)
谢谢