The listbox model is a new feature which will be introduced into Nana 1.4. The listbox model is to use an existing STL container and adopt the container as the storage for a listbox category.
//Definition of a person
struct person
{
std::string name;
unsigned age;
bool gender;
};
//A container stores persons
std::vector<person> persons;
//Insert 3 persons.
persons.push_back(person{"Steve", 20, true});
persons.push_back(person{"Nolan", 25, true});
persons.push_back(person{"Susan", 21, false});
//A listbox to list persons
nana::listbox lsbox(form, nana::rectangle{10, 10, 300, 200});
lsbox.append_header("name");
lsbox.append_header("age");
lsbox.append_header("gender");
//We have a container and a listbox.
//Now we need to defines two function to make the listbox 'recognize'
//the struct person.
auto value_translator = [](const std::vector<nana::listbox::cell>& cells)
{
person p;
p.name = cells[0].text;
p.age = std::stoul(cells[1].text);
p.gender = (cells[2].text == "male");
return p;
};
auto cell_translator = [](const person& p)
{
std::vector<nana::listbox::cell> cells;
cells.emplace_back(p.name);
cells.emplace_back(std::to_string(p.age));
cells.emplace_back(p.gender ? "male" : "female");
return cells;
};
//Everything is ready but last step
lsbox.at(0).model<std::recursive_mutex>(persons, value_translator, cell_translator);
The listbox displays container elements.
listbox defines 2 different model types.
1, Standalone model owns an internal container. It copys or moves from the actual argument container. The above example illustrates a standalone model, it copys the 'persons'.
lsbox.at(0).model<std::recursive_mutex>(std::move(persons), value_translator, cell_translator);
2, Shared model refers to the actual argument container. The following example illustrates the shared model.
lsbox.at(0).shared_model<std::recursive_mutex>(persons, value_translator, cell_translator);
lsbox.events().dbl_click([&]
{
lsb.at(0).append({ "Who", "10000", "male" });
auto size = persons.size(); //'persons' increases after double-click
});
Restriction of shared model Don't emplace/insert/emplace_back/erase/remove the referred container. The behavior is unspecified otherwise. For example
lsbox.at(0).shared_model<std::recursive_mutex>(persons, value_translator, cell_translator);
lsbox.events().dbl_click([&]
{
lsb.at(0).append({ "Who", "10000", "male" }); //It's OK
persons.push_back(person{"David", 24, true}); //adding new elements/removing elements to shared model referred container is behavior unspecified!
});
A model_guard is used for accessing the container of listbox model. model_guard is a RAII class that locks for atomically accessing model container.
lsbox.at(0).shared_model<std::recursive_mutex>(persons, value_translator, cell_translator);
lsbox.events().dbl_click([&]
{
//model_guard(object mdg) will lock the scope to
//atomically access model container.
auto mdg = lsbox.at(0).model();
auto & cont = mdg.container<std::vector<person>>();
//Loop through 'persons'
for(auto & ps : cont)
{
//ps.age;
}
//vs
for(auto & im : lsbox.at(0))
{
//auto age = std::stoi(im.text(1));
}
});
Anonymous