使用 Qt QGraphicsView/QGraphicsScene 绘制色轮

news2025/5/23 2:08:42

使用 Qt QGraphicsView/QGraphicsScene 绘制色轮

本文介绍如何在 Qt 中利用 QGraphicsViewQGraphicsScene 实现基础圆形绘制,以及进阶的色轮(Color Wheel)效果。
色轮是色彩选择器的常见控件,广泛应用于图形设计、绘画和 UI 取色等场景。本文将详细讲解两种常见的色轮实现方式,并配以完整代码和效果图。


一、QGraphicsView/QGraphicsScene 绘制圆形

1. 原理说明

Qt 的 QGraphicsView/QGraphicsScene 提供了强大的 2D 图形视图框架。QGraphicsScene 负责管理所有图形项,QGraphicsView 负责显示场景内容。
绘制圆形时,常用 QGraphicsEllipseItem,通过设置其矩形区域和填充颜色即可实现。

2. 代码实现

假设我们已经创建了一个 Qt Widgets Application 项目 Scence1。在类的构造函数中创建 QGraphicsSceneQGraphicsView,并添加到 QVBoxLayout 布局中:

Scence1::Scence1(QWidget *parent)
        : QWidget(parent)
{
    // 创建场景
    QGraphicsScene* scene = new QGraphicsScene(this);

    // 创建视图并设置场景
    QGraphicsView* view = new QGraphicsView(scene, this);

    paintEllipse(view, scene); // 绘制椭圆

    //paintColorWheel(view, scene); // 绘制色轮

    // 使用布局管理器添加视图到窗口
    QVBoxLayout* layout = new QVBoxLayout(this);
    layout->addWidget(view);
    setLayout(layout);

    ui.setupUi(this);
}

void Scence1::paintEllipse(QGraphicsView* view, QGraphicsScene* scene)
{
    // 设置画笔为蓝色,宽度为1
    QPen pen;
    pen.setColor(QColor(0, 0, 255));
    pen.setWidth(1);
    // 圆的半径
    int circleR = 160;
    // 创建一个椭圆
    QGraphicsEllipseItem* myEllipseItem = new QGraphicsEllipseItem();
    myEllipseItem->setRect(0, 0, 2 * circleR, 2 * circleR);
    myEllipseItem->setPen(pen);
    myEllipseItem->setBrush(QColor(0, 0, 255));
    // 添加到场景
    scene->addItem(myEllipseItem);
    // 设置视图的场景
    view->setScene(scene);
}

这样我们可以得到一个蓝色的圆形,完成了第一步:

二、QGraphicsView/QGraphicsScene 实现色轮

色轮是色彩学中常用的工具,通常以 HSV 色彩空间为基础。HSV 色彩空间将颜色分为色相(Hue)、饱和度(Saturation)、明度(Value),非常适合用于色轮的实现。

原理说明

色轮的本质是将色相(Hue)映射到圆周上,不同的实现方式可以带来不同的视觉效果和性能表现。
常见的两种实现方式如下:

方式一:多个扇形拼接色轮

实现思路
将圆分成若干个扇形,每个扇形代表一种色相(Hue)。
通过 HSV 颜色模型,改变色相值,生成不同颜色。
使用 QPainterPath 绘制扇形,并填充对应颜色。
每个扇形作为一个 QGraphicsPathItem 添加到 scene,便于后续交互。
代码实现

void Scence1::paintColorWheel(QGraphicsView* view, QGraphicsScene* scene)
{
    // 设置圆的半径
    int radius = 150;
    // 设置扇形数量
    int numSegments = 360;
    // 遍历每个扇形
    for (int i = 0; i < numSegments; ++i) {
        // 计算当前扇形的起始角度和结束角度
        qreal startAngle = i * 16;
        qreal endAngle = (i + 1) * 16;
        // 创建一个 QPainterPath 对象
        QPainterPath path;
        // 移动到圆心
        path.moveTo(0, 0);
        // 绘制扇形路径
        path.arcTo(-radius, -radius, 2 * radius, 2 * radius, startAngle, 16);
        // 填充颜色
        QColor color = QColor::fromHsv(i, 255, 255);
        QBrush brush(color);
        // 创建一个 QGraphicsPathItem 对象
        QGraphicsPathItem* item = new QGraphicsPathItem(path);
        item->setBrush(brush);
        // 添加到场景
        scene->addItem(item);
    }
    // 设置视图的场景
    view->setScene(scene);
}

这样我们就实现了一个简单的色轮效果:

方式二:使用渐变色填充色轮

