时间:2021-07-01 10:21:17 帮助过:29人阅读
Qt中提供了强大的2D绘图系统,可以使用相同的API在屏幕和绘图设备上进行绘制,主要基于QPainter、QPaintDevice和QPaintEngine这3个类。其中,QPainter类用来执行绘图操作;QPaintDevice类提供绘图设备(绘图设备类QPaintDevice是所有可以绘制的对象的基类,它
Qt中提供了强大的2D绘图系统,可以使用相同的API在屏幕和绘图设备上进行绘制,主要基于QPainter、QPaintDevice和QPaintEngine这3个类。其中,QPainter类用来执行绘图操作;QPaintDevice类提供绘图设备(绘图设备类QPaintDevice是所有可以绘制的对象的基类,它的子类主要有QWidget、QPixmap、QPicture、QImage和QPrinter),是一个二维空间的抽象,可以使用QPainter在其上进行绘制;QPaintEngine类提供了一些接口,可以用于QPainter在不同的设备上进行绘制。
绘图系统中由QPainter来完成具体的绘制操作,提供了大量高度优化的函数来完成GUI编程所需要的大部分绘制工作。QPainter可以在继承自QPaintDevice类的任何对象上进行绘制操作。重点:QPainter一般在一个部件重绘(Paint Event)的处理函数paintEvent()中绘制;首先要创建QPainter对象,再进行图形的绘制,最后销毁QPainter对象。
QPainter提供的常用图形绘制函数
实例代码如下:
#include "widget.h" #include "ui_widget.h" #include采用QPainter::QPainter(QPaintDevice* device)构造函数创建的对象会立即开始在设备上绘制,自动调用begin()函数,然后在QPainter的析构函数中调用end()函数结束绘制。Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) { ui->setupUi(this); } Widget::~Widget() { delete ui; } void Widget::paintEvent(QPaintEvent *event) { QPainter painter(this); //绘制线条 painter.drawLine(QPoint(0, 0), QPoint(100, 100)); //创建画笔 QPen pen(Qt::green, 5, Qt::DotLine, Qt::RoundCap, Qt::RoundJoin); //使用画笔 painter.setPen(pen); QRectF rectangle(70.0, 40.0, 80.0, 60.0); int startAngle = 30 * 16; int spanAngle = 120 * 16; //绘制圆弧 painter.drawArc(rectangle, startAngle, spanAngle); //重新设置画笔 pen.setWidth(1); pen.setStyle(Qt::SolidLine); painter.setPen(pen); //绘制一个矩形 painter.drawRect(160, 20, 50, 40); //创建画刷 QBrush brush(QColor(0, 0, 255), Qt::Dense4Pattern); //使用画刷 painter.setBrush(brush); //绘制椭圆 painter.drawEllipse(220, 20, 50, 50); //设置纹理 brush.setTexture(QPixmap("../yafeilinux.png")); //重新使用画刷 painter.setBrush(brush); //定义四个点 static const QPointF points[4] = { QPointF(270.0, 80.0), QPointF(290.0, 10.0), QPointF(350.0, 30.0), QPointF(390.0, 70.0) }; //使用四个点绘制多边形 painter.drawPolygon(points, 4); //使用画刷填充一个矩形区域 painter.fillRect(QRect(10, 100, 150, 20), QBrush(Qt::darkYellow)); //擦除一个矩形区域的内容 painter.eraseRect(QRect(50, 0, 50, 120)); //线性渐变 QLinearGradient linearGradient(QPointF(40, 190), QPointF(70, 190)); //插入颜色 linearGradient.setColorAt(0, Qt::yellow); linearGradient.setColorAt(0.5, Qt::red); linearGradient.setColorAt(1, Qt::green); //指定渐变区域以外的区域的扩散方式 linearGradient.setSpread(QGradient::RepeatSpread); //使用渐变作为画刷 painter.setBrush(linearGradient); painter.drawRect(10, 170, 90, 40); //辐射渐变 QRadialGradient radialGradient(QPointF(200, 190), 50, QPointF(275, 200)); radialGradient.setColorAt(0, QColor(255, 255, 100, 150)); radialGradient.setColorAt(1, QColor(0, 0, 0, 50)); painter.setBrush(radialGradient); painter.drawEllipse(QPointF(200, 190), 50, 50); //锥形渐变 QConicalGradient conicalGradient(QPointF(350, 190), 60); conicalGradient.setColorAt(0.2, Qt::cyan); conicalGradient.setColorAt(0.9, Qt::black); painter.setBrush(conicalGradient); painter.drawEllipse(QPointF(350, 190), 50, 50); //画笔使用线性渐变来绘制直线和文字 painter.setPen(QPen(linearGradient,2)); painter.drawLine(0, 280, 100, 280); painter.drawText(150, 280, tr("helloQt!")); }
渐变填充:在Qt中,QGradient类就是用来和QBrush一起制定渐变填充的。
1、线性渐变在开始点和结束点之间插入颜色;
2、辐射渐变在焦点和环绕它的圆环间插入颜色;
3、锥形渐变在圆心周围插入颜色;
这3钟渐变分别由QGradient的3个子类来表示:QLinearQradient表示线性渐变、QRadialGradient表示辐射渐变和QConicalGradient表示锥形渐变。
抗锯齿渲染
QPainter进行绘制时可以使用QPainter::setRenderHint()函数渲染提示来指定是否要使用坑锯齿功能,其功能主要是对图像的边缘进行平滑处理,使其看起来更加柔和流畅。
坐标变换
QPainter的逻辑坐标与绘图设备(绘图设备的默认坐标系统中原点是(0, 0))的物理坐标之间的映射由QPainter的变换矩阵、视口和窗口处理,逻辑坐标和物理坐标默认是一致的。绘图时可以使用QPainter::scale()函数缩放坐标系统;使用QPainter::rotate()函数顺时针旋转坐标系统;使用QPainter::translate()函数平移坐标系统;使用QPainter::shear()围绕原点来扭曲坐标系统。
1、基本变换
坐标系统的2D变换由QTransform类实现,而且QTransform类对象可以存储多个变换操作,当同样的变换要多次使用时,建议使用QTransform类对象。坐标系统的变换是通过变换矩阵实现的,可以在平面上变换一个点到另一个点。进行所有变换操作的变换矩阵都可以使用QPainter::worldTransform()函数获得,如果要设置一个变换矩阵,可以使用QPainter::setWorldTransform()函数,这两个函数也可以分别使QPainter::transform()和QPainter::setTransform()函数来替代。
在进行变换操作时,可能需要多次改变坐标系统再恢复,这样就显得很乱,而且很容易出现操作错误。这时可以使用QPainter::save()函数来保存QPainter的变换矩阵,它会把变换矩阵保存到一个内部栈中,然后在需要恢复变换矩阵时再使用QPainter::restore()函数将其弹出。
2、窗口——视口转换
使用QPainter绘制时会使用到逻辑坐标,然后再转换为绘图设备的物理坐标。逻辑坐标到物理坐标的映射由QPainter的worldTransform()函数、QPainter的viewport()以及window()函数进行处理。其中,视口表示物理坐标下制定的一个任意矩形,而窗口表示逻辑坐标下的相同矩形。默认的,逻辑坐标和屋里坐标是重合的,都相当于绘图设备上的矩形。一个很好的办法是让视口和窗口维持相同的宽高比来防止变形:
int side = qMin(width(), height()); int x = (width() / 2); int y = (height() / 2); //设置窗口—视口转换 painter.setViewport(x, y, side, side);
窗口——视口转换仅仅是线性变换,不会执行裁剪操作,这就意味着如果绘制范围超出了当前设置的窗口,那么仍然会使用相同的线性代数方法将绘制变换到视口上。
#include "widget.h" #include "ui_widget.h" #includeWidget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) { ui->setupUi(this); } Widget::~Widget() { delete ui; } void Widget::paintEvent(QPaintEvent *event) { QPainter painter(this); //填充界面背景为白色 painter.fillRect(rect(), Qt::white); painter.setPen(QPen(Qt::red, 11)); //绘制一条线段 painter.drawLine(QPoint(5, 6), QPoint(100, 99)); //将坐标系统进行平移,使(200, 150)点作为原点 painter.translate(200, 150); //开启抗锯齿 painter.setRenderHint(QPainter::Antialiasing); //重新绘制相同的线段 painter.drawLine(QPoint(5, 6), QPoint(100, 99)); //保存painter的状态 painter.save(); //将坐标系统旋转90度 painter.rotate(90); painter.setPen(Qt::cyan); //重新绘制相同的线段 painter.drawLine(QPoint(5, 6), QPoint(100, 99)); //恢复painter的状态 painter.restore(); painter.setBrush(Qt::darkGreen); //绘制一个矩形 painter.drawRect(-50, -50, 100, 50); painter.save(); //将坐标系统进行缩放 painter.scale(0.5, 0.4); painter.setBrush(Qt::yellow); //重新绘制相同的矩形 painter.drawRect(-50, -50, 100, 50); painter.restore(); painter.setPen(Qt::blue); painter.setBrush(Qt::darkYellow); //绘制一个椭圆 painter.drawEllipse(QRect(60, -100, 50, 50)); //将坐标系统进行扭曲 painter.shear(1.5, -0.7); painter.setBrush(Qt::darkGray); //重新绘制相同的椭圆 painter.drawEllipse(QRect(60, -100, 50, 50)); }
#include "widget.h" #include "ui_widget.h" #include#include #include #include Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) { ui->setupUi(this); setMouseTracking(true); QTimer *timer = new QTimer(this); connect(timer, SIGNAL(timeout()), this, SLOT(update())); timer->start(1000); angle = 0; } Widget::~Widget() { delete ui; } void Widget::paintEvent(QPaintEvent *event) { angle += 10; if(angle == 360) angle = 0; int side = qMin(width(), height()); QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); QTransform transform; transform.translate(width()/2, height()/2); transform.scale(side/300.0, side/300.0); transform.rotate(angle); painter.setWorldTransform(transform); painter.drawEllipse(-120, -120, 240, 240); painter.drawLine(0, 0, 100, 0); } void Widget::mouseMoveEvent(QMouseEvent *event) { QString pos = QString("%1,%2").arg(event->pos().x()).arg(event->pos().y()); QToolTip::showText(event->globalPos(), pos, this); }