【Qt】Qt界面美化 | 绘画

news2024/9/23 21:35:07

文章目录

  • 绘画概述
  • 绘制API
    • 1. 图形
      • (1). 线段
      • (2). 矩形
      • (3). 圆形
      • (4). 绘制文本
    • 2. 工具
      • (1). 画笔
      • (2). 画刷
    • 3. 绘制图片
      • QPainter图片操作
    • 绘图设备
      • (1). QPixmap
      • (2). QImage
      • (3). QPicture
  • 结束语

绘画概述

虽然 Qt 已经内置了很多的控件,但还是有很多时候需要“自定义”
Qt 提供了画图相关的API,可以允许我们在窗口上绘制任意的图形形状,来完成更复杂的界面设计。

绘图核心类

说明
QPainter类似“画家”的概念
用来绘图的对象,提供了一系列 drawXXX 方法,允许我们绘制各种图形
QPaintDevice“画板”
描述了 QPainter把图形画到哪个对象上,QWidget 是 QPaintDevice 的子类
QPen“画笔”
描述了 QPainter 画出来的线是什么样的
QBrush“画刷”
描述了 QPainter画出的图形其内部如何填充

绘图 API 的使用,一般不会在 QWidget 构造函数中使用,而是使用事件机制,编写在 paintEvent事件中
paintEvent会在以下情况被触发

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

所以要将绘图 API 放在paintEvent中,如果放在构造函数中,则发生上述情况,界面的绘制效果就无法确保符合预期了

绘制API

绘制图形逻辑都是编写在paintEvent

1. 图形

(1). 线段

绘制线段的API为drawLine(),Qt 提供了很多重载版本

API说明
drawLine(int x1, int y1, int x2, int y2)(x1, y1)是线段一端的坐标(x2, y2)是线段另一端的坐标,两点确定一条直线
drawLine(const QLineF &line)QLineF的构造函数也是传入两个坐标,如QLineF(10.0, 80.0, 90.0, 20.0)
drawLine(QPoint &p1, QPoint &p2)传入两个坐标,QPoint(100, 200)

代码示例:

void Widget::paintEvent(QPaintEvent *event)
{
    (void)event;//避免不必要的警告

    //画家不用创建在堆上,栈上即可
    //此处的this,是指定要在哪个界面绘画
    QPainter painter(this);
    painter.drawLine(QLineF(100.0, 100.0, 100.0, 300.0));
    painter.drawLine(100, 100, 275, 275);
    painter.drawLine(QPoint(100, 100), QPoint(300, 100));

}

在这里插入图片描述

(2). 矩形

绘制矩形的API为drawRect()

API说明
drawRect(int x, int y, int width, int height)(x, y)是矩形左上角的坐标,width 和 height分别是宽度和高度

Qt 的坐标是左手坐标系
在这里插入图片描述
代码示例:

void Widget::paintEvent(QPaintEvent *event)
{
    (void)event;//避免不必要的警告
    //矩形
    QPainter painter(this);
    painter.drawRect(100, 100, 300, 200);
}

在这里插入图片描述

(3). 圆形

绘制圆形的 API 为 drawEllipse()

API说明
drawEllipse(const QPoint &center, int rx, int ry)center 是圆心坐标,rx 和 ry 分别是圆形的外接矩形的宽度和高度
drawEllipse(int x, int y, int width, int height)(x, y)是圆心坐标,width 和 height 含义同 rx 和 ry

在这里插入图片描述
代码示例:

void Widget::paintEvent(QPaintEvent *event)
{
    (void)event;//避免不必要的警告
    //圆形
    QPainter painter(this);
    painter.drawEllipse(200, 200, 250, 150);
}

在这里插入图片描述

(4). 绘制文本

QPainter 也可以绘制文本
使用QPainter::drawText()绘制文字
使用QPainter::setFont()设置字体等信息

API说明
drawText(int x, int y, const QString &text)文本 text 的左上角坐标为(x, y)
drawText(const QPointF &position, const QString &text)用QPointF 封装坐标
drawText(const QRectF &rectangle, const QString &text)将 text 放入 rectangle矩形内显示

代码示例:

void Widget::paintEvent(QPaintEvent *event)
{
    (void)event;//避免不必要的警告
    //文本
    QPainter painter(this);
    //设置字体信息
    QFont font("华文行楷", 20);
    painter.setFont(font);
    //绘制文本
    painter.drawText(QRect(100, 100, 180, 200), "千里之行始于足下");
}

