该示例演示了如何使用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