首页 > 代码库 > Qt Quick 之 PathView 详解

Qt Quick 之 PathView 详解

    开始的开始,请给我的决赛博文投票:点此进入投票页面网页最下方有投票按钮,投我一票,谢谢

    PathView ,顾名思义,沿着特定的路径显示 Model 内的数据。 Model 可以是 QML 内建的 ListModel 、 XmlListModel ,也可以是在 C++ 中实现的 QAbstractListModel 的派生类。

    PathView 恐怕是 Qt Quick 提供的 Model-View 类库中最复杂也最灵活的一个了。

    要使用一个 PathView ,至少需要设置 model 、 delegate 、 path 三个属性。

    model 、 delegate 如果你学习过 ListView 肯定已经接触过,这里不再细说。 path 是 PathView 的专有特性,它指定 PathView 用来放置 item 的路径。要使用 PathView ,先要了解 Path 。

    版权所有 foruok ,如需转载请注明出处:作者 foruok ,博客 http://blog.csdn.net/foruok 。

Path

    西安是十三朝古都,虽然尿骚味很重,还是值得一游。于是你从杭州的武陵广场出发,准备去看兵马俑。先打的去萧山机场,步行进入航站楼,过安检,坐飞机到咸阳机场,出站,乘机场大巴到火车站,然后坐游 5 公交到兵马俑……在这个过程中,换乘的中间点很多,相邻两个中间点之间的,就是路径段;多个路径段最终形成了从杭州武陵广场到西安临潼兵马俑之间的路径;武陵广场是起点,兵马俑是终点。

    在 Qt 中 Path 就是直译为路径,一个路径是由多个路径元素组成的,从起点开始,首尾衔接,抵达终点。

    Path 的属性 startX 、 startY 描述路径起点。 pathElements 属性是个列表,是默认属性,它保存组成路径的多个路径元素,常见的路径元素有 PathLine 、 PathQuad 、 PathCubic 、 PathArc 、 PathCurve 、 PathSvg 。路径上最后一个路径元素的终点就是整个路径的终点,如果终点与起点重合,那么 Path 的 closed 属性就为 true 。

    路径元素除 PathSvg 外,都有 x 、 y 属性,以绝对坐标的形式指定本段路径的终点;而起点呢,就是前一个路径段的终点;第一个路径段的起点,就是 Path 的 startX 、 startY 所描述的整个路径的起点。另外还有 relativeX 、 relativeY 两个属性,以相对于起点的相对坐标的形式来指定终点。你还可以混合使用绝对坐标与相对坐标,比如使用 x 和 relativeY 来决定路径段的终点。

PathLine

    PathLine 是最简单的路径元素,在 Path 的起点或者上一段路径的终点,与本元素定义的终点之间绘制一条直线。
    一个最简的路径示例:
    Path {
        startX: 0;
        startY: 0;
        PathLine {
            x: root.width - 1;
            y: root.height - 1;
        }
    }

    上面的路径,是一条从界面左上角到右下角的直线。

PathQuad

    贝塞尔曲线( Bézier curve ),又称贝兹曲线或贝济埃曲线,是应用于二维图形应用程序的数学曲线。
    贝塞尔曲线于 1962 年,由法国工程师皮埃尔·贝塞尔( Pierre Bézier )所广泛发表,他运用贝塞尔曲线来为汽车的主体进行设计。贝塞尔曲线最初由 Paul de Casteljau 于 1959 年运用 de Casteljau 算法开发,以稳定数值的方法求出贝塞尔曲线。
    常见的贝塞尔曲线有线性贝塞尔曲线、二次方贝塞尔曲线、三次方贝塞尔曲线,当然也有四阶、五阶甚至更高阶的贝塞尔曲线。线性贝塞尔曲线其实只是两点之间的直线。二次方贝塞尔曲线,由两个端点和一个控制点以及一个函数来生成。三次方贝塞尔曲线,由两个端点和两个控制点以及一个函数来生成。
    在 Qt Quick 的 Path 主题中,提供了基于二次方贝塞尔曲线和三次方贝塞尔曲线的路径元素。
    在我们使用 Canvas 进行 2D 绘图时, Context2D 对象的 quadraticCurveTo(real cpx, real cpy, real x, real y) 方法可以在路径中添加一条二次方贝塞尔曲线, bezierCurveTo(real cp1x, real cp1y, real cp2x, real cp2y, real x, real y) 方法用来在路径中添加一条三次方贝塞尔曲线。
    PathQuad 元素定义一条二次贝塞尔曲线作为路径段。它的起点为上一个路径元素的终点(或者路径的起点),终点由 x 、 y 或 relativeX 、 relativeY 定义,控制点由 controlX 、 controlY 或 relativeControlX 、 relativeControlY 来定义。
    一个简单的二次方贝塞尔路径定义:
    Path {
        startX: 0;
        startY: 0;
        PathQuad {
            x: root.width - 1;
            y: root.height - 1;
            controlX: 0;
            controlY: root.height - 1;
        }
    }

    在 Qt Quick 中, Path 虽然描述了一条路径,但它是不可见的,不够形象化。这里我们通过使用 Canvas 来绘制同样的曲线,以求大家看了可以有个直观的印象。上面的路径定义,对应 qml 代码:
import QtQuick 2.0
import QtQuick.Controls 1.1

Canvas {
    width: 320;
    height: 240;

    onPaint: {
        var ctx = getContext("2d");
        ctx.lineWidth = 2;
        ctx.strokeStyle = "red";
        ctx.beginPath();
        ctx.moveTo(0, 0);
        ctx.quadraticCurveTo(0, height - 1, width - 1, height - 1);
        ctx.stroke();
    }
    
    Text {
        anchors.centerIn: parent;
        font.pixelSize: 20;
        text: "quadratic Bezier curve";
    }
}

    执行 "qmlscene pathQuad_canvas.qml" 命令,可以看到下图的效果:


PathArc

    PathArc 路径元素定义一条弧线,它的起点为上一个路径元素的终点(或者路径的起点),终点由 x 、 y 或 relativeX 、 relativeY 定义。弧线的半径由 radiusX 、 radiusY 定义。
    direction 属性定义绘制弧线的方向,默认取值 PathArc.Clockwise ,顺时针绘制弧线;要想逆时针绘制弧线,设置 direction 的值为 PathArc.Counterclockwise 。
    当你制定了弧线的起点、终点、半径、绘制方向后,还是可能存在两条弧线都能满足给定的参数,此时 useLargeArc 属性就可以派上用场了,其默认值为 false ,取较小的弧线,设置为 true 后,取较大的弧线。下图是存在两条弧线的一种情形示例:


    其它的路径元素我们就不一个一个来说了,用到时请自行研读 Qt 帮助,讲得很详细了。

PathAttribute

    PathAttribute 定义一些属性,它的声明语法类似下面:
    PathAttribute { name: "zOrder"; value: 0.2; }
    name 属性指定待定义属性的名字, real 类型的 value 属性的值为待定义的属性的值。
    PathAttribute 放在某个路径段的前面,指明这段路径起始时的属性值;路径段后面的 PathAttribute 指明路径段终止时的属性值;而在路径段上的属性值, Path 会根据起、止值自动插值计算。
    我们可以通过使用 PathAttribute 来定义一些属性,用于控制分布在路径上的 item 的外观。比如定义名为 "zOrder" 的属性,控制沿路径分布的 item 的 Z 序。
    下面是个简单的示例:
    Path {
            startX: 10;
            startY: 100;
            PathAttribute { name: "zOrder"; value: 0 }
            PathAttribute { name: "itemAlpha"; value: 0.1 }
            PathAttribute { name: "itemScale"; value: 0.6 }
            PathLine {
                x: root.width/2 - 40;
                y: 100;
            }
            PathAttribute { name: "zOrder"; value: 10 }
            PathAttribute { name: "itemAlpha"; value: 0.8 }
            PathAttribute { name: "itemScale"; value: 1.2 }
            PathLine {
                relativeX: root.width/2 - 60;
                relativeY: 0;
            }
            PathAttribute { name: "zOrder"; value: 0 }
            PathAttribute { name: "itemAlpha"; value: 0.1 }
            PathAttribute { name: "itemScale"; value: 0.6 }
        }

    我把路径分成了两段,起点是 (10, 100) 。为路径定义了三个属性, zOrder 、 itemAlpha 、 itemScale ,在 PathView 的 delegate 中会用到这些属性。以 zOrder 属性为例,起点处值为 0 ,中间值为 1 ,终点值为 0 ,其它的, Path 会自动根据两端的值来生成。
    PathAttribute 定义的属性,会导出为 delegate 的顶层 item 的附加属性,通过 PathView.${name} 的形式来访问。比如 zOrder 属性,在 delegate 中使用 PathView.zOrder 访问。