把文本设置在宽180px,高200px的矩形中
在这里插入图片描述

2. 工具

(1). 画笔

QPaint绘制图形时,是有默认的画笔的。但也可以自定义画笔。
QPen 定义了 QPainter 应该如何绘制形状、线条和轮廓。同时通过 QPen 设置画笔的线宽、颜色、样式、画刷

  • setWidth(int width):设置线宽
  • setStyle(Qt::PenStyle style):设置画笔的风格
  • QPen(const QColor &color):设置画笔的颜色

画笔的风格由 Qt::PenStyle 枚举
在这里插入图片描述
代码示例:

void Widget::paintEvent(QPaintEvent *event)
{
    (void)event;//避免不必要的警告
    //画笔
    QPainter painter(this);
    //初始化画笔,同时设置颜色
    QPen pen(QColor(255, 0, 0));
    //设置线宽
    pen.setWidth(3);
    //设置风格——虚线
    pen.setStyle(Qt::DashLine);
    //设置画笔
    painter.setPen(pen);
    //画圆
    painter.drawEllipse(100, 100, 200, 100);
}

在这里插入图片描述

(2). 画刷

Qt 使用 QBrush封装画刷操作 ,画刷大多用于填充。QBrush 定义了 QPainter 的填充模式,具有样式、颜色、渐变以及纹理等属性
画刷的格式定义了填充的样式,使用 Qt::BrushStyle 枚举,默认值是 Qt::NoBrush(不进行任何填充)
在这里插入图片描述

设置画刷主要通过 setBrush(const QBrush &brush),参数为画刷对象

void Widget::paintEvent(QPaintEvent *event)
{
    (void)event;//避免不必要的警告
    //画笔
    QPainter painter(this);
    //初始化画笔,同时设置颜色
    QPen pen(QColor(255, 0, 0));
    //设置线宽
    pen.setWidth(3);
    //设置风格——虚线
    pen.setStyle(Qt::DashLine);
    //设置画笔
    painter.setPen(pen);
    //画刷
    QBrush brush(Qt::cyan);//青色
    //设置风格
    brush.setStyle(Qt::Dense1Pattern);
    //设置画刷
    painter.setBrush(brush);
    //画圆
    painter.drawEllipse(100, 100, 200, 100);
}

在这里插入图片描述

3. 绘制图片

Qt 提供了四个类来处理图像数据:QImage、QPixmap、QBitmap、QPicture,都是常用的绘图设备。
QImage 主要用来处理 I/O处理,其对 I/O 处理操作进行了优化,而且可以用来直接访问和操作像素
QPixmap 主要用来在屏幕上显示图像,对图像在屏幕上显现进行了优化
QBitMap 是 QPixmap 的子类,用来处理颜色深度为1的图像,即只能显示黑白两种颜色
QPicture 用来记录并重演 QPainter 命令

QPainter图片操作

对图片的操作,同样在paintEvent()事件处理函数中编写

  1. 绘制简单图片

图片资源的添加与管理,参看【Qt】QWidget 的qrc文件部分

void Widget::paintEvent(QPaintEvent *event)
{
    (void)event;
    QPainter painter(this);
    //绘图
    painter.drawPixmap(0, 0, QPixmap(":/6.jpg"));
}

在这里插入图片描述

  1. 平移图片

平移图片实际是通过改变坐标来实现的,QPainter 提供了 translate()函数来实现坐标原点的改变
其函数原型如下:
在这里插入图片描述
参数(dx, dy)是将坐标原点平移到到(dx, dy)处

代码示例:

void Widget::paintEvent(QPaintEvent *event)
{
    (void)event;
    //平移图片
    QPainter painter(this);
    painter.translate(100, 100);
    //绘图
    painter.drawPixmap(0, 0, QPixmap(":/6.jpg"));
}

在这里插入图片描述

  1. 缩放图片

drawPixmap()的重载函数就可以实现图片的放大和缩小
在这里插入图片描述
通过 width 和 height 控制图片的宽度和高度
代码示例:

void Widget::paintEvent(QPaintEvent *event)
{
    (void)event;
    //缩放图片
    QPainter painter(this);
    painter.drawPixmap(0, 0, QPixmap(":/6.jpg"));//图片原始大小
    //将图片缩放成 100 * 100
    painter.drawPixmap(400, 400, 100, 100, QPixmap(":/6.jpg"));
}

在这里插入图片描述

  1. 旋转图片

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

