【QT】QPainter基本绘图

news2024/12/25 12:46:16
     

目录

1 QPainter绘图系统

1.1 QPainter与QPaintDevice

1.2 paintEvent事件和绘图区

1.3 QPainter绘图的主要属性

1.4 创建实例

2 QPen的主要功能

2.1 线条样式

2.2 线条端点样式

2.3 线条连接样式

3 QBrush的主要功能

4 渐变填充

5 QPainter绘制基本图形元件

5.1 基本图形元件

5.2 QPainterPath的使用


        GUI用户界面的优势是通过可视化的界面元素为用户提供便利的操作,界面上的按钮、编辑 框等各种界面组件其实都是通过绘图而得到的。 Qt 的二维绘图基本功能是使用 QPainter 在绘图设 备上绘图,绘图设各包括 QWidget 、 QPixmap 等,通过绘制一些基本的点、线、圆等基本形状组 成自己需要的图形,得到的图形是不可交互操作的图形。

1 QPainter绘图系统

1.1 QPainter与QPaintDevice

        Qt的绘图系统使用户可以在屏幕或打印设备上用相同的API绘图,绘图系统基于QPainter、 QPaintDevice和QPaintEngine类。QPainter是用来进行绘图操作的类,QPaintDevice是一个可以使 用QPainter进行绘图的抽象的二维界面,QPaintEngine给QPainter提供在不同设备上绘图的接口。 QPaintEngine类由QPainter和QPaintDevice内部使用,应用程序一般无需和QPaintEngine打交道, 除非要创建自己的设备类型。
        一般的绘图设备包括QWidget、QPixmap、Qlmage等,这些绘图设备为QPainter提供一个 “画布"。

1.2 paintEvent事件和绘图区

        QWidget类及其子类是最常用的绘图设备,从QWidget类继承的类都有paintEvent()事件,要 在设备上绘图,只需重定义此事件并编写响应代码。创建一个QPainter对象获取绘图设备的接口, 然后就可以在绘图设备的“画布”上绘图了。
        在paintEvent()事件里绘图的基本程序结构是:
void Widget::paintEvent(QPaintEvent *event)
{
    QPainter    painter(this);//创建与绘图设备关联的QPainter对象
    ...//painter在设备的窗口上画图
}
        首先创建一个属于本绘图设各的QPainter对象painter,然后使用这个painter在绘图设备的窗 口上画图。
        QWidget的绘图区就是其窗口内部区域。如图8-1 所示是在一个QWidget窗口上绘制了一个填充矩形 (这个实心矩形及其边框是程序绘制的图形,其他直线 和文字是为说明而加的),整个窗口内部的矩形区就是QPainter可以绘图的区域。
        QWidget的内部绘图区的坐标系统如图8-1所示, 坐标系统的单位是像素。左上角坐标为(0,0),向右是 x轴正方向,向下是Y轴正方向,绘图区的宽度由 QWidget::width()函数获取,高度由QWidget::height()函数获取,所以,绘图区右下角的的点的坐标 是(width(),height())。这个坐标系统是QWidget绘图区的局部物理坐标,称为视口(viewport)坐标。相应的还有逻辑坐标,称为窗口(window)坐标,后面再详细介绍。
        使用QPainter在QWidget上绘图就是在这样的一个矩形区域里绘图。

1.3 QPainter绘图的主要属性

        用QPainter在绘图设各上绘图,主要是绘制一些基本的图形元素,包括点、直线、圆形、矩 形、曲线、文字等,控制这些绘图元素特性的主要是的3个属性,分别如下。
  • pen属性:是一个QPen对象,用于控制线条的颜色、宽度、线型等,如图8-1所示矩形 边框的线条的特性就是由pen属性决定的。
  • brush属性:是一个QBrush对象,用于设置一个区域的填充特性,可以设置填充颜色、填 充方式、渐变特性等,还可以采用图片做材质填充。图8-1中的矩形用黄色填充就是由brush 属性设置决定的。
  • font属性:是一个QFont对象,用于绘制文字时,设置文字的字体样式、大小等属性。
        使用这3个属性基本就控制了绘图的基本特点,当然还有一些其他的功能结合使用,比如叠 加模式、旋转和缩放等功能。

