当前位置:   article > 正文

《Qt MOOC系列教程》第三章第十一节:视觉效果_qml radialgradient 弧形

qml radialgradient 弧形

Qt Quick和QML为开发人员提供了多种方式来为用户界面添加视觉效果。Qt Quick Shapes允许您创建各种形状并填充图案。QML有大量的动画类型,这使得使用甚至非线性时间轴来设置任何对象的动画都很容易。OpenGL程序可以很容易地创建渐变或渐变阴影。

让我们来看看如何在应用程序中添加视觉效果。

1. 形状

Shape类型,用于渲染任意形状(与我们已经看到的Rectangle类型相反)。Shape通过QPainterPath手动三角剖分生成几何形状然后使用GPU来进行渲染。

这种方法不同于通过QQuickPaintedItem或2D Canvas渲染形状,因为在软件中路径不会被栅格化。因此,Shape适合于创建扩展到屏幕更大区域的形状,避免因纹理上传或framebuffer blits而造成性能损失。此外,声明式API允许操作、绑定到路径元素属性,甚至使其具有动画效果,比如开始和结束位置、控制点等等。

它支持各种不同的路径,例如直线,椭圆形,弧形,二次曲线等。有关所有可用路径元素的列表,请参阅Path文档。

Item一样,Shape也允许将任何可视或非可视对象声明为子对象。ShapePath对象是专门处理的。这很有用,因为它允许添加可视项(如RectangleImage)和非可视对象(如Timer)作为Shape的子级。

在使用Shape时,注意潜在的性能影响是很重要的(你不需要记忆甚至完全理解这个列表,但是最好知道它):

  • 当应用程序使用基于三角剖分的通用Shape实现运行时,几何图形的生成完全在CPU上进行,这可能很耗时。改变Shape元素的集合,或者改变这些元素的属性,或者改变形状本身的某些属性,都会导致在每次更改时对受影响的路径进行重新处理。因此,将动画应用于这些属性可能会影响功能较弱的系统的性能。
  • 然而,ShapeAPI的数据驱动、声明性质通常意味着底层CPU和GPU资源有更好的可缓存性。一个ShapePath中的属性更改只会导致对受影响的ShapePath进行重新处理,而不改变Shape的其他部分。因此,与命令式绘制方法(例如QPainter)相比,频繁更改属性导致的总体系统负载相对较低。
  • 如果必须设置除笔划和填充颜色以外的属性动画,则建议将提供GL_NV_path_rendering的系统作为目标,其中属性更改的成本较小。
  • 同时,必须注意Shape场景中元素的数量,尤其是当使用GL_NV_path_rendering这种特殊的加速方法时。这种Shape项目在场景图中的表示方式不同于普通的基于几何的项目,并且在涉及OpenGL状态更改时会产生一定的成本。
  • 通常,在并非绝对必要时,场景应避免使用单独的Shape项目。比起使用多个Shape项,最好使用一个带有多个ShapePath元素的Shape项。如果不能避免使用大量个别Shape的场景应考虑设置Shape.vendorExtensionsEnabled为false。

现在,让我们看一个例子:

import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Shapes 1.0