实现思路
通过 QConicalGradient 创建圆锥形渐变,渐变的颜色从中心向外辐射。
使用 QGraphicsEllipseItem 绘制一个完整的圆形作为色轮的底图。
代码实现

void Scence1::paintColorWheel(QGraphicsView* view, QGraphicsScene* scene)
{
    // 设置圆的半径
    int radius = 150;
    // 创建一个 QConicalGradient 渐变对象
    QConicalGradient gradient(0, 0, 0);
    // 添加颜色停靠点
    for (int i = 0; i < 360; i += 10) {
        gradient.setColorAt(i / 360.0, QColor::fromHsv(i, 255, 255));
    }
    // 创建一个 QGraphicsEllipseItem 对象
    QGraphicsEllipseItem* item = new QGraphicsEllipseItem();
    item->setRect(-radius, -radius, 2 * radius, 2 * radius);
    // 设置渐变填充
    item->setBrush(gradient);
    // 添加到场景
    scene->addItem(item);
    // 设置视图的场景
    view->setScene(scene);
}

这种方式实现的色轮更加平滑,过渡自然:

三、总结

本文介绍了如何使用 Qt 的 QGraphicsViewQGraphicsScene 实现圆形及色轮的绘制。
通过两种方式实现色轮:一种是通过多个扇形拼接而成,另一种是使用渐变色填充。读者可以根据需求选择合适的实现方式。


附录:完整代码

#include "scence1.h"
#include "ui_scence1.h"

Scence1::Scence1(QWidget *parent)
        : QWidget(parent)
{
    // 创建场景
    QGraphicsScene* scene = new QGraphicsScene(this);

    // 创建视图并设置场景
    QGraphicsView* view = new QGraphicsView(scene, this);

    paintEllipse(view, scene); // 绘制椭圆

    //paintColorWheel(view, scene); // 绘制色轮

    // 使用布局管理器添加视图到窗口
    QVBoxLayout* layout = new QVBoxLayout(this);
    layout->addWidget(view);
    setLayout(layout);

    ui.setupUi(this);
}

void Scence1::paintEllipse(QGraphicsView* view, QGraphicsScene* scene)
{
    // 设置画笔为蓝色,宽度为1
    QPen pen;
    pen.setColor(QColor(0, 0, 255));
    pen.setWidth(1);
    // 圆的半径
    int circleR = 160;
    // 创建一个椭圆
    QGraphicsEllipseItem* myEllipseItem = new QGraphicsEllipseItem();
    myEllipseItem->setRect(0, 0, 2 * circleR, 2 * circleR);
    myEllipseItem->setPen(pen);
    myEllipseItem->setBrush(QColor(0, 0, 255));
    // 添加到场景
    scene->addItem(myEllipseItem);
    // 设置视图的场景
    view->setScene(scene);
}

void Scence1::paintColorWheel(QGraphicsView* view, QGraphicsScene* scene)
{
    // 设置圆的半径
    int radius = 150;
    // 设置扇形数量
    int numSegments = 360;
    // 遍历每个扇形
    for (int i = 0; i < numSegments; ++i) {
        // 计算当前扇形的起始角度和结束角度
        qreal startAngle = i * 16;
        qreal endAngle = (i + 1) * 16;
        // 创建一个 QPainterPath 对象
        QPainterPath path;
        // 移动到圆心
        path.moveTo(0, 0);
        // 绘制扇形路径
        path.arcTo(-radius, -radius, 2 * radius, 2 * radius, startAngle, 16);
        // 填充颜色
        QColor color = QColor::fromHsv(i, 255, 255);
        QBrush brush(color);
        // 创建一个 QGraphicsPathItem 对象
        QGraphicsPathItem* item = new QGraphicsPathItem(path);
        item->setBrush(brush);
        // 添加到场景
        scene->addItem(item);
    }
    // 设置视图的场景
    view->setScene(scene);
}

void Scence1::paintColorWheel(QGraphicsView* view, QGraphicsScene* scene)
{
    // 设置圆的半径
    int radius = 150;
    // 创建一个 QConicalGradient 渐变对象
    QConicalGradient gradient(0, 0, 0);
    // 添加颜色停靠点
    for (int i = 0; i < 360; i += 10) {
        gradient.setColorAt(i / 360.0, QColor::fromHsv(i, 255, 255));
    }
    // 创建一个 QGraphicsEllipseItem 对象
    QGraphicsEllipseItem* item = new QGraphicsEllipseItem();
    item->setRect(-radius, -radius, 2 * radius, 2 * radius);
    // 设置渐变填充
    item->setBrush(gradient);
    // 添加到场景
    scene->addItem(item);
    // 设置视图的场景
    view->setScene(scene);
}



