精华内容
下载资源
问答
  • QPainter

    2020-12-29 18:54:00
    Qt 中提供了强大的 2D 绘图系统,可以使用相同的 API 在屏幕和绘图设备上进行绘制,它主要基于QPainter、QPaintDevice 和 QPaintEngine 这三个类: QPainter 用于执行绘图操作,其提供的 API 在 GUI 或 QImage、...

    概念

    Qt 中提供了强大的 2D 绘图系统,可以使用相同的 API 在屏幕和绘图设备上进行绘制,它主要基于QPainter、QPaintDevice 和 QPaintEngine 这三个类:

    1. QPainter 用于执行绘图操作,其提供的 API 在 GUI 或 QImage、QOpenGLPaintDevice、QWidget 和QPaintDevice 显示图形(线、形状、渐变等)、文本和图像。
    2. QPaintDevice 不直接绘制物理显示画面,而利用逻辑界面的中间媒介。例如,绘制矩形图形时,为了将对象绘制到 QWidget、QGLPixelBuffer、QImage、QPixmap、QPicture 等多种界面中间,必须使用 QPaintDevice。
    3. QPaintEngine 提供了一些接口,可用于 QPainter 在不同的设备上进行绘制。

    绘图系统由 QPainter 完成具体的绘制操作,QPainter 类提供了大量高度优化的函数来完成 GUI 编程所需要的大部分绘制工作。它可以绘制一切想要的图形,从最简单的一条直线到其他任何复杂的图形,例如:点、线、矩形、弧形、饼状图、多边形、贝塞尔弧线等。此外,QPainter 也支持一些高级特性,例如反走样(针对文字和图形边缘)、像素混合、渐变填充和矢量路径等,QPainter 也支持线性变换,例如平移、旋转、缩放。

    QPainter 一般在部件的绘图事件 paintEvent() 中进行绘制,首先创建 QPainter 对象,然后进行图形的绘制,最后记得销毁 QPainter 对象。当窗口程序需要升级或者重新绘制时,调用此成员函数即使用 repaint()和 update() 后,调用函数 paintEvent()。

    paintEvent事件会在什么情况下被调用

    1. 在窗口部件第一次显示时,系统会自动产生一个绘图事件,从而强制绘制这个窗口部件;
    2. 当重新调整窗口部件的大小时,系统也会产生一个绘制事件;
    3. 当窗口部件被其他窗口部件遮挡,然后又再次显示出来的时候,就会对那些隐藏的区域产生一个绘制事件;
    4. 同时也可以调用QWidget::update()或者QWidget::repaint()来强制产生一个绘制事件。二者的区别是:
      1)repaint()函数会强制产生一个即时的重绘事件,而update()函数只是在Qt下一次处理事件时才调用一次绘制事件;
      2)如果多次调用update(),Qt会把连续多次的绘制事件压缩成一个单一的绘制事件,这样可避免闪烁现象。

    用法

    QPainter对象

    QPainter painter;
    

    设置字体-setFont()

    void setFont(const QFont &font);
    QFont font;
    font.setFamily("Consolas"); //款式
    font.setBold(true); //黑体
    font.setPixelSize(40 * ratioH); //大小
    painter.setFont(font);
    

    设置画笔-setPen()

    void setPen(const QPen &pen);
    void setPen(const QColor &color);
    painter.setPen(QColor(0,160,230));
    void setPen(Qt::PenStyle style);
    painter.setPen(Qt::NoPen); //置画笔为空笔 目的是使绘制的图形没有描边
    

    设置画刷-setBrush()

    QBrush brush(QColor::fromRgb(141, 121, 81));
    painter.setBrush(brush);
    

    画圆角矩形

    //QRectF构造一个(x,y)为左上角的坐标,给出宽度,高度的矩形
    void drawRoundedRect ( const QRectF & rect, qreal xRadius, qreal yRadius, Qt::SizeMode mode = Qt::AbsoluteSize )
    //xRadius,yRadius为椭圆的半径
    painter.drawRoundedRect(QRectF(2 * ratioW, 2 * ratioH, width() - 4 * ratioW, height() - 4 * ratioH), rX, rY);
    

    绘制文本
    设置文本两种方式:

    1. 在指定位置绘制文本,不会自动换行
    void QPainter::drawText(int x, int y, const QString &text)
    void QPainter::drawText(const QPoint &position, const QString &text)
    
    1. 在指定的矩形内绘制文本,设置 flags 能够实现自动换行,对齐等
    void QPainter::drawText(const QRect &rectangle, int flags, const QString &text, QRect *boundingRect = 0)
    

    flags 为下面的值之一或则为对其取或的结果:

    Qt::AlignLeft //左对齐
    Qt::AlignRight //右对齐
    Qt::AlignHCenter //水平居中
    Qt::AlignJustify //两端对齐
    Qt::AlignTop //顶部对齐
    Qt::AlignBottom //底部对齐
    Qt::AlignVCenter //垂直居中
    Qt::AlignCenter //居中
    
    void MainWindow::paintEvent(QPaintEvent *event)
    {
        Q_UNUSED(event);
    
        QPainter painter(this);
        // 设置画笔颜色
        painter.setPen(QColor(0, 160, 230));
    
        // 设置字体:微软雅黑、点大小50、斜体
        QFont font;
        font.setFamily("Microsoft YaHei");
        font.setPointSize(50);
        font.setItalic(true);
        painter.setFont(font);
    
        // 绘制文本
        painter.drawText(rect(), Qt::AlignCenter, "Qt");
    }
    

    在这里插入图片描述
    首先为该部件创建了一个 QPainter 对象,用于后面的绘制。
    使用 setPen() 来设置画笔的颜色(淡蓝色)。
    通过使用 QFont 来构建我们想要的字体,setFamily()设置字体为微软雅黑、setPointSize() 设置点大小30、setItalic() 设置斜体, 然后通过 setFont() 来设置字体
    最后调用 drawText() 来实现文本的绘制,这里的 rect() 是指当前窗体的显示区域,Qt::AlignCenter 指文本居中绘制。

    绘制直线

    void MainWindow::paintEvent(QPaintEvent *event)
    {
        Q_UNUSED(event);
    
        QPainter painter(this);
        // 反走样
        painter.setRenderHint(QPainter::Antialiasing, true);
        // 设置画笔颜色
        painter.setPen(QColor(0, 160, 230));
        // 绘制直线
        painter.drawLine(QPointF(0, height()), QPointF(width() / 2, height() / 2));
    }
    

    在这里插入图片描述
    首先我们通过 setRenderHint() 来设置反走样,要么绘制出来的线条会出现锯齿,调用 setPen() 来设置画笔颜色(淡蓝色)。
    最后调用 drawLine() 来实现直线的绘制,其中 QPointF(0, height()) 是指直线的起点坐标、QPointF(width() / 2, height() / 2) 是指直线的终点坐标。

    绘制矩形

    void MainWindow::paintEvent(QPaintEvent *event)
    {
        Q_UNUSED(event);
    
        QPainter painter(this);
    
        // 反走样
        painter.setRenderHint(QPainter::Antialiasing, true);
        // 设置画笔颜色、宽度
        painter.setPen(QPen(QColor(0, 160, 230), 2));
        // 设置画刷颜色
        painter.setBrush(QColor(255, 160, 90));
        painter.drawRect(50, 50, 160, 100);
    }
    

    在这里插入图片描述
    首先我们使用 setPen() 来设置画笔颜色(淡蓝色)、宽度(2 像素),用来设置矩形区域的边框。然后使用setBrush() 来设置画刷颜色(橙色),用来填充矩形区域,最后调用 drawRect() 来实现矩形的绘制,其中参数依次顺序为 x、y、w、h,是指区域从 x 为 50,y 为 50 的坐标点起,宽度为 160,高度为 100 的矩形。

    绘制弧形

    void MainWindow::paintEvent(QPaintEvent *event)
    {
        Q_UNUSED(event);
    
        // 矩形
        QRectF rect(90.0, 90.0, 80.0, 90.0);
        // 起始角度
        int startAngle = 30 * 16;
        // 跨越度数
        int spanAngle = 120 * 16;
    
        QPainter painter(this);
    
        // 反走样
        painter.setRenderHint(QPainter::Antialiasing, true);
    
        // 设置画笔颜色、宽度
        painter.setPen(QPen(QColor(0, 160, 230), 2));
    
        // 绘制弧线
        painter.drawArc(rect, startAngle, spanAngle);
    }
    

    在这里插入图片描述
    画弧线时,角度被分成了十六分之一,就是说,如果要 30 度,就需是 30*16。它有起始角度和跨度,还有位置矩形,所以,要想画出自己想要的弧线,就需要大概估算出各个参数的预估值。

    绘制椭圆

    void MainWindow::paintEvent(QPaintEvent *event)
    {
        Q_UNUSED(event);
    
        QPainter painter(this);
    
        // 反走样
        painter.setRenderHint(QPainter::Antialiasing, true);
    
        // 设置画笔颜色、宽度
        painter.setPen(QPen(QColor(0, 160, 230), 2));
    
        // 绘制椭圆
        painter.drawEllipse(QPointF(120, 60), 50, 20);
    
        // 设置画刷颜色
        painter.setBrush(QColor(255, 160, 90));
    
        // 绘制圆
        painter.drawEllipse(QPointF(120, 140), 40, 40);
    }
    

    在这里插入图片描述
    这里我们绘制了一个椭圆和一个圆形,都是调用 drawEllipse() 接口,我们可以很轻易的发现,如果为椭圆的时候,后面两个参数不一样,圆形则相同。首先我们来看第一个参数 QPointF 是指椭圆的中心点相对当前窗体 QPoint(0, 0) 点的位置,后面的参数指椭圆的 x 轴及 y 轴的半径。

    绘制多边形

    void MainWindow::paintEvent(QPaintEvent *event)
    {
        Q_UNUSED(event);
    
        QPainter painter(this);
    
        // 反走样
        painter.setRenderHint(QPainter::Antialiasing, true);
    
        // 设置画笔颜色
        painter.setPen(QColor(0, 160, 230));
    
        // 各个点的坐标
        static const QPointF points[4] = {QPointF(30, 40), QPointF(60, 150), QPointF(150, 160), QPointF(220, 100)};
    
        // 绘制多边形
        painter.drawPolygon(points, 4);
    }
    

    在这里插入图片描述
    首先,我们定义一个个坐标点的位置,这里有四个点,分别为:QPointF(30, 40)、QPointF(60, 150)、QPointF(150, 160)、 QPointF(220, 100),然后调用 drawPolygon() 将各个点连接起来,绘制为多边形。

    绘制图片

    void MainWindow::paintEvent(QPaintEvent *event)
    {
        Q_UNUSED(event);
    
        QPainter painter(this);
    
        // 反走样
        painter.setRenderHint(QPainter::Antialiasing, true);
    
        // 绘制图标
        painter.drawPixmap(rect(), QPixmap(":/Images/logo"));
    }
    

    在这里插入图片描述
    通过 drawPixmap() 来绘制图片,我们可以指定图片绘制的区域 QRect,这里为整个界面的区域,当界面伸缩的时候,图片也会跟着伸缩。

    反走样
    抗锯齿绘图:又称反走样,对图像的边缘进行平滑处理,使其看起来更加柔和流畅的一种技术.
    QPainter进行绘制时可以使用setRenderHint 渲染提示来指定是否要使用抗锯齿功能。

    QPainter::Antialiasing:指示绘图引擎在可能的情况下应该进行边缘的抗锯齿
    QPainter::TextAntialiasing:绘制的字体抗锯齿

    QT 只是和很多系统的绘图API一样,提供了抗锯齿的方法,不过抗锯齿的属性默认都是关闭的,为了直观的理解抗锯齿(反走样)的作用。我们先给出效果图:
    在这里插入图片描述

    void setRenderHint ( RenderHint hint, bool on = true )
    painter.setRenderHint(QPainter::Antialiasing); //抗锯齿
    

    开启抗锯齿(反走样)功能。
    这里设置Antialiasing属性为true,经过这句设置,我们就打开了反走样功能。QPainter和OPengl一样,是一个状态机。因此,我们这里打开了她,之后所有的代码都是开启反走样绘制的了。

    painter.setRenderHint(QPainter::Antialiasing, true);
    

    关闭反走样功能
    到了这里,我们就会发现,反走样的效果要比走样的好得多。那么为什么系统绘图的API(包含QT在内)为什么默认不打开反走样的呢?这是因为,反走样是一种比较复杂的算法,在一些对图像质量要求不高的应用中,是不需要进行开启反走样的。为了提高效率,一般的图形绘制,都是默认不开启反走样的。

    painter.setRenderHint(QPainter::Antialiasing, false);
    

    示例:
    manwindow.h

    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
     
    #include <QMainWindow>
     
    namespace Ui {
    class MainWindow;
    }
     
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
     
    public:
        explicit MainWindow(QWidget *parent = 0);
        ~MainWindow();
        void paintEvent(QPaintEvent *event);
     
    private:
        Ui::MainWindow *ui;
    };
     
    #endif // MAINWINDOW_H
    

    mainwindow.cpp

    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    #include <QPainter>
    #include <QRect>
    #include <QBrush>
    #include <QFont>
    //用到什么类就包含什么头文件
     
    //这个MainWindow类是系统自动为我起的名字,实际操作中可自定义
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
    }
     
    MainWindow::~MainWindow()
    {
        delete ui;
    }
     
    //核心代码
    void MainWindow::paintEvent(QPaintEvent *event)
    {
        QPainter painter(this);             // 创建QPainter一个对象
     
        // 画一条直线
        QPen pen;
        pen.setColor(Qt::yellow);           // 设置画笔为黄色
        painter.setPen(pen);                // 设置画笔
        painter.drawLine(rect().topLeft(), rect().bottomRight());
     
        // 画一个空心矩形
        pen.setColor(Qt::darkRed);
        painter.setPen(pen);
        painter.drawRect(QRect(1, 1, 100, 100));
     
        // 画一个实心矩形
        QBrush bruch(Qt::FDiagPattern);     // 画刷
        painter.setBrush(bruch);            // 设置画刷
        painter.drawRect(QRect(105, 1, 100, 100));
     
        // 画一个多点线
        pen.setColor(Qt::white);
        painter.setPen(pen);
        bruch.setStyle(Qt::NoBrush);        // 将画刷设置成null
        painter.setBrush(bruch);
        static const QPointF points[4] = {QPointF(210.0, 1), QPointF(220.0, 50.3), QPointF(300, 100.4), QPointF(260.4, 120.0)};
        painter.drawPolyline(points, 4);
     
        // 画多个点
        QPointF pointf[10];
        for (int i=0; i<10; ++i)
        {
            pointf[i].setX(2.0+i*10.0);
            pointf[i].setY(130.0);
        }
        painter.drawPoints(pointf, 10);
     
        // 画多条线
        QLineF linef[5];
        for (int j=0; j<5; ++j)
        {
            linef[j].setP1(QPointF(110.9+j*10, 120.0));
            linef[j].setP2(QPointF(120.8+j*12, 200.0));
        }
        painter.drawLines(linef, 5);
     
        // 画一个多边形
        QPolygonF polygon;
        polygon << QPointF(200.0, 120.0) << QPointF(230.0, 130.0) << QPointF(260.0, 180.0) << QPointF(200.0, 200.0);
        bruch.setStyle(Qt::CrossPattern);
        painter.setBrush(bruch);
        painter.drawPolygon(polygon, Qt::WindingFill);
     
        // 画一个圆角矩形
        QRectF rectangle(290.0, 110.0, 50, 50);
        bruch.setStyle(Qt::SolidPattern);
        painter.setBrush(bruch);
        painter.drawRoundedRect(rectangle, 20.0, 15.0);
     
        // 画一个QString
        painter.drawText(50, 300, "Hello DevDiv!");
     
        //ps:下面这两个有点绿啊。。。。。。如果挡住了上面的图形的话就把他们两个注释掉吧
        //画一个椭圆
        painter.setRenderHint(QPainter::Antialiasing, true);//启用反走样,告诉QPainter用不同颜色强度绘制边框以减少视觉扭曲,这种扭曲一般
        //会在边框转换为像素的时候发生。由此生成的结果是的到一条平滑的曲线
        painter.setPen(QPen(Qt::black, 12, Qt::DashDotDotLine, Qt::RoundCap));
        painter.setBrush(QBrush(Qt::green, Qt::SolidPattern));
        painter.drawEllipse(80, 80, 400, 240);
     
        //绘制三次贝塞尔曲线
        painter.setRenderHint(QPainter::Antialiasing, true);
        QPainterPath path;
        path.moveTo(80, 320);
        path.cubicTo(200, 80, 320, 80, 480, 320);
        painter.setPen(QPen(Qt::black, 8));
        painter.drawPath(path);
    }
    

    main.cpp

    #include "mainwindow.h"
    #include <QApplication>
     
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        MainWindow w;
        w.show();
     
        return a.exec();
    }
    

    QPainterPath类可以通过连接基本的图形元素来确定任意的矢量形状:直线,椭圆,多边形,弧形,贝塞尔曲线和其他的绘制路径。绘制路径是基本的图元,从这个意义上来说,任何图形或图形组合都可以用绘制路径描述。

    路径可以确定一个边缘,由边缘锁定的区域可以用画刷来填充。在现代应用中,渐变填充已成为单色填充的流行替代品。渐变填充利用颜色插值使得两个或更多颜色之间平滑过渡。他们常被用来创建三维效果,Plastique和Ckeanlooks风格就是使用渐变来渲染QPushButton的。

    QT支持三种类型的渐变:线性渐变、锥形渐变和辐射渐变,下面是例子:

    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    #include <QPainter>
    #include <QPen>
    #include <QBrush>
    #include <QFont>
     
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
    }
     
    MainWindow::~MainWindow()
    {
        delete ui;
    }
     
    void MainWindow::paintEvent(QPaintEvent *event)
    {
        Q_UNUSED(event);//没有使用event,去掉之后会有警告
     
        QPainter painter(this);//下面三个渐变位置重叠了,注意及时注释以看到所有效果
     
        //线性渐变
        // 反走样
        painter.setRenderHint(QPainter::Antialiasing, true);
        // 设置渐变色
        QLinearGradient linear(QPointF(80, 80), QPointF(150, 150));
        linear.setColorAt(0, Qt::black);
        linear.setColorAt(1, Qt::white);
        // 设置显示模式
        linear.setSpread(QGradient::PadSpread);
        // 设置画笔颜色、宽度
        painter.setPen(QPen(QColor(0, 160, 230), 2));
        // 设置画刷填充
        painter.setBrush(linear);
        // 绘制椭圆
        painter.drawRect(QRect(40, 40, 180, 180));
     
     
        //锥形渐变
        // 反走样
        painter.setRenderHint(QPainter::Antialiasing, true);
        // 设置渐变色
        QRadialGradient radial(110, 110, 50, 130, 130);
        radial.setColorAt(0, Qt::black);
        radial.setColorAt(1, Qt::white);
        // 设置显示模式
        radial.setSpread(QGradient::ReflectSpread );
        // 设置画笔颜色、宽度
        painter.setPen(QPen(QColor(0, 160, 230), 2));
        // 设置画刷填充
        painter.setBrush(radial);
        // 绘制椭圆
        painter.drawRect(QRect(40, 40, 180, 180));
     
        //辐射渐变
        // 反走样
        painter.setRenderHint(QPainter::Antialiasing, true);
        // 设置渐变色
        QConicalGradient conical(110, 110, 45);
        conical.setColorAt(0, Qt::black);
        conical.setColorAt(1, Qt::white);
        // 设置画笔颜色、宽度
        painter.setPen(QPen(QColor(0, 160, 230), 2));
        // 设置画刷填充
        painter.setBrush(conical);
        // 绘制椭圆
        painter.drawRect(QRect(40, 40, 180, 180));
    }
    

    目前,我们提到了画笔、画刷和字体设置,另外QPainter还有其他影响图形和文字的绘制方式设置,这里简单提及一点:
    当背景模式是Qt::QpaqueMode时,背景画刷可以用来填充几何图形的背景、文字或者位图

    展开全文

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,744
精华内容 1,497
关键字:

qpainter