[Qt] QPainter | Qpen | QPixmap

server/2025/1/23 9:24:04/

目录

绘图

1、基本概念

2、绘制各种形状

(1)绘制线段

(2)绘制矩形

(3)绘制圆形

(4)绘制文本

(5)设置画笔

【画笔的使用】

(6)设置画刷

3、绘制图片

(1) 绘制简单图片

(2)平移图片

(3)缩放图片

(4)旋转图片

4、其他设置

(1)移动画家位置

(2)保存 / 加载画家的状态

5、特殊的绘图设备

(1)QPixmap

(2)QImage

(3)QPicture


更多参考内容:

• 官⽅⽂档中的Qt Style Sheets Examples 章节

• https://github.com/GTRONICK/QSS

绘图

1、基本概念

虽然 Qt 已经内置了很多的控件,但是不能保证现有控件就可以应对所有场景。很多时候我们需要更强的 “自定制” 能力。

Qt 提供了画图相关的 API,允许我们在窗口上绘制任意的图形形状来完成更复杂的界面设计。

  • 所谓的 “控件” 本质上也是通过画图的方式画上去的。
  • 画图 API 和控件之间的关系,可以类比成机器指令和高级语言之间的关系。
  • 控件是对画图 API 的进一步封装,画图 API 是控件的底层实现。

(1)绘图 API 核心类

说明

QPainter

"绘画者" 或者 "画家".
用来绘图的对象,提供了一系列 drawXXX 方法,可以允许我们绘制各种图形.

QPaintDevice

"画板".
描述了 QPainter 把图形画到哪个对象上. 像咱们之前用过的 QWidget 也是一种 QPaintDevice (QWidget 是 QPaintDevice 的子类).

QPen

"画笔".
描述了 QPainter 画出来的线是什么样的.

QBrush

"画刷".
描述了 QPainter 填充一个区域是什么样的.

绘图 API 的使用一般不会在 QWidget 的构造函数中使用,而是要放到 paintEvent 事件中。

paintEvent 会在以下情况下被触发:

  • 控件首次创建。
  • 控件被遮挡,再解除遮挡。
  • 窗口最小化,再恢复。
  • 控件大小发生变化时。
  • 主动调用 repaint() 或者 update() 方法(这两个方法都是 QWidget 的方法)。
  • ... ...

2、绘制各种形状

(1)绘制线段

void drawLine(const QPoint &p1, const QPoint &p2);参数:p1:绘制起点坐标p2:绘制终点坐标
void drawLine ( int x1, int y1, int x2, int y2 );参数:x1,y1:绘制起点坐标x2,y2:绘制终点坐标

示例:

A. 在 "widget.h" 头文件中声明绘图事件

void paintEvent(QPaintEvent* event);

B. 在 "widget.cpp" 文件中重写 paintEvent() 方法

void Widget::paintEvent(QPaintEvent *event)
{(void) event;// 绘图工作就会放到这里来执行.QPainter painter(this);// 画一个线段.painter.drawLine(20, 20, 200, 20);painter.drawLine(QPoint(20, 100), QPoint(200, 100));painter.drawLine(20, 20, 100, 300);
}

实现效果如下:


(2)绘制矩形

void QPainter::drawRect(int x, int y, int width, int height);参数:x:窗⼝横坐标;y:窗⼝纵坐标;width:所绘制矩形的宽度;height:所绘制矩形的⾼度;

示例:

 // 画一个矩形.painter.drawRect(100, 100, 300, 200);

实现效果如下:


(3)绘制圆形

void QPainter::drawEllipse(const QPoint &center, int rx, int ry)参数:center:中⼼点坐标rx:横坐标ry:纵坐标

示例:

// 画圆形.painter.drawEllipse(200, 200, 400, 100);

实现效果:

(4)绘制文本

QPainter 类中不仅提供了绘制图形的功能,还可以使用 QPainter::drawText() 函数来绘制文字,也可以使用 QPainter::setFont() 设置字体等信息。

示例:

QFont font("微软雅黑", 24);painter.setFont(font);// 绘制文本.painter.drawText(0, 100, "hello");

实现效果:

(5)设置画笔

QPainter 在绘制时,是有一个默认的画笔的。在使用时也可以自定义画笔。在 Qt 中,QPen 类中定义了 QPainter 应该如何绘制形状、线条和轮廓。同时通过 QPen 类可以设置画笔的线宽、颜色、样式、画刷等。

画笔的颜色可以在实例化画笔对象时进行设置,画笔的宽度是通过 setWidth() 方法进行设置,画笔的风格是通过 setStyle() 方法进行设置,设置画刷主要是通过 setBrush() 方法。

  • 设置画笔颜色:QPen::QPen(const QColor &color) 画笔的颜色主要是通过 QColor 类设置;
  • 设置画笔宽度:void QPen::setWidth(int width)
  • 设置画笔风格:void QPen::setStyle(Qt::PenStyle style)

画笔的风格有:

【画笔的使用】
 QPen pen;// 设置成红色的线条pen.setColor(QColor(255, 0, 0));// 设置线条的粗细.pen.setWidth(5);// 设置线条的风格pen.setStyle(Qt::DashLine);// 让 painter 对象应用 pen 对象painter.setPen(pen);// 画圆形.painter.drawEllipse(200, 200, 400, 100);

实现效果如下:


(6)设置画刷

在 Qt 中,画刷是使用 QBrush 类来描述,画刷大多用于填充。QBrush 定义了 QPainter 的填充模式,具有样式、颜色、渐变以及纹理等属性。

画刷的格式中定义了填充的样式

使用 Qt::BrushStyle 枚举,默认值是 Qt::NoBrush,也就是不进行任何填充

可以通过 Qt 助手查找画刷的格式。如下图示:

设置画刷主要通过 void QPen::setBrush(const QBrush &brush) 方法,其参数为画刷的格式。

示例:

    QBrush brush;brush.setColor(QColor(0, 255, 0));// brush.setStyle(Qt::SolidPattern);brush.setStyle(Qt::CrossPattern);painter.setBrush(brush);

实现效果:


3、绘制图片

Qt 提供了四个类来处理图像数据:QImage、QPixmap、QBitmap 和 QPicture

  • 其中QImage主要用来进行 I/O 处理,它对 I/O 处理操作进行了优化,而且可以用来直接访问和操作像素;
  • QPixmap 主要用来在屏幕上显示图像,它对在屏幕上显示图像进行了优化;
  • QBitmap 是 QPixmap 的子类,用来处理颜色深度为 1 的图像,即只能显示黑白两种颜色;
  • QPicture 用来记录并重演 QPainter 命令。

(1) 绘制简单图片

A. 新建 Qt 项目,基类选择 QWidget,项目名称为 QPainter。

在 "widget.h" 头文件中声明绘画事件

void paintEvent(QPaintEvent *event);

B. 添加资源文件

首先准备一些图片资源文件,并将这些图片资源文件放在同一个文件夹中,将该文件夹复制到本项目中:

c. 点击 “构建并运行” 按钮,将资源文件添加到项目中

d. 在 "widget.cpp" 文件中实现画图片功能

void Widget::paintEvent(QPaintEvent *)
{//实例化 画家对象QPainter painter(this);//画图片painter.drawPixmap(0,0,QPixmap(":/picture/1.jpg"));
}

(2)平移图片

平移图片实际是通过改变坐标来实现。QPainter 类中提供了 translate() 函数来实现坐标原点的改变。

示例:

painter.translate(100,100);

(3)缩放图片

示例:

(4)旋转图片

图片的旋转使用的是 QPainter 类中的 rotate() 函数,它默认是以原点为中心进行旋转的。如果要改变旋转的中心,可以使用 translate() 函数完成。

示例:

 QPainter painter(this);QPixmap pixmap(":/picture/2.jpeg");painter.rotate(180);painter.translate(-800,-600);painter.drawPixmap(100,100,400,300,pixmap);

实现效果:

4、其他设置

(1)移动画家位置

有时候在绘制多个图形时,想使用同一坐标位置,那么绘制出来的图形肯定会重合,此时,可以通过移动画家的位置来使图形不发生重合。

【未移动画家位置】

实现效果如下:

【移动画家位置】

使用 translate 移动画家所在位置:

实现效果如下:

(2)保存 / 加载画家的状态

在绘制图形的过程中,可以通过 save() 函数来保存画家的状态,使用 restore() 函数还原画家状态。

save() 函数原型如下:

  • void QPainter::save();

restore() 函数原型如下:

  • void QPainter:: restore ();


示例:

实现效果如下:

说明:

在画第三个圆之前,由于还原了画家的状态,所以此时画家的位置坐标会移动到画家状态保存的地方,所以在绘制第三个圆的位置时实际是和第二个圆发生了重叠。


5、特殊的绘图设备

前面的代码中我们是使用 QWidget 作为绘图设备,在 Qt 中还存在下列三个比较特殊的绘图设备。

  • QPixmap 用于在显示器上显示图片
  • QImage 用于对图片进行像素级修改
  • QPicture 用于对 QPainter 的一系列操作进行存档

(1)QPixmap

QPixmap 核心特性:

  • 使用 QPainter 直接在上面进行绘制图形。
  • 通过文件路径加载并显示图片。
  • 搭配 QPainter 的 drawPixmap() 函数,可以把这个图片绘制到⼀个 QLabel、QPushButton 等控件上。
  • 和系统 / 显示设备强相关,不同系统 / 显示设备下,QPixmap 的显示可能会有所差别。

示例:

实现效果:

(2)QImage

QImage 的核心特性:

  • 使用 QPainter 直接在上面进行绘制图形。
  • 通过文件路径加载并显示图片。
  • 能够针对图片进行像素级别的操作(操作某个指定的像素)。
  • 独立于硬件的绘制系统,能够在不同系统之上提供一致的显示。

【QImage 作为绘图设备的使用】


【QImage 绘图时对像素的修改】

A. 新建 Qt 项目,添加图片资源文件到项目中