直接rolate旋转,会导致原先显示界面的图形被旋转到显示界面外

在这里插入图片描述
代码示例:

void Widget::paintEvent(QPaintEvent *event)
{
    (void)event;
    //旋转图片
    QPainter painter(this);
    painter.translate(200, 200);//先旋转原点
    painter.rotate(180);//旋转180度
    painter.translate(-200, -200);//旋转回来
    painter.drawPixmap(0, 0, QPixmap(":/6.jpg"));
}

在这里插入图片描述

  1. 保存/加载画家状态

在绘制图形的过程中,可以通过save()函数保存画家的状态,如当前原点坐标,旋转情况;使用restore()还原画家状态

代码示例:

void Widget::paintEvent(QPaintEvent *event)
{
    (void)event;
    //保存/加载画家状态
    QPainter painter(this);
    painter.drawEllipse(100, 100, 100, 100);//画个圆
    painter.translate(200, 200);//平移原点
    painter.save();//保存画家状态
    //新画一个圆
    painter.drawEllipse(100, 100, 100, 100);
    painter.translate(300, 300);//再平移
    painter.restore();//此时恢复画家状态
    //再画一个圆
    painter.drawEllipse(100, 100, 100, 100);
}

在这里插入图片描述
第二个圆和第三个圆重合了,因为把加载了之前的画家状态

绘图设备

上述代码都是使用 QWidget作为绘图设备,Qt 还提供了 如下三个绘图设备

  • QPixmap:用于在显示器上显示图片
  • QImage:用于对图片进行像素级修改
  • QPicture:用于对 QPainter 的一系列操作进行存档,是实现回放的一种方式

(1). QPixmap

QPixmap核心特性:

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

代码示例:

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    //绘制图形并保存
    //Pixmap绘图设备,尺寸设置为500 * 500
    QPixmap pix(500, 500);
    QPainter painter(&pix);//实例化画家对象
    painter.setPen(QPen(Qt::red));//设置画笔颜色
    painter.drawEllipse(100, 100, 200, 100);
    //保存绘制的图片
    pix.save("C:\\Users\\Lenovo\\Desktop\\code\\text.png");
}

在这里插入图片描述

(2). QImage

QImage 核心特性:

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

QImage 的构造函数,还可以设置绘图格式
在这里插入图片描述

代码示例:

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    //绘图设置的大小为500*500,绘图格式为:QImage::Format_RGB32
    QImage img(500, 500, QImage::Format_RGB32);
    img.fill(Qt::white);//设置背景色为白色,默认为黑色
    QPainter painter(&img);
    painter.setPen(QPen(Qt::cyan));//设置画笔颜色为青色
    painter.drawEllipse(100, 100, 100, 100);
    img.save("C:\\Users\\Lenovo\\Desktop\\code\\img.png");
}

在这里插入图片描述


QImage 也可以用于对图片像素进行修改

  • 通过 setPixel()设置某个像素的颜色值
  • 使用 qRgb 表示一个具体的颜色

代码示例:

void Widget::paintEvent(QPaintEvent *event)
{
    (void)event;
    QPainter painter(this);
    QImage img;
    img.load(":/1.jpg");//加载图片
    //修改像素点
    for(int i = 100; i < 200; ++i)
    {
        for(int j = 100; j < 200; ++j)
        {
            QRgb rgb = qRgb(0, 255, 0);
            img.setPixel(i, j, rgb);
        }
    }
    painter.drawImage(0, 0, img);
}

在这里插入图片描述

(3). QPicture

QPicture 核心特性:

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

QPicture 类似很多游戏的 Replay(回放功能)
此处的Replay并不是把整个游戏画面都录制下来,而是记录了地图中发生的所有事件(地图元素,玩家单位操作,中立生物行为等…)
当回放 Reply 时就是把上述记录的事件再一条条的执行一遍即可还原之前的游戏场景

如果要记录下 QPainter 的命令,首先要使用 QPainter::begin()函数,将QPicture 示例作为参数传递,以便告诉系统开始记录,记录完毕后使用 QPainter::end()终止
复现时,使用QPicture::load()加载记录,使用QPainter::drawPicture()复现绘图

