美文网首页
Qt官方示例-摆动的文字

Qt官方示例-摆动的文字

作者: Qt君 | 来源:发表于2020-01-19 23:13 被阅读0次

    该示例演示了如何使用QBasicTimer和timerEvent对小部件进行动画处理和使用QFontMetrics确定屏幕上文本的大小。

    demo.gif

      QBasicTimer是计时器的低级类。与QTimer不同,QBasicTimer不会从QObject继承。它不会在经过一定时间后发出timeout()信号,而是将QTimerEvent发送到我们选择的QObject。这使QBasicTimer成为QTimer的更轻量级替代。主要用于高度优化或性能要求较高的应用程序(例如嵌入式应用程序)。

      该示例包含两个类:

    • WigglyWidget是自定义的小部件,摇摆地显示文本。
    • Dialog是允许用户输入文本的对话框小部件。它结合了WigglyWidgetQLineEdit

    Dialog类定义

      Dialog类提供了一个对话窗口小部件,允许用户输入文本。然后显示WigglyWidget。

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

    Dialog类实现

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

    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);
    } 
    

    WigglyWidget类定义

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

      QBasicTimertimer类用于定期更新文本窗口,从而使文本移动。text变量用于存储当前显示的文本,并根据step计算摇摆线上每个字符的位置和颜色。

    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类的实现

      在构造函数中,我们使用QPalette::Midlight颜色WigglyWidget窗口的背景比通常的背景略浅。setFont为设置绘制背景的调色板中的画笔和字体大小。

      最后,我们启动计时器,调用QBasicTimer::start()可确保WigglyWidget接收计时器超时(每60毫秒)时生成的计时器事件,从而刷新文本动画。

    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);
    }
    

      sineTable表示正弦曲线的y值乘以100。它用于使WigglyWidget沿正弦曲线移动。

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

    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;
    

      每次paintEvent()调用该函数时,我们都会创建一个QPainter对象painter用于绘制窗口的内容。对于其中的每个字符text,我们根据step来确定颜色和在摆动线上的位置。另外,x以字符的宽度递增。

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

        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]);
        }
    }
    

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

      需要注意的是,调用update()并不会立即执行重绘时间,需要等待Qt的事件循环返回后才会执行重绘操作。

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

    关于更多

    • QtCreator软件可以找到:
    what_find.png
    • 或在以下Qt安装目录找到:
    C:\Qt\{你的Qt版本}\Examples\{你的Qt版本}\widgets\widgets\wiggly
    
    • 相关链接
    https://doc.qt.io/qt-5/qtwidgets-widgets-wiggly-example.html
    
    • Qt君公众号回复『Qt示例』获取更多内容。

    相关文章

      网友评论

          本文标题:Qt官方示例-摆动的文字

          本文链接:https://www.haomeiwen.com/subject/mrmdzctx.html