图形绘制 QPainter_qt drawroundedrect-程序员宅基地

技术标签: qt  Qt绘图  

QPainter painter(this); // 会立即开始在设备上绘制,自动调用begin()函数,然后析构函数中调用end()函数结束绘制。
QPainter painter;// 不带参数时,可以在后面调用QPainter::begin(QPaintDevice *device)来指定绘制设置,然后用完再调用end()函数。

void Widget::paintEvent((QPaintEvent *event)  
{  
        QPainter painter(this); //this为绘图设备,即表明在该部件上进行绘制  
        painter.drawLine(QPaint(0, 0), QPaint(100, 100));  
}  
//等价于
void Widget::paintEvent((QPaintEvent *event)  
{  
        QPainter painter;  
        painter.begin(this);  
        painter.drawLine(QPaint(0, 0), QPaint(100, 100));  
        painter.end();  
}  

使用画刷

画刷可以设置颜色和填充模式

QBrush brush(QColor(0,0,255), Qt::Dense4Pattern);  
painter.setBrush(brush);  

使用画笔

//参数为:画刷,线宽,画笔风格,画笔端点,画笔连接风格  
QPen pen(Qt::green, 5, Qt::DotLine, Qt::RoundCap, Qt::RoundJoin);  
painter.setPen(pen);  

QPainter 常用的画图方法,都是以 draw 开头,非常直观的列出了绘图函数和绘制出来的图形:
这里写图片描述

坐标系

数学中使用的坐标系是笛卡尔坐标系,X 轴正向向右,Y 轴正向向上。但是,QPainter 也有自己的坐标系,和笛卡尔坐标系有点不一样,原点在 widget 的左上角而不是正中心,X 轴正向向右,Y 轴正向向下。注意: 每个 widget 都有自己独立的坐标系。
这里写图片描述

QPainter是一个状态机

所谓状态机,就是说,QPainter保存的只是各种状态。怎么理解呢?比如,你把颜色设置成红色,那么,直到你重新设置另外的颜色,它的颜色会一直是红色。它的状态不会自己恢复,除非你使用了各种set函数。因此,如果在上面的代码中,我们在椭圆绘制之后再画一个椭圆,它的样式还会是绿色5px的轮廓和蓝色的填充,除非你显式地调用了set进行更新。这可能是绘图系统较多的实现方式,因为无论是OpenGL、QPainter还是Java2D,都是这样实现的。

画线 - drawLine()

void MainWidget::paintEvent(QPaintEvent *) {
    QPainter painter(this);
    painter.drawLine(30, 30, 150, 150);
}

画多线段 - drawLines()

给定 N 个点,第 1 和第 2 个点连成线,第 3 和第 4 个点连成线,……,N 个点练成 (N+1)/2 条线,如果 N 是奇数,第 N 个点和 (0,0) 连成线。

void MultipleLinesWidget::paintEvent(QPaintEvent *) {
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);
    painter.translate(20, 20);
    static const QPointF points[4] = {
        QPointF(0.0, 100.0),
        QPointF(20.0, 0.0),
        QPointF(100.0, 0.0),
        QPointF(120.0, 100.0)
    };
    painter.drawLines(points, 2); // 4 个点连成 2 条线
}

画折线- drawPolyline()

给定 N 个点,第 1 和第 2 个点连成线,第 2 和第 3 个点连成线,……,第 N-1 和第 N 个点连成线,N 个点共连成 N-1 条线。

void PolylineWidget::paintEvent(QPaintEvent *) {
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);
    painter.translate(20, 20);
    static const QPointF points[4] = {
        QPointF(0.0, 100.0),
        QPointF(20.0, 0.0),
        QPointF(100.0, 0.0),
        QPointF(120.0, 100.0)
    };
    painter.drawPolyline(points, 4);
}

画多边形 - drawPolygon()

给定 N 个点,第 1 和第 2 个点连成线,第 2 和第 3 个点连成线,……,第 N-1 和第 N 个点连成线,第 N 个点和第 1 个点连接成线形成一个封闭的多边形。
在我们学习OpenGL的时候,肯定听过这么一句话:OpenGL是一个状态机。所谓状态机,就是说,OpenGL保存的只是各种状态。怎么理解呢?比如,你把颜色设置成红色,那么,直到你重新设置另外的颜色,它的颜色会一直是红色。QPainter也是这样,它的状态不会自己恢复,除非你使用了各种set函数。因此,如果在上面的代码中,我们在椭圆绘制之后再画一个椭圆,它的样式还会是绿色5px的轮廓和蓝色的填充,除非你显式地调用了set进行更新。这可能是绘图系统较多的实现方式,因为无论是OpenGL、QPainter还是Java2D,都是这样实现的