代码示例:

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    //QPicture 复现绘图
    QPainter painter(this);
    QPicture pic;
    //开始记录
    painter.begin(&pic);
    painter.setPen(QPen(Qt::blue));
    painter.drawEllipse(200, 200, 150, 150);
    //终止记录
    painter.end();
    //保存记录
    pic.save("C:\\Users\\Lenovo\\Desktop\\code\\pic.png");
}
void Widget::paintEvent(QPaintEvent *event)
{
    (void)event;
    //QPicture 复现绘图
    QPainter painter(this);
    QPicture pic;
    //加载记录
  	pic.load("C:\\Users\\Lenovo\\Desktop\\code\\pic.png");
    //复现
    painter.drawPicture(0, 0, pic);
}

如此,每次显示窗口时,都会复现 QWidget 构造函数中的绘图操作
在这里插入图片描述

结束语

Qt 对于界面的优化和美化,还涉及很多知识

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

这些都是偏向“设计美工”方面的内容

以上就是本篇博客的所有内容,感谢你的阅读
如果觉得本篇文章对你有所帮助的话,不妨点个赞支持一下博主,拜托啦,这对我真的很重要。
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2126431.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

源于AI绘画的爆火,尝试做了一个工具网站

这两天做了一个 网页 Demo&#xff0c;实现了一些 AI 图像处理功能&#xff0c;前端用的是 React&#xff0c;后端用的是 Django 现在 &#xff0c;Demo 中已经实现的功能有两个&#xff1a; 1&#xff0c;人像分割&#xff1a;从图像中把人物分割出来&#xff0c;用一个透明…

Vue与React的Diff算法

虚拟DOM 定义 虚拟DOM是一种用于在前端开发中模拟真实DOM的技术。它是一种抽象的数据结构&#xff08;简单来说就是一个Javascript对象&#xff09;&#xff0c;用于描述HTML或XML文档的结构和内容。通过将页面的状态和结构保存在内存中&#xff0c;而不是直接操作真实的DOM&am…

C++·io流

本节主要是了解为主&#xff0c;需要具体使用时可以查看文档。 io流操作指的是对各种流的操作&#xff0c;我们经常使用的cin和cout是对标准流的操作&#xff0c;实际上它还可以对文件流操作。 官网资料&#xff1a;Input/Output - C Reference 流输入和流提取功能的实现中有着…

鸿蒙交互事件开发04——手势事件

1 概 述 手势事件是移动应用开发中最常见的事件之一&#xff0c;鸿蒙提供了一些方法来绑定手势事件。通过给各个组件绑定不同的手势事件&#xff0c;并设计事件的响应方式&#xff0c;当手势识别成功时&#xff0c;ArkUI框架将通过事件回调通知组件手势识别的结果。 …

记录一款人气领先的开源国产 ERP 系统

推荐一款人气领先的国产ERP系统&#xff0c;目前在Gitee上有12.3k star&#xff0c;在github上面也有1.2k 管伊佳ERP&#xff08;原名华夏ERP&#xff09;基于SpringBoot框架和SaaS模式&#xff0c;立志为中小企业提供开源好用的ERP软件&#xff0c;目前仅支持进销存财务生产功…

2025年第八届计算机图形和虚拟国际会议(ICCGV 2025)即将召开!

2025年第八届计算机图形和虚拟国际会议&#xff08;ICCGV 2025&#xff09;将于2025年2月21-23日在中国成都举行。随着信息技术的飞速发展&#xff0c;计算机图形学与虚拟现实技术正以前所未有的速度重塑着我们的认知世界与交互体验。从沉浸式游戏到精准医疗模拟&#xff0c;从…

气压测试实验(用IIC)

I2C: 如果没有I2c这类总线&#xff0c;连接方法可能会如下图&#xff1a; 单片机所有的通讯协议&#xff0c;无非是建立在引脚&#xff08;高低电平的变换高低电平持续的时间&#xff09;这二者的组合上&#xff0c;i2c 多了一个clock线&#xff0c;负责为数据传输打节拍。 (i2…

Unity3d中制作触发区域为圆形的按钮

一、常规矩形的Button制作 设置Highlighed Color为绿色。 此时当鼠标在button上方时会显示绿色&#xff1a; 二、圆形Button制作 在Button的Image中选择Source Image为Knob。 程序运行时&#xff0c;鼠标在矩形和圆形之间的区域&#xff0c;button还是会变成绿色。 所以&…

【时时三省】(C语言基础)指针进阶 例题5

山不在高&#xff0c;有仙则名。水不在深&#xff0c;有龙则灵。 ----CSDN 时时三省 abcdef是个常量字符串 把首地址a放在了p里面 第一个p 算的是指针变量的大小 它打印就是4或者8 第二个p1 p本来是a的地址 1就是b的地址 是地址就是打印四或者八 …

