• 在 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,可以不修改改像素,优化性能。

  • 相关阅读:
    基于微信小程序的线上课堂系统
    功率放大器可靠性怎么设计的好
    1 分钟 Serverless 搭建你的首个个人网站
    软件项目管理 9.1.软件配置管理基本概念
    git&&gitHub
    C#A类调用B类的方法,在方法中更新B类的控件
    Xiaojie雷达之路---脉冲压缩
    【每日一题】—— C. Yarik and Array(Codeforces Round 909 (Div. 3))(贪心)
    UniApp 开发微信小程序教程(一):准备工作和环境搭建,项目结构和配置
    java的Excel导出方式总结
  • 原文地址:https://blog.csdn.net/luansxx/article/details/126630025