如何在声明性QML中降低由RGB定义的颜色的饱和度



使用QtQuick,是否可以采用RGB定义的现有颜色并使其去饱和而无需诉诸Javascript?

function desaturate(colorString)
{
    let c = Qt.darker(colorString, 1.0);
    return Qt.hsla(c.hslHue, 0.0, c.hslLightness, c.a);
}

看到QtQuick是如何在Javascript引擎上运行的,我想说,如果不借助Javascript,在QML中不可能做任何事情。

为了调整饱和度,你必须将RGB转换为HSL颜色,然后再转换回RGB。QML有Qt.hsla()为后者,但上次我检查它没有提供从RGB到HSL的转换,所以我最终使用这个:

function rgbToHsl(r, g, b) {
  r /= 255
  g /= 255
  b /= 255
  var max = Math.max(r, g, b), min = Math.min(r, g, b)
  var h, s, l = (max + min) / 2
  if (max == min) {
    h = s = 0
  } else {
    var d = max - min
    s = l > 0.5 ? d / (2 - max - min) : d / (max + min)
    switch (max) {
    case r:
      h = (g - b) / d + (g < b ? 6 : 0)
      break
    case g:
      h = (b - r) / d + 2
      break
    case b:
      h = (r - g) / d + 4
      break
    }
    h /= 6;
  }
  return {"h":h, "s":s, "l":l};
}

所以你基本上是:

var ic = yourRGBColor.toString()
var r = parseInt(ic.substr(1, 2), 16)
var g = parseInt(ic.substr(3, 2), 16)
var b = parseInt(ic.substr(5, 2), 16)
var hsl = rgbToHsl(r, g, b)
hsl.s *= .5 // desaturate 50%
yourRGBColor = Qt.hsla(hsl.h, hsl.s, hsl.l, 1)

根据颜色模型修改颜色的hsvSaturationhslSaturation属性。

每秒逐渐使一个蓝色矩形去饱和的Test.qml示例(与qmlscene Test.qml一起运行):

import QtQuick 2.7
Item {
    width: 100
    height: 100
    Rectangle {
        anchors.fill: parent
        objectName: "precious"
        color: "#0000FF"
        Timer {
            running: true
            repeat: true
            onTriggered: parent.color.hslSaturation *= 0.8;
        }
    }
}

隐藏在大量文本中,在两个代码块之间,这些属性实际上以彩色QML基本类型记录。它们似乎对应于c++中颜色组件属性的qreal版本(名称以...F()结尾)。


正如@dtech所说,onTriggered:...在法律上已经是一行JavaScript了。如果你需要,你也可以在c++中找到元素的属性,并在那里修改属性。

示例main.cpp,显示上面的Test.qml,从一个已经非常不饱和的(纯c++)蓝色矩形开始,然后逐渐去饱和它(仍然在QML/JavaScript中完成):

#include <QGuiApplication>
#include <QQuickView>
#include <QQuickItem>
int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);
    QQuickView view(QUrl(QLatin1String("qrc:/Test.qml")));
    view.show();
    if ( QObject * rectangle = view.rootObject()->findChild<QObject*>("precious") )
    {
        qreal h, s, l, a;
        rectangle->property("color").value<QColor>().getHslF( &h, &s, &l, &a );
        s *= 0.2;
        rectangle->setProperty( "color", QVariant::fromValue(QColor::fromHsvF( h, s, l, a )) );
    }
    return app.exec();
}

现在您可以从Test.qml中删除明显的JavaScript行。


注意,我演示了一个非常粗糙的彩色动画。有一个特殊的ColorAnimation工具可以做得更好。

最新更新