drawPolygon() 和 drawPolyline() 很像,但是 drawPolygon() 画的是一个封闭的区域,可以填充颜色,而 drawPolyline() 画的是一些线段,即使它们连成一个封闭的区域也不能填充颜色。

void PolygonWidget::paintEvent(QPaintEvent *) {
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);
    painter.translate(20, 20);
    static const QPointF points[4] = {
        QPointF(0.0, 100.0),
        QPointF(20.0, 0.0),
        QPointF(100.0, 0.0),
        QPointF(120.0, 100.0)
    };
    painter.setBrush(Qt::yellow);
    painter.drawPolygon(points, 4);
}

可以用 drawPolygon() 来画圆,其实本没有圆,正多边形的边多了,便成了圆,这正是计算机里绘制曲线的原理,插值逼近,在曲线上取 N 个点,点之间用线段连接起来,当 N 越大时,连接出来的图形就越平滑,越接近曲线。

void PolygonCircleWidget::paintEvent(QPaintEvent *) {
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing); // 启用抗锯齿效果
    painter.translate(width() / 2, height() / 2); // 把坐标原点移动到 widget 的中心
    painter.setBrush(Qt::lightGray);
    const int COUNT  = 10;  // 边数,越大就越像圆
    const int RADIUS = 100; // 圆的半径
    QPointF points[COUNT];  // 顶点数组
    for (int i = 0; i < COUNT; ++i) {
        float radians = 2 * M_PI / COUNT * i; // M_PI 是 QtMath 里定义的,就是 PI
        float x = RADIUS * qCos(radians);
        float y = RADIUS * qSin(radians);
        points[i] = QPointF(x, y);
    }
    painter.drawPolygon(points, COUNT);
}

画矩形 - drawRect()

void MainWidget::paintEvent(QPaintEvent *) {
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);
    painter.translate(30, 30);
    int x = 0;
    int y = 0;
    int w = 100;
    int h = 100;
    painter.drawRect(x, y, w, h);
}

画圆角矩形- drawRoundRect() & drawRoundedRect()

绘制圆角矩形有 2 个方法:drawRoundRect() 和 drawRoundedRect(),需要给定圆角矩形左上角的坐标、长、宽、圆角的半径。

当 drawRoundedRect() 中第 7 个参数 Qt::SizeMode 为 Qt::RelativeSize 时,表示圆角半径的单位是百分比,取值范围是 [0, 100],此时 drawRoundedRect() 等价于 drawRoundRect(),其实底层是用这个百分比和对应边长的一半相乘得到圆角的半径(单位是像素)。Qt::SizeMode 为 Qt::AbsoluteSize 时,表示圆角半径的单位是像素。

void RoundRectWidget::paintEvent(QPaintEvent *) {
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);
    painter.setBrush(Qt::lightGray);
    painter.translate(30, 30);
    painter.drawRoundRect(0, 0, 100, 100, 50, 50); // 50%, 50%
    painter.drawRoundedRect(130, 0, 100, 100, 50, 50, Qt::AbsoluteSize); // 50px, 50px
    painter.drawRoundedRect(260, 0, 100, 100, 100, 100, Qt::RelativeSize); // 100%, 100%
}

画圆、椭圆 - drawEllipse()

void EllipseWidget::paintEvent(QPaintEvent *) {
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);
    painter.translate(30, 30);
    painter.drawRect(0, 0, 200, 100);    // 椭圆的包围矩形
    painter.setBrush(Qt::lightGray);
    painter.drawEllipse(0, 0, 200, 100); // 椭圆
    painter.drawEllipse(230, 0, 100, 100); // 圆
}

画弧、弦、饼图 - drawArc()、drawChord()、drawPie()

画弧使用 drawArc()
画弦使用 drawChord()
画饼图用 drawPie()

void QPainter::drawArc(const QRectF & rectangle, int startAngle, int spanAngle)
void QPainter::drawPie(const QRectF & rectangle, int startAngle, int spanAngle)
void QPainter::drawChord(const QRectF & rectangle, int startAngle, int spanAngle)