1.4 创建实例

        为演示QPainter绘图的基本功能,创建一个Qt Widget Application项目samp8_1,并选择窗口 基类为QWidget,自动创建窗体。创建后的项目有一个Widget类,为了简化代码功能,Widget窗 口里不再放置任何其他组件,只用来绘图。
        下面是Widget类的完整定义。只是重新定义了paintEvent()事件,在此事件里编写绘图的代 码。Q_DECL_OVERRIDE宏表示这个函数是对父类虚函数的重载。
class Widget : public QWidget
{
    Q_OBJECT
protected:
    void    paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE;

public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();

private:
    Ui::Widget *ui;
};
        下面是Widget类构造函数和paintEvent()函数的代码,在界面上绘制如图8-1所示的一个填充 矩形,演示了QPainter绘图的基本过程。
Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);

    setPalette(QPalette(Qt::white));//设置窗口为白色背景
    setAutoFillBackground(true);
    this->resize(400,400);
}

void Widget::paintEvent(QPaintEvent *event)
{
    QPainter    painter(this);//创建QPainter对象
    painter.setRenderHint(QPainter::Antialiasing);//
    painter.setRenderHint(QPainter::TextAntialiasing);//

    int W=this->width(); //绘图区宽度
    int H=this->height(); //绘图区高度
    QRect rect(W/4,H/4,W/2,H/2); //中间区域矩形框

//设置画笔
    QPen    pen;
    pen.setWidth(3); //线宽
    pen.setColor(Qt::red); //划线颜色
    pen.setStyle(Qt::SolidLine);//线的类型,实线、虚线等
    pen.setCapStyle(Qt::FlatCap);//线端点样式
    pen.setJoinStyle(Qt::BevelJoin);//线的连接点样式
    painter.setPen(pen);

//设置画刷
    QBrush  brush;
    brush.setColor(Qt::yellow); //画刷颜色
    brush.setStyle(Qt::SolidPattern); //画刷填充样式
    painter.setBrush(brush);
//绘图
    painter.drawRect(rect);
}
   在paintEvent()函数中,首先创建与Widget关联的QPainter对象painter,这样就可以用这个 painter在Widget上绘图了。
        下面的代码获取Widget窗口的宽度和高度,并定义了位于中间区域的矩形rect,这个矩形的 大小随Widget的大小变化而变化,因为它的大小定义中利用了Widget的宽度和高度,而不是固 定大小。
int W=this->width(); //绘图区宽度
int H=this->height(); //绘图区高度
QRect rect(W/4,H/4,W/2,H/2); //中间区域矩形框
        然后定义了一个QPen类的对象pen,设置其线宽、颜色、线型等,然后设置为painter的pen。 再定义了一个QBrush类的对象brush,设置其颜色为黄色,填充方式为实体填充,然后设置为painter的brush。
        这样设置好painter的pen和brush属性后,调用QPainter类的drawRect()函数,就可以绘制 前面定义的矩形了,矩形框的线条特性由pen决定,填充特性由brush决定。运行程序就可以得到 如图8-1所示的居于界面中间的填充矩形框。
        为了不使程序结构太过于复杂,在paintEvent()函数里直接设置pen和brush的各种属性,而 不是设计复杂的界面程序来修改这些设置。要实现什么绘图功能,只需在paintEvent()函数里直接 修改代码即可。

2 QPen的主要功能

        QPen用于绘图时对线条进行设置,主要包括线宽、颜色、线型等,表8-1是QPen类的主要 接口函数。通常一个设置函数都有一个对应的读取函数,例如setco]or()用于设置画笔颜色,对应 的读取画笔颜色的函数为color(),表8仅列出设置函数(省略了函数参数中的const关键字)。
        线条颜色和宽度的设置无需多说,QPen影响线条特性的另外3个主要属性是线条样式(style)、 端点样式(capStyle)和连接样式(joinStyle)o

2.1 线条样式

        setStyle(Qt::PenStyiestyle)函数用于设置线条样式,参数是一个枚举类型Qt::PenStyle的常量, 几种典型的线条样式的绘图效果如图8-2所示。Qt::PenStyle类型还有一个常量Qt::NoPen表示不 绘制线条。
        除了几种基本的线条样式外,用户还可以自定义线条样式,自定义线条样式时需要用到 setDashOffset()和setDashPattern()函数。

