Qt 学习之路 :动态视图

Repeater适用于少量的静态数据集。但是在实际应用中,数据模型往往是非常复杂的,并且数量巨大。这种情况下,Repeater并不十分适合。于是,QtQuick 提供了两个专门的视图元素:ListViewGridView。这两个元素都继承自Flickable,因此允许用户在一个很大的数据集中进行移动。同时,ListViewGridView能够复用创建的代理,这意味着,ListViewGridView不需要为每一个数据创建一个单独的代理。这种技术减少了大量代理的创建造成的内存问题。

由于ListViewGridView在使用上非常相似,因此我们以ListView为例进行介绍。

ListView类似前面章节提到的Repeater元素。ListView使用模型提供数据,创建代理渲染数据。下面是ListView的简单使用:

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

import QtQuick 2.2

Rectangle {

width: 80

height: 300

color: "white"

ListView {

anchors.fill: parent

anchors.margins: 20

clip: true

model: 100

delegate: numberDelegate

spacing: 5

}

Component {

id: numberDelegate

Rectangle {

width: 40

height: 40

color: "lightGreen"

Text {

anchors.centerIn: parent

font.pixelSize: 10

text: index

}

}

}

}

代码运行结果如下图所示:

如果数据模型包含的数据不能在一屏显示完全,ListView只会显示整个列表的一部分。但是,作为 QtQuick 的一种默认行为,ListView并不能限制显示范围就在代理显示的区域内。这意味着,代理可能会在ListView的外部显示出来。为避免这一点,我们需要设置clip属性为true,使得超出ListView边界的代理能够被裁减掉。注意下图所示的行为(左面是设置了clipListView而右图则没有):

对于用户而言,ListView是一个可滚动的区域。ListView支持平滑滚动,这意味着它能够快速流畅地进行滚动。默认情况下,这种滚动具有在向下到达底部时会有一个反弹的特效。这一行为由boundsBehavior属性控制。boundsBehavior属性有三个可选值:Flickable.StopAtBounds完全消除反弹效果;Flickable.DragOverBounds在自由滑动时没有反弹效果,但是允许用户拖动越界;Flickable.DragAndOvershootBounds则是默认值,意味着不仅用户可以拖动越界,还可以通过自由滑动越界。

当列表滑动结束时,列表可能停在任意位置:一个代理可能只显示一部分,另外部分被裁减掉。这一行为是由snapMode属性控制的。snapMode属性的默认值是ListView.NoSnap,也就是可以停在任意位置;ListView.SnapToItem会在某一代理的顶部停止滑动;ListView.SnapOneItem则规定每次滑动时不得超过一个代理,也就是每次只滑动一个代理,这种行为在分页滚动时尤其有效。

默认情况下,列表视图是纵向的。通过orientation属性可以将其改为横向。属性可接受值为ListView.VerticalListView.Horizontal。例如下面的代码:

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

import QtQuick 2.2

Rectangle {

width: 480

height: 80

color: "white"

ListView {

anchors.fill: parent

anchors.margins: 20

clip: true

model: 100

orientation: ListView.Horizontal

delegate: numberDelegate

spacing: 5

}

Component {

id: numberDelegate

Rectangle {

width: 40

height: 40

color: "lightGreen"

Text {

anchors.centerIn: parent

font.pixelSize: 10

text: index

}

}

}

}

当列表视图横向排列时,其中的元素按照从左向右的顺序布局。使用layoutDirection属性可以修改这一设置。该属性的可选值为Qt.LeftToRightQt.RightToLeft

在触摸屏环境下使用ListView,默认的设置已经足够。但是,如果在带有键盘的环境下,使用方向键一般应该突出显示当前项。这一特性在 QML 中称为“高亮”。与普通的代理类似,视图也支持使用一个专门用于高亮的代理。这可以认为是一个额外的代理,只会被实例化一次,并且只会移动到当前项目的位置。

下面的例子设置了两个属性。第一,focus属性应当被设置为true,这允许ListView接收键盘焦点。第二,highlight属性被设置为一个被使用的高亮代理。这个高亮代理可以使用当前项目的xyheight属性;另外,如果没有指定width属性,也可以使用当前项目的width属性。在这个例子中,宽度是由ListView.view.width附加属性提供的。我们会在后面的内容详细介绍这个附加属性。

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

38

39

import QtQuick 2.2

Rectangle {

width: 240

height: 300

color: "white"

ListView {

anchors.fill: parent

anchors.margins: 20

clip: true

model: 100

delegate: numberDelegate

spacing: 5

highlight: highlightComponent

focus: true

}

Component {

id: highlightComponent

Rectangle {

width: ListView.view.width

color: "lightGreen"

}

}

Component {

id: numberDelegate

Item {

width: 40

height: 40

Text {

anchors.centerIn: parent

font.pixelSize: 10

text: index

}

}

}

}

运行结果如下图所示:

在使用高亮时,QML 提供了很多属性,用于控制高亮的行为。例如,highlightRangeMode设置高亮如何在视图进行显示。默认值ListView.NoHighlightRange意味着高亮区域和项目的可视范围没有关联;ListView.StrictlyEnforceRange则使高亮始终可见,如果用户试图将高亮区域从视图的可视区域移开,当前项目也会随之改变,以便保证高亮区域始终可见;介于二者之间的是ListView.ApplyRange,它会保持高亮区域可视,但是并不强制,也就是说,如果必要的话,高亮区域也会被移出视图的可视区。

默认情况下,高亮的移动是由视图负责的。这个移动速度和大小的改变都是可控的,相关属性有highlightMoveSpeedhighlightMoveDurationhighlightResizeSpeed以及highlightResizeDuration。其中,速度默认为每秒 400 像素;持续时间被设置为 -1,意味着持续时间由速度和距离控制。同时设置速度和持续时间则由系统选择二者中较快的那个值。有关高亮更详细的设置则可以通过将highlightFollowCurrentItem属性设置为false达到。这表示视图将不再负责高亮的移动,完全交给开发者处理。下面的例子中,高亮代理的y属性被绑定到ListView.view.currentItem.y附加属性。这保证了高亮能够跟随当前项目。但是,我们不希望视图移动高亮,而是由自己完全控制,因此在y属性上面应用了一个Behavior。下面的代码将这个移动的过程分成三步:淡出、移动、淡入。注意,SequentialAnimationPropertyAnimation可以结合NumberAnimation实现更复杂的移动。有关动画部分,将在后面的章节详细介绍,这里只是先演示这一效果。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

Component {

id: highlightComponent

Item {

width: ListView.view.width

height: ListView.view.currentItem.height

y: ListView.view.currentItem.y

Behavior on y {

SequentialAnimation {

PropertyAnimation { target: highlightRectangle; property: "opacity"; to: 0; duration: 200 }

NumberAnimation { duration: 1 }

PropertyAnimation { target: highlightRectangle; property: "opacity"; to: 1; duration: 200 }

}

}

Rectangle {

id: highlightRectangle

anchors.fill: parent

color: "lightGreen"

}

}

}

最后需要介绍的是ListView的 header 和 footer。header 和 footer 可以认为是两个特殊的代理。虽然取名为 header 和 footer,但是这两个部分实际会添加在第一个元素之前和最后一个元素之后。也就是说,对于一个从左到右的横向列表,header 会出现在最左侧而不是上方。下面的例子演示了 header 和 footer 的位置。header 和 footer 通常用于显示额外的元素,例如在最底部显示“加载更多”的按钮。

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

38

39

40

41

42

43

44

45

46

47

48

49

50

import QtQuick 2.2

Rectangle {

width: 80

height: 300

color: "white"

ListView {

anchors.fill: parent

anchors.margins: 20

clip: true

model: 4

delegate: numberDelegate

spacing: 5

header: headerComponent

footer: footerComponent

}

Component {

id: headerComponent

Rectangle {

width: 40

height: 20

color: "yellow"

}

}

Component {

id: footerComponent

Rectangle {

width: 40

height: 20

color: "red"

}

}

Component {

id: numberDelegate

Rectangle {

width: 40

height: 40

color: "lightGreen"

Text {

anchors.centerIn: parent

font.pixelSize: 10

text: index

}

}

}

}

需要注意的是,header 和 footer 与ListView之间没有预留间距。这意味着,header 和 footer 将紧贴着列表的第一个和最后一个元素。如果需要在二者之间留有一定的间距,则这个间距应该成为 header 和 footer 的一部分。

GridViewListView非常相似,唯一的区别在于,ListView用于显示一维列表,GridView则用于显示二维表格。相比列表,表格的元素并不依赖于代理的大小和代理之间的间隔,而是由cellWidthcellHeight属性控制一个单元格。每一个代理都会被放置在这个单元格的左上角。

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

import QtQuick 2.2

Rectangle {

width: 240

height: 300

color: "white"

GridView {

anchors.fill: parent

anchors.margins: 20

clip: true

model: 100

cellWidth: 45

cellHeight: 45

delegate: numberDelegate

}

Component {

id: numberDelegate

Rectangle {

width: 40

height: 40

color: "lightGreen"

Text {

anchors.centerIn: parent

font.pixelSize: 10

text: index

}

}

}

}

ListView类似,GridView也可以设置 header 和 footer,也能够使用高亮代理和类似列表的边界行为。GridView支持不同的显示方向,这需要使用flow属性控制,可选值为GridView.LeftToRightGridView.TopToBottom。前者按照先从左向右、再从上到下的顺序填充,滚动条出现在竖直方向;后者按照先从上到下、在从左到右的顺序填充,滚动条出现在水平方向。

时间: 2024-10-10 17:28:03

Qt 学习之路 :动态视图的相关文章

Qt 学习之路:视图选择 (QItemSelectionModel)

