QT QPainter绘图之视口和窗口简介

news2024/9/21 4:39:21

1、视口和窗口的定义与原理

绘图设备的物理坐标是基本的坐标系,通过 QPainter 的平移、旋转等变换可以得到更容易操作的逻辑坐标。

为了实现更方便的坐标,QPainter 还提供了视口 (Viewport)和窗口 (Window)坐标系,通过QPainter 内部的坐标变换矩阵自动转换为绘图设备的物理坐标。

视口表示绘图设备的任意一个矩形区域的物理坐标,可以只选取物理坐标的一个矩形区域用于绘图。默认情况下,视口等于绘图设备的整个矩形区。

窗口与视口是同一个矩形,只不过是用逻辑坐标定义的坐标系。窗口可以直接定义矩形区的逻辑坐标范围。图下图所示是对视口和窗口的图示说明。

上图中左图中的矩形框代表绘图设备的物理大小和坐标范围,假设宽度为 300 像素,高度为200 像素。现在要取其中间的一个正方形区域作为视口,灰色的正方形就是视口,绘图设备的物理坐标中,视口的左上角坐标为(50,0),右下角坐标为(250,200)。定义此视口,可以使用QPainter的 setViewport()函数,其函数原型为: 

void QPainter::setViewport(int x,int y, int width, int height)

要定义上图中左图中的视口,使用下面的语句:

painter.setViewport(50,0,200,200);

表示从绘图设备物理坐标系统的起点(50,0)开始,取宽度为 200、高度为 200 的一个矩形区域作为视口。

对于上图中左图的视口所表示的正方形区域,定义一个窗口(上图中右图),窗口坐标的中心在正方形中心,并设置正方形的逻辑边长为 100。可使用QPainter 的 setWindow()函数,其函数原型为:void QPainter::setWindow(int x,int y, int width,int height)所以,此处定义窗口的语句是:
painter. setWindow (-50,-50,100,100);

它表示对应于视口的矩形区域,其窗口左上角的逻辑坐标是(-50,-50),窗口宽度为 100,高度为 100。这里设置的窗口还是一个正方形,使得从视口到窗口变换时,长和宽的变化比例是相同的。实际可以任意指定窗口的逻辑坐标范围,长和宽的变化比例不相同也是可以的。

2、视口和窗口的使用实例

使用窗口坐标的优点是,只需按照窗口坐标定义来绘图,而不用管实际的物理坐标范围的大小。例如在一个固定边长为 100 的正方形窗口内绘图,当实际绘图设备大小变化时,绘制的图形会自动变化大小。这样,就可以将绘图功能与绘图设备隔离开来,使得绘图功能适用于不同大小、不同类型的设备。

实例如下演示了使用视口和窗口的方法:

void WidgetView::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    int W = width();
    int H = height();
    int side = qMin(W, H);
    QRect rect((W-side)/2, (H-side)/2, side, side);
    painter.drawRect(rect);

    painter.setViewport(rect);
    painter.setWindow(-100, -100, 200, 200);
    painter.setRenderHint(QPainter::Antialiasing);
    QPen pen;
    pen.setWidth(1);
    pen.setColor(Qt::red);
    pen.setStyle(Qt::SolidLine);
    painter.setPen(pen);
    for(int i = 0; i < 36; i++)
    {
        painter.drawEllipse(QPoint(50, 0), 50, 50);
        painter.rotate(10);
    }
}

运行实例程序 ,可以得到如下图所示的图形效果。当窗口的宽度大于高度时,以高度作为正方形的边长;当高度大于宽度时,以宽度作为正方形边长,且图形是自动缩放的。

 程序首先定义了一个正方形视口,正方形以绘图设备的长、宽中较小者为边长。然后定义窗口,定义的窗口是原点在中心,边长为 200 的正方形。上图的图形效果实际上是画了36 个圆得到的,循环部分的代码如下:

    for(int i = 0; i < 36; i++)
    {
        painter.drawEllipse(QPoint(50, 0), 50, 50);
        painter.rotate(10);
    }

 每个圆的圆心在X轴上的(50,0),半径为 50。画完一个圆之后坐标系旋转 10°,再画相同的圆,这就巧妙应用了坐标轴的旋转。

二)绘图叠加的效果
对上面的程序稍作修改,增加渐变填充和叠加效果的设置。