void Scence1::paintAxis(QGraphicsScene* scene, int hueCircleR)
{
    // 画三条分割线
    QPen pen;
    pen.setWidth(1);
    pen.setColor(QColor(0, 0, 0));
    pen.setStyle(Qt::DashDotLine);
    pen.setWidth(1);

    // 分割线1:210度到30度
    QGraphicsLineItem* splitLine1 = new QGraphicsLineItem();
    splitLine1->setLine(QLineF(
        hueCircleR + hueCircleR * cos(210 * 3.14159 / 180), hueCircleR - hueCircleR * sin(210 * 3.14159 / 180),
        hueCircleR + hueCircleR * cos(30 * 3.14159 / 180), hueCircleR - hueCircleR * sin(30 * 3.14159 / 180)));
    splitLine1->setPen(pen);

    // 分割线2:270度到90度
    QGraphicsLineItem* splitLine2 = new QGraphicsLineItem();
    splitLine2->setLine(QLineF(
        hueCircleR + hueCircleR * cos(270 * 3.14159 / 180), hueCircleR - hueCircleR * sin(270 * 3.14159 / 180),
        hueCircleR + hueCircleR * cos(90 * 3.14159 / 180), hueCircleR - hueCircleR * sin(90 * 3.14159 / 180)));
    splitLine2->setPen(pen);

    // 分割线3:330度到150度
    QGraphicsLineItem* splitLine3 = new QGraphicsLineItem();
    splitLine3->setLine(QLineF(
        hueCircleR + hueCircleR * cos(330 * 3.14159 / 180), hueCircleR - hueCircleR * sin(330 * 3.14159 / 180),
        hueCircleR + hueCircleR * cos(150 * 3.14159 / 180), hueCircleR - hueCircleR * sin(150 * 3.14159 / 180)));
    splitLine3->setPen(pen);

    // 添加分割线到场景
    scene->addItem(splitLine1);
    scene->addItem(splitLine2);
    scene->addItem(splitLine3);

    // 设置字体
    QFont font("Arial", 8);
    font.setBold(true);

    // 添加文字标注
    QGraphicsTextItem* textItem1 = new QGraphicsTextItem();
    textItem1->setPlainText(QString("CB\n210"));
    textItem1->setFont(font);
    textItem1->setPos(hueCircleR + hueCircleR * cos(210 * 3.14159 / 180) - 30, hueCircleR - hueCircleR * sin(210 * 3.14159 / 180) - 20);

    QGraphicsTextItem* textItem2 = new QGraphicsTextItem();
    textItem2->setPlainText(QString("30\nRY"));
    textItem2->setFont(font);
    textItem2->setPos(hueCircleR + hueCircleR * cos(30 * 3.14159 / 180) + 5, hueCircleR - hueCircleR * sin(30 * 3.14159 / 180) - 20);

    QGraphicsTextItem* textItem3 = new QGraphicsTextItem();
    textItem3->setPlainText(QString("BM 270"));
    textItem3->setFont(font);
    textItem3->setPos(hueCircleR + hueCircleR * cos(270 * 3.14159 / 180) - 30, hueCircleR - hueCircleR * sin(270 * 3.14159 / 180) + 0);

    QGraphicsTextItem* textItem4 = new QGraphicsTextItem();
    textItem4->setPlainText(QString("90 YG"));
    textItem4->setFont(font);
    textItem4->setPos(hueCircleR + hueCircleR * cos(90 * 3.14159 / 180) - 20, hueCircleR - hueCircleR * sin(90 * 3.14159 / 180) - 20);

    QGraphicsTextItem* textItem5 = new QGraphicsTextItem();
    textItem5->setPlainText(QString("330\nMR"));
    textItem5->setFont(font);
    textItem5->setPos(hueCircleR + hueCircleR * cos(330 * 3.14159 / 180) + 5, hueCircleR - hueCircleR * sin(330 * 3.14159 / 180) - 20);

    QGraphicsTextItem* textItem6 = new QGraphicsTextItem();
    textItem6->setPlainText(QString("GC\n150"));
    textItem6->setFont(font);
    textItem6->setPos(hueCircleR + hueCircleR * cos(150 * 3.14159 / 180) - 30, hueCircleR - hueCircleR * sin(150 * 3.14159 / 180) - 20);

    // 添加文字到场景
    scene->addItem(textItem1);
    scene->addItem(textItem2);
    scene->addItem(textItem3);
    scene->addItem(textItem4);
    scene->addItem(textItem5);
    scene->addItem(textItem6);
}