chapter14-集合——(List-LikedHashSet)——day18

目录 528-LikedHashSet介绍 529-LikedHashSet源码介绍 528-LikedHashSet课堂练习 528-LikedHashSet介绍 529-LikedHashSet源码介绍 528-LikedHashSet课堂练习

【计网】从零开始认识网络socket

优于别人&#xff0c;并不高贵&#xff0c; 真正的高贵应该是优于过去的自己。 --- 海明威 --- 从零开始认识网络socket 1 网络通信流程2 IP地址 VS MAC地址3 网络socket3.1 理解源 IP 地址和目的 IP 地址3.2 传输层的典型代表3.3 网络字节序3.4 socket编程基础 1 网络通信流…

高压直流接触器及使用注意事项

高压直流接触器及使用注意事项 1.概述2.接触器和继电器有什么区别3.节能线圈4.安装位置5.直流继电器线圈抑制6.高压继电器和接触器有哪些应用?7.线圈效率的决定因素是什么?对线圈驱动器有什么要求?8.负载极性对接触器的影响9.触点参数注意事项10.线圈供电要求1.概述 航空接…

基于单片机实现的的多点分布室内环境监测系统

基于STM32单片机为基础设计的一款室内环境监测系统程序源码 程序分为接收端和采集端两部分 接收端与采集端均以STM32单片机作为控制核心&#xff0c;两者通过ZigBee无线通信技术进行连接。接收端主要用于接收数据并将其实时显示以及报警。 采集端主要用于监测室内环境的各类数…

【Python工具】Python 装饰器实现统计函数执行时长

文章目录 1、背景2、轮子 1、背景 业务基本代码堆积完毕了&#xff0c;部分流程需要调优&#xff0c;想着在几个关键执行路径上进行时间记录&#xff0c;类似 SQL 慢日志一样的方法&#xff0c;方便进行性能问题发现。 了解了下&#xff0c;应该是采用装饰器实现是代码侵入最…

林草湿地址、导出echart为word

2.导出 // 导出exportDoc () {this.loading truelet arrRefs [this.$refs.endChart, this.$refs.processChart, this.$refs.officeEndChart]setTimeout(() > {Promise.all(arrRefs.map((canvasDom) > {return this.html2canvasHandle(canvasDom)})).then(res > {let…

如何让潜意识帮你实现你的目标

潜意识的力量是意识的3万倍以上 如果你有一个宏大的目标&#xff0c;怎么借助潜意识实现你的目标呢 比如&#xff0c;我的目标是&#xff1a;帮助100万人颠覆潜意识&#xff0c;实现人生蜕变&#xff0c;并且培养一万名潜意识开发导师 这么宏大的一个目标&#xff0c;怎么让…

B-树底层原理

一、B-树介绍 定义&#xff1a; B-树&#xff08;B-Tree&#xff09;是一种自平衡的树形数据结构&#xff0c;广泛应用于数据库和操作系统中。它的设计目标是减少搜索、顺序访问、插入和删除操作中比较次数和移动次数&#xff0c;特别适合于磁盘中数据的存储和检索。 性质&a…

运维团队日志管理策略参考

在运维工作中&#xff0c;日志管理是一项至关重要的任务。有效的日志管理不仅能够帮助运维团队实时监控系统状态、发现潜在问题&#xff0c;还能为故障排查和系统性能优化提供宝贵的数据支持。本文结合运维行业的实际需求&#xff0c;介绍了一套全面的日志管理策略&#xff0c;…

AutoDroid: LLM-powered Task Automation inAndroid论文学习

光看题目怎么和上一篇差不多&#xff1f;又是纯用LLM的&#xff1f; 当然还是有一点不一样的&#xff1a; 这里的最大特点是加上了UI领域知识&#xff0c;可以大幅增强LLM在处理UI方面的知识的能力。根据文章的说法&#xff0c;使用了这招他们的LLM可以吊打GPT4V&#xff0c;准…

node.js 完全卸载和下载配置

一、介绍 &#xff08;1&#xff09;node.js Node.js发布于2009年5月&#xff0c;由Ryan Dahl开发&#xff0c;是一个基于ChromeV8引擎的JavaScript运行环境&#xff0c;使用了一个事件驱动、非阻塞式I/O模型&#xff0c; [1]让JavaScript 运行在服务端的开发平台&#xff0c…