qt - QML 中的多色渐变
问题描述
我开始学习 Qt 框架,我想为窗口创建一个多色渐变(如下图)背景:
我浏览了有关 QML 类型的官方文档Linear/Conical/Radial/Shape Gradient
,也浏览了 Google。但看不到任何实现这一目标的选择。
有没有其他方法可以使它成为可能?最好在 QML 中。
编辑1:
如评论中所述,GradientStop
可用于多种颜色。但它不能用来产生给定图像中的结果。
解决方案
At first familiarize with Qt example quick\scenegraph\fboitem
. It demonstrates creating custom QML control with C++/OpenGL backend.
Also you can implement it with ShaderEffect
QML control. I recommend this site https://www.shadertoy.com/new for debugging your shaders. Also you can use, for example, Canvas
for passing arrays to your shader as texture (ShaderEffect
doesn't allow passing arrays normally, https://bugreports.qt.io/browse/QTBUG-50493).
Here is possible implementation of your control with dynamic points count, colors and positions.
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();
}
}
}
}
}
I'm not OpenGL guru, so this code isn't perfect. I'll be glad if someone will edit this answer to make it better.
推荐阅读
- c# - 使用 C# 调用 swagger Web 服务
- jquery - 选中某个复选框时将显示输入文本。取消勾选后会隐藏
- xamarin.forms - Xamarin ContentPage.ToolbarItems 移动到页面底部
- nullpointerexception - 如何在 getOntClass() 上调试 NullPointerException?
- php - this.map.tick 不是函数
- spring-data - _class 字段和 spring 数据 couchbase
- python - 如何将另一列上的一列乘以该月第一天的值
- odoo-12 - 如何在odoo 12中将字段添加到product.template
- jquery - 通过 jquery 操作 WebVTT 提示
- r - Change line width of leaflet's stroke in leaflet