2.2 线条端点样式

        setCapStyle(Qt::PenCapStyle style)函数用于设置线条端点样式,参数是一个枚举类型 Qt::PenCapStyle的常量,该枚举类型的3种取值及其绘图效果如图8-3所示。

2.3 线条连接样式

        setJoinStyle(QtLLPenJoinStyle style)函数用于设置线条连接样式,参数是一个枚举类型 Qt::PenJoinStyle的常量,该枚举类型的取值及其绘图效果如图8-4所示。

3 QBrush的主要功能

        QBrush定义了QPainter绘图时的填充特性,包括填充颜色、填充样式、材质填充时的材质图 片等,其主要函数见表8-2(省略了函数参数中的const关键字)。
        setStyle(Qt::BrushStyle style)函数设置画刷的样式,参数是Qt::
Brushstyle style 枚举类型,该枚 举类型典型的几种取值见表8-3,详细的取值请参考Qt的帮助文件。几种典型取值的填充效果如 图8-5所示。
        渐变填充需要使用专门的类作为Brush赋值给QPainter,这部分在后面详细介绍。其他各种 线型填充只需设置类型参数即可,使用材质需要设置材质图片。
        下面是使用资源文件里的一个图片进行材质填充的示例程序,用材质图片填充一个矩形,程 序运行结果如图8-6所示。
void Widget::paintEvent(QPaintEvent *event)
{
    QPainter    painter(this);//创建QPainter对象
    int W=this->width(); //绘图区宽度
    int H=this->height(); //绘图区高度
    QRect rect(W/4,H/4,W/2,H/2); //中间区域矩形框

//设置画笔
    QPen    pen;
    pen.setWidth(3); //线宽
    pen.setColor(Qt::red); //划线颜色
    pen.setStyle(Qt::SolidLine);//线的类型,实线、虚线等
    painter.setPen(pen);

//设置画刷
    QPixmap texturePixmap(":images/images/texture.jpg");
    QBrush  brush;
    brush.setStyle(Qt::TexturePattern); //画刷填充样式
    brush.setTexture(texturePixmap);
    painter.setBrush(brush);
//绘图
    painter.drawRect(rect);
}

4 渐变填充

        使用渐变填充需要用渐变类的对象作为Painter的brush,有3个实现渐变填充的类。
  • QLinearGradient:线性渐变。指定一个起点及其颜色,终点及其颜色,还可以指定中间的 某个点的颜色,起点至终点之间的颜色会线性插值计算,得到线性渐变的填充颜色。
  • QRadialGradient:有简单辐射渐变和扩展辐射渐变两种方式。简单辐射渐变是在一个圆内 的一个焦点和一个端点之间生成渐变颜色,扩展辐射渐变是在一个焦点圆和一个中心圆之 间生成渐变色。
  • QConicalGradient:圆锥形渐变,围绕一个中心点逆时针生成渐变颜色。
        这3种渐变的示例效果如图8-7所示。
        这3个渐变类都继承自QGradient类,除了生成渐变颜色的方式不同之外,在设定的渐变颜 色坐标范围之外,还需要用QGradient类的setSpread(QGradient::Spread method)函数设置延展方式。
枚举类型QGradient::Spread有3种取值,分别表示3种延展效果,图8-8是使用辐射渐变时3种 延展方式的效果。setSpread()对圆锥形渐变不起作用。
  • PadSpread模式是用结束点的颜色填充外部区域,这是缺省的方式。
  • Repeatspread模式是重复使用渐变方式填充外部区域。
  • Reflectspread是反射式重复使用渐变方式填允外部区域。
下面的代码演示使用渐变效果绘图,程序中使用了辐射渐变。
void Widget::paintEvent(QPaintEvent *event)
{
    QPainter    painter(this);//创建QPainter对象
    int W=this->width(); //绘图区宽度
    int H=this->height(); //绘图区高度

//径向渐变
    QRadialGradient  radialGrad(W/2,H/2,qMax(W/8,H/8),W/2,H/2);
    radialGrad.setColorAt(0,Qt::green);
    radialGrad.setColorAt(1,Qt::blue);
    radialGrad.setSpread(QGradient::ReflectSpread);
    painter.setBrush(radialGrad);
//绘图
    painter.drawRect(this->rect);//填充更大区域,会有延展效果
}
        上面的代码中定义QRadialGradient对象时使用的构造函数原型是:
QRadialGradient(qreal cx,qreal cy,qreal radius,qreal fx,qreal fy)
        其中,(cx,cy)是辐射填充的中心点,程序中设置为(W/2,H/2),也就是Widget窗口的中心;radius是辐射填充区的半径,程序中设置为qMax(W/8,H/8);(fx,fy)是焦点坐标,程序中设置为(W/2,H/2),与中心点相同。
        设置辐射渐变的起点颜色和终点颜色的语句是:
    radialGrad.setColorAt(0,Qt::green);
    radialGrad.setColorAt(1,Qt::blue);
        这里的“点”使用了逻辑坐标,0表示起点,即辐射中心点;1表示终点,即填充区圆的圆周。再用setSpread()函数设置延展方式为QGradient::ReflectSpread。
        最后的绘图语句是:
painter.drawRect(this->rect);
        这里绘制一个矩形,但是使用的矩形是this->rect(),即Widget窗口的整个矩形区域,它大于定义的辐射填充区域,所以会有延展效果。程序运行效果如图8-9所示。
        若使用线性渐变填充,示例代码如下(只列出QLinearGradient定义的部分)。定义QLinearGradient对象时指定了线性渐变的起点和终点,设置颜色时可以在起点和终点之间设置多个点的颜色值。
//线性渐变
//  QLinearGradient  linearGrad(rect.left(),rect.top(),
                  rect.right(),rect.bot//tom()); //对角线                      QLinearGradient  linearGrad(rect.left(),rect.top(),
                   rect.right(),rect.top());//从左到右
    linearGrad.setColorAt(0,Qt::blue);//起点颜色
    linearGrad.setColorAt(0.5,Qt::green);//中间点颜色
    linearGrad.setColorAt(1,Qt::red);//终点颜色
    linearGrad.setSpread(QGradient::ReflectSpread);  //展布模式
    painter.setBrush(linearGrad);
 创建QLinearGradient对象时传递了两个坐标点,分别表示填充区的起点和终点,起点和终点 的定义方式不同,可以实现水平渐变、垂直渐变、或对角渐变等不同效果。
        使用圆锥形渐变的示例代码如下。创建QConicalGradient对象时指定了中心点坐标和起始角 度,然后设置多个点的颜色。但是注意,圆锥形填充没有延展效果。
//圆锥型渐变
    QConicalGradient  coniGrad(W/2,H/2,45);
    coniGrad.setColorAt(0,Qt::yellow);
    coniGrad.setColorAt(0.5,Qt::blue);
    coniGrad.setColorAt(1,Qt::green);
    painter.setBrush(coniGrad);

5 QPainter绘制基本图形元件

5.1 基本图形元件

        QPainter提供了很多绘制基本图形的功能,包括点、直线、椭圆、矩形、曲线等,山这些基 本的图形可以构成复杂的图形。QPainter中提供的绘制基本图元的函数见表8-4。每个函数基本上 都有多种参数形式,这里只列出函数名,给出了其中一种参数形式的示例代码,并且假设己经通
过以下的代码获得了绘图窗口的painter、窗口宽度w和高度H
QPainter painter(this);//创建QPainter对象
int W=this->width(); //绘图区宽度
int H=this->height(); //绘图区高度
        同一个函数名的其他参数形式的函数原型可查阅Qt的帮助文件。

        这些基本图形元件的绘制用户可以通过修改samp8_1的paintEvent()里的代码进行测试,这里就不再详细举例和说明了。

5.2 QPainterPath的使用

        在表8-4列举的QPainter绘制基本图形元件的函数中,一般的图形元件的绘制都比较简单和直观,只有drawPath()函数是绘制一个复合的图形对象,它使用一个QPainterPath类型的参数作为绘图对象。drawpath()函数的原型是:

void QPainter::drawPath(const QPainterPath &path)

        QPainterPath是一系列绘图操作的顺序集合,便于重复使用。一个PainterPath由许多基本的绘图操作组成,如绘图点移动、划线、画圆、画矩形等,一个闭合的PainterPath是终点和起点连接起来的绘图路径。使用QPainterPath的优点是绘制某些复杂形状时只需创建一个PainterPath,然后调用QPainter::drawPath()就可以重复使用。例如绘制一个复杂的星星图案需要多次调用lineto()函数,定义一个QPainterPath类型的变量path记录这些绘制过程,再调用drawPath(path)就可以完成星型图案的绘制。

        QPainterPath提供了很多函数可以添加各种基本图形元件的绘制,其功能与QPainter提供的绘制基本图件的功能类似,也有一些用于PainterPath的专用函数,如closeSubpath()、connectPath()等,对于QPainterPath的函数功能不做详细说明,可以参考Qt帮助文件查看QPainterPath类的详细描述。

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

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

相关文章

burp靶场--身份认证漏洞

burp靶场–身份认证漏洞 https://portswigger.net/web-security/authentication#what-is-authentication 1.身份认证漏洞: ### 身份验证漏洞 从概念上讲,身份验证漏洞很容易理解。然而,由于身份验证和安全性之间的明确关系,它们…

基于Java SSM框架实现学校招生信息网系统项目【项目源码+论文说明】

基于java的SSM框架实现学生招生信息网系统演示 摘要 随着科学技术的飞速发展,社会的方方面面、各行各业都在努力与现代的先进技术接轨,通过科技手段来提高自身的优势,学校招生信息网当然也不能排除在外。学校招生信息网是以实际运用为开发背…

【大数据】Flink 中的状态管理

Flink 中的状态管理 1.算子状态2.键值分区状态3.状态后端4.有状态算子的扩缩容4.1 带有键值分区状态的算子4.2 带有算子列表状态的算子4.3 带有算子联合列表状态的算子4.4 带有算子广播状态的算子 在前面的博客中我们指出,大部分的流式应用都是有状态的。很多算子都…

OpenCV 0 - VS2019配置OpenCV

1 配置好环境变量 根据自己的opencv的安装目录配置 2 新建一个空项目 3 打开 视图->工具栏->属性管理器 4 添加新项目属性表 右键项目名(我这是opencvdemo)添加新项目属性表,如果有配置好了的属性表选添加现有属性表 5 双击选中Debug|x64的刚添加的属性表 6 (重点)添…

[LVGL] 可点击的文字label

LVGL8.x 自带的label 是没有点击响应的功能,即使加了lv_obj_add_event_cb 也不起作用,为了解决这个问题,我们使用了按钮控件去模拟纯label的效果;有了这个demo用户就可以实现类似超链接 点击一个文字就跳转到某个页面的功能。 st…

Kotlin 教程(环境搭建)

Kotlin IntelliJ IDEA环境搭建 IntelliJ IDEA 免费的社区版下载地址:Download IntelliJ IDEA – The Leading Java and Kotlin IDE 下载安装后,我们就可以使用该工具来创建项目,创建过程需要选择 SDK, Kotlin 与 JDK 1.6 一起使…

【大数据】详解 Flink 中的 WaterMark

详解 Flink 中的 WaterMark 1.基础概念1.1 流处理1.2 乱序1.3 窗口及其生命周期1.4 Keyed vs Non-Keyed1.5 Flink 中的时间 2.Watermark2.1 案例一2.2 案例二2.3 如何设置最大乱序时间2.4 延迟数据重定向 3.在 DDL 中的定义3.1 事件时间3.2 处理时间 1.基础概念 1.1 流处理 流…

1.【Vue3】前端开发引入、Vue 简介

1. 前端开发引入 1.1 前端开发前置知识 通过之前的学习,已经通过 SpringBoot 和一些三方技术完成了大事件项目的后端开发。接下来开始学习大事件项目的前端开发,前端部分借助两个框架实现: Vue3(一个 JS 框架)基于 …

Vue-Router: 如何使用路由元信息来管理路由?

Vue-Router是Vue.js官方的路由管理器,它可以帮助我们快速构建单页应用程序(SPA)。除了常见的路由功能外,Vue-Router还支持使用路由元信息来管理和控制路由。路由元信息是可以附加到路由上的自定义属性,它可以帮助我们实…