Pos(hueCircleR + hueCircleR * cos(150 * 3.14159 / 180) - 30, hueCircleR - hueCircleR * sin(150 * 3.14159 / 180) - 20);

    // 添加文字到场景
    scene->addItem(textItem1);
    scene->addItem(textItem2);
    scene->addItem(textItem3);
    scene->addItem(textItem4);
    scene->addItem(textItem5);
    scene->addItem(textItem6);
}

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

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

相关文章

使用glsl 来做视频矫正

描述、优点 使用glsl来代替opencv的undistort 和 鱼眼矫正,并且最后使用opencv的LUT给glsl 来使用,来达到加速的目的,并且做到和opencv 一模一样的效果,达到实时视频的加速矫正。 优点: 没有cuda,也可以做到实时视频矫正,包含各类板子和amd的cpu,intel核显 矫正的基本作…

03-Web后端基础(Maven基础)

1. 初始Maven 1.1 介绍 Maven 是一款用于管理和构建Java项目的工具&#xff0c;是Apache旗下的一个开源项目 。 Apache 软件基金会&#xff0c;成立于1999年7月&#xff0c;是目前世界上最大的最受欢迎的开源软件基金会&#xff0c;也是一个专门为支持开源项目而生的非盈利性…

蓝桥杯19682 完全背包

问题描述 有 N 件物品和一个体积为 M 的背包。第 i 个物品的体积为 vi​&#xff0c;价值为 wi​。每件物品可以使用无限次。 请问可以通过什么样的方式选择物品&#xff0c;使得物品总体积不超过 M 的情况下总价值最大&#xff0c;输出这个最大价值即可。 输入格式 第一行…

DeepSeek源码解构:从MoE架构到MLA的工程化实现

文章目录 **一、代码结构全景&#xff1a;从模型定义到分布式训练****二、MoE架构&#xff1a;动态路由与稀疏激活的工程化实践****1. 专家路由机制&#xff08;带负载均衡&#xff09;****数学原理&#xff1a;负载均衡损失推导** **三、MLA注意力机制&#xff1a;低秩压缩与解…

【VLNs篇】02:NavGPT-在视觉与语言导航中使用大型语言模型进行显式推理

方面 (Aspect)内容总结 (Content Summary)论文标题NavGPT: 在视觉与语言导航中使用大型语言模型进行显式推理 (NavGPT: Explicit Reasoning in Vision-and-Language Navigation with Large Language Models)核心问题探究大型语言模型 (LLM) 在复杂具身场景&#xff08;特别是视…

(T_T),不小心删掉RabbitMQ配置文件数据库及如何恢复

一、不小心删除 今天是2025年5月15日&#xff0c;非常沉重的一天&#xff0c;就在今早8点左右的时候我打算继续做我的毕业设计&#xff0c;由于开机的过程十分缓慢&#xff08;之前没有&#xff09;&#xff0c;加上刚开机电脑有卡死的迹象&#xff0c;再加上昨天晚上关电脑前…

TDengine 安全部署配置建议

背景 TDengine 的分布式、多组件特性导致 TDengine 的安全配置是生产系统中比较关注的问题。本文档旨在对 TDengine 各组件及在不同部署方式下的安全问题进行说明&#xff0c;并提供部署和配置建议&#xff0c;为用户的数据安全提供支持。 安全配置涉及组件 TDengine 包含多…

蓝桥杯框架-LED蜂鸣器继电器

蓝桥杯框架-LED蜂鸣器继电器 一&#xff0c;新建工程文件二&#xff0c;配置keil三&#xff0c;完善框架 一&#xff0c;新建工程文件 在桌面上新建一个文件夹&#xff1a;用于存放所有工程文件 在文件夹中再建立一个文件夹DEMO_01&#xff1a;这是我们的第一个工程文件 在第…

uniapp-商城-64-后台 商品列表(商品修改---页面跳转,深浅copy应用,递归调用等)

完成了商品的添加和展示&#xff0c;下面的文字将继续进行商品页面的处理&#xff0c;主要为商品信息的修改的页面以及后天逻辑的处理。 本文主要介绍了商品信息修改页面的实现过程。首先&#xff0c;页面布局包括编辑和删除功能&#xff0c;未来还可添加上架和下架按钮。通过c…

Dify的大语言模型(LLM) AI 应用开发平台-本地部署