Window {
    visible: true
    width: 640
    height: 480
    title: qsTr("Shapes")

    Shape {
        id: shape
        anchors.fill: parent
        ShapePath {
            strokeWidth: 10
            strokeColor: "black"
            fillGradient: RadialGradient {
                centerX: shape.width / 2; centerY: shape.height / 2
                centerRadius: shape.width * 0.1
                focalX: centerX; focalY: centerY
                spread: ShapeGradient.RepeatSpread
                GradientStop { position: 0; color: "yellow" }
                GradientStop { position: 1; color: "blue" }
            }
            strokeStyle: ShapePath.SolidLine
            startX: shape.width * 0.3; startY: shape.height * 0.1
            PathLine { x: shape.width * 0.7; y: shape.height * 0.1 }
            PathLine { x: shape.width * 0.9; y: shape.height * 0.3 }
            PathLine { x: shape.width * 0.9; y: shape.height * 0.7 }
            PathLine { x: shape.width * 0.7; y: shape.height * 0.9 }
            PathLine { x: shape.width * 0.3; y: shape.height * 0.9 }
            PathLine { x: shape.width * 0.1; y: shape.height * 0.7 }
            PathLine { x: shape.width * 0.1; y: shape.height * 0.3 }
            PathLine { x: shape.width * 0.3; y: shape.height * 0.1 }
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

在这里插入图片描述

ShapePath中,我们用直线定义了形状,并用重复的RadialGradient去填充它。如果您在执行代码时遇到困难(即使您没有做到),请继续尝试一下!试着注释掉一些PathLine,看看会发生什么。将RadialGradientspread属性更改为ShapeGradient.ReflectSpread看看会变成什么形状。

2. 动画

Qt Quick旨在创建具有流畅用户体验的动态用户界面。显然,也可以创建传统的,更静态的用户界面。实现流畅的用户体验的一种方法是动画。开发人员可以从各种QML类型中选择动画类型,例如PropertyAnimationSequentialAnimationSpringAnimationBehaviorAnimatedSprite等(参见完整的文档列表)。Animation扩展出了大量的动画类型,它提供了控制动画状态的方法:start()stop()pause()。此外,还有一些属性可以设置动画的执行次数(loops)或检查动画是否正在运行(running)。

动画会插入属性值,这些属性值在类型之间可能相差很大。AnimatedSprite显示图像帧,PathAnimation沿着定义的路径对项目的位置和旋转进行动画处理。默认情况下,大多数动画都是线性的,但是Qt为非线性动画提供了很多缓冲曲线(缓冲曲线的完整列表可以在此处找到)。您可以右键单击Qt Creator中的动画对象,然后使用上下文菜单显示“Qt Quick 工具栏”。工具栏是研究不同缓冲曲线在不同特性设置下如何工作的一种简单方法,因为它为所有更改设置了动画。

最基本的动画可以通过属性动画来实现。下面的代码片段使用OutBounce缓冲曲线将红色矩形移至右侧。可以使用属性targettargets定义对象的属性。在此示例中,target是父级,因此我们无需定义它。类似地,可以使用一个或多个属性来定义哪个或哪些属性使用动画。该示例使用另一个漂亮的语法PropertyAnimation on x,它定义了该矩形的x属性是具有动画效果的。

Rectangle {
    width: 50; height: 50
    color: "red"

    PropertyAnimation on x {
        from: 50; to: 150
        duration: 1000;
        easing.type: Easing.OutBounce;
        loops: Animation.Infinite
    }
}    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

上面的动画运行了无数次。可以通过将running属性设置为false或通过调用stop()来停止动画。

Rectangle {
    width: 50; height: 50
    color: "red"

    PropertyAnimation on x {
        id: animation
        running: false
        from: 50; to: 150
        duration: 1000;
        easing.type: Easing.OutBounce;
        loops: Animation.Infinite
    }

    TapHandler {
        onTapped: animation.running ? animation.stop() : animation.start();
    }
}    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

Behavior类型是定义动画的非常优雅的方式。每当属性值更改时,Behavior就对更改进行动画处理。修改前面的示例使移动到鼠标单击位置的矩形具有动画效果,可以像在下面示例中这样实现:

Rectangle {
    id: rect
    width: 50; height: 50
    color: "red"

    Behavior on x { 
        PropertyAnimation { 
            easing.amplitude: 2.9; easing.type: Easing.InElastic; duration: 500 
        } 
    }
    Behavior on y { 
        PropertyAnimation { duration: 500 } 
    }
}

MouseArea {
    anchors.fill: parent
    onClicked: { rect.x = mouse.x; rect.y = mouse.y }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

请注意,不必在动画中定义所有的属性。例如,一个非常简单的动画对象可以是NumberAnimation { }。这将在250毫秒(默认值)内使用一条线性曲线使所定义的属性产生动画效果。

Qt提供了许多便利的QML类型,以使动画的使用非常简单。例如,PathAnimation会沿着预定义的路径设置动画。路径由一种Path类型定义,可以由任意数量的直线,圆弧,Svg或二次曲线以及三次方贝塞尔曲线组成。(请参阅路径文档)。

下面的例子显示了相当随机的路径,由两个三次贝塞尔曲线组成。火箭是一个图像,会沿着路径运动。

Path {
    startX: rocket.width/2; startY: rocket.height/2

    PathCubic {
        x: window.width - rocket.width/2
        y: window.height - rocket.height/2

        control1X: x; control1Y: rocket.height/2
        control2X: rocket.width/2; control2Y: y
    }
    PathCubic {
        x: window.width - rocket.width/2
        y: window.height - rocket.height/2

        control1X: x; control1Y: rocket.height/2
        control2X: rocket.width/2; control2Y: y
    }
} 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

定义完路径后,可以在其他类型中使用相同的路径。如果要绘制路径,可以使用Shape

Shape {
    anchors.fill: parent
    ShapePath {
        strokeWidth: 4
        strokeColor: "white"
        fillColor: "transparent"

        // The path definition goes here
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

最后,我们可以使用动画项目PathAnimation来移动项目。

Item {
    id: rocket
    x: 0; y: 0
    width: 128; height: 96

    Image {
        source: "qrc:/images/rocket.png"
        anchors.centerIn: parent
        rotation: 90
    }

    MouseArea {
        anchors.fill: parent
        onClicked: pathAnim.running ? pathAnim.stop() : pathAnim.start()
    }
}

PathAnimation {
    id: pathAnim
    duration: 2000
    easing.type: Easing.InOutQuad

    target: rocket
    orientation: PathAnimation.RightFirst
    anchorPoint: Qt.point(rocket.width/2, rocket.height/2)

    path: Path {
        // The path definition goes here
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

在这里插入图片描述

除了PropertyAnimation及其子类型外,还有一些动画类型,它们是扩展了Item而不是Animation类型。AnimatedSpriteAnimatedImage使显示动图变得容易,包括几个帧或gif动画。AnimatedSprite允许帧水平或垂直组织,如下图所示。图像由51个水平排列的雪花帧组成。

唯一需要做的就是确定在帧序列中可见帧的时间。

AnimatedSprite {
    id: animSprite
    width: parent.width * 0.25
    height: parent.height * 0.25
    running: true
    source: "qrc:/images/snowflake.png"
    frameCount: 51  // Frame width automatically calculated
    frameDuration: 10
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

2.1 状态与动画状态转场

动画通常与状态和转场一起使用。每个Qt Quick项都有一个state属性,它定义了该项的状态。也可以在states属性中定义一个状态列表。每个状态都由一个字符串名称标识。状态名称默认是一个空字符串“”

下面的例子中有两个矩形。在默认状态下,我们只想显示红色矩形view1。蓝色矩形view2在红色矩形的右边并且大小与父对象一致。所以,如果父对象设置了clip属性,那么它是不可见的。

Rectangle {
    id: view1
    color: "red"
    width: parent.width
    height: parent.height
}

Rectangle {
    id: view2
    color: "blue"
    width: parent.width
    height: parent.height
    x: parent.width
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

如果想添加更多状态,可以使用PropertyChanges类型,它用于定义在该状态下哪些属性更改为哪些值。请注意,我们不必定义多个状态,因为默认状态在开始时定义了矩形位置。当状态变为“inView2”时,红色矩形的位置在父元素的左边,蓝色矩形填充父元素。当状态发生时,如果没有显式地为项的state属性指定新的状态名,那么可选的when属性将很有用。

states: [
    State {
        name: "inView2"
        when: tapHandler.pressed
        PropertyChanges {
            target: view1
            x: -root.width
        }
        PropertyChanges {
            target: view2
            x: 0
        }
    }
]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

请注意,示例中还没有动画。动画在转场列表中定义。当状态发生变化时,可能会有一个状态转换,该转换会为用更改的属性设置动画PropertyChanges

transitions: [
    Transition {
        from: ""
        to: "inView2"
        NumberAnimation { properties: "x"; duration: 1000 }
    },
    Transition {
        from: "inView2"
        to: ""
        NumberAnimation { properties: "x"; duration: 1000 }
    }
]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

下面是我们的例子:(看上去卡顿是由.gif图片导致的,与Qt无关)
在这里插入图片描述

在我们的示例中,从默认状态到“inView2”状态的转场和从“inView2”状态到默认状态是相似的。这种情况下只需要一个转场,我们可以通过将reversible属性设置为true来实现。

Transition {
    from: ""
    to: "inView2"
    reversible: true
    NumberAnimation { properties: "x"; duration: 1000 }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

效果与前面一样,但是代码更干净,也更容易阅读。

3. 图形效果

图形效果是将效果应用于QML项目的视觉项目。每个效果都有其自己的特定效果属性。效果是使用OpenGL顶点着色器和片元着色器来修改顶点位置或片段、像素、颜色来获得效果。在具有图形处理器的硬件平台上,效果是非常有效的。但是在使用软件渲染的嵌入式平台中,通常应该避免效果的使用,以便为更重要的任务节省CPU资源。

使用Rectangle类型及其radius属性在Qt中创建矩形甚至椭圆非常简单。矩形可以用渐变色绘制,但是我们如何创建非线性渐变呢?一种解决方案是使用RadialGradient

在下面的示例中,我们在窗口中创建了一个径向渐变。它使用了两种颜色,先从黄色变为黑色,在从黑色变为黄色。

import QtQuick 2.12
import QtGraphicalEffects 1.12
import QtQuick.Window 2.12

Window {
    visible: true
    width: 640
    height: 480
    title: qsTr("Radial gradient")

    RadialGradient {
        anchors.fill: parent
        gradient: Gradient {
            GradientStop { position: 0.0; color: "yellow" }
            GradientStop { position: 0.5; color: "black" }
            GradientStop { position: 1.0; color: "yellow" }

        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

其他渐变也同样易于使用。

渐变示例
线性渐变
锥形渐变在这里插入图片描述
径向渐变

Source

获取更多信息,请关注作者公众号:程序员练兵场
在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/81465
推荐阅读
相关标签
  

闽ICP备14008679号