I’m trying to implement a menu structure for a little program I’m going to code.
There’s MenuItem which contains a Label, an associated function, a link to its parent and a vector that contains references to its children. Then there is Menu which is mainly responsible to select a new MenuItem and keeps track of which Item is currently active. Unfortunately when I use MenuItem in Menu and change the current MenuItem to one of its children I cant go further cause the following list of children is empty. Seems like the vector doesn’t get copied right. I tried to implement a copy constructor but that didn’t help. Here is my source as follows.
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
typedef void (*fptr)(int);
using namespace std;
void test(int i)
{
cout << "test function called with argument: " << i << endl;
}
class MenuItem
{
private:
vector<MenuItem*> children;
string label;
fptr f;
MenuItem* parent;
public:
MenuItem(string newLabel, fptr newFunction = NULL):label(newLabel),f(newFunction)
{
}
void addChild(MenuItem& mi)
{
mi.parent = this;
children.push_back(&mi);
}
MenuItem* getChild(int i)
{
return children[i];
}
MenuItem* getParent()
{
return parent;
}
string getLabel()
{
return label;
}
int countChildren()
{
return children.size();
}
void list()
{
vector<MenuItem*>::iterator i;
for(i = children.begin(); i < children.end(); ++i)
{
MenuItem* m = *i;
label = m->label;
stringstream s;
s << (i - children.begin());
cout << s.str() << ": " << label << endl;
}
}
void invoke(int i)
{
f(i);
}
};
class Menu
{
private:
MenuItem* current;
public:
Menu(MenuItem* m)
{
current = m;
open(0);
}
void open(int i)
{
current = current->getChild(i);
if(current->countChildren() > 0)
{
cout << "[" << current->getLabel() << "]" << endl;
current->list();
}
else
current->invoke(i);
}
void back(int i)
{
current = current->getParent();
}
};
int main() {
MenuItem m1("Root");
MenuItem m2("List Media");
MenuItem m6("List Movies",&test);
MenuItem m7("List Music",&test);
MenuItem m8("List Games",&test);
MenuItem m9("List Books",&test);
MenuItem m3("Find Media");
MenuItem m10("Find Movies",&test);
MenuItem m14("Find by title",&test);
MenuItem m15("Find by genre",&test);
MenuItem m11("Find Music",&test);
MenuItem m16("Find by title",&test);
MenuItem m17("Find by genre",&test);
MenuItem m12("Find Games",&test);
MenuItem m18("Find by title",&test);
MenuItem m19("Find by genre",&test);
MenuItem m13("Find Books",&test);
MenuItem m20("Find by title",&test);
MenuItem m21("Find by genre",&test);
MenuItem m4("Add Media");
MenuItem m22("Add Movie",&test);
MenuItem m23("Add Music",&test);
MenuItem m24("Add Game",&test);
MenuItem m25("Add Book",&test);
MenuItem m5("Delete Media");
MenuItem m26("Add Movie",&test);
MenuItem m27("Add Music",&test);
MenuItem m28("Add Game",&test);
MenuItem m29("Add Book",&test);
m1.addChild(m2);
m2.addChild(m6);
m2.addChild(m7);
m2.addChild(m8);
m2.addChild(m9);
m1.addChild(m3);
m3.addChild(m10);
m10.addChild(m14);
m10.addChild(m15);
m3.addChild(m11);
m11.addChild(m16);
m11.addChild(m17);
m3.addChild(m12);
m12.addChild(m18);
m12.addChild(m19);
m3.addChild(m13);
m13.addChild(m20);
m13.addChild(m21);
m1.addChild(m4);
m4.addChild(m22);
m4.addChild(m23);
m4.addChild(m24);
m4.addChild(m25);
m1.addChild(m5);
m5.addChild(m26);
m5.addChild(m27);
m5.addChild(m28);
m5.addChild(m29);
Menu m(&m1);
int option;
while(1){
cout << "Media Library> ";
cin >> option;
m.open(option);
}
}
The issue with this seems to be the
open(0);in the constructor of Menu. This of course causes you to descend automatically into the “List Media” section, which has no further subsections.This should probably be replaced with
current->list();