Qt中已经有一些封装好的对话框,比如QMessageBox、QColorDialog等,使用起来快捷方便,但缺点是我们无法为它们自定义样式,所以可能难以“融入”我们的项目。既然如此,那就自己做一个把。抱着这样的想法,我设计了一个颜色编辑选取对话框。

设计界面时,我参考了photoshop的拾色器、windows的画图软件以及一个手绘控件软件mockup。

最终完成的界面如下:

它包括以下一些功能:

  • 选取预设的基本颜色
  • 添加自定义颜色方便下次选取
  • 从颜色拾取区域选择颜色
  • 预览当前颜色和新选择的颜色
  • 查看和编辑调整颜色的hsv、rgb和16进制值

下面对一些重点难点作相关介绍:

一、色调、饱和度、亮度

从上图可以看到,右边的矩形是调整色调的区域,这部分亮度和饱和度都是100%,色调值由下往上递增,范围是0-360。

左边的正方形区域是在某个色调值下,调整饱和度和亮度。亮度由下往上递增,饱和度由左往右递增。

色调(Hue)、饱和度(Saturation)、亮度(Brightness或Value)三者决定一个颜色(注:这里不考虑透明度),也就是我们所说的hsv。

同样地,一个颜色可以用hsv表示,也可以用RGB来表示。

根据上面的原理,设计相关算法也就不难了。

1.色调

m_huePixmap = QPixmap(34, 270);
m_huePixmap.fill(Qt::transparent);
QPainter painter(&m_huePixmap);
painter.setRenderHint(QPainter::Antialiasing);
QLinearGradient hueGradient(0, m_iColorHeight, 0, 0);
for (double i = 0; i < 1.0; i += 1.0 / 16)
{
hueGradient.setColorAt(i, QColor::fromHsvF(i, 1, 1, 1));
}
hueGradient.setColorAt(1, QColor::fromHsvF(0, 1, 1, 1));
painter.setPen(Qt::NoPen);
painter.setBrush(QBrush(hueGradient));
painter.drawRect(0, topMargin, m_iColorWidth, m_iColorHeight);

请原谅代码中一些费解的变量和值。

在这里,我们使用的是QLinearGeadient渐变来画一个pixmap,由下往上,饱和度百分值由0增加到1.0。

2.饱和度、亮度

一开始我的想法是这个问题能不能像色调一样,也用渐变来解决,但是并没有想到合适的办法。

于是只能遍历每个像素并设置颜色,一共遍历了256 * 256次!

for (int i = 0; i <= 255; ++i)
{
uchar *colorUnit = m_svImg.scanLine(i);
for (int j = 0; j <= 255; ++j)
{
color.setHsv(m_iHue, j, 255 - i);
QRgb curRgb = color.rgb();
colorUnit[j * 4] = qBlue(curRgb);
colorUnit[j * 4 + 1] = qGreen(curRgb);
colorUnit[j * 4 + 2] = qRed(curRgb);
colorUnit[j * 4 + 3] = 255;
}
}

QImage有一个函数setPixel,设置每一个像素点的Rgb值,但是该函数效率很低。根据qt给出的建议,使用scanLine()这个函数

一开始我用的是QPixmap,但发现并没有设置像素颜色的函数,于是换成了QImage。

当时还找了别人写的一些颜色编辑器demo,发现他们居然都用的setPixel,效率之低难以置信。于是硬着头皮在Qt文档中找答案,最终找到了scanLine,效率提高了不少。

但是遍历256*256次总让人感觉不那么自在!

~

~

~

直到有一天,灵光一现。在这个正方形区域中,同一垂直线上的色调值和饱和度值是一样的,同一水平线上的色调值和亮度值是一样的。那么从左往右是从白色#ffffff到当前色调区域所选颜色的渐变,由上往下可以是一个透明度从0到255的渐变。将二者结合起来,正好得到了我想要的。或许,这就是缘分吧:

//1
QLinearGradient svGradient(0, 0, m_iAreaWidth, 0);
svGradient.setColorAt(1, newColor);
svGradient.setColorAt(0, QColor("#ffffff")); //2
QLinearGradient vGradient(0, 0, 0, m_iAreaWidth);
vGradient.setColorAt(0, QColor(0, 0, 0, 0));
vGradient.setColorAt(1, QColor(0, 0, 0, 255)); //最后将两个Pixmap重合

通过“肉眼”的观察,能明显感觉到效率提高了很多很多!

二、逻辑问题

另一大难点就是逻辑问题,界面中各个区域有一个改变,就可能引起其它所有区域的改变。

比如:色调改变 - 饱和度亮度区域需要重绘 - 颜色预览区域新的颜色改变 - 16进制文本编辑框和RGB、HSV的spinbox都会随之改变

正所谓“牵一发而动全身”,更复杂的是,这些控件是相互影响的!

如果思考不周,将导致程序逻辑混乱、程序出现死循环或者多次循环影响效率等问题。

我在写这个程序时主要用了3种方法避免混乱:

1.通过信号槽连接传递变化

2.调用其它类的公有函数

3.设置“flag”,通过判断它的布尔值来决定是否调用函数。

第2和第3都是为了防止信号槽传递时可能导致程序的混乱。

三、关于QLineEdit的思考

左边的lineEdit中展示的是颜色RGB值的16进制形式,范围000000-ffffff,可以通过正则表达式对使用者的输入进行限制。也可以加上inputMask,对格式进行更加严格的限制。然而限制太多反而会影响用户体验,需慎重考虑。

我的做法如下:

1.使用正则表达式控制输入范围。