void WidgetView::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    int W = width();
    int H = height();
    int side = qMin(W, H);
    QRect rect((W-side)/2, (H-side)/2, side, side);
    painter.drawRect(rect);

    painter.setViewport(rect);
    painter.setWindow(-100, -100, 200, 200);
    painter.setRenderHint(QPainter::Antialiasing);
    QPen pen;
    pen.setWidth(1);
    pen.setColor(Qt::red);
    pen.setStyle(Qt::SolidLine);
    painter.setPen(pen);
    
    QLinearGradient linearGrad(0,0,100,0);
    linearGrad.setColorAt(0, Qt::yellow);
    linearGrad.setColorAt(1, Qt::green);
    linearGrad.setSpread(QGradient::PadSpread);
    painter.setBrush(linearGrad);
    painter.setCompositionMode(QPainter::RasterOp_NotSourceOrDestination);//设置复合模式
  //painter.setCompositionMode(QPainter::CompositionMode_Difference);
  //painter.setCompositionMode(QPainter::CompositionMode_Exclusion);
    for(int i = 0; i < 36; i++)
    {
        painter.drawEllipse(QPoint(50, 0), 50, 50);
        painter.rotate(10);
    }
}

在上面的程序中,对单个圆使用了线性渐变填充,单个圆从左到右,由黄色渐变为绿色。使用 QPainter:setCompositionMode()函数设置组合模式,即后面绘制的图与前面绘制的图的叠加模式。函数参数是一个QPainter:CompositionMode 枚举类型值,可以查看 Qt 帮助,这个枚举类型有近 40 种取值,表示了后绘制图形与前面图形的不同叠加运算方式

下图是其中两种叠加模式下的绘图效果,可以发现采用不同的叠加模式,可以得到不同的绘图效果,甚至是意想不到的绚丽效果。用户可以自己修改程序,设置不同渐变颜色、渐变填充模式、不同叠加模式,也许能绘制出更炫的图形呢。

 

 

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

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

相关文章

【多线程】线程安全问题

1. 一段线程不安全的代码 我们先来看一段代码&#xff1a; public class ThreadDemo {public static int count 0;public static void main(String[] args) {for (int i 0; i < 10_0000; i) {count;}System.out.println("count " count);} } // 打印结果&…

Side Window Filtering 边窗滤波

原理分析 通常用常规图像算法做检测类的算法需要将图像特征增强&#xff0c;其中就需要滤波&#xff0c;把噪点去掉&#xff0c;如果直接用滤波&#xff0c;像高斯滤波&#xff0c;中值滤波&#xff0c;均值滤波等等&#xff0c;不仅会把噪点过滤掉&#xff0c;也会把图像的一些…

An error occurred during installation: No such plugin: cloudbees-folder

An error occurred during installation: No such plugin: cloudbees-folder Index of /packages/jenkins/plugins/cloudbees-folder 下载文件【cloudbees-folder.hpi】

Machine Learning-Ex6(吴恩达课后习题)Support Vector Machines

目录 1. Support Vector Machines 1.1 Example Dataset 1 1.2 SVM with Gaussian Kernels 1.2.1 Gaussian Kernel 1.2.2 Example Dataset 2 1.2.3 Example Dataset 3 2. Spam Classification 2.1 Preprocessing Emails 2.1.1 Vocabulary List 2.2 Extracting Feature…

ffmpeg学习发现av_err2str使用报错问题

最近在学习ffmpeg,照着书上敲代码,发现有个av_err2str错误.书上环境是linux系统的,我使用的windows系统编译器使用的是VS2015.可能是微软的编译器和GCC编译器不太一样这个宏函数用不了. 会报这个错误. 网上找资料超级少,找到一个类似的按照上面修改ffmpeg代码.上面的错误没有了…

Java——装箱和拆箱

一.装箱和拆箱的概念 基本数据(Primitive)类型的自动装箱(autoboxing)、拆箱(unboxing)是自J2SE 5.0开始提供的功能。Java语言规范中说道&#xff1a;在许多情况下包装与解包装是由编译器自行完成的&#xff08;在这种情况下包装称为装箱&#xff0c;解包装称为拆箱&#xff09…

360文件恢复怎么做?3种文件恢复方法分享!

案例&#xff1a;360文件恢复怎么做&#xff1f; 【为了防止病毒入侵和更好的保护电脑&#xff0c;我在电脑上安装了360杀毒软件&#xff0c;但是我昨天在进行垃圾扫描时&#xff0c;软件把我一个很重要的文件删除了&#xff0c;有没有朋友遇到过这种情况呀&#xff1f;我应该…

高数三重积分+离散二元关系+线代矩阵解线性方程

&#x1f442; 梦寻古镇 - 羽翼深蓝Wings - 单曲 - 网易云音乐 &#x1f442; 老男孩 - 1个球 - 单曲 - 网易云音乐 目录 &#x1f33c;前言 &#x1f33c;高数 &#x1f418;B站 -- 三重积分 &#x1f418;课本 -- 7种曲面 公式 &#x1f418;PPT -- 知识点 例题 &a…

【Android FrameWork(五)】- ServiceManager