PathPercent

    PathPercent 放在组成路径的元素后面,比如放在 PathLine 后面,指明它前面的那部分路径(通常由一个或多个 Path 元素组成)所放置的 item 数量占整个路径上所有 item 数量的比率。
    PathPercent 的 value 属性为 real 值,范围 0.0 至 1.0 。需要注意的是,在一个 Path 中使用 PathPercent ,PathPercent 元素的 value 值是递增的,某一段路径如果在两个 PathPercent 之间,那么这段路径上面放置的 item 数量占路径上总 item 数量的比率,是后面的 PathPercent 与 前面的 PathPercent 的 value 之差。
    下面是个简单的示例:
     Path {
            startX: 10;
            startY: 100;
            PathLine {
                x: root.width/2 - 40;
                y: 100;
            }
            PathPercent { value: 0.28; }
            PathLine {
                relativeX: root.width/2 - 60;
                relativeY: 0;
            }
        }

    第一个路径段上放置的 item 数量占路径上总 item 数的 28% ,结合实例会看到左边矩形稀疏、右边紧凑这样的效果。

PathView

    了解了 Path 、PathAttribute 及 PathPercent 等对象,咱们再来看 PathView 。
    像 ListView 一样, PathView 有一个 count 属性,保存 PathView 要显示的 item 总数。另外 PathView 还有一个 pathItemCount 属性,指定在路径上可见的 item 数量,它可以与 count 不同。
    preferredHighlightBegin 和 preferredHighlightEnd 属性的值是 real 类型的,范围 0.0 至 1.0 。preferredHighlightBegin 指定当前 item 在 view 中的首选起始位置, preferredHighlightEnd 指定当前 item 在 view 中的首选结束位置。与它们相关的,还有一个 highlightRangeMode 属性,可以取值 PathView.NoHighlightRange 、 PathView.ApplyRange 或 PathView.StrictlyEnforceRange 。比如我们想严格地将当前 item 限制在路径的中央,可以设置 highlightRangeMode 为 PathView.StrictlyEnforceRange ,设置 preferredHighlightBegin 和 preferredHighlightEnd 都为 0.5 。
    highlight 属性指定为当前 item 绘制高亮效果的组件。
    PathView 像 Flickable 一样,当用户拖动 view 时,具有弹簧效果。 interactive 属性设置为 true ,用户就可以拖动 PathView ,如果产生了弹动, flicking 会变为 true 。 flickDeceleration 属性设置弹簧效果的衰减速率,默认值为 100 。
    decrementCurrentIndex() 、 incrementCurrentIndex() 两个方法可以递减、递增 PathView 维护的当前 item 的索引。这两个函数有循环效果,如果你不需要,可以自己修改 currentIndex 属性来实现你的逻辑。
    PathView 还向 delegate 导出了 isCurrentItem(布尔值) 、onPath(布尔值) 、 view 三个附加属性。在 delegate 的顶层 item 内使用 PathView.isCurrentItem 可以获知本 item 是否为 PathView 的当前 item ;使用 PathView.onPath 则可以知道本 item 是否在路径上; PathView.view 则指向 item 所属的 PathView 实例,你可以通过它来访问 PathView 的方法、属性、信号等。
    有关 PathView 的更多细节,请研读 Qt 帮助中有关 PathView 的文档,现在该来看一个 PathView 的实例了,下面是 pathview_simple.qml :
import QtQuick 2.0
import QtQuick.Controls 1.1

