表示可以有子菜单的菜单的数据结构

时间:2012-10-23 18:49:43

标签: c++

例如,我可以有类似的东西,

A
B
 ba
 bb
C
 Ca
D

现在我有一个2D数组,但这不是很一般,因为如果我想将最大子级从2扩展到3,我需要另一个维度。任何建议?

5 个答案:

答案 0 :(得分:6)

复合模式在这里是一个合适的应用程序:

Composite Pattern

(来自维基百科:) http://en.wikipedia.org/wiki/Composite_pattern

在你的情况下:

  • 创建一个名为“Menu”的基类(这对应于上图中的 Component 部分)
  • 创建一个名为“MenuItem”的派生类(这对应于上图中的 Leaf 部分)
  • 创建一个名为“SubMenu”的派生类(这对应于上图中的 Composite 部分)SubMenu可以包含更多Menu--可以是更多MenuItem或SubMenu。

通过对每个SubMenu对象实施一个计数器,您可以根据插入顺序将菜单元素的所需顺序排列到复合“SubMenu”中:每次调用aSubMenu.add(newMenuItemOrSubMenu)时,aSubMenu都应增加自己的使用订购号计数并标记新项目。 (实现的具体细节取决于您,您根本不必使用单独的计数器,只需使用列表或数组)

答案 1 :(得分:2)

也许这就是:

class MenuNode
{
public:
    MenuNode(std::string new_label);
    void Add(MenuNode * new_node);
private:
    std::string label;
    std::vector<MenuNode *> children; // changed to vector to preserve order
};

用法:

MenuNode menu("root"),
         file("File"),
         edit("Edit"),
         open("Open..."),
         close("Close"),
         save("Save..."),
         prefs("Preferences"),
         yes_foo("Activate Foo"),
         no_foo("Deactivate Foo");

menu.Add(&file);
menu.Add(&edit);

file.Add(&open);
file.Add(&close);
file.Add(&save);

edit.Add(&prefs);

prefs.Add(&yes_foo);
prefs.Add(&no_foo);

代表:

Main Menu
  File
    Open...
    Close
    Save...
  Edit
    Preferences
      Activate Foo
      Deactivate Foo

请注意这个例子的明显缺陷,即依赖于(可能)临时变量的地址。您将无法在函数中创建它并将其返回。

实现的部分缺失也是如此,例如,无法遍历示例代码中节点的私有状态。

答案 2 :(得分:2)

sampson-chen提到的复合设计模式是我为小型开发人员监视器实现的正确方法,让您从菜单结构中选择一些测试方法。

我有一个基类“菜单项”,我从中导出子菜单和叶子(菜单项)。叶子只执行某些操作,而子菜单则打开另一个菜单级别。

例如,基类可能与此类似(当您想使用shared_pointers时):

 /*************************************************************//*!
 * @brief The base class for all menu entry types (sub menus and sub menu entries/items)
 ******************************************************************/
class MenuEntry : public boost::enable_shared_from_this<MenuEntry>
{

  public:
    virtual ~MenuEntry(){}

/**************************************************************//*!
 * @brief Default implementation to add menu entries; has to be re implemented
 * @param[in] newSubMenuEntry - the new menu entry (another sub menu or leaf)
 **************************************************************/
virtual void add(boost::shared_ptr<MenuEntry> newSubMenuEntry)=0;

/*****************************************************************//*!
 * @brief Default implementation for call to menu entries; always returns false
 * @return false - the function has not been re implemented
 ****************************************************************/
virtual bool call(void)
{
  // the member function has not been re-implemented
  return false;
}

/*****************************************************************************//*!
 * @brief Default implementation, has to be reimplemented
 * @return emptyVector - an empty vector
 *********************************************************************************/
virtual std::vector<boost::shared_ptr<MenuEntry> > getChildren(void)
{
  std::vector<boost::shared_ptr<MenuEntry> > emptyVector;
  return emptyVector;
}


/*******************************************************************************//*!
 * @brief Gives a pointer to the parent of the actual menu entry
 * @return m_parent - pointer to the parent
 ******************************************************************************/
boost::shared_ptr<MenuEntry> parent(void)
{
  return m_parent;
}

/***************************************************************************//*!
 * @brief Default implementation for selecting a menu entry
 * @param[in] desiredMenuEntry - the desired menu entry which shall be selected
 * @return notExisting - a pointer to <b>this</b>
 **********************************************************************************/
virtual boost::shared_ptr<MenuEntry> select(boost::shared_ptr<MenuEntry> desiredMenuEntry)=0;

/**************************************************************************//*!
 * <B>Criticality: C0 \n\n</B>
 * @brief Sets a pointer to the parent of new menu entry
 * @param[in] pointerToParent - pointer to the parent
 ****************************************************************************/
void setParent(boost::shared_ptr<MenuEntry> pointerToParent)
{
  m_parent = pointerToParent;
}

/***************************************************************************//*!
 * @brief Default implementation for destroying children
 *****************************************************************************/
virtual void destroy(void)=0;

  protected:
    /************************************************************************//*!
     * @brief Constructor for a menu entry (sub menu or leaf)
     * @param[in] menuEntryName - the name for the sub menu or leaf
     *************************************************************************/
    MenuEntry(std::string menuEntryName)
    {
      m_menuEntryName = menuEntryName;
    }

};

在select方法中,我检查返回值,如果我有一个执行某事的叶子,或者子菜单,我必须更改我的指针。

为方便起见,您可以添加方法,在子菜单中查找所有子菜单条目以进行显示,或者使用实际菜单路径等构建标题行的方法......另一个想法是扫描方法您的菜单树,以避免双菜单条目asf。

答案 3 :(得分:1)

使用树。无论如何,这最好在树中定义。

其中:rootNode已连接到ABCDB已与babb相关联。 C已与Ca相关联。等。

enter image description here

答案 4 :(得分:0)


我在我的Github

上使用struct作为细节

ConsoleMenu.h

typedef int (*MENU_FUNCTION_POINTER)();

typedef struct _MENU MENU;
typedef MENU* MENU_POINTER;

struct _MENU
{
    bool isValid; // C++ can not compare struct is NULL
    string text;
    MENU_FUNCTION_POINTER func;

    bool isOpen;
    MENU_POINTER childMenu;
    MENU_POINTER parent;
};

class ConsoleMenu
{
private:
    static MENU _chapters[];
    static MENU _chapter1[];
    static MENU _chapter2[];
};

ConsoleMenu.cpp

MENU ConsoleMenu::_chapters[] = {
    {true, "Chapter 1", NULL, false, ConsoleMenu::_chapter1, NULL},
    {true, "Chapter 2", NULL, false, ConsoleMenu::_chapter2, NULL},
    {true, "Chapter 3", NULL, false, NULL, NULL},
    {true, "Chapter 4", NULL, false, NULL, NULL},
    {false, "unused", NULL, false, NULL, NULL}
};

MENU ConsoleMenu::_chapter1[] = {
    {true, "Example 1.1", Example1, false, NULL, ConsoleMenu::_chapters},
    {true, "Example 1.2", Example2, false, NULL, ConsoleMenu::_chapters},
    {false, "unused", NULL, false, NULL, NULL}
};

MENU ConsoleMenu::_chapter2[] = {
    {true, "Example 2.1", NULL, false, NULL, ConsoleMenu::_chapters},
    {true, "Example 2.2", NULL, false, NULL, ConsoleMenu::_chapters},
    {true, "Example 2.3", NULL, false, NULL, ConsoleMenu::_chapters},
    {false, "unused", NULL, false, NULL, NULL}
};