QT6 源(88):阅读与注释定时器控件 QTimer ,源代码以及属性测试,

(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)

谢谢

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值