这里写图片描述
rectangle: 包围矩形
startAngle: 开始的角度,单位是十六分之一度,如果要从 45 度开始画,则 startAngle 为 45 * 16
spanAngle: 覆盖的角度,单位是十六分之一度
绘制圆心为包围矩形的正中心,0 度在圆心的 X 轴正方向上
角度的正方向为逆时针方向
这里写图片描述

void ArcChordPieWidget::paintEvent(QPaintEvent *) {
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);
    static int startAngle = 45 * 16; // 开始角度是 45 度
    static int spanAngle = 130 * 16; // 覆盖角度为 130 度
    static QRectF boundingRect(0, 0, 150, 150); // 包围矩形
    painter.translate(30, 30);
    painter.setBrush(Qt::NoBrush);
    painter.drawRect(boundingRect); // 绘制包围矩形
    painter.setBrush(Qt::lightGray);
    painter.drawArc(boundingRect, startAngle, spanAngle); // 画弧
    painter.translate(180, 0);
    painter.setBrush(Qt::NoBrush);
    painter.drawRect(boundingRect); // 绘制包围矩形
    painter.setBrush(Qt::lightGray);
    painter.drawChord(boundingRect, startAngle, spanAngle); // 画弦
    painter.translate(180, 0);
    painter.setBrush(Qt::NoBrush);
    painter.drawRect(boundingRect); // 绘制包围矩形
    painter.setBrush(Qt::lightGray);
    painter.drawPie(boundingRect, startAngle, spanAngle); // 画饼图
}

绘制 QPixmap - drawPixmap()

void MainWidget::paintEvent(QPaintEvent *) {
    QPainter painter(this);
    QPixmap pixmap(":/img/Butterfly.png"); // 从资源文件读取 pixmap

    painter.drawPixmap(0, 0, pixmap); // 绘制 pixmap
}

绘制 QImage - drawImage()

void MainWidget::paintEvent(QPaintEvent *) {
    QPainter painter(this);
    QImage image(":/img/Butterfly.png"); // 从资源文件读取 image
    painter.drawImage(0, 0, image); // 绘制 image
}

绘制路径QPainterPath - drawPath()

    QPainterPath path;  
    path.addEllipse(-4, -4, 8, 8);//添加一个圆  
    path.addRect(-5, -5, 10, 10); //添加一个矩形  
    painter.drawPath(path);  

填充与擦除

/使用画刷填充一个矩形区域  
painter.fillRect(QRect(10,100,150,20), QBrush(Qt::darkYellow));  

//擦除一个矩形区域的内容  
painter.eraserRect(QRect(50,0,50,120)); 
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/TemetNosce/article/details/78025784

智能推荐

ATOM基础教程一ATOM插件推荐(4)_atom git 插件-程序员宅基地

文章浏览阅读3.3w次,点赞8次,收藏26次。ATOM常用插件推荐simplified-chinese-menu ATOM的汉化插件file-icons 文件图标美化atom-beautify 代码格式一键美化last-cursor-position 光标自由切换到上一次/下一次编辑位置minimap代码小地图sync-settings 插件备份、按键绑定备份activate-power-mode 输入时有震撼效果_atom git 插件

React native 界面响应慢 卡顿的几个优化方向(思路)_react-native中点击按钮提交数据按钮卡顿-程序员宅基地

文章浏览阅读4.8k次,点赞2次,收藏5次。React native 界面响应慢 卡顿的几个解决思路(陆续整理中)最近在项目优化中整理了一些对优化性能有帮助的线索,大家可以参考一下:1.耗时的操作使用Promise异步操作(如果用户界面操作频率很高可能依然会出现标题4的情况)避免出现长时间等待的情况。2.避免过度绘制,自定义组件可以考虑继承PureComponentshouldComponentUpdate避免无变化的重复setState生命周期文档https://blog.csdn.net/loveseal518/art_react-native中点击按钮提交数据按钮卡顿

vue如何引入echart 地图,及报错总结_vue2bmap api is not loaded-程序员宅基地

文章浏览阅读2.5k次,点赞7次,收藏15次。官网效果图首先安装依赖npm i echarts 引入import echarts from "echarts"; //可视化map.jsexport function loadBMap(ak) { return new Promise(function (resolve, reject) { if (typeof BMap !== 'undefined') { resolve(BMap) return true_vue2bmap api is not loaded

推荐 EditorConfig Notepad++ 插件-程序员宅基地

