Qt官方示例-擺動的文字

該示例演示瞭如何使用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示例』獲取更多內容。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章