1 Star 0 Fork 38

oostudy/qtguide

forked from qtguide/qtguide 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
ch08-03.htm 57.03 KB
一键复制 编辑 原始数据 按行查看 历史
qtguide 提交于 2017-05-29 10:29 +08:00 . ch8.3.3
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824
<!DOCTYPE html>
<html>
<head>
<meta content="text/html; charset=UTF-8" http-equiv="content-type">
<title>ch08-03</title>
<link href="css/style.css" rel="stylesheet" type="text/css">
<link rel="stylesheet" href="thumbnailviewer.css" type="text/css">
<script src="thumbnailviewer.js" type="text/javascript">
/***********************************************
* Image Thumbnail Viewer Script- © Dynamic Drive (www.dynamicdrive.com)
* This notice must stay intact for legal use.
* Visit http://www.dynamicdrive.com/ for full source code
***********************************************/
</script> </head>
<body>
<div class="os1">8.3 树形控件</div>
<br>
本节首先介绍树形控件 QTreeWidget 的内容,然后介绍它的树形节点条目 QTreeWidgetItem。 树形控件的节点可以有多层、多个子节点,
如果将子节点全部展开,那么每一行都是一个数据条目。QTreeWidgetItem
比较特殊,一个条目内部可以有多列数据信息,相当于表格控件一整行的表格单元集成为一个条目,所以树形条目要比前面两节的列表条目和表格条目都复杂。第三小节介绍迭代器和
递归遍历算法,因为树形控件每行的条目之间可以是兄弟关系或父子关系,含有子节点的条目可以折叠也可以展开,进行遍历时有专门的迭代器
QTreeWidgetItemIterator 实现,也可以自行编写递归算法遍历所有条目。<br>
本节介绍完 QTreeWidget 、QTreeWidgetItem、QTreeWidgetItemIterator
等内容之后,通过两个例子展示树形控件的用法,如果读者提前学习一下树形遍历的递归算法,对本节的内容理解会有帮助。<br>
<br>
<div class="os2">8.3.1 QTreeWidget</div>
<br>
在 Qt 设计师界面可以直接拖动树形控件到窗口里,下图展示树形控件的外观和构成:<br>
<center> <img src="images/ch08/ch08-03-01.png" alt="treewidget" width="800"></center>
默认情况下,树形控件最上面是一个树头条目,树头条目也是 QTreeWidgetItem 对象,可以有多列内容。<br>
树头下面是真正的树形控件所有条目,在折叠的情况下,如上图所示,每行一个顶级条目,顶级条目也是 QTreeWidgetItem 对象,顶级条目的父节点指针
QTreeWidgetItem::​parent() 为 NULL。<br>
将所有节点展开之后,可以看到每个节点可以有多个子节点:<br>
<center> <img src="images/ch08/ch08-03-02.png" alt="treewidget2" width="800"></center>
对于包含子节点的父节点,左边会有小的三角形指示器,用于控制折叠或展开父节点。子节点也可以拥有更低级别的子节点(孙节点),以此类推,树形控件没有限定子节点
的层数。顶级节点和其子孙节点的数据结构一样,都可以有多列数据,只是添加的函数、父节点指针不一样。下面介绍树形控件的函数和功能,在 8.3.2
节介绍树形节点条目 QTreeWidgetItem,8.3.3 节介绍树形条目迭代器 QTreeWidgetItemIterator
和递归遍历算法,最后两个小节是示例程序的实践。<br>
<br>
树形控件的构造函数很简单:<br>
<div class="code"> QTreeWidget(QWidget * parent = 0)</div>
参数里只有指定父窗口或父控件的指针 parent 。树形控件在添加条目之前,必须要先设置列数:<br>
<div class="code">void setColumnCount(int columns) //设置列数</div>
<div class="code">int columnCount() const //获取列数</div>
默认的列数是 1 列,如果涉及到多列数据,比如文件浏览树,有文件名、文件类型、大小、修改时间等等,就需要设置为多列数据的树。<br>
树形控件设置好列数就可以添加相应的顶级条目,添加顶级条目是由树形控件自身的函数实现,而子条目则由 QTreeWidgetItem
的函数实现。本小节主要围绕树形控件和其基类的函数来讲,树形控件也可以设置和表格控件类似的表头,这里称为树头条目,放在本小节末尾再讲。<br>
<br>
(1)添加和访问顶级条目<br>
树形控件顶级条目的操作比较类似 QListWidget 的列表条目操作函数。新建条目之后,可以用如下函数把条目添加到树形控件的顶级条目列表末尾:
<div class="code">void QTreeWidget::​addTopLevelItem(QTreeWidgetItem * item)
//添加一个顶级条目到末尾</div>
<div class="code">void QTreeWidget::​addTopLevelItems(const
QList&lt;QTreeWidgetItem *&gt; &amp; items) //添加多个顶级条目到末尾</div>
如果希望将条目插入到指定顶级条目列表的 index 序号位置,使用如下函数:<br>
<div class="code">void QTreeWidget::​insertTopLevelItem(int index,
QTreeWidgetItem * item)</div>
<div class="code">void QTreeWidget::​insertTopLevelItems(int index, const
QList&lt;QTreeWidgetItem *&gt; &amp; items)</div>
树形控件所有的顶级条目父节点指针都为 NULL (父节点是指树形层次中的节点关系,而条目的父控件依然是树形控件本身)。<br>
添加了顶级条目之后,可以对顶级条目进行计数:<br>
<div class="code">int QTreeWidget::​topLevelItemCount() const</div>
<br>
(2)移除顶级条目<br>
移除顶级条目的函数也是take*打头:<br>
<div class="code">QTreeWidgetItem * QTreeWidget::​takeTopLevelItem(int
index)</div>
index是顶级条目的序号,该函数只是从树形控件卸下顶级条目,但不会删除条目的内存空间,如果希望彻底删除,那么手动 delete 该函数返回的条目。<br>
如果要清空所有的顶级条目和子条目,使用槽函数:<br>
<div class="code">void QTreeWidget::​clear()</div>
<br>
(3)条目访问函数<br>
对于顶级条目,如果知道顶级条目的序号获取对应的条目:<br>
<div class="code">QTreeWidgetItem * QTreeWidget::​topLevelItem(int index)
const</div>
反过来,对于已知顶级条目对象,查看其顶级序号:<br>
<div class="code">int QTreeWidget::​indexOfTopLevelItem(QTreeWidgetItem *
item) const</div>
如果条目不是顶级条目或者条目不属于该控件,那么会返回 -1。<br>
树形控件实际运行时,可能既有顶级条目,也有展开后的子孙条目同时显示,所以某个条目上面或下面的相邻条目不一定是同级别的兄弟条目,有可能是叔辈祖辈的条目,也
可能是子辈孙辈条目。获取某个条目的相邻条目函数为:<br>
<div class="code">QTreeWidgetItem * QTreeWidget::​itemAbove(const
QTreeWidgetItem * item) const //上面相邻条目</div>
<div class="code">QTreeWidgetItem * QTreeWidget::​itemBelow(const
QTreeWidgetItem * item) const //下面相邻条目</div>
<br>
从屏幕控件显示角度,如果根据树形控件内部相对坐标获取条目(树形控件显示区域的左上角为原点),使用下面函数:<br>
<div class="code">QTreeWidgetItem * QTreeWidget::​itemAt(const QPoint &amp;
p) const</div>
<div class="code">QTreeWidgetItem * QTreeWidget::​itemAt(int x, int y) const</div>
这两个函数是一个意思,一个用 QPoint 对象表示相对坐标,另一个直接用 x 和 y 数值表示坐标,​如果对应坐标没有条目,会返回 NULL,注意判断
返回值。<br>
树形控件也是自带滚动条的,如果条目特别多,自动显示滚动条,对于树形控件在屏幕可见的条目,可以根据条目对象获取它的可视矩形(树形控件显示区域的左上角为原
点):<br>
<div class="code">QRect QTreeWidget::​visualItemRect(const QTreeWidgetItem *
item) const</div>
<br>
(4)当前条目的操作<br>
树形控件的选中操作默认比较像 QListWidget,如果不手动设置,只能选中一个高亮条目。<br>
获取当前高亮选中条目的函数为:<br>
<div class="code">QTreeWidgetItem * QTreeWidget::​currentItem() const</div>
树形控件可以有多列,当前条目被点击选中的列号为:<br>
<div class="code">int QTreeWidget::​currentColumn() const</div>
树形控件内的条目一般都没有固定行号,因为条目可以展开也可以折叠,行号是变化的,所以没有基于行号的操作函数。<br>
<br>
如果要设置某个条目为当前选中的状态:<br>
<div class="code">void QTreeWidget::​setCurrentItem(QTreeWidgetItem * item)</div>
<div class="code">void QTreeWidget::​setCurrentItem(QTreeWidgetItem * item,
int column)</div>
<div class="code">void QTreeWidget::​setCurrentItem(QTreeWidgetItem * item,
int column, QItemSelectionModel::SelectionFlags command)</div>
第一个 ​setCurrentItem() 函数相当于设置该条目整行高亮选中,第二个是设置该条目行的 column
列高亮选中,第三个函数是单次选中命令,参考“8.2.4 选中区域和选中行为”的单次选中命令内容,只是树形控件是一整行为一个条目,定位到条目的某列数据,就
类似指定表格控件的单元格。<br>
如果当前高亮选中的状态发生变化,会触发如下信号:<br>
<div class="code">void QTreeWidget::​currentItemChanged(QTreeWidgetItem *
current, QTreeWidgetItem * previous)</div>
参数里分别是当前高亮选中的条目,和之前高亮选中的条目,注意指针可能是 NULL,使用指针前一定要判断指针非空。<br>
<br>
(5)条目查找和排序<br>
如果要根据模板子串查找某列文本匹配的条目,使用如下函数:<br>
<div class="code">QList&lt;QTreeWidgetItem *&gt;
QTreeWidget::​findItems(const QString &amp; text, Qt::MatchFlags flags,
int column = 0) const</div>
&nbsp;参数里text是模板子串,flags是匹配标志(参看“8.1.1
QListWidget”中的字符串匹配标志表格),第三个参数是指定查找的列。该函数只查找一列的文本,其他列的文本是不查找的。如果需要查找所有列数据,那么要根据不
同列号逐列查询。<br>
<br>
类似表格控件,树形控件也可以按照列的文本进行自动排序,自动排序的设置函数为:<br>
<div class="code">bool&nbsp;&nbsp; &nbsp;isSortingEnabled()
const&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //设置是否自动排序</div>
<div class="code">void&nbsp;&nbsp; &nbsp;setSortingEnabled(bool
enable)&nbsp;&nbsp; //查看是否开启自动排序 </div>
指定排序的列号和升序降序,使用从基类继承的函数:<br>
<div class="code">void QTreeView::​sortByColumn(int column, Qt::SortOrder
order)</div>
在没有开启自动排序的情况下,也可以调用该函数进行一次性的条目排序。<br>
<br>
(6)条目显示和运行时条目编辑<br>
可以为条目的某列“单元格”设置单独的控件来静态显示(控件不具有编辑功能):<br>
<div class="code">void QTreeWidget::​setItemWidget(QTreeWidgetItem * item,
int column, QWidget * widget) //设置条目列控件</div>
<div class="code">QWidget * QTreeWidget::​itemWidget(QTreeWidgetItem * item,
int column) const //获取条目列控件,不设置就是NULL</div>
注意该函数只能在条目添加到树形控件之后才能调用,否则无效,并且条目列控件只能用于显示,无法编辑,如果要定制可编辑的“单元格”控件,必须用基类
QTreeView 并继承 QItemDelegate 做代理,这些内容到后面模型视图章节讲解。<br>
<span style="font-weight: bold;">再次强调:itemWidget
条目控件,在默认情况下是与条目本身数据完全无关的,是条目数据的替换品,而不是协作模式。只有手动设置信号与槽,它们才可能关联上。</span><br>
QListWidget 和 QTreeWidget 的条目控件都是静态显示,不能编辑。<br>
QTreeWidget 控件的条目列控件 widget 还必须把 autoFillBackground 属性设置为
true,如果不是自动填充背景,那么默认是透明背景,这样控件的内容和内部模型数据(就是条目的列数据)同时显示,文本会重影,效果就糟糕了。<br>
删除条目的列控件使用如下函数:<br>
<div class="code">void QTreeWidget::​removeItemWidget(QTreeWidgetItem *
item, int column)</div>
这个函数没有返回值,会自动地彻底删除条目列控件。<br>
<br>
在大多数情况下都用不到 itemWidget ,因为能够为条目设置可编辑标志位,然后调用如下函数开启树形控件自带的文本编辑器:<br>
<div class="code">void QTreeWidget::​editItem(QTreeWidgetItem * item, int
column = 0)</div>
参数 item 是指定的条目,column
是条目的列(类似“单元格”)。在没有为条目设置可编辑标志位的情况下,可以调用下面一对函数进行持续编辑器的开启和关闭:<br>
<div class="code">void QTreeWidget::​openPersistentEditor(QTreeWidgetItem *
item, int column = 0)</div>
<div class="code">void QTreeWidget::​closePersistentEditor(QTreeWidgetItem *
item, int column = 0)</div>
注意这对函数一开一关,要成对调用,否则编辑完了不会自动关闭持续编辑器。<br>
<br>
(7)信号<br>
关于当前高亮选中变化的信号 currentItemChanged() 前面讲过了,这里先列几个常规的信号,然后再将树形控件独有的信号。常规信号就是下面这
几个:(条目列就类似表格控件的单元格)<br>
<div class="code">void itemActivated(QTreeWidgetItem * item, int column)
//条目列被激活</div>
<div class="code">void itemChanged(QTreeWidgetItem * item, int
column)&nbsp;&nbsp; //条目列的数据发生变化,比如文本或图标修改了</div>
<div class="code">void itemClicked(QTreeWidgetItem * item, int column)&nbsp;
//条目列被单击</div>
<div class="code">void itemDoubleClicked(QTreeWidgetItem * item, int column)
//条目列被双击</div>
<div class="code">void itemEntered(QTreeWidgetItem * item, int column)
//进入条目列</div>
<div class="code">void itemPressed(QTreeWidgetItem * item, int column)
//条目列被点 击按下</div>
树形控件最独特的就是展开和折叠信号:<br>
<div class="code">void QTreeWidget::​itemExpanded(QTreeWidgetItem *
item)&nbsp; //条目展开时发送信号</div>
<div class="code">void QTreeWidget::​itemCollapsed(QTreeWidgetItem * item)
//条目折叠时发送信号</div>
如果调用槽函数&nbsp; expandAll() 展开所有子孙条目,那么不会触发 ​itemExpanded() 信号,因为触发太多会非常影响性能。<br>
类似地,如果用槽函数 collapseAll() 折叠所有子孙条目,也不会触发 ​itemCollapsed() 信号,以免影响性能。<br>
举例来说,在文件夹浏览的时候,因为操作系统里的文件太多,没法一次性构建完整的文件树,那么就可以用展开和折叠信号实时枚举某一层次文件夹的内容,而不是一次性
枚举文件系统所有文件,因为一次性枚举所有文件的性能太糟糕。<br>
树形控件还有一个 itemSelectionChanged() 信号,一般在多选模式才会用到,稍后讲解。<br>
<br>
(8)槽函数<br>
树形控件的槽函数包括四个(基类的另算):<br>
<div class="code">void clear() //清空整个树形控件</div>
<div class="code">void collapseItem(const QTreeWidgetItem * item) //折叠指定的条目</div>
<div class="code">void expandItem(const QTreeWidgetItem * item)&nbsp; //展开指定
条目</div>
<div class="code">void scrollToItem(const QTreeWidgetItem * item,
QAbstractItemView::ScrollHint hint = EnsureVisible) //滚动到指定条目</div>
滚动函数 scrollToItem() 第二个参数是滚到到该条目的显示方式,参考“8.1.1
QListWidget”QAbstractItemView:: ​ ScrollHint 枚举常量的表格。<br>
<br>
(9)基类 QTreeView 的函数<br>
QTreeView 的功能函数也很多,这里列举几个可能常用的,详细的内容等到模型视图章节讲解。关于列隐藏或显示、设置列宽的函数如下:<br>
<div class="code">void QTreeView::​setColumnHidden(int column, bool hide)
//设置列隐藏或显示</div>
<div class="code">bool QTreeView::​isColumnHidden(int column) const
//判断列是否隐藏 </div>
<div class="code">void QTreeView::hideColumn(int column) //槽函数,隐藏指定列</div>
<div class="code">void QTreeView::showColumn(int column) //槽函数,显示指定列</div>
<div class="code">void QTreeView::​setColumnWidth(int column, int width)
//设置列宽</div>
<div class="code">int QTreeView::​columnWidth(int column) const //获取指定列的宽度</div>
<div class="code">void QTreeView::​resizeColumnToContents(int column)
//槽函数,自动调整 指定列的宽度</div>
属性 indentation 控制显示父子节点的缩进宽度:<br>
<div class="code">int indentation() const&nbsp;&nbsp;&nbsp; //获取父子节点的缩进宽度</div>
<div class="code">void setIndentation(int i) //设置缩进宽度</div>
<div class="code">void resetIndentation()&nbsp;&nbsp;&nbsp; //重置缩进宽度为默认值</div>
基类还有几个常用的折叠和展开槽函数:<br>
<div class="code">void collapseAll() //折叠所有子孙节点,这样只能看到顶级节点</div>
<div class="code">void expandAll() //展开所有子孙节点,完全展开的树</div>
<div class="code">void expandToDepth(int depth) //展开 depth 层级的子节点</div>
expandToDepth() 函数是指一直展开,直到将第 depth 层级的子节点都展开为止。以顶级条目为第 0 层级,顶级条目的直接子节点为第 1
层级,孙子节点为第 2 层级,依次类推。<br>
例如 expandToDepth(0) 的效果如下:<br>
<center> <img src="images/ch08/ch08-03-03.png" alt="expand0"></center>
如果调用 expandToDepth(1) 展开第1级的节点:<br>
<center> <img src="images/ch08/ch08-03-04.png" alt="expand1"></center>
如果把 expandToDepth() 参数设置成负数,那么相当于展开无穷大级别,就是展开所有的子孙节点。<br>
<br>
(10)树头条目<br>
树形控件只有一个表头,就是显示在上面的水平表头,本节也叫树头条目。设置树头条目的函数为:<br>
<div class="code">void QTreeWidget::​setHeaderItem(QTreeWidgetItem * item)
//设置树头条目,树头条目可以有多列数据,相当于多列的表头一次性设置了</div>
<div class="code">void QTreeWidget::​setHeaderLabel(const QString &amp;
label) //只设置第 0 列的表头</div>
<div class="code">void QTreeWidget::​setHeaderLabels(const QStringList &amp;
labels) //设置多列的表头</div>
<div class="code">QTreeWidgetItem * QTreeWidget::​headerItem() const
//获取树头条目</div>
树头条目本质其实也是由 QHeaderView 子控件来显示的,可以在基类找到相关函数:<br>
<div class="code">QHeaderView * QTreeView::​header() const //获取表头视图控件</div>
<div class="code">void QTreeView::​setHeader(QHeaderView * header) //设置表头视图,
一般树形控件不需要用这个函数</div>
<div class="code">void QTreeView::setHeaderHidden(bool hide) //设置表头是否隐藏</div>
<div class="code">bool QTreeView::isHeaderHidden() const //判断是否隐藏了表头</div>
无论是 QTableWidget 还是 QTreeWidget 的表头,都是 QHeaderView 子控件显示,QHeaderView
参考“8.2.3 表头设置”的内容。<br>
<br>
(11)选中行为和选中模式<br>
与 QTableWidget 类似,QTreeWidget也从祖类 QAbstractItemView 继承了选中行为和选中模式的属性:<br>
<div class="code">QAbstractItemView::SelectionBehavior&nbsp;
selectionBehavior() const //获取选中行为,按条目选中、整行或整列选中</div>
<div class="code">void
setSelectionBehavior(QAbstractItemView::SelectionBehavior behavior)
//设置选中行为</div>
<div class="code">QAbstractItemView::SelectionMode&nbsp; selectionMode()
const //获取选中模式,比如单选、多选、扩展选择</div>
<div class="code">void setSelectionMode(QAbstractItemView::SelectionMode
mode) //设置选中模式</div>
关于选中模式和选中行为的枚举常量参看“8.2.4 选中区域和选中行为”小节中的枚举常量表格,单次选中命令的函数和枚举常量也参考该小节。<br>
<br>
默认情况下,树形控件是按照整行选中,并且是单选模式,如果把选中模式改成多选的
QAbstractItemView::ExtendedSelection,那么树形控件也可以使多选的,这时候信号
itemSelectionChanged() 就能派上用场:<br>
<div class="code">void QTreeWidget::​itemSelectionChanged()</div>
多选状态变化时会触发该信号(单选模式也触发,只是不需要用这个信号),可以关联该信号,监视当前所有选中的条目:<br>
<div class="code">QList&lt;QTreeWidgetItem *&gt;
QTreeWidget::​selectedItems() const</div>
注意,这里的选中条目仅仅是指实际显示的直接选中的条目,不包括折叠隐藏的子孙条目计数,因为选中父节点与选中其子孙节点没关系,不会递归选中所有子孙:<br>
<center> <img src="images/ch08/ch08-03-05.png" alt="select"></center>
树形控件及其基类没有递归选中子条目的属性或函数,如果希望递归选中某个节点的所有子孙节点,那么需要自行编写递归函数。关于树形控件类本身的内容介绍到这,因为
涉及到父子节点隶属关系、节点展开和折叠,树形控件还有很大一部分功能都是由其条目类 QTreeWidgetItem 的函数实现的,下面来学习这个树形控件条
目类。<br>
<br>
<div class="os2">8.3.2 QTreeWidgetItem</div>
<br>
树形控件条目的内容是最复杂的,因为每一个条目涉及到内部多列数据的操作、父子节点操作,这些都是之前列表控件条目和表格控件条目不具备的特性。我们首先介绍树形
控件条目的构造函数,然后按父子节点操作、通用数据操作和非通用数据操作三方面介绍树形控件条目。<br>
(1)构造函数和复制函数<br>
QTreeWidgetItem 构造函数较多,首先看不带父对象指针的构造函数:<br>
<div class="code">QTreeWidgetItem(int type = Type)</div>
<div class="code">QTreeWidgetItem(const QStringList &amp; strings, int type
= Type)</div>
<div class="code">QTreeWidgetItem(const QTreeWidgetItem &amp; other)</div>
类型 type 一般用于派生类的自定义条目类型,基本用不到。第二个构造函数字符串列表 strings
就是条目内多列的文本,类似把表格控件一整行的多列文本塞到一个条目内部了。第三个是复制构造函数,复制时除了
type()、treeWidget()、parent(),其他的都复制。<br>
克隆函数:<br>
<div class="code">QTreeWidgetItem * QTreeWidgetItem::​clone() const</div>
&nbsp;​clone()是按照本条目一模一样造出一个新的条目,是深拷贝,与本条目(包括子孙节点)不共享内存,函数返回的新条目也没有复制
type()、treeWidget()、​parent() ,新条目是自由的,没归属。<span style="font-weight: bold;">
clone() 函数会克隆所有的子孙节点,并且新子孙节点之间的关系也一样</span>,QTreeWidgetItem&nbsp;源码中使用压栈出栈
方式实现了子孙节点的遍历复制。<br>
赋值=函数:<br>
<div class="code">QTreeWidgetItem &amp; operator=(const QTreeWidgetItem
&amp; other)</div>
&nbsp;等于号函数与克隆函数有本质区别,它只拷贝
other&nbsp;这一个节点内的数据到本节点里,包括显示的字符串和多列数据、标志位等,type() 和
treeWidget()、​parent()的内容不会修改。<span style="font-weight: bold;">等于号函数不涉及任何子孙节
点,也不改变隶属的父节点。</span><br>
顺便提一下小于号函数:<br>
<div class="code">virtual bool operator&lt;(const QTreeWidgetItem &amp;
other) const</div>
&nbsp;如果为树形控件指定了排序的列号sortColumn(),那么按该列的文本字典序比较大小,否则都按照第0列的文本比较。<br>
<br>
(2)父子节点操作<br>
条目查看父节点的指针使用函数:<br>
<div class="code">QTreeWidgetItem * QTreeWidgetItem::​parent() const&nbsp;
//常量,子节点不能改父节点指针</div>
注意子节点是不能修改父节点指针的,只能父节点换子节点,不能子节点换父节点。<br>
<br>
最常用的是节点控制自己的直接子节点,添加子节点使用函数:<br>
<div class="code">void addChild(QTreeWidgetItem * child) //添加一个子节点到末尾</div>
<div class="code">void addChildren(const QList&lt;QTreeWidgetItem *&gt;
&amp; children) //添加多个子节点末尾</div>
<div class="code">void insertChild(int index, QTreeWidgetItem * child)
//插入子节点序号&nbsp;index&nbsp;序号位置</div>
<div class="code">void insertChildren(int index, const
QList&lt;QTreeWidgetItem *&gt; &amp; children)//插入多个子节点到&nbsp;index 位置</div>
直接子节点的计数(与孙辈或更低辈分的节点数目无关)用如下函数:
<div class="code">int childCount() const</div>
<br>
根据序号获取直接子节点的指针使用函数(如果序号超界返回NULL):<br>
<div class="code">QTreeWidgetItem * child(int index) const&nbsp; //序号查子节点指针</div>
反过来,根据子节点指针查序号的函数如下(如果查不到序号返回-1):
<div class="code">int indexOfChild(QTreeWidgetItem * child) const</div>
移除子节点使用如下函数:
<div class="code">void removeChild(QTreeWidgetItem * child)&nbsp;
//根据子节点指针解除父子关系</div>
<div class="code">QTreeWidgetItem * takeChild(int index)&nbsp; //根据子节点序号解除父子
关系,返回卸下后的自由节点指针</div>
<div class="code">QList&lt;QTreeWidgetItem *&gt; takeChildren()&nbsp;
//卸下所有子节点</div>
注意这几个函数只是解除父子关系,卸下的子节点还存在内存中,如果要完全删除需要手动&nbsp;delete&nbsp; 每个节点。<br>
当节点有隶属的树形控件时,可以使用下面函数对子节点排序:<br>
<div class="code">void sortChildren(int column, Qt::SortOrder order)&nbsp;
// 根据指定列号column排序,升序或降序由order指定</div>
如果条目不属于任何树形控件,那么该排序函数无效。<br>
<br>
条目还可以控制自己的子节点指示器(条目显示时左边的加号 +)如何显示:<br>
<div class="code">QTreeWidgetItem::ChildIndicatorPolicy
childIndicatorPolicy() const //获取子节点指示器显示策略</div>
<div class="code">void
QTreeWidgetItem::​setChildIndicatorPolicy(QTreeWidgetItem::ChildIndicatorPolicy
policy) //设置子节点指示器显示策略</div>
子节点指示器显示策略 QTreeWidgetItem::ChildIndicatorPolicy 有三种:<br>
<br>
<table class="tabel">
<tbody>
<tr class="d1">
<td style="width: 337px;" align="center"><b>ChildIndicatorPolicy 枚举常量</b></td>
<td style="width: 88px;" align="center"><b>数值</b></td>
<td style="width: 397px;" align="center"><b> 描述</b></td>
</tr>
<tr>
<td>QTreeWidgetItem::ShowIndicator</td>
<td> 0 </td>
<td>无论有无子节点都显示指示符。 </td>
</tr>
<tr class="d1">
<td>QTreeWidgetItem::DontShowIndicator</td>
<td> 1 </td>
<td>始终不显示指示符。 </td>
</tr>
<tr>
<td>QTreeWidgetItem::DontShowIndicatorWhenChildless</td>
<td> 2</td>
<td> 条目有子节点就显示指示符,没子节点就不显示。 </td>
</tr>
</tbody>
</table>
<br>
默认值是最后一个,有子节点就显示指示符,没有子节点就不显示指示符,这种方式也最为科学,一般不需要改指示符显示策略。<br>
<br>
关于父子节点操作函数介绍到这,这些函数的特点就是只处理直接的子节点,与孙子辈、更低辈分节点无关,孙子辈由儿子辈去管理,以此类推,族谱树中各层节点只管理亲
儿 子,其他辈分都不管。 递归操作 就是这样,只管处理儿子辈代码,孙子辈的由儿子辈去管,层层下推,就是递归的过程。<br>
<br>
(3)通用数据操作<br>
通用数据一般是用于 QDataStream
保存条目的信息到文件中,也可以从文件中加载通用数据生成以前的树。树形控件条目的通用数据函数与前面章节列表条目、表格条目类似,但是多了指定列号的参数,因为每个属
性条目有多列数据,每列数据有分多种角色,因此属性条目使用二维向量存储通用数据:<br>
<div class="code"><span style=" color:#008000;">//</span><span style=" color:#c0c0c0;">
</span><span style=" color:#008000;">One</span><span style=" color:#c0c0c0;">
</span><span style=" color:#008000;">item</span><span style=" color:#c0c0c0;">
</span><span style=" color:#008000;">has</span><span style=" color:#c0c0c0;">
</span><span style=" color:#008000;">a</span><span style=" color:#c0c0c0;">
</span><span style=" color:#008000;">vector</span><span style=" color:#c0c0c0;">
</span><span style=" color:#008000;">of</span><span style=" color:#c0c0c0;">
</span><span style=" color:#008000;">column</span><span style=" color:#c0c0c0;">
</span><span style=" color:#008000;">entries.</span><span style=" color:#c0c0c0;">
</span><span style=" color:#008000;">Each</span><span style=" color:#c0c0c0;">
</span><span style=" color:#008000;">column</span><span style=" color:#c0c0c0;">
</span><span style=" color:#008000;">has</span><span style=" color:#c0c0c0;">
</span><span style=" color:#008000;">a</span><span style=" color:#c0c0c0;">
</span><span style=" color:#008000;">vector</span><span style=" color:#c0c0c0;">
</span><span style=" color:#008000;">of</span><span style=" color:#c0c0c0;">
</span><span style=" color:#008000;">(role,</span><span style=" color:#c0c0c0;">
</span><span style=" color:#008000;">value)</span><span style=" color:#c0c0c0;">
</span><span style=" color:#008000;">pairs.</span>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;"> </span><span style=" color:#800080;">QVector</span><span
style=" color:#000000;">&lt;</span><span style=" color:#c0c0c0;"> </span><span style=" color:#800080;">QVector</span><span
style=" color:#000000;">&lt;</span><span style=" color:#800080;">QWidgetItemData</span><span
style=" color:#000000;">&gt;</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">&gt;</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#800000;">values</span><span
style=" color:#000000;">;</span></pre>
</div>
对于通用数据的设置和读取,也有 data() 和 setData() 函数,只是多了列号:<br>
<div class="code">QVariant QTreeWidgetItem::​data(int column, int role)
const</div>
<div class="code">void QTreeWidgetItem::​setData(int column, int role, const
QVariant &amp; value)</div>
其他针对各个角色的读写函数如下表所示:<br>
<br>
<table class="tabel">
<tbody>
<tr class="d1">
<td style="width: 183.867px;" align="center"><b>获取函数</b></td>
<td style="width: 218.667px;" align="center"><b>设置函数</b></td>
<td style="width: 166.733px;" align="center"><b>数据角色</b></td>
<td style="width: 269.5px;" align="center"><b> 描述 </b></td>
</tr>
<tr>
<td>text(int column)</td>
<td> setText(int column, const QString &amp;text)</td>
<td> Qt::DisplayRole </td>
<td> 条目显示的文本。 </td>
</tr>
<tr class="d1">
<td>icon(int column)</td>
<td> setIcon(int column, const QIcon &amp;icon)</td>
<td> Qt::DecorationRole </td>
<td> 条目显示的图标。 </td>
</tr>
<tr>
<td>statusTip(int column)</td>
<td> setStatusTip(int column, const QString &amp;statusTip)</td>
<td> Qt::StatusTipRole </td>
<td> 如果主界面有状态栏,鼠标悬停在该条目上时显示该状态信息到状态栏。 </td>
</tr>
<tr class="d1">
<td>toolTip(int column)</td>
<td> setToolTip(int column, const QString &amp;toolTip) </td>
<td> Qt::ToolTipRole </td>
<td> 鼠标悬停在该条目上时显示的工具提示信息。 </td>
</tr>
<tr>
<td>whatsThis(int column)</td>
<td> setWhatsThis(int column, const QString &amp;whatsThis)</td>
<td> Qt::WhatsThisRole </td>
<td> 如果主界面窗口标题栏有?帮助按钮,点击帮助按钮再点击该条目会显示该帮助信息。 </td>
</tr>
<tr class="d1">
<td>font(int column)</td>
<td> setFont(int column, const QFont &amp;font)</td>
<td> Qt::FontRole </td>
<td> 显示条目文本用的字体。 </td>
</tr>
<tr>
<td>textAlignment(int column</td>
<td> setTextAlignment(int column, int alignment)</td>
<td> Qt::TextAlignmentRole </td>
<td> 文本的对齐方式。 </td>
</tr>
<tr class="d1">
<td>backgroundColor(int column)</td>
<td> setBackgroundColor(int column, const QColor &amp;color)</td>
<td> Qt::BackgroundColorRole </td>
<td> 文本背景色。 </td>
</tr>
<tr>
<td>textColor(int column)</td>
<td> setTextColor(int column, const QColor &amp;color)</td>
<td> Qt::TextColorRole </td>
<td> 文字颜色。 </td>
</tr>
<tr class="d1">
<td>background(int column)</td>
<td> setBackground(int column, const QBrush &amp;brush) </td>
<td> Qt::BackgroundRole </td>
<td> 条目的背景画刷。 </td>
</tr>
<tr>
<td>foreground(int column)</td>
<td> setForeground(int column, const QBrush &amp;brush) </td>
<td> Qt::ForegroundRole </td>
<td> 条目的前景画刷。 </td>
</tr>
<tr class="d1">
<td>checkState(int column)</td>
<td> setCheckState(int column, Qt::CheckState state)</td>
<td> Qt::CheckStateRole </td>
<td> 条目自带的复选框选中状态,可以是三态复选框。 </td>
</tr>
<tr>
<td>sizeHint(int column)</td>
<td> setSizeHint(int column, const QSize &amp;size) </td>
<td> Qt::SizeHintRole </td>
<td> 条目显示的建议尺寸。 </td>
</tr>
</tbody>
</table>
<br>
&nbsp;树形条目也有相应的数据流读写函数,就是用于读取或保存这些通用数据:<br>
<div class="code">QDataStream &amp;&nbsp;&nbsp;
&nbsp;operator&lt;&lt;(QDataStream &amp; out, const QTreeWidgetItem &amp;
item) //外部函数,将条目写入数据流</div>
<div class="code">QDataStream &amp;&nbsp;&nbsp;
&nbsp;operator&gt;&gt;(QDataStream &amp; in, QTreeWidgetItem &amp; item)
//外部函数,读取数据流中的条目数据</div>
<div class="code">void QTreeWidgetItem::​write(QDataStream &amp; out) const
//成员函数,将条目数据写入数据流</div>
<div class="code">void QTreeWidgetItem::​read(QDataStream &amp; in)
//成员函数,从数据流中读取条目数据</div>
&nbsp;运算符重载函数 operator&lt;&lt;() 和 operator&gt;&gt;() 本质就是调用上面的 ​write() 和
​read()&nbsp;函数。<br>
<br>
(4)非通用数据操作<br>
条目在构造函数指定的类型可以用如下函数获取,这个类型是只读的:<br>
<div class="code">int QTreeWidgetItem::​type() const</div>
在添加到树形控件之后,都可以用如下函数查看条目隶属的树形控件:<br>
<div class="code">QTreeWidget * QTreeWidgetItem::​treeWidget() const&nbsp;
//常量,节点不能自行更换隶属,要从树形控件增删节点</div>
<br>
&nbsp;程序运行时除了树形控件本身的
QTreeWidget::​selectedItems()&nbsp;可以判断选中条目,每个条目对象自己也有函数获取高亮选中状态或设置是否高亮选中:(默认情况
下,树形条目自身是否高亮选中与子孙条目的情况无关)<br>
<div class="code">bool QTreeWidgetItem::​isSelected() const</div>
<div class="code">void QTreeWidgetItem::​setSelected(bool select)</div>
<br>
树形条目初始化时也有默认的标志位,并且运行时可以修改标志位:<br>
<div class="code">Qt::ItemFlags QTreeWidgetItem::​flags() const</div>
<div class="code">void QTreeWidgetItem::​setFlags(Qt::ItemFlags flags)</div>
树形条目构造时的默认标志位如下:&nbsp; <br>
&nbsp;Qt::ItemIsSelectable<br>
&nbsp;&nbsp; |Qt::ItemIsUserCheckable<br>
&nbsp;&nbsp; |Qt::ItemIsEnabled<br>
&nbsp;&nbsp; |Qt::ItemIsDragEnabled<br>
&nbsp;&nbsp; |Qt::ItemIsDropEnabled<br>
树形条目默认不能编辑,如果希望条目文本可以双击编辑,可以用下面一句代码:<br>
<div class="code">&nbsp;&nbsp;&nbsp; item-&gt;setFlags( (item-&gt;flags()) |
Qt::ItemIsEditable ); //双击条目会自动 开启文本编辑器</div>
这个标志会对树形条目所有列的文本编辑都生效,开启后该条目每个列的数据都能双击编辑。对于开启
Qt::ItemIsEditable&nbsp;标志位的条目,除了用户双击等操作启用编辑器,也可以用函数代码指定开启条目的某列数据编辑器:<br>
<div class="code">void QTreeWidget::​editItem(QTreeWidgetItem * item, int
column = 0)</div>
<br>
树形条目默认有 Qt::ItemIsUserCheckable&nbsp;标志,可以复选,但是复选框默认却看不到,可以用下面代码真正地显示复选框:<br>
<div class="code">item-&gt;setCheckState(0, Qt::Unchecked);&nbsp;
//显示第0列的复选框,要指定列号</div>
<br>
树形条目的复选框状态很特殊,如果不使用三态复选(默认情况),那么当前条目的复选状态与子孙条目复选状态无关。<br>
如果开启树形条目的三态复选,那么当前条目的复选状态与子孙有关:<br>
&nbsp;&nbsp;&nbsp; 如果所有子孙勾选,那么父节点勾选 Qt::Checked;<br>
&nbsp;&nbsp;&nbsp; 如果部分子孙勾选,那么父节点部分勾选 Qt::PartiallyChecked;<br>
&nbsp;&nbsp;&nbsp; 如果所有子孙不勾选,那么父节点不勾选 Qt::Unchecked。<br>
三态勾选其实是真正反映父子勾选关系的,如果用复选框,那么有子孙的节点应该用三态的,无子孙的叶子节点用二态的,并且应当将所有树形控件的条目都显示复选框:<br>
<div class="code"><span style=" color:#c0c0c0;">&nbsp;&nbsp; </span><span style=" color:#008000;">//
迭代器</span>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;"> </span><span style=" color:#800080;">QTreeWidgetItemIterator</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">it</span><span style=" color:#000000;">(</span><span
style=" color:#800000;">ui</span><span style=" color:#000000;">-&gt;</span><span
style=" color:#800000;">treeWidget</span><span style=" color:#000000;">);</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;"> </span><span style=" color:#808000;">while</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">(*</span><span style=" color:#000000;">it</span><span
style=" color:#000000;">)</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">{</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;"> </span><span style=" color:#008000;">//取出当前条目</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;"> </span><span style=" color:#800080;">QTreeWidgetItem</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">*</span><span style=" color:#000000;">item</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">=</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">*</span><span style=" color:#000000;">it</span><span style=" color:#000000;">;</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;"> </span><span style=" color:#808000;">if</span><span
style=" color:#000000;">(</span><span style=" color:#000000;">item</span><span style=" color:#000000;">-&gt;</span><span
style=" color:#000000;">childCount</span><span style=" color:#000000;">()</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">&gt;</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000080;">0</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">)</span><span
style=" color:#008000;">//有子节点开启三态复选,没子节点是二态复选</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">{</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">item</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#000000;">setFlags</span><span
style=" color:#000000;">(</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">item</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#000000;">flags</span><span
style=" color:#000000;">()</span><span style=" color:#c0c0c0;"> </span><span style=" color:#000000;">|</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#800080;">Qt</span><span style=" color:#000000;">::</span><span
style=" color:#800080;">ItemIsTristate</span><span style=" color:#c0c0c0;"> </span><span
style=" color:#000000;">);</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">}</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">item</span><span
style=" color:#000000;">-&gt;</span><span style=" color:#000000;">setCheckState</span><span
style=" color:#000000;">(</span><span style=" color:#000080;">0</span><span style=" color:#000000;">,</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#800080;">Qt</span><span style=" color:#000000;">::</span><span
style=" color:#800080;">Unchecked</span><span style=" color:#000000;">);</span><span
style=" color:#c0c0c0;"> </span><span style=" color:#008000;">//正常应该只用第0列的复选框,代表一整行条目</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;"> </span><span style=" color:#008000;">//找下一个条目</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">++</span><span
style=" color:#000000;">it</span><span style=" color:#000000;">;</span></pre>
<pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span
style=" color:#c0c0c0;"> </span><span style=" color:#000000;">}</span></pre>
</div>
迭代器 QTreeWidgetItemIterator
专门用于遍历树形控件或某个父节点的所有子孙条目,因为树形结构是分叉结构,不同于列表控件的一维遍历,也不同于表格控件的二维遍历,因此需要迭代器或递归算法来穷举子孙
条目,下面小节专门介绍这些内容。<br>
<br>
<div class="os2">8.3.3 迭代器和递归遍历</div>
<br>
我们拿一棵经典的二叉树做例子:<br>
<center> <img src="images/ch08/ch08-03-06.png" alt="tree"></center>
在上面树图中,A是总树的根,总树有两棵子树,分别隶属B、C。没有子孙的是叶子节点:D、E、F、G。<br>
对于树的遍历,存在多种方式:<br>
①先序遍历( pre-order traversal ):根节点-&gt;左子树-&gt;右子树;对于每棵子树内的遍历顺序也一样类推。<br>
以上图为例,先序遍历为:A&nbsp; -&gt;B-&gt;D-&gt;E&nbsp; -&gt;&nbsp; C-&gt;F-&gt;G。<br>
对于多叉树,先序遍历规则就是:根节点-&gt;第一棵子树-&gt;第二棵子树-&gt;第三棵子树&nbsp;等等。<br>
<br>
②后序遍历( post-order traversal
):左子树-&gt;右子树-&gt;根节点;对于每棵子树内的遍历顺序也一样类推。后序遍历时父节点和根节点一定是在后面出现的,所以遍历时打头的是叶子。<br>
以上图为例,后序遍历为:D-&gt;E-&gt;B&nbsp; -&gt;&nbsp; F-&gt;G-&gt;C&nbsp; -&gt;A。<br>
对于多叉树,后序遍历规则就是:第一棵子树-&gt;第二棵子树-&gt;第三棵子树....-&gt;根节点。<br>
<br>
③中序遍历( in-order traversal
):左子树-&gt;根节点-&gt;右子树;对于每棵子树内的遍历顺序也一样类推。这种遍历仅对二叉树有意义,二叉树的父节点正好在左右子树中间,但多叉树没有中间的概
念。<br>
以上图为例,中序遍历为:D-&gt;B-&gt;E&nbsp; -&gt;A&nbsp; -&gt;F-&gt;C-&gt;G。<br>
<br>
④按层遍历( level-order traversal ):第0层-&gt;第1层-&gt;第2层 ……。这种很直观,比如上面的树就是
A-&gt;B-&gt;C-&gt;D-&gt;E-&gt;F-&gt;G 。<br>
<br>
通常遍历树的节点需要写较为复杂的递归代码或者用压栈出栈代码实现,这些代码都比较麻烦,因此 Qt 专门为树形控件提供了迭代器
QTreeWidgetItemIterator ,这个迭代器以先序遍历方式访问树形控件每个节点,大多数情况下就不需要我们自己去编写遍历算法了。我们可以将
QTreeWidgetItemIterator 想象成为一个保存节点指针的一维链表,链表每个元素指向树形控件一个节点,顺序是按照先序遍历。<br>
QTreeWidgetItemIterator&nbsp;构造函数如下:<br>
<div class="code">&nbsp;&nbsp;&nbsp; QTreeWidgetItemIterator(const
QTreeWidgetItemIterator &amp; it) </div>
<div class="code">&nbsp;&nbsp;&nbsp; QTreeWidgetItemIterator(QTreeWidget *
widget, IteratorFlags flags = All)</div>
<div class="code">&nbsp;&nbsp;&nbsp; QTreeWidgetItemIterator(QTreeWidgetItem
* item, IteratorFlags flags = All)</div>
第一个是复制构造函数,按照参数&nbsp;it&nbsp;指定的迭代器一样构造新的迭代器,构造时新迭代器的当前条目也与 it&nbsp;的当前条目一样。<br>
第二个构造函数是根据树形控件指针,获取该控件内所有节点,形成遍历的链表,参数
flags&nbsp;是迭代器标志位,可以筛选节点类型,等会列举迭代器标志位。<br>
第三个构造函数是以某个节点作为根,遍历以这个节点为根的子树。参数 flags&nbsp;是迭代器标志位,用于筛选节点类型,如下表所示:<br>
<br>
<table class="tabel">
<tbody>
<tr class="d1">
<td align="center"><b>IteratorFlags 枚举常量</b></td>
<td align="center"><b>数值</b></td>
<td align="center"><b> 描述</b></td>
</tr>
<tr>
<td>QTreeWidgetItemIterator::All</td>
<td> 0x00000000 </td>
<td>&nbsp;默认值,枚举所有节点。 </td>
</tr>
<tr class="d1">
<td>QTreeWidgetItemIterator::Hidden</td>
<td> 0x00000001 </td>
<td>&nbsp;枚举隐藏节点。 </td>
</tr>
<tr>
<td>QTreeWidgetItemIterator::NotHidden</td>
<td> 0x00000002 </td>
<td>&nbsp;枚举非隐藏节点。 </td>
</tr>
<tr class="d1">
<td>QTreeWidgetItemIterator::Selected</td>
<td> 0x00000004</td>
<td>&nbsp;枚举高亮选中节点。 </td>
</tr>
<tr>
<td>QTreeWidgetItemIterator::Unselected</td>
<td> 0x00000008 </td>
<td>&nbsp;枚举未选中节点。 </td>
</tr>
<tr class="d1">
<td>QTreeWidgetItemIterator::Selectable</td>
<td> 0x00000010 </td>
<td>&nbsp;枚举可以选中的节点。 </td>
</tr>
<tr>
<td>QTreeWidgetItemIterator::NotSelectable</td>
<td> 0x00000020 </td>
<td>&nbsp;枚举不可选中的节点。 </td>
</tr>
<tr class="d1">
<td>QTreeWidgetItemIterator::DragEnabled</td>
<td> 0x00000040 </td>
<td>&nbsp;枚举能够拽出的节点。 </td>
</tr>
<tr>
<td style="width: 273px;">QTreeWidgetItemIterator::DragDisabled</td>
<td style="width: 193px;"> 0x00000080 </td>
<td>&nbsp;枚举不能拽出去的节点。 </td>
</tr>
<tr class="d1">
<td>QTreeWidgetItemIterator::DropEnabled</td>
<td> 0x00000100</td>
<td>&nbsp;枚举可接收拖进来的节点。 </td>
</tr>
<tr>
<td style="width: 273px;">QTreeWidgetItemIterator::DropDisabled</td>
<td style="width: 193px;"> 0x00000200 </td>
<td>&nbsp;枚举不能接收拖进来的节点。 </td>
</tr>
<tr class="d1">
<td style="height: 16px;">QTreeWidgetItemIterator::HasChildren</td>
<td> 0x00000400</td>
<td>&nbsp;枚举所有父节点。 </td>
</tr>
<tr>
<td style="width: 273px;">QTreeWidgetItemIterator::NoChildren</td>
<td style="width: 193px;"> 0x00000800 </td>
<td>&nbsp;枚举所有叶子节点。 </td>
</tr>
<tr class="d1">
<td>QTreeWidgetItemIterator::Checked</td>
<td> 0x00001000</td>
<td>&nbsp;枚举复选框勾选的节点。 </td>
</tr>
<tr>
<td style="width: 273px;">QTreeWidgetItemIterator::NotChecked</td>
<td style="width: 193px;"> 0x00002000 </td>
<td>&nbsp;枚举复选框没有勾选的节点。 </td>
</tr>
<tr class="d1">
<td>QTreeWidgetItemIterator::Enabled</td>
<td> 0x00004000</td>
<td>&nbsp;枚举所有启用的节点。 </td>
</tr>
<tr>
<td style="width: 273px;">QTreeWidgetItemIterator::Disabled</td>
<td style="width: 193px;"> 0x00008000 </td>
<td>&nbsp;枚举所有禁用的节点。 </td>
</tr>
<tr class="d1">
<td>QTreeWidgetItemIterator::Editable</td>
<td> 0x00010000</td>
<td>&nbsp;枚举可以编辑的节点。 </td>
</tr>
<tr>
<td style="width: 273px;">QTreeWidgetItemIterator::NotEditable</td>
<td style="width: 193px;"> 0x00020000 </td>
<td>&nbsp;枚举不能编辑的节点。 </td>
</tr>
<tr class="d1">
<td>QTreeWidgetItemIterator::UserFlag</td>
<td> 0x01000000</td>
<td>&nbsp;枚举自定义的用户节点。 </td>
</tr>
</tbody>
</table>
<br>
这些枚举标志位大部分与节点条目自身的标志位 Qt::​ItemFlags
枚举常量相对应,比如是否可编辑,是否能选中,用于筛选指定标志位的节点;还有一部分标志位,如是否折叠隐藏,是否高亮选中,与用户实时的操作相关。<br>
<br>
QTreeWidgetItemIterator&nbsp;重载了多个运算符函数,方便程序员使用,比如&nbsp;Qt&nbsp;文档中的示例代码:<br>
<div class="code">&nbsp;&nbsp;&nbsp; QTreeWidgetItemIterator it(treeWidget);<br>
&nbsp;&nbsp;&nbsp; while (*it) {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ((*it)-&gt;text(0) ==
itemText)&nbsp; //查找匹配文本的条目<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
(*it)-&gt;setSelected(true);&nbsp; //文本找到了就高亮显示<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ++it;<br>
&nbsp;&nbsp;&nbsp; }</div>
&nbsp;这段代码根据树形控件
treeWidget&nbsp;构造了迭代器&nbsp;it,it内部有个游标,实时指向遍历的属性条目,在未遍历的时候,指向先序遍历第一个条目,运算符函数
operator*() 用于取出当前条目的指针,比如 *it&nbsp;就是遍历过程中的当前条目;<br>
迭代器支持 ++it&nbsp;和 it++,第一个前加加是在执行语句前移到下一条目,第二个后加加是执行语句之后移到下一个条目;<br>
还有 --it&nbsp;&nbsp;it-- ,是逆向遍历,与加加的遍历顺序是反的;<br>
迭代器也支持跳跃式遍历,如即 it += 5,&nbsp;it-=5 ,这是跳到后面第 5 个或跳到前面第 5 个。<br>
QTreeWidgetItemIterator 类似链表,与数组不同,它没有 []
运算符函数,不能按照序号取节点指针,在穷举完所有节点之前也是不知道总数目多少。遍历过程中,*it
数值为&nbsp;NULL&nbsp;时,就是穷举完了,后面已经没有节点了。可以用&nbsp;while&nbsp;循环单独对节点数目计数,或者指定
IteratorFlags&nbsp;去穷举父节点多少个,叶子节点多少个等。关于迭代器的内容介绍到这,我们在下面小节专门用例子来解释递归算法。<br>
<br>
<div class="os2">8.3.4 示例1</div>
<br>
使用设计师编辑树形条目。递归算法代码讲解。<br>
<br>
<div class="os2">8.3.5 示例2</div>
<br>
使用代码生成条目。*.tree 文件打开和保存。 <br>
<br>
<br>
<br>
<br>
<table style="text-align: left; width: 100%;" border="0" cellpadding="2" cellspacing="2">
<tbody>
<tr>
<td style="width: 40%;">
<div style="text-align: center;"><a href="ch08-02.htm"><img class="pic"
style="width: 32px; height: 32px;" alt="prev" src="images/pics/prev.png"></a></div>
</td>
<td style="width: 20%;">
<div style="text-align: center;"><a href="contents.htm"><img class="pic"
style="width: 32px; height: 32px;" alt="contents" src="images/pics/contents.png"></a></div>
</td>
<td style="width: 40%;">
<div style="text-align: center;"><a href="ch08-04.htm"><img class="pic"
style="width: 32px; height: 32px;" alt="next" src="images/pics/next.png"></a></div>
</td>
</tr>
</tbody>
</table>
</body>
</html>
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
HTML
1
https://gitee.com/oostudy_admin/qtguide.git
git@gitee.com:oostudy_admin/qtguide.git
oostudy_admin
qtguide
qtguide
master

搜索帮助