B. 在 widget.h 头文件中声明绘图事件

C. 在 widget.cpp 文件中重写绘图事件,使用 QImage 对图片像素进行修改

  • 通过 setPixel 设置某个像素的颜色值
  • 使用 qRgb 表示一个具体的颜色
#include "widget.h"
#include <QPainter>Widget::Widget(QWidget *parent): QWidget(parent)
{
}void Widget::paintEvent(QPaintEvent *)
{QPainter painter(this); // 实例化画家对象QImage img;img.load(":/picture/3.jpg"); // 加载图片// 修改像素点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);}}painter.drawImage(0, 0, img);
}

D. 执行效果

修改像素之后

(3)QPicture

QPicture 核心特性:

  • 使用 QPainter 直接在上面进行绘制图形。
  • 通过文件路径加载并显示图片。
  • 能够记录 QPainter 的操作步骤。
  • 独立于硬件的绘制系统,能够在不同系统之上提供⼀致的显示。

注意 QPicture 加载的必须是自身的存档文件,而不能是任意的 png, jpg 等图片文件。

如果要记录下 QPainter 的命令

  • 首先要使用 QPainter::begin() 函数,将 QPicture 实例作为参数传递进去,以便告诉系统开始记录
  • 记录完毕后使用 QPainter::end() 命令终止。

示例:

展示效果如下:

通过 QPicture 重现绘图指令后,实现的效果如下:

💡:


Qt 中对于界面的优化美化,还涉及到很多其他的话题,如果在工作中如果涉及到了,再针对性学习即可。

  • Qt 动画
  • Qt 3D 图形
  • QQuick
  • 使用第三方控件库
  • Qt Design Studio
  • ... ...

http://www.ppmy.cn/server/160697.html

相关文章

leetcode 300. 最长递增子序列

题目如下 数据范围 这道题用暴力的角度来做的话时间复杂度是O(2^n)结合数据范围来看显然会超时。 那么我们可以考虑动态规划&#xff1a; 令dp[i]是以nums[i]为结尾的递增子序列的长度那么dp[i] max(dp[j] 1,dp[i])其中0 < j < i当然要满足nums[i] > nums[j]。 (…

【算法】贪心

贪心 1.简单贪心1.货仓选址2.最大子段和3.纪念品分组4.排座椅5.矩阵消除游戏 2.推公式1.拼数2.Protecting the Flowers3.奶牛玩杂技 3.哈夫曼编码1.【模板】哈夫曼编码2.字符编码3.合并果子 4.区间问题1.线段覆盖2.Radar Installation3.Sunscreen4.Stall Reservations 1.简单贪…

GDB相比IDE有什么优点

GDB(GNU Debugger)相比于集成开发环境(IDE)具有一些独特的优点,主要体现在其灵活性、可定制性和低级控制能力。具体来说,GDB有以下几个优点: 1. 轻量级且无依赖 GDB是一个命令行工具,不依赖于任何复杂的图形界面或大型库,这使得它非常适合在资源受限的环境中使用,比…

事件委托,其他事件,电梯导航,固定导航

事件委托改造 tab 栏切换 tab栏切换&#xff1a;前边的案例是 for 循环遍历每个 li 注册鼠标进入事件&#xff0c;给添加了 active类的 a 删除掉 active类&#xff0c;然后给点击的 a 添加上 active类&#xff08;也就是将已经有的 active 类删除掉&#xff0c;为当前点击到的…

技术洞察:C++在后端开发中的前沿趋势与社会影响

文章目录 引言C在后端开发中的前沿趋势1. 高性能计算的需求2. 微服务架构的兴起3. 跨平台开发的便利性 跨领域技术融合与创新实践1. C与人工智能的结合2. C与区块链技术的融合 C对社会与人文的影响1. 提升生产力与创新能力2. 促进技术教育与人才培养3. 技术与人文的深度融合 结…

【统计信号处理基础——估计与检测理论】Vol1.Ch2. 最小方差无偏估计

系列目录 【统计信号处理基础——估计与检测理论】Vol1.Ch1. 引言 文章目录 1. 无偏估计量2. 最小方差准则3. 最小方差无偏估计的存在性4. 求最小方差无偏估计量5. 扩展到矢量参数习题2.1 本章寻找未知确定性参数的好的估计量。我们将注意力限制在通过平均产生真值的估计量上&a…

SpringBoot为什么要禁止循环依赖?

大家好&#xff0c;我是锋哥。今天分享关于【SpringBoot为什么要禁止循环依赖?】面试题。希望对大家有帮助&#xff1b; SpringBoot为什么要禁止循环依赖? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 Spring Boot 禁止循环依赖的原因与 Spring 框架本身的设计…

低空经济(2)国外发展概述

低空经济国外发展概述 1.概述2.美国3.欧洲4.其他地区 1.概述 世界低空经济起步于农业服务&#xff0c;1920年后公务航空进入市场。二战推动的技术进步使低空经济迅猛发展&#xff0c;1950年直升机进入低空经济市场&#xff0c;开始海上石油服务、山地救援等业务。截至2014年&a…