一、概述虽然Qt已经内置了很多控件但是不能保证现有控件就可以应对所有场景。很多时候我们需要更强的“自定制”能力。Qt提供了画图相关的API可以允许我们在窗口上绘制任意的图像形状来完成更加复杂的界面设计。所谓的“控件”本质也是通过画图的方式画上去的画图API和控件之间的关系可以类比成机器指令和高级语言之间的关系控件是对画图API的进一步封装画图API是控件的底层实现绘图API核心类绘图API的使用一般不会在QWidget的构造函数中使用而是要放到painEvent事件中painEvent会在以下情况被触发控件首次创建控件被遮挡再解除遮挡窗口最小化再恢复控件的大小发生变化主动调用repain() 或 update()方法……因此如果把绘图api放到构造函数中调用那么一旦出现上诉情况界面的绘制效果就无法确保符合预期。二、各种形状绘制2.1 绘制线段void MainWindow::paintEvent(QPaintEvent *) { QPainter painter(this); // p1 - p2 painter.drawLine(QPoint(20, 50), QPoint(200, 50)); // x1,y1, - x2,y2 painter.drawLine(20, 100, 200, 100); }2.2 绘制矩形void MainWindow::paintEvent(QPaintEvent *) { QPainter painter(this); // x,y,width,height painter.drawRect(20, 20, 100, 50); }2.3 绘制圆形void MainWindow::paintEvent(QPaintEvent *) { QPainter painter(this); // center-pos, rX, rY 以点为圆心画一个rxry的圆 painter.drawEllipse(QPoint(100, 100), 50, 50); painter.drawEllipse(QPoint(100, 100), 20, 40); // x, y, w, h 在以x,y为左上角顶点画一个w * h的矩形然后画一个内切圆 painter.drawEllipse(100, 100, 100, 50); }2.4 绘制文本QPainter类 中不仅提供了绘制图形的功能还可以使⽤ QPainter::drawText() 函数来绘制⽂字也可以使⽤QPainter::setFont() 设置字体等信息。void MainWindow::paintEvent(QPaintEvent *) { QPainter painter(this); //需系统中存在该字体 QFont font(华文行楷, 24); painter.setFont(font); painter.setPen(Qt::green); painter.drawText(QRect(100, 100, 500, 500), Hey 画上灶炉与柴火); }三、绘制设置3.1 画笔1简介QPainter在绘制时存在一个默认画笔。在绘制时也可以自定义画笔。在Qt中QPen类定义了QPainter应该如何绘制形状、线条、轮廓。同时通过QPen类可以设置画笔的线宽、颜色、样式、画刷等设置画笔颜色Qpen::QPen(const QColor color)设置画笔宽度void QPen::setWidth(int width)设置画笔风格void QPen::setStyle(Qt::PenStyle style)2画笔风格enum PenStyle { // pen style NoPen, SolidLine, DashLine, DotLine, DashDotLine, DashDotDotLine, CustomDashLine #ifndef Q_MOC_RUN , MPenStyle 0x0f #endif };3示例void MainWindow::paintEvent(QPaintEvent *) { QPainter painter(this); QPen pen(QColor(255, 0, 0)); pen.setWidth(3); pen.setStyle(Qt::DashLine); painter.setPen(pen); painter.drawEllipse(QPoint(100, 100), 50, 50); }3.2 画刷1简介在Qt中使用QBrush类来描述画刷画刷大多用于填充。QBrush定义了QPainter的填充模式具有样式、颜色、渐变、纹理等属性。画刷的格式中定义了填充的样式使用Qt::BrushStyle枚举默认值是Qt::NoBrush也就是不进行任何填充。2画刷格式3示例void MainWindow::paintEvent(QPaintEvent *) { QPainter painter(this); //设置画笔 QPen pen(QColor(255, 0, 0)); pen.setWidth(3); pen.setStyle(Qt::DashLine); painter.setPen(pen); //设置画刷 QBrush brush(Qt::blue); brush.setStyle(Qt::Dense1Pattern); painter.setBrush(brush); painter.drawEllipse(QPoint(100, 100), 50, 50); }四、绘制图片4.1 简介Qt提供了四个类来处理图像数据QImage、QPixmap、QBitmap、QPicture,他们都是常用的绘图设备。QImage主要用于进行I/O处理它对I/O处理操作进行了优化可以用来直接访问和操作像素QPixmap主要用于在屏幕上显示图像它针对屏幕上显示图像进行了优化QBitmap是QPixmap的子类用于处理颜色深度为1的图像即只能显示黑白两种颜色QPicture用于记录并重演QPainter命令4.2 绘制简单图片void MainWindow::paintEvent(QPaintEvent *) { QPainter painter(this); painter.drawPixmap(0, 0, QPixmap(getPictureFilePath())); }4.3 平移图片平移图片实际是通过改变坐标来实现QPainter类中提供了translate()函数来实现坐标原点的改变。void MainWindow::paintEvent(QPaintEvent *) { QPainter painter(this); painter.translate(100, 100); painter.drawPixmap(0, 0, QPixmap(getPictureFilePath())); }4.4 缩放图片在Qt中图片的放大和缩小可以使用QPainter类中的drawPixmap()重载函数来实现void MainWindow::paintEvent(QPaintEvent *) { QPainter painter(this); //绘制点5050图片尺寸w*h: 100 * 120 painter.drawPixmap(50, 50, 100, 120, QPixmap(getPictureFilePath())); }4.5 旋转图片图片的旋转使用的是QPainter类中的rotate()函数它默认以原点为中心进行旋转如果需要改变中心使用translate()函数改变当前绘制原点。void MainWindow::paintEvent(QPaintEvent *) { QPainter painter(this); //转移绘制原点 painter.translate(100, 200); //设置旋转角度: 正-顺时针负-逆时针 painter.rotate(90); painter.translate(-100, -200); painter.drawPixmap(0, 0, 100, 100, QPixmap(getPictureFilePath())); }注意每次translate移动的坐标都是以当前原点进行计算①原点移动到100 200以窗口原点参照原点位置100 200x轴→y轴↓②顺时针旋转90度以窗口原点参照原点位置100 200 x轴↓y轴←③原点移动到-100 -200以窗口原点参照原点位置300 100 x轴↓y轴←④绘制图片以窗口原点参照图片位置300 100顺时针旋转90度五、绘画设置5.1 移动画家位置在需要进行多次绘制时如果想使用同一坐标那么绘制出来的图形会出现重合此时可以移动画家位置来避免。void MainWindow::paintEvent(QPaintEvent *) { QPainter painter(this); //坐标原点00 painter.drawEllipse(QPoint(100, 100), 50, 50); painter.translate(200, 0); //坐标原点200, 0 painter.drawEllipse(QPoint(100, 100), 50, 50); }5.2 保存/加载画家状态在绘制的过程中可以使用save()来保存画家的状态使用restore()来恢复画家的状态。注意save是以栈结构保存当前状态restore就是从栈中取出栈顶所以可以保存多个状态再逐个取出遵循后进先出原则如果多调用了restore()qt会做判空检测不会崩溃暂不确定是否所有qt版本都会兜底最好确保save与restore成对出现如果少调用了restore会导致绘画状态残留可能导致后续所有绘制偏离预期void MainWindow::paintEvent(QPaintEvent *) { QPainter painter(this); painter.save(); //保存状态 //移动画家 painter.translate(200, 100); painter.drawEllipse(QPoint(0, 0), 50, 50); //还原状态 painter.restore(); painter.drawRect(0, 0, 50, 50); }六、特殊的绘图设备一般常用的绘图设备为QWidget在Qt中还存在下列三个比较特殊的绘图设备QPixmap用于在显示器上显示图片QImage用于对图片进行像素级修改QPicture用于对QPinter的一系列操作进行存档6.1 QPixmap核心特性使用QPainter直接在上面进行绘制图形通过文件路径加载并显示图片搭配QPinter的drawPixmap()函数可以将该图片绘制到一个QWidget上和系统/显示设备强相关不同系统/显示设备下QPixmap的显示可能会有所差异示例void MainWindow::myDraw() { QPixmap pix(500, 500); pix.fill(Qt::white); //填充图片背景 QPainter painter(pix); painter.setPen(Qt::red); painter.drawEllipse(QPoint(100, 100), 100, 100); //保存绘制的图片 QString strSavePath QDir(getPictureFileDir()).filePath(pix.png); if (!pix.save(strSavePath)) { qWarning() Failed to save image: strSavePath; } }执行后会将绘制的图片保存到指定位置6.2 QImage核心特性使用QPainter直接在上面进行绘制图形通过文件路径加载并显示图片能够针对图片进行像素级别的操作操作某个指定的像素独立于硬件的绘制系统能够在不同系统之上提供一致的显示示例① 使用QImage绘图设备进行绘图void MainWindow::myDraw() { //绘图设备大小500*500绘图格式QImage::Format_RGB32 QImage img(500, 500, QImage::Format_RGB32); img.fill(Qt::white); //填充图片背景 QPainter painter(img); painter.setPen(Qt::green); painter.drawEllipse(QPoint(100, 100), 100, 100); //保存绘制的图片 QString strSavePath QDir(getPictureFileDir()).filePath(img.png); if (!img.save(strSavePath)) { qWarning() Failed to save image: strSavePath; } }②使用QImage加载图片并针对指定像素进行修改void MainWindow::paintEvent(QPaintEvent *) { QPainter painter(this); QImage img; img.load( QDir(getPictureFileDir()).filePath(img.png)); //修改像素点 for(int i 100; i 200; i) { for(int j 100; j 200; j) { QRgb rgb qRgb(0, 0, 255); img.setPixel(i, j, rgb); } } //将修改后的图片绘制到当前widget中 painter.drawImage(0, 0, img); }6.3 QPicture核心特性使用QPainter直接在上面进行绘图通过文件路径加载并显示图片能够记录QPainter的操作步骤独立于硬件的绘制系统能够在不同的系统上提供一致的显示注意QPicture加载的必须是自身的存档文件不能是任意的png、jpg等图片文件记录QPainter的命令需要先使用QPinter::begin()函数将QPicture实例作为参数传递进去以便告诉系统开始记录记录完毕后使用QPainter::end()命令终止示例MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui-setupUi(this); QPicture pic; QPainter painter; painter.begin(pic);//开始绘制 painter.setPen(Qt::blue); painter.drawEllipse(QPoint(200, 200), 100, 100); painter.end();//结束绘制 pic.save(getPictureFileDir() pic.pic); } void MainWindow::paintEvent(QPaintEvent *) { QPainter painter(this); //重现绘图指令 QPicture pic; pic.load(getPictureFileDir() pic.pic); painter.drawPicture(0, 0, pic); }