2.手动编辑lineEdit中的内容时,光标位于lineEdit中,捕获textEdited信号,改变颜色值。

3.鼠标点击界面其它部分,使lineEdit失去焦点,然后捕获它的编辑结束editingFinished信号,使其中的文本恢复6位的格式。

为了使鼠标点击界面其它部分时输入框失去焦点,需要设置主窗口的focus属性:

setFocusPolicy(Qt::ClickFocus);

在设计这部分时,我也参考了photoshop的方法,可以打开ps感受一下哦。

源码放在了github上,请原谅其中一些蹩脚的代码,因为最初使用Qt4编写的,后来在Qt5上运行也就没怎么修改。

点我进入github

Qt——设计颜色编辑选取对话框的更多相关文章

  1. Qt——设计颜色编辑器

    Qt中有一些封装好的对话框,比如QMessageBox.QColorDialog等,用途很广,但缺点是样式难以改变,直接拿来用可能与我们自己的系统样式不搭配,显得很难看. 所以我在无聊的时候,就自己写 ...

  2. GTK 预置对话框 GtkDialog 文件/颜色/字体选取等 GtkFileSelection

    (GTK2) 文档链接 作用:打开一个预置的对话框,如文件选取对话框 GtkFileSelection 效果下图所示 ╰── GtkDialog ├── GtkAboutDialog ├── GtkC ...

  3. UI设计, 弹出对话框 设计(区分强调按钮和普通按钮,给用户一个 正向建议的强调按钮)

    在UI设计时,经常会需要 设计 弹出对话框,以下是个样式设计: 0.标准对话框 说明 Title space : 标题区 contents space : 内容区 function space: 功能 ...

  4. qt学习001之运行对话框

    使用QT实现Window下运行对话框 1.摆放控件 首先设置并摆放相应的对话框控件,并更改相应名称:        2.实现功能 1)在文本框中输入信息后,点击确定或回车可以运行系统中相应的程序: 点 ...

  5. QML-关于Qt.rgba()颜色无法正常显示问题

    GitHub:八至 作者:狐狸家的鱼 本文链接:关于Qt.rgba()颜色的正确写法 当在正常给color属性写颜色的时候,用十六进制能正常显示,但是用Qt.rgba()时,颜色无法正常显示出来. 按 ...

  6. qt creator中编辑Makefile的设置

    在qt creator中编辑Makefile时的Tab键总是不能识别,需要这样设置

  7. qt中不能编辑

    下载的qt代码不能编辑,原因是文本编码是GB2312,现在选择的是utf-8,把编码改过来就可以编辑了

  8. QT设计UI:QT模式对话框打开文件

    使用QT模式对话框,并使显示框 为背景色: 方法使用了QCheckBox *native;   #include <QCheckBox> 初始化函数代码: //设置默认打开图像位置 nat ...

  9. C/C++ -- Gui编程 -- Qt库的使用 -- 标准对话框

    -----mywidget.cpp----- #include "mywidget.h" #include "ui_mywidget.h" #include & ...

随机推荐

  1. 20145234黄斐《Java程序设计》第一周学习总结

    教材学习内容总结 1.java是SUN公司推出的面相网络的编程语言,当时取名Oak,后改名Java. 2.Java三大平台分别为:Java SE.Java EE与Java ME. 3.Java不仅是程 ...

  2. 【LG1527】[国家集训队]矩阵乘法

    [LG1527][国家集训队]矩阵乘法 题面 洛谷 题解 我也不知道为什么取个这样的名字... 其实就是区间\(kth\)扩展到二维 还是用整体二分搞啦,把树状数组换成二维的 其他的基本没有什么差别 ...

  3. Android7.0 应用内升级

    Android7.0应用内升级 最近线上项目在7.0机器上出现应用内升级失败,原来是由于Android7.0权限问题导致. 如果项目的 targetSdkVersion>=24 在处理应用内升级 ...

  4. Spring学习记录-Java 11运行eureka-server报javax.xml.bind.JAXBContext not present错

    在pom.xml加入依赖就行 <dependency> <groupId>org.glassfish.jaxb</groupId> <artifactId&g ...

  5. Linux命令应用大词典-第8章 日期和时间

    8.1 cal:显示日历信息 8.2 date:显示和设置系统日期和时间 8.3 hwclock:查看和设置硬件时钟 8.4 clock:查看和设置硬件时钟 8.5 clockdiff:主机之间测量时 ...

  6. 新的征程 in ZJU

    争取考上了心仪的学校 并进入了心仪的实验室 但是对我来说,未来将是更多的挑战 首先我觉得我学习能力还是不足,无法做到一天的高效率学习 实验室的方向是可视化,我觉得这个是个非常复杂的方向 数学,pyth ...

  7. Java学习 · 初识 容器和数据结构

    容器和数据结构 1.   集合的引入 a)     集合的使用场景:需要将一些相同结构的个体整合到一起时 i.           新闻列表 ii.           邮件列表 iii.       ...

  8. spring java config 初探

    Java Config 注解 spring java config作为同xml配置形式的另一种表达形式,使用的场景越来越多,在新版本的spring boot中 大量使用,今天我们来看下用到的主要注解有 ...

  9. MySQL Proxy使用

    使用MySQL将读写请求转接到主从Server. 一 安装MySQL Proxy MySQL Proxy的二进制版非常方便,下载解压缩后即用. 解压缩的目录为: $mysql-proxy_instal ...

  10. 一:HDFS 用户指导

    1.hdfs的牛逼特性 Hadoop, including HDFS, is well suited for distributed storage and distributed processin ...