# 12.1 wxTreeCtrl
树状控件以层的形式展示信息,它的子项可以展开也可以合并.下图演示了wxWidgets的树状控件例子,它正以不同的字体和风格以及颜色进行展示.每一个树状控件的子项都代表一个wxtreeItemId对象,它拥有一个文本标签和一个可选图标,并且文本和图标的内容都可以动态修改.树状控件可以以单选或者多选的形式创建.如果你希望在wxtreeItemId上绑定一些数据,你需要实现自己的wxTreeItemData派生类,然后调用 wxTreeCtrl::SetItemData函数以及wxTreeCtrl::GetItemData函数.这个数据在子项被释放的时候将会被一并释放(delete调用),如果你将其指向你实际的数据,需要注意避免重复释放.
![](img/mht8FFD%281%29.tmp)
因为应用程序可以检测到树状控件的子项被单击的事件,你可以用这个特点通过更改子项的图片来达到模拟其他的控件的目的.比如说,你可以很容易用树状控件的子项来模拟一个复选框.
下面的代码演示了怎样创建一个树状控件,定义其子项的绑定数据以及图片:
```
#include "wx/treectrl.h"
// 声明一个代表和子项绑定的数据的类
class MyTreeItemData : public wxTreeItemData
{
public:
MyTreeItemData(const wxString& desc) : m_desc(desc) { }
const wxString& GetDesc() const { return m_desc; }
private:
wxString m_desc;
};
// 子项相关的图片
#include "file.xpm"
#include "folder.xpm"
// 创建一个树状控件
wxTreeCtrl* treeCtrl = new wxTreeCtrl(
this, wxID_ANY, wxPoint(0, 0), wxSize(400, 400),
wxTR_HAS_BUTTONS|wxTR_SINGLE);
wxImageList* imageList = new wxImageList(16, 16);
imageList->Add(wxIcon(folder_xpm);
imageList->Add(wxIcon(file_xpm);
treeCtrl->AssignImageList(imageList);
// 根节点使用文件夹图标,而两个字节点使用文件图标
wxTreeItemId rootId = treeCtrl->AddRoot(wxT("Root"), 0, 0,
new MyTreeItemData(wxT("Root item")));
wxTreeItemId itemId1 = treeCtrl->AppendItem(rootId,
wxT("File 1"), 1, 1,
new MyTreeItemData(wxT("File item 1")));
wxTreeItemId itemId2 = treeCtrl->AppendItem(rootId,
wxT("File 2"), 1, 1,
new MyTreeItemData(wxT("File item 2")));
```
wxTreeCtrl的窗口类型
wxTreeCtrl有如下表所示的额外的窗口类型:
| wxtr_DEFAULT_STYLE | 这个值是各个平台上树状控件实现和默认值最接近的值 |
|:--- |:--- |
| wxtr_EDIT_LABELS | 是否子项文本可编辑 |
| wxtr_NO_BUTTONS | 不必显示用于展开或者合并子项的按钮 |
| wxtr_HAS_BUTTONS | 显示用于展开或者合并子项的按钮 |
| wxTR_NO_LINES | 不必显示用于表示层级关系的垂直虚线 |
| wxtr_FULL_ROW_HIGHLIGHT | 当选中某个子项的时候高亮显示整行(在windows平台上,除非设置了wxtr_NO_LINES,否则这个类型将被忽略) |
| wxtr_LINES_AT_ROOT | 不必显示根节点之间的连线.这个类型只有在设置wxtr_HIDE_ROOT 并且没有设置wxtr_NO_LINES 的时候有效 |
| wxtr_HIDE_ROOT | 不显示根节点,这将导致第一层的字节点成为一系列根节点 |
| wxtr_ROW_LINES | 使用这个类型在已显示的行之间绘制一个高对比的边界 |
| wxTR_HAS_VARIABLE_ROW_HEIGHT | 设置这个类型允许各行采用不同的高度,否则各行都将采用和最大的行高同样的高度.这个类仅适用于树状控件的标准实现(而非各个平台的原生实现) |
| wxtr_SINGLE | 单选模式 |
| wxtr_MULTIPLE | 多选模式 |
| wxtr_EXTENDED | 允许多选非连续的子项(该功能仅是部分实现) |
wxTreeCtrl的事件
树状控件产生wxtreeEvent类型的事件,这种事件可以在父子关系的窗口之间传递.
| EVT_TREE_BEGIN_DRAG(id, func)EVT_TREE_BEGIN_RDRAG(id, func) | 在用户开始拖放操作的时候产生,这个事件的使用细节请参考第11章,"剪贴板和拖放操作" |
|:--- |:--- |
| EVT_TREE_BEGIN_LABEL_EDIT(id, func) EVT_TREE_END_LABEL_EDIT(id, func) | 当用户开始编辑或者刚刚完成编辑子项标签的时候产生 |
| EVT_TREE_DELETE_ITEM(id, func) | 当某个子项被删除的时候产生 |
| EVT_TREE_GET_INFO(id, func) | 当某个子项的数据被请求的时候产生 |
| EVT_TREE_SET_INFO(id, func) | 当某个子项的数据被设置的时候产生 |
| EVT_TREE_ITEM_ACTIVATED(id, func) | 当某个子项被激活(双击或者使用键盘选择)的时候产生 |
| EVT_TREE_ITEM_COLLAPSED(id, func) | 给定的子项已被收缩(合并)的时候产生 |
| EVT_trEE_ITEM_COLLAPSING(id, func) | 给定的子项即将收缩(合并)的时候产生,这个事件可以被Veto以阻止收缩. |
| EVT_TREE_ITEM_EXPANDED(id, func) | 给定子项已被展开的时候产生 |
| EVT_TREE_ITEM_EXPANDING(id, func) | 给定子项即将展开的时候产生,这个事件可以被Veto以阻止展开 |
| EVT_TREE_SEL_CHANGED(id, func) | 选中的子项发生变化以后(新的子项被选中或者旧的选中项不被选中的时候)产生 |
| EVT_TREE_SEL_CHANGING(id, func) | 选中的子项即将发生变化的时候产生,该事件可以被Veto以阻止变化产生 |
| EVT_TREE_KEY_DOWN(id, func) | 检测针对该树状控件的键盘事件 |
| EVT_TREE_ITEM_GET_TOOLTIP(id, func) | 这个事件仅支持windows平台,它使得你可以给某个子项设置单独的工具提示 |
wxTreeCtrl的成员函数
下面列出了wxTreeCtrl控件的一些重要的成员函数.
使用AddRoot函数增加第一个子项,然后使用AppendItem, InsertItem或PrependItem来增加随后的子项.使用Delete移除一个子项,使用DeleteAllItems删除某个子项所有的子项,或者使用DeleteChildren删除某个子项的所有直接子项.
使用SetItemText设置某个子项的标签,使用SetItemTextColour,SetItemBackgroundColour,SetItemBold和SetItemFont来设置标签的外观.
如果你想给某个子项指定一幅图片,首先需要使用SetImageList函数将某个图片列表和这个树状控件绑定.每个子项可以指定四个状态的图片,分别是wxTReeItemIcon_Normal,wxTReeItemIcon_Selected, wxtreeItemIcon_Expanded和wxTReeItemIcon_SelectedExpanded,你可以使用 SetItemImage函数给每个状态指定一个图片列表中图片索引.如果你只给wxTReeItemIcon_Normal状态指定了一个索引,那么别的状态也将都使用这个图片.
使用Scroll函数以便将某个子项移动到可见区域,使用EnsureVisible使得这个子项在需要的时候展开以便其可以位于可见区域.使用Expand函数展开某个子项,Collapse和CollapseAndReset函数合并某个子项,后者还将移除其所有的子项,如果你正在使用的树状控件有很多子项,你可能希望只增加可见部分的子项以便提高性能.在这种情况下,你可以处理EVT_TREE_ITEM_EXPANDING事件,在需要的时候才增加子项,在收缩的时候则移除所有子项.而且你还需要调用SetItemHasChildren函数以便没有子项的子项也可以显示一个可扩展按钮,即使它真的没有.
使用SelectItem选择或者去选择某个子项.如果是单选类型,你可以使用GetSelection函数得到正被选中的子项,如果当前没有子项被选中,则返回一个未初始化的wxTReeItemId,你可以调用wxTreeItemId::IsOk函数来判断其有效性.而对于多选类型,你可以使用GetSelections函数获取当前选中的子项,你需要传递一个wxArrayTreeItemItemIds类型的引用作为参数. Unselect函数在单选情况下去选中当前的子项,而UnselectAll函数则用在多选情况下去选中所有正被选中的子项,UnselectItem 函数可以用来在多选情况下去选中某一个子项.
遍历某个树状控件的所有子项也有多种方法:你可以先使用GetRootItem函数获得根节点,然后使用GetFirstChild和 GetNextChild遍历所有子项.使用GetNextSibling和GetPrevSibling获取某个子项后一个和前一个兄弟节点.使用 ItemHasChildren函数判断某个子项是否有字节点,使用GetParent函数获取某个子项的父节点.GetCount函数则用来返回树状控件中所有子项的个数,而GetChildrenCount则返回某个子项的字节点的数目.
HitTest函数在实现你自己拖放的时候是很有用的,它使得你可以通过鼠标位置找到这个位置对应的子项以及子项的某个特定部分.具体返回值请参考相关手册中的内容.使用GetBoundingRect函数可以得到某个子项对应的矩形区域.
更多关于树状控件的信息请参考使用手册以及samples/treectrl中的wxTreeCtrl例子.
- 第一章 介绍
- 1.1 为什么要使用wxWidgets?
- 1.2 wxWidgets的历史
- 1.3 wxWidgets社区
- 1.4 wxWidgets和面向对象编程
- 1.5 wxWidgets的体系结构
- 1.6 许可协议
- 第一章小结
- 第二章 开始使用
- 2.1 一个小例子
- 2.2 应用程序类
- 2.3 Frame窗口类
- 2.4 事件处理函数
- 2.5 Frame窗口的构造函数
- 2.6 完整的例子
- 2.7 wxWidgets程序一般执行过程
- 2.8 编译和运行程序
- 第二章小结
- 第三章 事件处理
- 3.1 事件驱动编程
- 3.2 事件表和事件处理过程
- 3.3 过滤某个事件
- 3.4 挂载事件表
- 3.5 动态事件处理方法
- 3.6 窗口标识符
- 3.7 自定义事件
- 第三章小结
- 第四章 窗口的基础知识
- 4.1 窗口解析
- 4.2 窗口类概览
- 4.3 基础窗口类
- 4.4 顶层窗口
- 4.5 容器窗口
- 4.6 非静态控件
- 4.7 静态控件
- 4.8 菜单
- 4.9 控制条
- 第四章小结
- 第五章绘画和打印
- 5.1 理解设备上下文
- 5.2 绘画工具
- 5.3 设备上下文中的绘画函数
- 5.4 使用打印框架
- 5.5 使用wxGLCanvas绘制三维图形
- 第五章小节
- 第六章处理用户输入
- 6.1 鼠标输入
- 6.2 处理键盘事件
- 6.3 处理游戏手柄事件
- 第六章小结
- 第七章使用布局控件进行窗口布局
- 7.1 窗口布局基础
- 7.2 窗口布局控件
- 7.3 使用布局控件进行编程
- 7.4 更多关于布局的话题
- 第七章小结
- 第八章使用标准对话框
- 8.1信息对话框
- 8.2 文件和目录对话框
- 8.3 选择和选项对话框
- 8.4 输入对话框
- 8.5 打印对话框
- 第八章小结
- 第九章创建定制的对话框
- 9.1 创建定制对话框的步骤
- 9.2 一个例子:PersonalRecordDialog
- 9.3 在小型设备上调整你的对话框
- 9.4 一些更深入的话题
- 9.5 使用wxWidgets资源文件
- 第九章小结
- 第十章使用图像编程
- 10.1 wxWidgets中图片相关的类
- 10.2 使用wxBitmap编程
- 10.3 使用wxIcon编程
- 10.4 使用wxCursor编程
- 10.5 使用wxImage编程
- 10.6 图片列表和图标集
- 10.7 自定义wxWidgets提供的小图片
- 第十章小结
- 第十一章剪贴板和拖放操作
- 11.1 数据对象
- 11.2 使用剪贴板
- 11.3 实现拖放操作
- 第十一章小结
- 第十二章高级窗口控件
- 12.1 wxTreeCtrl
- 12.2 wxListCtrl
- 12.3 wxWizard
- 12.4 wxHtmlWindow
- 12.5 wxGrid
- 12.6 wxTaskBarIcon
- 12.7 编写自定义的控件
- 第十二章小结
- 第十三章数据结构类
- 13.1 为什么没有使用STL?
- 13.2 字符串类型
- 13.3 wxArray
- 13.4 wxList和wxNode
- 13.5 wxHashMap
- 13.6 存储和使用日期和时间
- 13.7 其它常用的数据类型
- 第十三章小结
- 第十四章文件和流操作
- 14.1 文件类和函数
- 14.2 流操作相关类
- 第十四章小结
- 第十五章内存管理,调试和错误处理
- 15.1 内存管理基础
- 15.2 检测内存泄漏和其它错误
- 15.3 构建自防御的程序
- 15.4 错误报告
- 15.5 提供运行期类型信息
- 15.6 使用wxModule
- 15.7 加载动态链接库
- 15.8 异常处理
- 15.9 调试提示
- 第十五章小结
- 第十六章编写国际化程序
- 16.1 国际化介绍
- 16.2 从翻译说起
- 16.3 字符编码和Unicode
- 16.4 数字和日期
- 16.5 其它媒介
- 16.6 一个小例子
- 第十六章小结
- 第十七章编写多线程程序
- 17.1 什么时候使用多线程,什么时候不要使用
- 17.2 使用wxThread
- 17.3 用于线程同步的对象
- 17.4 多线程的替代方案
- 第十七章小结
- 第十八章使用wxSocket编程
- 18.1 Socket类和功能概览
- 18.2 Socket及其基本处理介绍
- 18.3 Socket标记
- 18.4 使用Socket流
- 18.5 替代wxSocket
- 第十八章小结
- 第十九章使用文档/视图框架
- 19.1 文档/视图基础
- 19.2 文档/视图框架的其它能力
- 19.3 实现Undo/Redo的策略
- 第十九章小结
- 第二十章完善你的应用程序
- 20.1 单个实例和多个实例
- 20.2 更改事件处理机制
- 20.3 降低闪烁
- 20.4 实现联机帮助
- 20.5 解析命令行参数
- 20.6 存储应用程序资源
- 20.7 调用别的应用程序
- 20.8 管理应用程序设置
- 20.9 应用程序安装
- 20.10 遵循用户界面设计规范
- 20.11 全书小结