• 在 Qt 中实现变色的图标(tintColor)


    响应状态的按钮图标

    很多时候,设计要求当按钮的状态变化时(比如 hover、按下,禁用),按钮的背景、文字、图标能够改变颜色,以反馈按钮的当前状态。如下图:

    改变文字、背景的颜色很容易,但是改变图标颜色就比较麻烦了。早期的方案,是提供一整套不同颜色图片,分别设置给不同的状态。

    比如 iOS 上的 UIButton:

    1. func setImage(UIImage?, for: UIControl.State)
    2. // Sets the image to use for the specified state.

    再比如 Android 上的 Drawable selector:

    1. "1.0" encoding="utf-8"?>
    2. <selector xmlns:android="http://schemas.android.com/apk/res/android">
    3. <item android:drawable="@drawable/button_1_selected" android:state_pressed="true"/>
    4. <item android:drawable="@drawable/button_1_normal" android:state_focused="true"/>
    5. <item android:drawable="@drawable/button_1_normal"/>
    6. selector>

    所有一旦要新加或者改变一个图标,都要设计提供一组图片文件,开发一个个的加到代码项目中,再添加一组设置图片的代码,是特别的麻烦。

    后来,一些平台提供了相关的解决方案,就是 tintColor。有了 tintColor, 只要一张图片就可以了,通过代码就可以改变图标的颜色。

    这里我们主要针对 Qt 框架,对其他平台的 tintColor 有兴趣的话,可以查看下面给出的文档:

    Apple Developer Documentation

    ImageView  |  Android Developers

    Qml Image 增加 tintColor

    在 Qt 中,目前并不支持 tintColor,所有还需要我们自己造轮子。

    不过我们只打算在 Qml 中支持,如果你使用 QWidget,也可以参考我们的思路自己动手实现一个。

    先看一下最终给使用者的控件:

    1. import QtQuick 2.12
    2. import QtQuick.Controls 2.5
    3. Image {
    4. property url originSource
    5. property string tintColor
    6. source: {
    7. if (Qt.colorEqual(tintColor, "transparent"))
    8. return originSource
    9. return "image://EffectSync/tint/")
    10. + encodeURIComponent(originSource)
    11. + "?tintColor=" + tintColor
    12. }
    13. }

    使用者只需要设置 originSource 和 tintColor 就可以了。

    实现 QQuickImageProvider

    上面的关键是 "image://" 开头的 url,是通过 ImageProvider 实现的。

    如何实现 QQuickImageProvider,在我的另一篇文章中有进过,所以不再重复了。

    实现 tintColor 效果

    在 QQuickImageProvider 中,拿到原始图片 image 后,我们直接就地修改 image 的像素,将所有颜色,替换为 tintColor 的 r、g、b 值:

    1. auto size = image.bytesPerLine();
    2. auto a = tintColor_.alpha();
    3. auto r = tintColor_.red() * a / 255;
    4. auto g = tintColor_.green() * a / 255;
    5. auto b = tintColor_.blue() * a / 255;
    6. for (int i = 0; i < image.height(); ++i) {
    7. auto bytes = image.scanLine(i);
    8. auto end = bytes + size;
    9. while (bytes < end) {
    10. if (bytes[3]) {
    11. a = bytes[3];
    12. if (a == 255) {
    13. bytes[0] = b;
    14. bytes[1] = g;
    15. bytes[2] = r;
    16. } else {
    17. bytes[0] = b * a / 255;
    18. bytes[1] = g * a / 255;
    19. bytes[2] = r * a / 255;
    20. }
    21. }
    22. bytes += 4;
    23. }
    24. }

    注意,QImage 图片的像素一般是 premultiplied ,所以要乘以原始像素的 alpha 值。但是如果原始像素 alpha 为 0,可以不修改改像素,优化性能。

  • 相关阅读:
    [附源码]Python计算机毕业设计Django学生社团信息管理系统
    hyperledger fabric2.4测试网络添加组织数量
    Matlab点云处理及可视化第1期—基于KD树的邻域点搜索(柱状邻域、球状邻域及KNN)
    Mock平台3-初识Antd React 开箱即用中台前端框架
    CRM项目 - 心得
    Redis(七)优化建议
    RLF and OOS
    线代 | 考研线性代数 解题方法汇总(非知识点汇总)
    【JavaEE&Spring】Spring Web MVC⼊⻔
    【附源码】Python计算机毕业设计汽车交易平台
  • 原文地址:https://blog.csdn.net/luansxx/article/details/126630025