LandrayOA内存调优 / JAVA内存调优 / Tomcat web.xml 超时时间调优实战

目录 一、背景说明 二、LandrayOA / Tomcat 内存调优 2.1 \win64\tomcat\conf\web.xml 文件调优 2.2 \win64\tomcat\bin\catalina64.bat 文件调优 一、背景说明 随着系统的使用时间越来越长,数据量越多,发现系统的有些功能越来越慢&…

在腾讯云上部署幻兽帕鲁,实现游戏自由!

在帕鲁的世界,你可以选择与神奇的生物「帕鲁」一同享受悠闲的生活,也可以投身于与偷猎者进行生死搏斗的冒险。帕鲁可以进行战斗、繁殖、协助你做农活,也可以为你在工厂工作。你也可以将它们进行售卖,或肢解后食用。引用自&#xf…

第17章_反射机制(理解Class类并获取Class实例,类的加载与ClassLoader的理解,反射的基本应用,读取注解信息,体会反射的动态性)

文章目录 第17章_反射机制本章专题与脉络1. 反射(Reflection)的概念1.1 反射的出现背景1.2 反射概述1.3 Java反射机制研究及应用1.4 反射相关的主要API1.5 反射的优缺点 2. 理解Class类并获取Class实例2.1 理解Class2.1.1 理论上2.1.2 内存结构上 2.2 获取Class类的实例(四种方…

Linux系统优化要义

这里不敢说 linux优化奥义,主要是本文比较浅显,适合普通开发相关人员去读 linux作为服务器系统的王者,以稳定性著称,但对于不同的“应用场景”,相关配置还需调整,才能保证业务稳定性。以下是相关总结 IO优…

函数入门.

函数入门 1. 初识函数2. 函数的参数2.1 参数2.2 默认参数2.3 动态参数 3. 函数返回值总结作业 1. 初识函数 函数到底是个什么东西? 函数,可以当做是一大堆功能代码的集合。 def 函数名():函数内编写代码......函数名()例如: # 定义名字叫in…

Linux 驱动开发基础知识—— 具体单板的 LED 驱动程序(五)

个人名片: 🦁作者简介:一名喜欢分享和记录学习的在校大学生 🐯个人主页:妄北y 🐧个人QQ:2061314755 🐻个人邮箱:2061314755qq.com 🦉个人WeChat:V…

THM学习笔记——john

John the Ripper是目前最好的哈希破解工具之一。 John基本语法: john [options] [path to file] john:调用John the Ripper程序。 [path to file]:包含你要尝试破解的哈希的文件,如果它们在同一个目录中,你就不需要命名…

S275 4G网络IO模块:智能酒店的理想选择

行业背景 随着物联网技术的发展,酒店服务也变得更加“智能”——自动灯光效果、室内温湿度控制、各种人性化操作等贴心服务,带给顾客真正的宾至如归之感。 同时,智慧酒店更为管理者提供了高效的管理手段,将酒店物耗、能耗、人员…

CSS探索浏览器兼容性

学习如何探索浏览器的兼容性对于编写跨浏览器兼容的CSS代码非常重要。以下是一些学习CSS兼容性的方法: MDN文档:Mozilla开发者网络(MDN)提供了广泛而详细的CSS文档,其中包含有关CSS属性、选择器和功能的信息。在MDN上…

解决 PDF.js v2.3.200 (build: 4ae3f9fc) 信息:PDFDocument: Stream must have data

文章标题 问题描述:思考分析:解决方案:参考资料 问题描述: 项目中使用PDF.js去预览已上传的附件文件时,加载PDF文件的时候报了以下的错误 错误信息如下 PDF.js v2.3.200 (build: 4ae3f9fc) 信息:PDFDocu…

基于QC-LDPC编码的循环移位网络的FPGA实现

一、桶式移位寄存器(barrel shifter) 八位桶式移位寄存器的VHDL实现如下,由于每一层结构相似,于是采用生成语句for_generate实现,使用该代码实现的RTL级分析和理论的结构一致,仿真结果也符合预期。 entity barrel_shift isGENE…