文章浏览阅读355次,点赞7次,收藏7次。推荐 EditorConfig Notepad++ 插件EditorConfig Notepad++ 插件 是一款用于 Notepad++ 的插件,旨在帮助开发者保持代码风格的一致性。这款插件支持多种编程语言,并且可以根据项目中的 .editorconfig 文件自动应用相应的代码风格。能用来做什么?有了 EditorConfig Notepad++ 插件,你可以:在多个开发人员之间保持...

怎样快速将文字转换成语音?这种操作很简单-程序员宅基地

文章浏览阅读822次。  我们在听讲座,开会的时候经常会记一些笔记,但是我们并不是打字员,很多时候是跟不上说话速度的?这时候我们就可以将其录下来在进行整理,下面是小编分享的方法,希望可以帮助到大家!  步骤一:打开文字转语音软件,在画布的左侧有三个工具栏【文字转语音】【录音转文字】【翻译】点击选择【文字转语音】;  步骤二:在画布右边出现的工具栏中将需要进行转换的文字复制进文本框中;  步骤三:在输入的过程中如果出现错..._将文字转换成语音

C++ STL编程轻松入门-程序员宅基地

文章浏览阅读1.6k次。图1、STL和c++标准模板库作为C++标准不可缺少的一部分,STL应该是渗透在C++程序的角角落落里的。STL不是实验室里的宠儿,也不是程序员桌上的摆设,她的激动人心并非昙花一现。本教程旨在传播和普及STL的基础知识,若能借此机会为STL的推广做些力所能及的事情,到也是件让人愉快的事情。 1、  "什么是STL?",假如你对STL还知之甚少,那么我想,你一定很想知_c++ stl编程轻松入门

随便推点

Generalplus公司的GP329730A_gp329733a-程序员宅基地

文章浏览阅读603次。最近用了Generalplus公司的GP329730A,与之前的STM32不同,这是一款ARM9核心的芯片欢迎使用Markdown编辑器你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下Markdown的基本语法知识。新的改变我们对Markdown编辑器进行了一些功能拓展与语法支持,除了标准的Mar..._gp329733a

idea报错:java.lang.UnsatisfiedLinkError: Could not load library. Reasons: [no leveldbjni64-1.8 in java-程序员宅基地

文章浏览阅读3.3k次。java.lang.UnsatisfiedLinkError: Could not load library. Reasons: [no leveldbjni64-1.8 in java.library.path, no leveldbjni-1.8 in java.library.path, C:\Windows\System32\leveldbjni.dll: Can't find depen..._could not load library. reasons: [no leveldbjni64-1.8 in java.library.path,

GNU C __attribute__ 机制简介_c attribute-程序员宅基地

文章浏览阅读646次。GNU C __attribute__ 机制简介 2006-06-17 13:54:00 标签:   [推送到技术圈] 摘要:在学习linux内核代码及一些开源软件的源码(如:DirectFB),经常可以看到有关__attribute__的相关使用。本文结合自己的学习经历,较为详细的介绍了__attribute__相关语法及其使用。-----------_c attribute

CentOS之间rsync做文件增量(备份)同步-程序员宅基地

文章浏览阅读1.9k次。服务器192.168.0.248:本地服务器47.56.34.2:远程服务器目的将远程服务器数据同步到本地服务器前提两台服务器安装rsync和crontabsyum install -y rsyncyum install -y crontabs设置免密登陆在本地服务器..._centos rsync 增量

【Node.js】深度解析搭建后台服务器-http模块_node.js http深度解析-程序员宅基地

文章浏览阅读2.8w次,点赞65次,收藏71次。http 模块是 Node.js 官方提供的、用来创建 web 服务器的模块。通过 http 模块提供的方法,就能方便的把一台普通的电脑,变成一台 Web 服务器,从而对外提供 Web 资源服务。在 Node.js 中,我们不需要使用Apache等这些第三方 web 服务器软件。因为我们可以基于 Node.js 提供的 http 模块,通过几行简单的代码,就能轻松的手写一个服务器软件,从而对外提供 web 服务。_node.js http深度解析

brew 安装pip_mac 下安装pip-程序员宅基地

文章浏览阅读448次。pip是常用的Python包管理工具,类似于Java的maven。用python的同学,都离不开pip。 在新mac中想用home-brew安装pip时,遇到了一些小问题:bogon:~ yj$ brew install pipError: No available formula with the name "pip"..._brew pip

推荐文章

热门文章

相关标签