学了qss之后会了一些美化,但是发现还有很多qss没法实现,那么这个文章就适合你了
当然不喜欢使用qss的比如我,也可以通过该文章快速学习通过重载paintEvent来绘制你想要的控件
paintEvent是一个虚函数,需要子类进行重载才能实现自定义绘制
paintEvent是一个绘制函数,会在调用后绘制图形
示例
这里先给出一个示例,然后来逐步解析这个示例让你理解
1 | void QtWidget::paintEvent(QPaintEvent* Event) { |
这样一段简单的代码你就得到了一个圆
接下来逐步解析这段代码
1 | QWidget::paintEvent(Event); |
这段代码,是调用父类的绘制函数,来绘制一些默认和设置过后的图形
1 | QPainter painter(this); |
声明了一个QPainter对象,它是一个画笔,可以用来绘制你想在控件上绘制的图形
QPainter的构造函数需要传入QPainterDevice,你不知道这是啥,没关系,你只要知道Qt中所有的控件都是它的子类就行了
这里我们传入了当前对象的指针,作为这个QPainter的绘图设备
1 | QPen pen(QColor("#b883a0")); |
这里传入了一个QColor也就是颜色去构造pen,QPen是一个画笔,当然它和前面的QPainter不一样,它储存着画笔的信息,是用来画图形的边框的
1 | QBrush brush(QColor("#b883a0")); |
QBrush是一个画刷,它储存的是填充封闭图形的画刷的信息
1 | painter.setPen(pen); |
这里应该不用过多解释了,将pen和brush分别传入painter中
1 | painter.drawEllipse(QRect(0, 0, width(), height())); |
painter对象调用了drawEllipse函数绘制了一个圆,传入了一个QRect,QRect构造函数中的参数分别是(x轴坐标,y轴坐标,控件的宽,控件的高)
更多的绘制函数,可以参阅Qt文档 里面有解释
1 | painter.end(); |
最后调用end函数,结束绘画,当然不止end函数能结束绘制,销毁painter也是会结束绘制的
实现了这么个窗口
相信到这里已经明白paintEvent函数后需要干什么和怎样绘制自己想要的控件了
解释部分
上文没有讲到的类
QFont
这是一个字体类,里面储存了字体的信息,传入QPainter对象后,会在调用drawText时被读取
paintEvent的触发时机和方式
接下来说paintEvent会在什么时候被调用
- show()
这是一个显示函数,它会调用paintEvent来绘制图形,注意,只有在被隐藏之后调用show()才会调用paintEvent来绘制,已经调用一次show()且没有调用hide()隐藏是不会调用paintEvent来重绘的,如果状态改变了需要重绘可以看下文的两个函数 - updata()
这是一个重绘函数,它不会立即调用paintEvent来重绘图形,它会返回主事件循环时安排一个绘制事件进行处理,Qt会对其优化速度和减少闪烁,updata()在调用之后通常只会调用一次paintEvent,当然也会有例外,见下文给出的文章 - repaint()
这是一个重绘函数,它会直接调用paintEvent来重绘图形
这个函数有风险,可能会一直递归循环调用父类的paintEvent,最好是在需要快速重绘的时候,比如动画等等,再去调用 - 窗口大小修改后
比如拉动窗口边缘去改变窗口大小的时候就会直接调用paintEvent函数去重绘图形
Qt的文档给出了说明:
Warning: If you call repaint() in a function which may itself be called from paintEvent(), you may get infinite recursion. The update() function never causes recursion.
自定义绘制paintEvent方法导致的递归循环 文章有解释,可以去看看
优缺点
优点当然是自定义程度高,可以绘制一切你想绘制的图形
缺点对于小白来说,复用性不高,可能这个类到另外一个场景就要再写一个,当然使用一些时间后就会知道如何增加复用性
去增加几个成员变量,在使用paintEvent去绘制时根据你的成员变量去绘制也能提高复用性
比如
1 | // QtWidget.h |
这里面就定义了两个成员变量,在paintEvent中绘制,增加了复用性
本文就到这里了,如果有什么地方写错了,可以在下面提出来