該示例演示瞭如何使用QBasicTimer和timerEvent對小部件進行動畫處理和使用QFontMetrics肯定屏幕上文本的大小。
QBasicTimer
是計時器的低級類。與QTimer不一樣,QBasicTimer不會從QObject繼承。它不會在通過必定時間後發出timeout()
信號,而是將QTimerEvent發送到咱們選擇的QObject。這使QBasicTimer成爲QTimer的更輕量級替代。主要用於高度優化或性能要求較高的應用程序(例如嵌入式應用程序)。 html
該示例包含兩個類:ide
WigglyWidget
是自定義的小部件,搖擺地顯示文本。Dialog
是容許用戶輸入文本的對話框小部件。它結合了WigglyWidget
和QLineEdit
。Dialog類提供了一個對話窗口小部件,容許用戶輸入文本。而後顯示WigglyWidget。函數
class Dialog : public QDialog { Q_OBJECT public: explicit Dialog(QWidget *parent = nullptr); };
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類提供了波浪線顯示文本。咱們將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; };
在構造函數中,咱們使用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
沿正弦曲線移動。this
而QFontMetrics對象提供有關文本的字體信息。該x變量是水平位置,是表示開始繪製文本的位置。y變量是文本基線的垂直位置。計算兩個變量以使文本在水平和垂直居中。爲了計算基線,咱們考慮了字體的上升(基線上方的字體的高度)和字體的降低(基線下方的字體的高度)。若是降低等於上升,則它們會相互抵消,而且基線位於height()/2
處。spa
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::horizontalAdvance(text)
返回單個字符進度的總和QFontMetrics::horizontalAdvance(text[i]))
。實際上,狀況並不是老是如此,由於QFontMetrics::horizontalAdvance(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); } ... }
C:\Qt\{你的Qt版本}\Examples\{你的Qt版本}\widgets\widgets\wiggly
https://doc.qt.io/qt-5/qtwidgets-widgets-wiggly-example.html