Qt 绘图
Qt 绘图
8.1 QPainter 基本绘图
8.1.1 QPainter 绘图系统
Qt的二维图形绘制基本上是使用QPainter在绘图设备上绘图,绘图设备包括QWidget、QPixmap等,通过绘制一些基本的点,线、圆等基本图形,得到的图形是不可交互操作的图形。
1.QPainter与QPaintDevice
Qt的绘图系统基于QPainter、QPaintDevice、QPaintEngine类。QPainter 是专门用来绘图操作的类,QPaintDevice是使QPainter可以进行绘图的二维界面。QPaintEngine给QPainter提供在不同绘图设备上的接口。
一般的绘图设备包括QWidget、QPixmap、QImage等,这些绘图设备为QPainter提供一个“画布“。
2.paintEvent事件和绘图区
QWidget及其子类是最常用的绘图设备,从QWidget类继承的子类都有paintEvent()事件。要在设备上绘图,只需重定义此事件并编写响应代码。创建一个QPainter对象获取绘图设备接口,然后就可以在绘图设备的”画布“上绘图了。
QWidget的绘图区域就是其窗口内部区域。如图:
QWidget 内部的绘图区的坐标系统的单位是像素。左上角坐标为(0,0),向右是X轴正方向,向下是Y轴正方向,绘图区的宽度由QWidget::width()函数获取,高度由QWidget::height()函数获取。这个坐标系统是QWidget绘图区的局部物理坐标,称为视口(viewport)坐标,相应的还有逻辑坐标,被称为窗口(window)坐标。
3.QPainter绘图的主要属性
①pen 属性:是一个QPen对象,用于控制线条的颜色、宽度、线型等。
②brush 属性:是一个QBrush对象,用于设置一个区域的填充特性,可以设置填充颜色、填充方式、渐变特性等,还可以采用图片作为材质填充。
③Font 属性:是一个QFont对象,用于绘制文字时,设置文字的字体样式、大小等属性。
下面是一个使用QPainter绘图示例:
第一步:在构造函数中添加了如下代码,将QMainWindow居中:
// 或者,如果你想先将窗口设置为居中,然后再最大化
// 首先计算屏幕中心点的位置
QRect screenGeometry = QApplication::primaryScreen()->availableGeometry();
int x = (screenGeometry.width() - this->width()) / 2;
int y = (screenGeometry.height() - this->height()) / 2;
// 将窗口移动到屏幕中心
this->move(x, y);
// 然后最大化窗口
this->showMaximized();
// 设置窗口为白色背景
setPalette(QPalette(Qt::white));
setAutoFillBackground(true);
第二步:重载paintEvent,在实现中编写代码:
void MainWindow::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
painter.setRenderHint(QPainter::TextAntialiasing);
// 绘图区宽度
int nW = width();
// 绘图区高度
int nH = height();
// 中间区域矩形框
QRect rect(nW/4,nH/4,nW/2,nH/2);
QPen pen;
pen.setWidth(3);
pen.setColor(Qt::red);
// 线的样式、实线、虚线等
pen.setStyle(Qt::SolidLine);
// 线端点样式
pen.setCapStyle(Qt::FlatCap);
// 线的连接点样式
pen.setJoinStyle(Qt::BevelJoin);
painter.setPen(pen);
// 设置画刷
QBrush brush;
// 设置画刷颜色
brush.setColor(Qt::yellow);
// 画刷填充样式
brush.setStyle(Qt::SolidPattern);
painter.setBrush(brush);
// 绘图
painter.drawRect(rect);
}
上述代码设置了QPen 和画刷对象后,调用QPainter的drawRect函数绘制矩形。
绘制效果如下:
8.1.2 QPen 主要功能
QPen 用于对线条进行设置,主要包括线宽、颜色、线型等。QPen的主要函数,参考Qt文档即可。除了颜色和线宽,QPen影响线条的另外3个属性是线条样式(style)、端点样式(capStyle)、连接样式(joinStyle)。
1.线条样式(style)
QPen的setStyle()函数用于设置线条样式。参数是一个枚举类型Qt::PenStyle的常量。参考Qt文档效果如下:
除了基本样式外,用户还可以自定义线条样式,自定义线条样式需要用到setDashOffset()和setDashPattern()函数。
2.端点样式(capStyle)
QPen的setCapStyle()函数用于设置线条样式。参数是一个枚举类型Qt::PenCapStyle的常量。参考Qt文档效果如下:
3.连接样式(joinStyle)
QPen的setJoinStyle()函数用于设置连接样式。参数是一个枚举类型Qt::PenJoinStyle的常量。参考Qt文档效果如下:
8.1.3 QBrush 主要功能
QBrush 定义了QPainter绘图时的填充特性,包括填充颜色、填充样式、填充材质。使用setBrush来设置填充样式,参数是Qt::BrushStyle枚举类型。效果如下:
渐变填充需要专门的类来设置,使用材质填充时需要设置材质图片。
使用材质填充示例如下:
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
painter.setRenderHint(QPainter::TextAntialiasing);
// 绘图区宽度
int nW = width();
// 绘图区高度
int nH = height();
// 中间区域矩形框
QRect rect(nW/4,nH/4,nW/2,nH/2);
QPen pen;
pen.setWidth(3);
pen.setColor(Qt::red);
// 线的样式、实线、虚线等
pen.setStyle(Qt::SolidLine);
// 线端点样式
pen.setCapStyle(Qt::FlatCap);
// 线的连接点样式
pen.setJoinStyle(Qt::BevelJoin);
painter.setPen(pen);
QPixmap pixmap(":Images/Image/texture.jpg");
QBrush brush;
// 画刷填充样式
brush.setStyle(Qt::TexturePattern);
// 设置材质图片
brush.setTexture(pixmap);
painter.setBrush(brush);
// 绘图
painter.drawRect(rect);
效果如下图:
8.1.4 渐变系统
使用渐变填充需要用渐变类的对象作为QPainter 的brush,有3个实现渐变填充的类。
①QLinearGradient:线性渐变,指定一个起点及其颜色,终点及其颜色,还可以指定中间的某个点的颜色,起点至终点的某个点的颜色会线性插值计算,得到线性渐变的填充颜色。
②QRadialGradient:有简单辐射渐变和扩展辐射渐变两种方式。简单辐射渐变是在一个圆内的一个焦点和一个端点之间生成渐变颜色。扩展辐射渐变是在一个焦点圆和一个中心圆之间生成渐变颜色。
③QConicalGradient:圆锥形渐变,围绕一个中心点逆时针生成渐变颜色。
效果如下图:
这3个渐变类都继承自QGradient,除了生成渐变的颜色方式不同之外,在设定的渐变颜色坐标范围之外,还需要用QGradient类的setSpread(QGradient::Spread method)函数设置延展方式。枚举类型QGradient::Spread有3种取值,分别对应3种延展效果。
PadSpread模式:是用结束点的颜色填充外部外部区域,这是默认的填充方式。
RepeatSpread模式:重复使用渐变方式填充外部区域。
ReflectSpread模式:反射方式使用渐变方式填充外部区域。
效果如下:
辐射渐变使用示例:
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
painter.setRenderHint(QPainter::TextAntialiasing);
// 绘图区宽度
int nW = width();
// 绘图区高度
int nH = height();
// 径向渐变
QRadialGradient radialgradient(nW/2,nH/2,qMax(nW/8,nH/8),nW/2,nH/2);
radialgradient.setColorAt(0,QColor(Qt::green));
radialgradient.setColorAt(1,QColor(Qt::blue));
radialgradient.setSpread(QGradient::ReflectSpread);
painter.setBrush(radialgradient);
// 绘图,填充更大区域,会有延展效果
painter.drawRect(this->rect());
运行效果如下:
8.1.5 QPainter绘制基本图形元件
QPainter 提供了很多绘制基本图形的功能,包括点、直线、椭圆、矩形、曲线等,由这些基本图形可以构成复杂的图形。
1.绘制基本图形:
代码如下:
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
painter.setRenderHint(QPainter::TextAntialiasing);
// 绘图区宽度
int nW = width();
// 绘图区高度
int nH = height();
QRect rect0(0,0,100,100);
// 起始90°
int nStartAngle = 90*16;
// 旋转90°
int nRotate = 90*16;
// 绘制曲线
painter.drawArc(rect0,nStartAngle,nRotate);
// 绘制一段弦
QRect rect1(100 ,0,100,100);
painter.drawChord(rect1,nStartAngle,nRotate);
// 根据给定的点画凸多边形
QPoint pts[] = {
QPoint(5*nW/12,nH/4),
QPoint(3*nW/4,5*nH/12),
QPoint(5*nW/12,3*nH/4),
QPoint(nW/4,5*nH/12)
};
painter.drawConvexPolygon(pts,4);
// 绘制椭圆
QRect rect2(200,0,100,50);
painter.drawEllipse(rect2);
// 在指定的区域内绘制图片
QRect rect3(300,0,100,100);
QImage image(":Images/Image/qt.jpg");
painter.drawImage(rect3,image);
// 画直线
QLine line(400,0,500,100);
painter.drawLine(line);
// 画一批直线
QRect rect4(500,0,100,100);
QVector<QLine> vtLines;
vtLines.append(QLine(rect4.topLeft(),rect4.bottomRight()));
vtLines.append(QLine(rect4.topRight(),rect4.bottomLeft()));
vtLines.append(QLine(rect4.topLeft(),rect4.bottomLeft()));
vtLines.append(QLine(rect4.topRight(),rect4.bottomRight()));
painter.drawLines(vtLines);
// 绘制由QPainterPath对象定义的路线
QRect rect5(605,0,100,100);
QPainterPath path;
path.addEllipse(rect5);
path.addRect(rect5);
painter.drawPath(path);
// 绘制扇形
QRect rect6(705,0,100,100);
int nStartAngle1 = 40*16;
int nRotate1 = 120*16;
painter.drawPie(rect6,nStartAngle1,nRotate1);
// 绘制Pixmap图片
QRect rect7(805,0,100,100);
QPixmap pixmap(":Images/Image/qt.jpg");
painter.drawPixmap(rect7,pixmap);
// 画一个点
painter.drawPoint(QPoint(855,0));
// 画一批点
QPoint points[]= {
QPoint(5*nW/12,nH/4),
QPoint(3*nW/4,5*nH/12),
QPoint(2*nW/4,5*nH/12)
};
painter.drawPoints(points,3);
// 绘制多变形
QPoint pts2[]= {
QPoint(5*nW/12,nH/4),
QPoint(3*nW/4,5*nH/12),
QPoint(5*nW/12,3*nH/4),
QPoint(2*nW/4,5*nH/12)
};
painter.drawPolygon(pts2,4);
// 画多点连接的线,最后一个点不会和第一个点连接
QPoint pts3[]= {
QPoint(5*nW/12,nH/4),
QPoint(3*nW/4,5*nH/12),
QPoint(5*nW/12,3*nH/4),
QPoint(2*nW/4,5*nH/12),
};
painter.drawPolyline(pts3,4);
// 绘制圆角矩形
QRect rect8(900,0,100,50);
painter.drawRoundedRect(rect8,20,20);
// 绘制文本,只能绘制单行文本,字体的大小等属性由QPainter::font()决定
QRect rect9(1000,0,100,100);
QFont font;
font.setPointSize(30);
font.setBold(true);
painter.setFont(font);
painter.drawText(rect9,"Hello Qt");
// 擦除某个区域,等效于用背景色填充该区域
QRect rect10(1100,0,100,100);
painter.eraseRect(rect10);
// 填充某个QPainterPath定义的绘图路径,但是轮廓线不显示
QRect rect11(0,200,100,100);
QPainterPath path1;
path1.addEllipse(rect11);
path1.addRect(rect11);
painter.fillPath(path1,Qt::red);
// 填充一个矩形,无边框线
QRect rect12(100,200,100,100);
painter.fillRect(rect12,Qt::green);
代码运行结果:
2.QPainterPath的使用
QPainterPath是一系列绘图操作的顺序集合,便于重复使用。一个QPainterPath由许多基本的绘图操作完成,如绘图点移动、划线、画圆、画矩形等,一个闭合的QPainterPath是终点和起点连接起来的绘图路径。
说明:上面的描述来自《Qt 5.9 C++开发指南》一书中,需要更加详细的说明,请参考该书。
上述源码:Gitee