前言 今天闲着&#xff0c;捣鼓一下 Dify 这个开源平台&#xff0c;在 mac 系统上&#xff0c;本地部署并运行 Dify 平台&#xff0c;下面记录个人在本地部署Dify 的过程。 Dify是什么&#xff1f; Dify是一个开源的大语言模型&#xff08;LLM&#xff09;应用开发平台&#…

使用教程:8x16模拟开关阵列可级联XY脚双向导通自动化接线

以下通过点亮LED进行基本使用流程演示&#xff0c;实际可以连接复杂外设&#xff08;SPI、CAN、ADC等&#xff09; 单模块使用 RX、TX、5V和GND接到串口模块&#xff1b;X5接5V&#xff1b;Y2接LED;LED-接GND 串口模块插上电脑后&#xff0c;LED没有亮&#xff1b;因为此时模…

8 种快速易用的Python Matplotlib数据可视化方法

你是否曾经面对一堆复杂的数据&#xff0c;却不知道如何让它们变得直观易懂&#xff1f;别慌&#xff0c;Python 的 Matplotlib 库是你数据可视化的最佳伙伴&#xff01;它简单易用、功能强大&#xff0c;能将枯燥的数字变成引人入胜的图表。无论是学生、数据分析师还是程序员&…

C# 深入理解类(实例构造函数)

实例构造函数 实例构造函数是一个特殊的方法&#xff0c;它在创建类的每个新实例时执行。 构造函数用于初始化类实例的状态。如果希望能从类的外部创建类的实例&#xff0c;需要将构造函数声明为public。 图7-2阐述了构造函数的语法。除了下面这几点&#xff0c;构造函数看起…

RabbitMQ——消息确认

一、消息确认机制 生产者发送的消息&#xff0c;可能有以下两种情况&#xff1a; 1> 消息消费成功 2> 消息消费失败 为了保证消息可靠的到达消费者&#xff08;&#xff01;&#xff01;&#xff01;注意&#xff1a;消息确认机制和前面的工作模式中的publisher confi…

测试W5500的第2步_使用ioLibrary库创建TCP客户端

ioLibrary库下载地址&#xff1a;文件下载地址:https://gitee.com/wiznet-hk/STM32F10x_W5500_Examples 源文件下载地址:https://gitee.com/wiznet-hk 没有注册的&#xff0c;只能复制粘贴了。 本文介绍了如何初始化STM32的硬件资源&#xff0c;配置W5500的网络参数&#xff…

深度学习之用CelebA_Spoof数据集搭建一个活体检测-训练好的模型用MNN来推理

一、模型转换准备 首先确保已完成PyTorch到ONNX的转换&#xff1a;深度学习之用CelebA_Spoof数据集搭建活体检测系统&#xff1a;模型验证与测试。这里有将PyTorch到ONNX格式的模型转换。 二、ONNX转MNN 使用MNN转换工具进行格式转换&#xff1a;具体的编译过程可以参考MNN的…

开源安全大模型Foundation-Sec-8B实操

一、兴奋时刻 此时此刻,晚上22点55分,从今天早上6点左右开始折腾,花费了接近10刀的环境使用费,1天的休息时间,总算是把Foundation-Sec-8B模型跑起来了,中间有两次胜利就在眼前,但却总在远程端口转发环节出问题,让人难受。直到晚上远程Jupyter访问成功那一刻,眉开眼笑,…

【JavaWeb】MySQL

1 引言 1.1 为什么学&#xff1f; 在学习SpringBootWeb基础知识(IOC、DI等)时&#xff0c;在web开发中&#xff0c;为了应用程序职责单一&#xff0c;方便维护&#xff0c;一般将web应用程序分为三层&#xff0c;即&#xff1a;Controller、Service、Dao 。 之前的案例中&am…

微信小游戏流量主广告自动化浏览功能案例5

功能需求&#xff1a; 支持APP单行文本框输入1个小程序链接&#xff0c;在“文件传输助手”界面发送小程序链接并进入。 主要有“文章列表首页”和“文章内容”页面。每个页面支持点击弹窗广告、槽位广告、视频广告入口、视频广告内第三方广告。 弹窗广告、槽位广告、视频广…

软件的技术架构、应用架构、业务架构、数据架构、部署架构

一、各架构定义 1. 技术架构&#xff08;Technical Architecture&#xff09; 定义&#xff1a;技术架构关注的是支撑系统运行的底层技术基础设施和软件平台&#xff0c;包括硬件、操作系统、中间件、编程语言、框架、数据库管理系统等技术组件的选择和组合方式。它描述了系统…