从Qt官方给的例程可以看出,如果想将绘图加入事件循环共有两种方式:绘图事件和定时器事件两种方式,通常使用前者。
(一) painterEvent
在绘图事件中,如果想使用update()刷新页面是行不通的,除非使用新的定时器定时刷新页面。painterEvent来自QWidget的virtual protected function,其他一些控件例如QLabel、QLineEdit、QMenuBar等的painterEvent也是继承QWidget的。所以这些有继承QWidget的类中基本都存在painterEvent。
————————————————
在画图之前需要前置知识点:
(1) Qt坐标系统
https://blog.csdn.net/hgcprg/article/details/53537106
https://www.cnblogs.com/lifexy/p/9203929.html
(二)TimerEvent
在timerEvent就比较容易控制绘图的刷新了,因为是定时器事件,可以控制时间。在官方例程中也提供了这种方法:
/**
* PathDeform.h
*/
#ifndef PATHDEFORM_H
#define PATHDEFORM_H
#include "arthurwidgets.h"
#include <QPainterPath>
#include <QBasicTimer>
#include <QDateTime>
class PathDeformRenderer : public ArthurFrame
{
Q_OBJECT
Q_PROPERTY(bool animated READ animated WRITE setAnimated)
Q_PROPERTY(int radius READ radius WRITE setRadius)
Q_PROPERTY(int fontSize READ fontSize WRITE setFontSize)
Q_PROPERTY(int intensity READ intensity WRITE setIntensity)
Q_PROPERTY(QString text READ text WRITE setText)
public:
PathDeformRenderer(QWidget *widget, bool smallScreen = false);
void paint(QPainter *painter);
void mousePressEvent(QMouseEvent *e);
void mouseReleaseEvent(QMouseEvent *e);
void mouseMoveEvent(QMouseEvent *e);
void timerEvent(QTimerEvent *e);
QSize sizeHint() const { return QSize(600, 500); }
bool animated() const { return m_animated; }
int radius() const { return int(m_radius); }
int fontSize() const { return m_fontSize; }
int intensity() const { return int(m_intensity); }
QString text() const { return m_text; }
public slots:
void setRadius(int radius);
void setFontSize(int fontSize) { m_fontSize = fontSize; setText(m_text); }
void setText(const QString &text);
void setIntensity(int intensity);
void setAnimated(bool animated);
signals:
void clicked();
private:
void generateLensPixmap();
QPainterPath lensDeform(const QPainterPath &source, const QPointF &offset);
QBasicTimer m_repaintTimer;
QTime m_repaintTracker;
QVector<QPainterPath> m_paths;
.......
};///
/**
* PathDeform.cpp
*/
void PathDeformRenderer::timerEvent(QTimerEvent *e)
{
if (e->timerId() == m_repaintTimer.timerId()) { //判断定时器id是否绘图定时器的ID
if (QLineF(QPointF(0,0), m_direction).length() > 1)
m_direction *= 0.995;
qreal time = m_repaintTracker.restart();
QRect rectBefore = circle_bounds(m_pos, m_radius, m_fontSize);
qreal dx = m_direction.x();
qreal dy = m_direction.y();
if (time > 0) {
dx = dx * time * .1;
dy = dy * time * .1;
}
m_pos += QPointF(dx, dy);
if (m_pos.x() - m_radius < 0) {
m_direction.setX(-m_direction.x());
m_pos.setX(m_radius);
} else if (m_pos.x() + m_radius > width()) {
m_direction.setX(-m_direction.x());
m_pos.setX(width() - m_radius);
}
if (m_pos.y() - m_radius < 0) {
m_direction.setY(-m_direction.y());
m_pos.setY(m_radius);
} else if (m_pos.y() + m_radius > height()) {
m_direction.setY(-m_direction.y());
m_pos.setY(height() - m_radius);
}
#ifdef QT_OPENGL_SUPPORT
if (usesOpenGL()) {
update();
} else
#endif
{
QRect rectAfter = circle_bounds(m_pos, m_radius, m_fontSize);
update(rectAfter | rectBefore);
QApplication::syncX();
}
}
}
void PathDeformRenderer::mouseReleaseEvent(QMouseEvent *e)
{
if (e->buttons() == Qt::NoButton && m_animated) {
m_repaintTimer.start(10, this);
m_repaintTracker.start();
}
if (!m_mouseDrag && m_smallScreen)
emit clicked();
}
然后其他地方启动绘图的定时器即可。