选择是视图中常用的一个操作.在列表.树或者表格中,通过鼠标点击可以选中某一项,被选中项会变成高亮或者反色.在 Qt 中,选择也是使用了一种模型.在 model/view 架构中,这种选择模型提供了一种更通用的对选择操作的描述.对于一般应用而言,Qt 内置的选择模型已经足够,但是,Qt 还是允许你创建自己的选择模型,来实现一些特殊的操作. Qt 使用QItemSelectionModel类获取视图中项目的选择情况.这个模型保持有项目的索引,并且独立于任何视图.这意味着,我们可以让不同的视图共享同一

Qt 学习之路 :视图代理

与 Qt model/view 架构类似,在自定义用户界面中,代理扮演着重要的角色.模型中的每一个数据项都要通过一个代理向用户展示,事实上,用户看到的可视部分就是代理. 每一个代理都可以访问一系列属性和附加属性.这些属性及附加属性中,有些来自于数据模型,有些则来自于视图.前者为代理提供了每一个数据项的数据信息:后者则是有关视图的状态信息. 代理中最常用到的是来自于视图的附加属性ListView.isCurrentItem和ListView.view.前者是一个布尔值,用于表示代理所代表的数据项是

Qt学习之路

  Qt学习之路_14(简易音乐播放器) Qt学习之路_13(简易俄罗斯方块) Qt学习之路_12(简易数据管理系统) Qt学习之路_11(简易多文档编辑器) Qt学习之路_10(Qt中statusBar,MessageBox和Timer的简单处理) Qt学习之路_9(Qt中Item Widget初步探索) Qt学习之路_8(Qt中与文件目录相关操作) Qt学习之路_7(线性布局和网格布局初步探索) Qt学习之路_6(Qt局域网聊天软件) Qt学习之路_5(Qt TCP的初步使用) Qt学习之路

QT学习之路(1):彩票绝对不中模拟器

//============================================//绝对不中,彩票开奖模拟器#include "mainwindow.h"#include "ui_mainwindow.h"#include <QHash>#include <QDebug>MainWindow::MainWindow(QWidget *parent) :    QMainWindow(parent),    ui(new Ui::M

QT学习之路--创建一个对话框

Q_OBJECT:这是一个宏,凡是定义信号槽的类都必须声明这个宏. 函数tr()全名是QObject::tr(),被他处理过的字符串可以使用工具提取出来翻译成其他语言,也就是做国际化使用. 对于QT学习之路:Qt学习之路(7):创建一个对话框(上)这个程序.编译出现 invalid use of incomplete type ‘class QPushButton’ findButton->setEnabled(!text.isEmpty()); ^ In file included from

Qt 学习之路 2 --- 读书笔记

一.文章来由 来自豆子老师非常好的一本Qt教程,但是只有网络版,所以用这个做笔记了,不动笔墨不读书嘛~~ 二.读书笔记 1.Qt 学习之路 2(2):Qt 简介 1.1 关于 Qt 的一站式解决 Qt 是一个著名的 C++ 应用程序框架.但并不只是一个 GUI 库,因为 Qt 十分庞大,并不仅仅是 GUI 组件.使用 Qt,在一定程度上你获得的是一个"一站式"的解决方案:不再需要研究 STL,不再需要 C++ 的,不再需要到处去找解析 XML.连接数据库.访问网络的各种第三方库,因为

Qt 学习之路:模型-视图高级技术

PathView PathView是 QtQuick 中最强大的视图,同时也是最复杂的.PathView允许创建一种更灵活的视图.在这种视图中,数据项并不是方方正正,而是可以沿着任意路径布局.沿着同一布局路径,数据项的属性可以被更详细的设置,例如缩放.透明度等. 使用PathView首先需要定义一个代理和一个路径.除此之外,PathView还可以设置很多其它属性,其中最普遍的是pathItemCount,用于设置可视数据项的数目:preferredHighlightBegin.preferred

Qt学习之路1---软件下载安装及工程简介

1.下载安装目前最新版的qt,官网链接:https://www.qt.io/qt5-8/: 和qt4不同,qt5在线安装,轻巧快速,而且不用配置一些繁琐的东西,安装之后会出现Qt creator这就是我们之后使用的IDE. 2.Qt creator工程包含不同类型的文件 _ .pro项目描述文件 _ .pro.user 用户配置描述文件  _ .ui 界面描述文件  _ 资源文件(图片,音频等) 2.1 .pro项目描述文件的基本组成 _ .#  注释符 _ QT 模块声明 _ TARGET  

Qt学习之路(24): QPainter(改写paintEvent)

多些大家对我的支持啊!有朋友也提出,前面的几节有关event的教程缺少例子.因为event比较难做例子,也就没有去写,只是把大概写了一下.今天带来的是新的部分,有关Qt的2D绘图.这部分不像前面的内容,还是比较好理解的啦!所以,例子也会增加出来. 有人问豆子拿Qt做什么,其实,豆子就是在做一个Qt的画图程序,努力朝着Photoshop和GIMP的方向发展.但这终究要经过很长的时间.很困难的路程的,所以也放在网上开源,有兴趣的朋友可以来试试的呀… 好了,闲话少说,来继续我们的学习吧! Qt的绘图系