13.4 wxList和wxNode

wxList类是一个双向链表,可以用来存储任何类型的数据.wxWidgets需要你显式的定义一个针对某种数据类型的新的类来使用它,以便对存储于其中的数据提供足够的类型检查.wxList类还允许你指定一个索引类型以便进行基本的查找操作(如果你想使用基于结构的快速随机访问,请参考下一节的 wxHashMap类).

wxList使用了一个虚类wxNode.当你定义一个新的wxList派生类的时候,你同时定义了一个派生自wxNodeBase的类,以便对节点提供类型安全检查.节点类最重要的函数包括:GetNext,GetPrevious和GetData.它们的功能显而易见,分别为:获取下一个子项,获取前一个子项以及获取子项的数据.

唯一值得说明的是wxList的删除操作,默认情况下,从链表中移除一个节点并不会导致节点内部数据的释放.你需要调用 DeleteContents函数来改变这种默认的行为,设置数据随着节点一起释放.如果你想清除整个链表并且释放其中的数据,你应该先调用 DeleteContents,参数为True,然后再调用Clear函数.

我们用不着在这里把手册的内容重新粘贴一遍.我们将举一个简单的例子来演示怎样创建你自己的链表类型.注意WX_DECLARE_LIST宏通常应该位于头文件中,而WX_DEFINE_LIST宏通常应该位于源文件中.

// 我们将存储于链表的数据类型
class Customer
{
public:
    int CustID;
    wxString CustName;
};
// 通常应该位于头文件中
WX_DECLARE_LIST(Customer, CustomerList);
// 下面的定义应该位于源文件中,并且通常位于所有Customer声明之后
#include <wx/listimpl.cpp>
WX_DEFINE_LIST(CustomerList);
// 用于排序的比较函数
int listcompare(const Customer** arg1, const Customer** arg2)
{
    return ((*arg1)->CustID < (*arg2)->CustID);
}
// 链表操作举例
void ListTest()
{
    // 定义一个我们自定义链表的实例
    CustomerList* MyList = new CustomerList();
    bool IsEmpty = MyList->IsEmpty(); // will be true
    // 创建一些自定义对象实例
    Customer* CustA = new Customer;
    CustA->CustID = 10;
    CustA->CustName = wxT("Bob");
    Customer* CustB = new Customer;
    CustB->CustID = 20;
    CustB->CustName = wxT("Sally");
    Customer* CustC = new Customer;
    CustC->CustID = 5;
    CustC->CustName = wxT("Dmitri");
    // 将其增加到链表中
    MyList->Append(CustA);
    MyList->Append(CustB);
    // 实现随机插入
    MyList->Insert((size_t)0, CustC);
    int Count = MyList->GetCount(); // will be 3
    // 如果找不到,返回wxNOT_FOUND
    int index = MyList->IndexOf(CustB); // will be 2
    // 自定义的节点里包含了我们自定义的类型
    CustomerList::Node* node = MyList->GetFirst();
    // 节点遍历
    while (node)
    {
        Customer* Cust = node->GetData();
        // 进行一些处理
        node = node->GetNext();
    }
    // 返回特定位置的节点
    node = MyList->Item(0);
    // 按照排序函数排序
    MyList->Sort(listcompare);
    // 移除包含某个对象的节点
    MyList->DeleteObject(CustA);
    // 我们需要自己释放这个对象
    delete CustA;
    // 找到包含某个对象的节点
    node = MyList->Find(CustB);
    // 指示内部数据随节点的删除而删除
    MyList->DeleteContents(true);
    // 删除B的节点的时候,B也被释放了
    MyList->DeleteNode(node);
    // 现在调用Clear,所有的节点和其中数据都将被释放
    MyList->Clear();
    delete MyList;
}