Qt 工具类(04):计时器QBasicTimer类及Wiggly Example示例

一、前言

QBasicTimer类为对象提供计时器事件。
 Header : #include < QBasicTimer>
 qmake : QT += core

二、详述

是Qt内部使用的快速,轻量级和低级的类。如果要在应用程序中使用计时器,我们建议使用更高级别的QTimer类而不是此类。请注意,此计时器是重复计时器,除非调用stop()函数,否则它将发送后续计时器事件。

使用此类,请创建一个QBasicTimer,并使用超时间隔和指向QObject子类的指针来调用其start()函数。当计时器超时时,它将向QObject子类发送计时器事件。可以使用stop()随时停止计时器。 isActive()对于正在运行的计时器返回true;即它已经开始,还没有达到超时时间,还没有停止。可以使用timerId()检索计时器的ID。

个类的对象不能被复制,但是可以被移动,所以你可以通过将它们保存在只支持移动类型的容器中来维护一个基本计时器列表,例如std::vector。

Wiggly示例使用QBasicTimer定期重绘窗口小部件。

三、公共函数

  1. 构造函数
    QBasicTimer(QBasicTimer &&other)
    QBasicTimer()
  2. 赋值符号重载
    QBasicTimer & operator=(QBasicTimer &&other)
  3. 析构函数
    ~QBasicTimer()
  4. void start(int msec, QObject *object)
    以msec毫秒超时启动(或重新启动)计时器。计时器将是Qt::CoarseTimer。
  5. void start(int msec, Qt::TimerType timerType, QObject *obj)
    这是一个重载函数。
    以msec毫秒超时和给定的计时器类型启动(或重新启动)计时器。obj 将接收计时器事件。
  6. void stop()
    停止计时器。
  7. void swap(QBasicTimer &other)
    交换计时器。【文档有错误,呵呵】
  8. int timerId() const
    返回ID

五、Wiggly Example

Wiggly示例显示了如何使用QBasicTimer和timerEvent()为小部件设置动画。 此外,该示例演示了如何使用QFontMetrics确定屏幕上文本的大小。

QBasicTimer是计时器的低级类。 与QTimer不同,QBasicTimer不继承自QObject。 它不会在经过一定时间后发出timeout()信号,而是将QTimerEvent发送到我们选择的QObject。 这使QBasicTimer成为QTimer的更轻量级替代。 Qt的内置小部件在内部使用它,并且Qt的API中提供了Qt的API,用于高度优化的应用程序(例如嵌入式应用程序)。

该示例包含两个类:

  • WigglyWidget是自定义的小部件,以摆动的行显示文本。
  • 对话框是允许用户输入文本的对话框小部件。 它结合了WigglyWidget和QLineEdit。

我们将首先快速浏览Dialog类,然后再回顾WigglyWidget类。

5.1 Dialog Class 定义

class Dialog : public QDialog
{
    Q_OBJECT
public:
    Dialog(QWidget *parent = nullptr);
};

Dialog类提供了一个对话框小部件,允许用户输入文本。 然后由WigglyWidget渲染文本。

5.2 Dialog Class 实现

 Dialog::Dialog(QWidget *parent)
     : QDialog(parent)
 {
     WigglyWidget *wigglyWidget = new WigglyWidget;
     QLineEdit *lineEdit = new QLineEdit;

     QVBoxLayout *layout = new QVBoxLayout(this);
     layout->addWidget(wigglyWidget);
     layout->addWidget(lineEdit);

     connect(lineEdit, &QLineEdit::textChanged, wigglyWidget, &WigglyWidget::setText);
     lineEdit->setText(tr("Hello world!"));

     setWindowTitle(tr("Wiggly"));
     resize(360, 145);
 }

构造函数中,我们创建一个摆动的窗口小部件以及行编辑,然后将这两个窗口小部件置于垂直布局中。 我们将行编辑的textChanged()信号连接到摆动小部件的setText()插槽,以获得与摆动小部件的实时交互。 小部件的默认文本为“ Hello world!”。

5.3 WigglyWidget Class 定义

 class WigglyWidget : public QWidget
 {
     Q_OBJECT

 public:
     WigglyWidget(QWidget *parent = nullptr);

 public slots:
     void setText(const QString &newText) { text = newText; }

 protected:
     void paintEvent(QPaintEvent *event) override;
     void timerEvent(QTimerEvent *event) override;

 private:
     QBasicTimer timer;
     QString text;
     int step;
 };