Rectangle {
    width: 480;
    height: 300;
    color: "black";
    id: root;
   
    Component {
        id: rectDelegate;
        Item {
            id: wrapper;
            z: PathView.zOrder;
            opacity: PathView.itemAlpha;
            scale: PathView.itemScale;
            Rectangle {
                width: 100;
                height: 60;
                color: Qt.rgba(Math.random(), Math.random(), Math.random(), 1);
                border.width: 2;
                border.color: wrapper.PathView.isCurrentItem ? "red" : "lightgray";
                Text {
                    anchors.centerIn: parent;
                    font.pixelSize: 28;
                    text: index;
                    color: Qt.lighter(parent.color, 2);
                }
            }           
        }
    }
   
    PathView {
        id: pathView;
        anchors.fill: parent;
        interactive: true;
        pathItemCount: 7;
        preferredHighlightBegin: 0.5;
        preferredHighlightEnd: 0.5;
        highlightRangeMode: PathView.StrictlyEnforceRange;

        delegate: rectDelegate;
        model: 15;

        path:Path {
            startX: 10;
            startY: 100;
            PathAttribute { name: "zOrder"; value: 0 }
            PathAttribute { name: "itemAlpha"; value: 0.1 }
            PathAttribute { name: "itemScale"; value: 0.6 }
            PathLine {
                x: root.width/2 - 40;
                y: 100;
            }
            PathAttribute { name: "zOrder"; value: 10 }
            PathAttribute { name: "itemAlpha"; value: 0.8 }
            PathAttribute { name: "itemScale"; value: 1.2 }
            PathLine {
                relativeX: root.width/2 - 60;
                relativeY: 0;
            }
            PathAttribute { name: "zOrder"; value: 0 }
            PathAttribute { name: "itemAlpha"; value: 0.1 }
            PathAttribute { name: "itemScale"; value: 0.6 }
        }

        focus: true;
        Keys.onLeftPressed: decrementCurrentIndex();
        Keys.onRightPressed: incrementCurrentIndex();
    }
}

    我定义了一个很简单的 delegate :在带边框的矩形内显示 item 索引。 delegate 的顶层 item 使用了路径内通过 PathAttribute 定义的 zOrder 、itemAlpha 、 itemScale 等附加属性来控制 item 的大小、透明度。 Rectangle 对象的颜色随机生成。边框则通过 isCurrentItem 附加属性来分别设置,注意附加属性只在顶层 item ,即 wrapper 内可以直接访问,所以 Rectangle 内使用 wrapper.PathView.isCurrentItem 来访问。
    model 更简单,只给了个数字。
    path 对象在 PathAttribute 一节介绍过了。
    focus 设置为 true ,是为了处理按键事件。左右方向键可以循环浏览 PathView 内的 item 。
    我设置路径上可见的 item 数量为 7 ,当前 item 保持在路径中央。
    执行 "qmlscene pathview_simple.qml" 命令,效果下图所示:


    请注意观察 item 之间的遮挡效果:当前 item 在最上面,路径两端的 item 在最下面,中间的 item 递推。这是把路径分为两个路径元素并且将 PathAttribute 定义 的zOrder 属性应用在 delegate 上的效果,你可以去掉 zOrder 属性声明及相关的语句看看效果。当然你也可以修改 itemAlpha 、 itemScale 两个属性来试试。
    如果你想让试试 PathPercent 的效果,可以在第一个 PathLine 后面加入代码 "PathPercent { value: 0.28; }" ,然后就可以看到下图的效果:


    看上去有点儿怪怪的,大家来找茬吧。
    没错,当前选中的 item 以及它的高亮框被挡住了嗳。调整下 preferredHighlightBegin 属性,设置其值为 0.3 ,再来看下图:
    

    嗷卖糕的,好啦!
    版权所有 foruok ,如需转载请注明出处:作者 foruok ,博客 http://blog.csdn.net/foruok 。

    PathView 还有很多其它属性,使用到时请自行研究 Qt 帮助。
    回顾一下本系列文章:
  • Qt Quick 简介
  • QML 语言基础
  • Qt Quick 之 Hello World 图文详解
  • Qt Quick 简单教程
  • Qt Quick 事件处理之信号与槽
  • Qt Quick事件处理之鼠标、键盘、定时器
  • Qt Quick 事件处理之捏拉缩放与旋转
  • Qt Quick 组件与对象动态创建详解
  • Qt Quick 布局介绍
  • Qt Quick 之 QML 与 C++ 混合编程详解
  • Qt Quick 图像处理实例之美图秀秀(附源码下载)
    最后的最后,请给我的决赛博文投票:点此进入投票页面网页最下方有投票按钮,投我一票,谢谢

Qt Quick 之 PathView 详解