【问题标题】:MultiColor Gradient in QMLQML 中的多色渐变
【发布时间】:2020-08-02 21:22:02
【问题描述】:

我开始学习 Qt 框架,我想为 Window 创建一个 MultiColored Gradient(如下图)背景:

我浏览了Linear/Conical/Radial/Shape Gradient QML 类型的官方文档,也浏览了 Google。但看不到任何实现这一目标的选项。

还有其他方法可以实现吗?最好在 QML 中。

编辑 1:

如评论中所述,GradientStop 可用于多种颜色。但它不能用于生成给定图像中的结果。

【问题讨论】:

  • LinearGradients 可以是“多色的”,但不是您显示的方式。我不知道 QML 中有任何东西会自动为您生成那种图像。您也许可以通过重叠模糊矩形或其他东西手动构建它,但使用图像文件看起来更容易。
  • @JarMan 感谢您的输入,但问题是颜色不会是静态的。我计划让它每隔预定义的秒数动态改变颜色。其实我的目标是让它看起来像“呼吸”的效果。这种多色渐变构成了它的基础。这就是为什么我在没有给出太多见解的情况下问这个问题。
  • 可能需要创建自己的cpp对象来做,然后暴露给qml。

标签: qt qml qt5 gradient


【解决方案1】:

首先熟悉Qt示例quick\scenegraph\fboitem。它演示了使用 C++/OpenGL 后端创建自定义 QML 控件。

您也可以使用ShaderEffect QML 控件来实现它。我推荐这个站点https://www.shadertoy.com/new 来调试你的着色器。例如,您还可以使用 Canvas 将数组作为纹理传递给着色器(ShaderEffect 不允许正常传递数组,https://bugreports.qt.io/browse/QTBUG-50493)。

这是您的控件的可能实现,包括动态点数、颜色和位置。

import QtQuick 2.12
import QtQuick.Controls 2.5

ApplicationWindow {
    id: window
    visible: true
    width: 640
    height: 480
    title: "Custom gradient"

    Item {
        anchors.fill: parent

        layer.enabled: true
        layer.effect: ShaderEffect {
            readonly property var dataTex: dataCanvas
            readonly property int count: dataCanvas.colors.length

            fragmentShader: "
                  varying highp vec2 qt_TexCoord0;
                  uniform lowp float qt_Opacity;
                  uniform sampler2D dataTex;
                  const uniform lowp int count;
                  void main() {
                      vec3 col = 0.0;

                      for (int i = 0; i < count; i++) {
                          vec4 color = texture2D(dataTex, vec2(i / (float)count + 0.01, 0.0));
                          vec2 point = texture2D(dataTex, vec2(i / (float)count + 0.01, 1.0)).rg;

                          float dist = distance(qt_TexCoord0, point);
                          col += color * (1.0 - dist);
                      }

                      gl_FragColor = vec4(col, 1.0);
                  }
        ";
        }

        // Because ShaderEffect doesn't allow passing arrays to shader, we will
        // convert arrays to graphical representation and pass them as texture.
        Canvas {
            id: dataCanvas
            readonly property var colors: ["cyan", "red", "green", "darkblue", "yellow"]
            readonly property var positions: [Qt.point(0,0),
                                              Qt.point(10, parent.height - 20),
                                              Qt.point(parent.width / 2, parent.height / 4),
                                              Qt.point(parent.width, 0),
                                              Qt.point(parent.width, parent.height)]

            height: 2
            width: colors.length
            antialiasing: false
            visible: false

            onPaint: {
                if (colors.length !== positions.length) {
                    console.error("Array size of 'colors' doesn't equal array size of 'positions'");
                    return;
                }

                var ctx = getContext("2d");
                ctx.reset();
                ctx.lineWidth = 1;

                for (var i = 0; i < colors.length; i++) {
                    ctx.beginPath();
                    ctx.strokeStyle = colors[i];
                    ctx.moveTo(i, 0);
                    ctx.lineTo(i+1, 0);
                    ctx.stroke();
                    ctx.closePath();

                    ctx.beginPath();
                    ctx.strokeStyle = Qt.rgba(positions[i].x / parent.width, positions[i].y / parent.height, 0, 1);
                    ctx.moveTo(i, 1);
                    ctx.lineTo(i+1, 1);
                    ctx.stroke();
                    ctx.closePath();
                }
            }
        }
    }
}

看起来就是这样

我不是 OpenGL 专家,所以这段代码并不完美。如果有人会编辑此答案以使其更好,我会很高兴。

【讨论】:

    【解决方案2】:

    Ihor 的回答很好。我发现 Qt 实际上也提供了一个可能有用的示例。查看他们的Squircle 示例。我不会在这里全部重现,但它会在 C++ 中创建一个 QQuickItem 并在其上进行一些自定义 OpenGL 渲染。然后可以在 QML 中使用该对象。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-07-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-02-22
      相关资源
      最近更新 更多