WigglyWidget类提供显示文本的摆动行。 我们将QWidget子类化,并重新实现标准的paintEvent()和timerEvent()函数以绘制和更新窗口小部件。 另外,我们实现了一个公共setText()插槽,用于设置小部件的文本。

QBasicTimer类型的timer变量用于定期更新小部件,从而使小部件移动。 text变量用于存储当前显示的文本,并用于计算摆动行上每个字符的位置和颜色。

5.4 WigglyWidget Class 实现

 WigglyWidget::WigglyWidget(QWidget *parent)
     : QWidget(parent), step(0)
 {
     setBackgroundRole(QPalette::Midlight);
     setAutoFillBackground(true);

     QFont newFont = font();
     newFont.setPointSize(newFont.pointSize() + 20);
     setFont(newFont);

     timer.start(60, this);
 }

构造函数中,我们使用QPalette :: Midlight颜色角色使小部件的背景比通常的背景略浅。 背景角色定义了Qt用于绘制背景的小部件调色板中的画笔。 然后,我们将小部件的字体放大20点。

后,我们启动计时器; 调用QBasicTimer :: start()可确保该特定的摆动小部件将接收到计时器超时(每60毫秒)时生成的计时器事件。

 void WigglyWidget::paintEvent(QPaintEvent * /* event */)
 {
     static constexpr int sineTable[16] = {
         0, 38, 71, 92, 100, 92, 71, 38, 0, -38, -71, -92, -100, -92, -71, -38
     };

     QFontMetrics metrics(font());
     int x = (width() - metrics.horizontalAdvance(text)) / 2;
     int y = (height() + metrics.ascent() - metrics.descent()) / 2;
     QColor color;

当将QPaintEvent发送到窗口小部件时,都会调用paintEvent()函数。绘画事件被发送到需要更新自身的小部件,例如,由于覆盖小部件被移动而导致部分小部件暴露时。对于摆动的窗口小部件,还会从timerEvent()插槽每60毫秒生成一次绘制事件。

sineTable代表正弦曲线的y值乘以100。它用于使摆动的小部件沿正弦曲线移动。

QFontMetrics对象提供有关小部件字体的信息。 x变量是我们开始绘制文本的水平位置。 y变量是文本基线的垂直位置。计算两个变量的目的是使文本水平和垂直居中。为了计算基线,我们考虑了字体的上升(基线上方的字体的高度)和字体的下降(基线下方的字体的高度)。如果下降等于上升,则它们会相互抵消,并且基线位于height()/ 2。

     QPainter painter(this);
     for (int i = 0; i < text.size(); ++i) {
         int index = (step + i) % 16;
         color.setHsv((15 - index) * 16, 255, 191);
         painter.setPen(color);
         painter.drawText(x, y - ((sineTable[index] * metrics.height()) / 400),
                          QString(text[i]));
         x += metrics.horizontalAdvance(text[i]);
     }
 }

次调用paintEvent()函数时,我们都会创建一个QPainter对象绘制程序以绘制小部件的内容。 对于文本中的每个字符,我们基于step来确定颜色和摆动线上的位置。 另外,x以字符的宽度递增。

简单起见,我们假定QFontMetrics :: horizontalAdvance(text)返回各个字符前进的总和(QFontMetrics :: horizontalAdvance(text [i]))。 实际上,情况并非总是如此,因为QFontMetrics :: horizontalAdvance(text)还考虑了某些字母(例如’A’和’V’)之间的字距调整。 结果是文本不能完美居中。 您可以通过在行编辑中键入“ AVAVAVAVAVAVAV”来验证这一点。

 void WigglyWidget::timerEvent(QTimerEvent *event)
 {
     if (event->timerId() == timer.timerId()) {
         ++step;
         update();
     } else {
         QWidget::timerEvent(event);
     }
 }

timerEvent()函数接收为此窗口小部件生成的所有计时器事件。 如果从小部件的QBasicTimer发送了一个计时器事件,我们将增加步骤以使文本移动,然后调用QWidget :: update()刷新显示。 其他任何计时器事件都将传递给timerEvent()函数的基类实现。

QWidget :: update()插槽不会立即重绘; 相反,当Qt返回主事件循环时,插槽会安排一个绘画事件进行处理。 然后由WigglyWidget的paintEvent()函数处理绘画事件。

六、总结

Wiggly Example 是一个有趣的小程序,要求能理解颜色空间的HSV模式,Qt字体的度量,通过这个小例子一窥基本计时器的功能。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值