文章目录 前言源码分析1.service_mananger流程2.Binder通信流程&#xff08;ServiceManager.addService&#xff09;3.Binder的cmd流程图 拓展知识总结1.service_manager2.Binder 前言 接上一篇文章 源码分析 1.service_mananger流程 2.Binder通信流程&#xff08;ServiceMan…

VScode好用的设置(鼠标滚动缩进字体大小等等)

首先我们打开VScode软件&#xff0c;找到左下角的设置 点击设置&#xff0c;找到setting.json&#xff0c;然后点进去 把下面的复制进去&#xff0c;如果想看&#xff0c;可以鼠标悬浮在上面点击看详情 { "workbench.startupEditor": "none", "files.…

电商平台架构演变

大家好&#xff0c;我是易安&#xff01; 今天&#xff0c;我以国内这些年来电商平台的架构的角度&#xff0c;来具体说明下&#xff0c;电商架构是如何一步步演进的。 从2003年淘宝上线开始&#xff0c;国内电商平台经历了高速的发展&#xff0c;在这个过程中&#xff0c;系统…

dwebsocket实现后端数据实时刷新

执行定时任务的时候&#xff0c;我们需要了解执行百分比或者实时数据返回&#xff0c;这时候可以采用的方法1.ajax请求后端服务器&#xff0c;然后前端页面局部渲染获取百分比 2.使用webscoket进行长连接交流刷新 ajax使用方法使用interval函数来实现定时请求&#xff0c;本次这…

【三十天精通Vue 3】第十七天 Vue 3的服务器渲染详解

✅创作者&#xff1a;陈书予 &#x1f389;个人主页&#xff1a;陈书予的个人主页 &#x1f341;陈书予的个人社区&#xff0c;欢迎你的加入: 陈书予的社区 &#x1f31f;专栏地址: 三十天精通 Vue 3 文章目录 引言一、Vue 3 服务器端渲染概述1.1 服务器端渲染的概念1.2 Vue 3…

【SpringBoot实践】Web请求中日期字符串与LocalDate、LocalDateTime的通用转换

1.背景 最近在做一个后台项目&#xff0c;在这个项目中涉及到了多种与日期相关的请求参数&#xff0c;在请求对象中使用了LocalDate与LocalDateTime两个日期类型。通过日期字符串与前端进行交互&#xff0c;也包含两种格式&#xff1a;yyyy-MM-dd HH:mm:ss与yyyy-MM-dd。 在以…

STM32 学习笔记_5 调试方法;外部中断

调试 OLED&#xff1a;方便&#xff0c;试试更新&#xff0c;但是显示框小。 串口&#xff1a;数据全&#xff0c;但是带电脑不方便。 MDK 自带 debug OLED 调试 4个引脚的&#xff1a;3.3~5V 电压&#xff0c;地&#xff0c;SCL SDA 的 IIC。 我们把 GND-VCC-SCL-SDA 接…

微信小程序国际化

参考文件: 国际化&#xff08;微信小程序TS 微信小程序国际化 一、环境目录 注意:一定要注意项目目录结构&#xff0c;新建文件夹miniprogram&#xff0c;并把前面新建的文件移到这个目录中 二、安装根目录依赖 在NEW-FAN-CLOCK1 中安装根目录依赖 npm i -D gulp minipro…

provide和inject,Teleport,Fragment

作用:实现祖孙组件间通信 套路:父组件有一个provide选项来提供数据&#xff0c;子组件有一个inject选项来开始使用这些数据 父组件 只要provide了&#xff0c;那么后代都能拿到&#xff0c;父子之间一般使用props&#xff0c;祖孙组件一般采用provide 响应式数据判断 isRef:…

TIA博途中文本列表的具体使用方法介绍与示例

TIA博途中文本列表的具体使用方法介绍与示例 一、 文本列表的概念 应用场景:设备的当前操作模式、当前的运行流程、当前的运行状态等 功能介绍:  根据信号数值的不同,显示不同的文本  通过下拉列表选择不同的文本给变量赋值  通过文本列表实现配方元素数值的选择输入…

直播系统开发中如何优化API接口的并发

概述 在直播系统中&#xff0c;API接口并发的优化是非常重要的&#xff0c;因为它可以提高系统的稳定性和性能。本文将介绍一些优化API接口并发的方法。 理解API接口并发 在直播系统中&#xff0c;API接口是用于处理客户端请求的关键组件。由于许多客户端同时连接到系统&…

云计算与多云混合云架构的比较与选择

第一章&#xff1a;引言 随着互联网的迅速发展&#xff0c;云计算逐渐成为了一个热门话题。而随着企业的不断发展&#xff0c;多云混合云架构逐渐成为了一种重要的技术架构。本文将从中国国内资深IT专家的角度&#xff0c;对云计算和多云混合云架构进行比较和选择的分析&#…