重绘事件
根据博客园这篇文章的介绍:
在Qt中,paintEvent方法是进行重绘的,只要出现以下几种情况,系统就会自动调用paintEvent方法。
a)当窗口部件第一次显示时,系统会自动产生一个绘图事件
b)重新调整窗口部件大小
c)当窗口部件被其他部件遮挡,然后又再次显示出来时,就会对隐藏的区域产生一个重绘事件也可以通过调用QWidget::update()和QWidget::repaint()来产生一个绘图事件,其中repaint会强制产生一个即时的重绘事件,update会在Qt下一次处理事件时才会调用绘制事件,如果窗口部件在屏幕上是不可见的,则update和repaint什么都不会做。如果连续多次调用update方法,Qt会自动的将其压缩为一个单一的绘制事件,避免闪烁现象
因此,要实现绘图操作,就需要重写该函数,该函数不需要主动调用,也不需要关联到信号上,系统将会自动调用。
函数的原型:
[virtual protected] void QWidget::paintEvent(QPaintEvent *event)
绘制基本图形
在绘图事件中,可以通过QPainter画家类进行绘制操作。并可以给画家设置画笔QPen、画刷QBrush。
void GameWnd::paintEvent(QPaintEvent *event)
{
QPainter painter(this); // 创建画家对象,并指定其绘图设备
QPen pen(QColor(255, 102, 102)); // 创建画笔,可以指定绘图的线条颜色
// 设置画笔宽度、风格
pen.setWidth(5);
pen.setStyle(Qt::DashDotLine);
// 绘制直线
painter.drawLine(0, 0, 100, 100);
// 设置画家的画笔
painter.setPen(pen);
// 绘制矩形
painter.drawRect(20, 20, 100, 80);
QBrush brush(Qt::cyan); // 创建画刷,指定颜色,画刷的作用是绘制图形内部颜色
brush.setStyle(Qt::Dense3Pattern); // 设置风格
painter.setBrush(brush);
// 绘制圆形
painter.drawEllipse(QPoint(100, 100), 50, 50);
// 绘制文字
painter.drawText(10, 150, "这是一段文本内容");
painter.drawText(QRect(10, 180, 100, 50), "这是一段文本内容");
}
还可以进行一些其他的操作,例如抗锯齿、坐标系统移动及还原:
// 设置抗锯齿
painter.setRenderHint(QPainter::Antialiasing);
painter.drawEllipse(QPoint(100, 200), 50, 50);
// 保存画家状态
painter.save();
// 移动画家
painter.translate(100, 0); // 坐标系横移了100
painter.drawEllipse(QPoint(100, 200), 50, 50);
// 还原状态
painter.restore();
绘制资源图像
使用画家QPainter
的drawPixmap
函数可以绘制资源图片。该函数有多个重载:
void
drawImage(const QRectF &target, const QImage &image, const QRectF &source, Qt::ImageConversionFlags flags = Qt::AutoColor)
void
drawImage(const QRect &target, const QImage &image, const QRect &source, Qt::ImageConversionFlags flags = Qt::AutoColor)
void
drawImage(const QPointF &point, const QImage &image, const QRectF &source, Qt::ImageConversionFlags flags = ...)
void
drawImage(const QPoint &point, const QImage &image, const QRect &source, Qt::ImageConversionFlags flags = ...)
void
drawImage(const QRectF &rectangle, const QImage &image)
void
drawImage(const QRect &rectangle, const QImage &image)
void
drawImage(const QPointF &point, const QImage &image)
void
drawImage(const QPoint &point, const QImage &image)
void
drawImage(int x, int y, const QImage &image, int sx = 0, int sy = 0, int sw = -1, int sh = -1, Qt::ImageConversionFlags flags = Qt::AutoColor)
可以实现多种绘制方式,并可以进行缩放绘制。
另外在绘制前可以先通过painter.translate
,传入图片宽高一半,使坐标中心点移动到图片中心,然后再通过painter.rotate
传入度数值进行旋转,就可以使图片中心旋转,绘制之后再通过painter.translate
复原原点。
示例:滚动背景绘制
1)将背景图添加到资源文件中,并在代码中创建背景图对象
类声明中定义:
QPixmap *m_pBgPixmap; // 背景图资源
类实现中加载图片资源:
m_pBgPixmap = new QPixmap(":/imgs/bg");
2)在重绘定时器中调用repaint函数,触发重绘事件,并在重绘事件中调用绘制函数绘制滚动背景,为了记录滚动耗时,需要定义一个耗时计时器:
QElapsedTimer countScroll; // 记录时间间隔
在程序启动时启动计时定时器:
countScroll.start();
定义一个绘制背景图的函数,在重绘事件中调用:
void GameWnd::paintScene()
{
int sw = m_pBgPixmap->width();
int sh = m_pBgPixmap->height();
int dw = this->width();
int dh = this->height();
static float scrollTime = 0.0f;
scrollTime += countScroll.elapsed();
countScroll.restart();
if (scrollTime >= 20000)
{
scrollTime = 0.0f;
}
// 计算卷动高度
int shScroll = (int)(scrollTime / 20000 * sh);
//qDebug() << "卷动高度:" << shScroll;
// 分两部分绘制
QPainter painter(this);
painter.drawPixmap(0, 0, dw, shScroll, *m_pBgPixmap, 0, sh - shScroll, sw, shScroll);
painter.drawPixmap(0, shScroll, dw, dh - shScroll, *m_pBgPixmap, 0, 0, sw, sh - shScroll);
}