使用多维数组创建菜单

时间:2015-06-11 18:57:47

标签: c++ c arrays

我对c和c ++很新。我白天是c#程序员,很少再使用数组了。不过,我正在研究一个c ++项目。我想为GUI创建一个类似于:

的菜单
Menu Item 1
    Item 1.1
        Item 1.1.1
        Item 1.1.2
    Item 1.2
        Item 1.2.1
        Item 1.2.2
Menu Item 2
    Item 2.1
        Item 2.1.1
        Item 2.1.2
    Item 2.2
        Item 2.2.1
        Item 2.2.2

我能够创建一个二维版本,但想要构建一个三维版本。非常感谢任何帮助。

这是我的二维版本:​​

    const char* menu[2][4] = 
    {
        {"Menu Item 1", "1.1 Item", "1.2 Item", "1.3 Item"},
        {"Menu Item 2", "2.1 Item", "2.2 Item", "2.3 Item"}

    };


    for(int i = 0; i < NUMOFCHO; i++){

        printf("%s\n\r", menu[i][0]);

        for(int k = 1; k < NUMOFITEMS; k++){
            printf("--%s\n\r", menu[i][k]);         

        }
    }   

3 个答案:

答案 0 :(得分:2)

如果您想要任何灵活性,静态数组可能不是最好的数据结构。

我建议使用动态大小的容器,例如std::vector

您经常会看到这样的菜单结构使用&#34;树&#34;类型层次结构,其中菜单的每个级别都有一个名称及其子级(子菜单项)。以下是您如何使用这些概念。

struct MenuItem
{
    // name of the menu item
    std::string name;

    // sub menu items
    std::vector<MenuItem> children;
};

使用递归遍历菜单最简单,这是一个简单的例子。

void printMenu(const std::vector<MenuItem> &menu, int level) 
{
    // string containing tabs depending on the level of the menu
    std::string prefix( level, '\t' );

    // we're visiting the next menu level
    ++level;

    // iterate over this level of the menu
    for (const auto &item : menu) 
    {
        // display the item name
        std::cout << prefix << item.name << std::endl;

        // visit this level's children
        printMenu( item.children, level );
    }
}

以下是如何初始化所提供的示例菜单结构。

std::vector<MenuItem> menu 
{
    {
        { 
            { "Menu Item 1" },
            { 
                {
                    { "Item 1.1" },
                    { 
                        {
                            { "Item 1.1.1" },
                            { {} }
                        },
                        {
                            { "Item 1.1.2" },
                            { {} }
                        }
                    }
                },
                {
                    { "Item 1.2" },
                    {
                        {
                            { "Item 1.2.1" },
                            { {} }
                        },
                        {
                            { "Item 1.2.2" },
                            { {} }
                        }
                    }
                },
            }
        },
        {
            { "Menu Item 2" },
            {
                {
                    { "Item 2.1" },
                    {
                        {
                            { "Item 2.1.1" },
                            { {} }
                        },
                        {
                            { "Item 2.1.2" },
                            { {} }
                        }
                    }
                },
                {
                    { "Item 2.2" },
                    {
                        {
                            { "Item 2.2.1" },
                            { {} }
                        },
                        {
                            { "Item 2.2.2" },
                            { {} }
                        }
                    }
                },
            }
        }
    }
};

要访问特定菜单项,您可以执行以下操作。

// Item 2.2.1
std::string item = menu[ 1 ].children[ 1 ].children[ 0 ].name;

甚至在结构初始化后添加项目。

menu[ 1 ].children[ 1 ].children.push_back({
    { "Testing" }, // name
    { {} }         // children
});

/*
    Menu Item 1
        Item 1.1
                Item 1.1.1
                Item 1.1.2
        Item 1.2
                Item 1.2.1
                Item 1.2.2
    Menu Item 2
        Item 2.1
                Item 2.1.1
                Item 2.1.2
        Item 2.2
                Item 2.2.1
                Item 2.2.2
                Testing
*/

您可以找到完整的示例here

答案 1 :(得分:1)

对于嵌套菜单,数组通常是不好的选择。

根据我的经验,菜单通常是链接在一起而不是在数组中:

Menu1  
  Item1 --> Menu1.1
    |  
    v  
  Item2 --> Menu1.2
    |
    v
  Item3

我通常会有一个菜单包含项目。每个项目都可以指向另一个子菜单。这允许项目没有子菜单的情况。

答案 2 :(得分:0)

我有一个解决方案,我在C中实施了一段时间。它设置为8级,但技术上没有深度限制。它是嵌入式的,因此它使用静态内存来处理所有内容,但可以轻松修改它以使用动态分配。您可以在my github page找到来源,但我会在这里详细解释一下。

菜单围绕k-ary树(k-tree)构建,k-tree树实现为二叉树(b-tree)。与常规k树不同,其中节点可以具有多个子菜单,这对于菜单系统是有意义的,因为系统是内存和资源约束的,所以二进制树生成更多。它允许静态分配的节点,而不使用固定大小的数组来存储子节点。这个实现起初有点令人困惑,但实际上在几个资源敏感的系统中使用,例如Linux内核。

常规k树表示为:

struct t {
   int n;
   int numKids;
   struct t **kids;
}

结果树结构看起来像:

   TOP
   |
   [ list of kids ]
   |     |      |
   k1    k2     k3
   |
   |
   [list of kids]
   |     |     |
   k1.1  k1.2  k1.3

如果你有像malloc这样的东西,但在嵌入式的东西上,这个表示法有效 使用malloc是诅咒的系统,如果你想添加另一个孩子,请使用 一个有限长度的静态数组,除了必须记录数字 在结构中的阵列中的孩子们。

相反,使用以下结构:

struct t {
   int n;
   struct t *firstChildNode;
   struct t *firstSiblingNode;
   struct t *trueParentNode;
   struct t *fakeParentNode;
};

,树形表示如下:

  [TOP NODE ] <-
  -----------   \
  ^|  ^          \
  ||  |           \ fP
  ||  |tP, fP      \
  ||  |_______  fS  \__________     fS
  ||  [NODE 2]------>[NODE 2.1]---------->NULL
  ||  ------- <------ ---------
  ||       |      tP      |
  ||       |fC            |fC
  ||fC     V              V
  ||      NULL          NULL
  ||
  |tP, fP
  ||
  |V_____
  [NODE1]
  -------
     ^
     |tP, fp
     |_________   fS
     [NODE 1.1] -----> NULL
         |
         |fC
         |
         V
       NULL

其中:

  
      
  • fP = fakeParentNode - 此指针用于确定实际位置    它将出现在经典的k-ary树中。
  •   
  • tP = trueParentNode - 此指针用于显示此节点实际连接的位置,因为它可能是另一个节点的子节点   节点或兄弟姐妹。
  •   
  • fC = firstChildNode - 指向第一个子节点的指针。
  •   
  • fS = firstSiblingNode - 指向第一个兄弟节点的指针。
  •   

从任何节点,您只能访问第一个孩子或第一个兄弟,使其成为经典的b树。从第一个孩子开始,您就可以访问它了 孩子和兄弟姐妹。同样对于第一个兄弟指针。这样一切 节点存储在一个列表中,该列表可以由静态分配组成 结构。真假父指针用于轻松追踪 每个子节点的祖先。伪父指针用于映射a 这个b树上的经典k树结构。

这种看似令人困惑的方法有几个好处:

  
      
  • 每个节点都是固定大小,可以静态分配。
  •   
  • 表示子节点不需要数组。
  •   
  • 许多算法很容易表达,因为它只是一个b树。
  •   

菜单的这种实现受到限制,因为删除节点的功能不存在,因为这似乎不是菜单的必要功能。添加菜单或菜单项非常简单。请参阅menu_top.c中的示例

此设计灵感来自https://blog.mozilla.org/nnethercote/2012/03/07/n-ary-trees-in-c/

ktree.c的代码:

/* Includes ------------------------------------------------------------------*/
#include "ktree.h"
#include "qp_port.h"                                        /* for QP support */
#include "project_includes.h"

/* Compile-time called macros ------------------------------------------------*/
Q_DEFINE_THIS_FILE                  /* For QSPY to know the name of this file */
DBG_DEFINE_THIS_MODULE( DBG_MODL_DBG );/* For debug system to ID this module */

/* Private typedefs ----------------------------------------------------------*/
/* Private defines -----------------------------------------------------------*/
/* Private macros ------------------------------------------------------------*/
/* Private variables and Local objects ---------------------------------------*/
static treeNode_t Menu1;
char *const Menu1Txt = "Menu 1";

   static treeNode_t MenuItem1;
   char *const MenuItem1_1Txt = "Menu Item 1.1";

   static treeNode_t MenuItem2;
   char *const MenuItem1_2Txt = "Menu Item 1.2";

   static treeNode_t MenuItem3;
   char *const MenuItem1_3Txt = "Menu Item 1.3";

   static treeNode_t MenuItem4;
   char *const MenuItem1_4Txt = "Menu Item 1.4";

static treeNode_t Menu2;
char *const Menu2Txt = "Menu 2";

   static treeNode_t MenuItem2_1;
   char *const MenuItem2_1Txt = "Menu Item 2.1";

   static treeNode_t MenuItem2_2;
   char *const MenuItem2_2Txt = "Menu Item 2.2";

   static treeNode_t MenuItem2_3;
   char *const MenuItem2_3Txt = "Menu Item 2.3";

   static treeNode_t MenuItem2_4;
   char *const MenuItem2_4Txt = "Menu Item 2.4";

static treeNode_t Menu3;
char *const Menu3Txt = "Menu 3";

   static treeNode_t Menu3_1;
   char *const Menu3_1Txt = "Menu 3_1";

      static treeNode_t MenuItem3_1_1;
      char *const MenuItem3_1_1Txt = "Menu Item 3.1.1";

      static treeNode_t MenuItem3_1_2;
      char *const MenuItem3_1_2Txt = "Menu Item 3.1.2";

      static treeNode_t MenuItem3_1_3;
      char *const MenuItem3_1_3Txt = "Menu Item 3.1.3";

      static treeNode_t MenuItem3_1_4;
      char *const MenuItem3_1_4Txt = "Menu Item 3.1.4";

   static treeNode_t Menu3_2;
   char *const Menu3_2Txt = "Menu 3_2";

      static treeNode_t MenuItem3_2_1;
      char *const MenuItem3_2_1Txt = "Menu Item 3.2.1";

      static treeNode_t MenuItem3_2_2;
      char *const MenuItem3_2_2Txt = "Menu Item 3.2.2";

      static treeNode_t MenuItem3_2_3;
      char *const MenuItem3_2_3Txt = "Menu Item 3.2.3";

      static treeNode_t MenuItem3_2_4;
      char *const MenuItem3_2_4Txt = "Menu Item 3.2.4";

   static treeNode_t Menu3_3;
   char *const Menu3_3Txt = "Menu 3_3";

      static treeNode_t Menu3_3_1;
      char *const Menu3_3_1Txt = "Menu 3_3_1";

         static treeNode_t MenuItem3_3_1_1;
         char *const MenuItem3_3_1_1Txt = "Menu Item 3.3.1.1";

         static treeNode_t MenuItem3_3_1_2;
         char *const MenuItem3_3_1_2Txt = "Menu Item 3.3.1.2";

         static treeNode_t MenuItem3_3_1_3;
         char *const MenuItem3_3_1_3Txt = "Menu Item 3.3.1.3";

      static treeNode_t Menu3_3_2;
      char *const Menu3_3_2Txt = "Menu 3_3_2";

         static treeNode_t MenuItem3_3_2_1;
         char *const MenuItem3_3_2_1Txt = "Menu Item 3.3.2.1";

         static treeNode_t MenuItem3_3_2_2;
         char *const MenuItem3_3_2_2Txt = "Menu Item 3.3.2.2";

         static treeNode_t MenuItem3_3_2_3;
         char *const MenuItem3_3_2_3Txt = "Menu Item 3.3.2.3";

      static treeNode_t Menu3_3_3;
      char *const Menu3_3_3Txt = "Menu 3_3_3";

         static treeNode_t MenuItem3_3_3_1;
         char *const MenuItem3_3_3_1Txt = "Menu Item 3.3.3.1";

         static treeNode_t MenuItem3_3_3_2;
         char *const MenuItem3_3_3_2Txt = "Menu Item 3.3.3.2";

         static treeNode_t MenuItem3_3_3_3;
         char *const MenuItem3_3_3_3Txt = "Menu Item 3.3.3.3";

      static treeNode_t Menu3_3_4;
      char *const Menu3_3_4Txt = "Menu 3_3_4";

         static treeNode_t MenuItem3_3_4_1;
         char *const MenuItem3_3_4_1Txt = "Menu Item 3.3.4.1";

         static treeNode_t MenuItem3_3_4_2;
         char *const MenuItem3_3_4_2Txt = "Menu Item 3.3.4.2";

         static treeNode_t MenuItem3_3_4_3;
         char *const MenuItem3_3_4_3Txt = "Menu Item 3.3.4.3";

/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/

/******************************************************************************/
void KTREE_nodeCtor( treeNode_t *node )
{
   /* Initialize the root node */
   node->firstChildNode = NULL;
   node->firstSiblingNode = NULL;
   node->fakeParentNode = NULL;
   node->trueParentNode = NULL;
}

/******************************************************************************/
uint8_t KTREE_findDepth( treeNode_t *node, uint8_t currDepth )
{
   /* Make sure the node is not null.  If this happens, it's a bug. */
   if ( NULL == node ) {
      ERR_printf("!!!Node is null\n");
      return( 0 );
   }

   if ( NULL == node->fakeParentNode ) {
      /* If no fake parents exist, this is the top.  Return the calculated
       * depth */
      return( currDepth );
   } else {
      /* Parent exists; recurse after incrementing the depth */
      return (KTREE_findDepth( node->fakeParentNode, ++currDepth ));
   }
}

/******************************************************************************/
void KTREE_addChild(
      treeNode_t *childToAdd,
      treeNode_t *trueParentNode,
      treeNode_t *fakeParentNode
)
{
   /* Find the parent node */
   if ( NULL == trueParentNode ) {
      childToAdd->trueParentNode = NULL;
      childToAdd->fakeParentNode = NULL;
      return;
   } else if ( NULL == trueParentNode->firstChildNode ) {

      /* If the node where we want to add a child currently has no children,
       * add the child node here to the childNode field. */
      trueParentNode->firstChildNode = childToAdd;
//      dbg_slow_printf("whereToAddChild=0x%08x\n", (uint32_t )whereToAddChild);
   } else {
      /* Otherwise, add a sibling to the child of this node */
      KTREE_addNextSibling( childToAdd, trueParentNode->firstChildNode, fakeParentNode);
//      dbg_slow_printf("Adding a sibling to the child of node '%s'\n", trueParentNode->text);
   }
}

/******************************************************************************/
void KTREE_addNextSibling(
      treeNode_t *siblingToAdd,
      treeNode_t *trueParentNode,
      treeNode_t *fakeParentNode
)
{
   if( NULL == trueParentNode->firstSiblingNode ) {
      /* In the node being added, set its parents. */
      siblingToAdd->fakeParentNode = fakeParentNode;
      siblingToAdd->trueParentNode = trueParentNode;

      /* Set the empty firstSiblingNode pointer to new node being added. */
      trueParentNode->firstSiblingNode = siblingToAdd;
//      dbg_slow_printf("Added node '%s' as a sibling to node '%s'\n", siblingToAdd->text, trueParentNode->text);
   } else {
//      dbg_slow_printf("Sibling '%s' already exists here.  Trying next one\n", trueParentNode->text);
      KTREE_addNextSibling(siblingToAdd, trueParentNode->firstSiblingNode, fakeParentNode);
   }
}

/******************************************************************************/
void KTREE_printTree( treeNode_t *node, uint8_t level )
{
   if ( NULL == node ) {
//      dbg_slow_printf("Node at level %d is null, not printing\n", level);
      return;
   } else {
      KTREE_printNode( node, level );
   }

   if ( NULL != node->firstChildNode ) {
//      dbg_slow_printf("Child exists, descending one level\n");
      KTREE_printTree( node->firstChildNode, level+1 );
   }

   if ( NULL != node->firstSiblingNode ) {
//      dbg_slow_printf("Sibling exits, moving right\n");
      KTREE_printTree( node->firstSiblingNode, level );
   }

}

/******************************************************************************/
void KTREE_printNode( treeNode_t *node, uint8_t level )
{
   for ( uint8_t i = 0; i < level; i++ ) {
      printf("*--");
   }
   printf("NodeText: %s\n", node->text);
   for ( uint8_t i = 0; i < level; i++ ) {
      printf("*--");
   }
   printf("True Parent   pointer: 0x%08x\n", (uint32_t)node->trueParentNode);
   for ( uint8_t i = 0; i < level; i++ ) {
      printf("*--");
   }
   printf("Fake Parent   pointer: 0x%08x\n", (uint32_t)node->fakeParentNode);
   for ( uint8_t i = 0; i < level; i++ ) {
      printf("*--");
   }
   printf("First Sibling pointer: 0x%08x\n", (uint32_t)node->firstSiblingNode);
   for ( uint8_t i = 0; i < level; i++ ) {
      printf("*--");
   }
   printf("First Child   pointer: 0x%08x\n", (uint32_t)node->firstChildNode);
}

/******************************************************************************/
void KTREE_fakeMenuTest( void )
{
   /* First Node */
   KTREE_nodeCtor( &Menu1 );
   Menu1.text = Menu1Txt;

      /* Add a child node */
      KTREE_nodeCtor( &MenuItem1 );
      MenuItem1.text = MenuItem1_1Txt;
      KTREE_addChild( &MenuItem1, &Menu1, &Menu1 );

      /* Add siblings to that child node */
      KTREE_nodeCtor( &MenuItem2 );
      MenuItem2.text = MenuItem1_2Txt;
      KTREE_addChild( &MenuItem2, &Menu1, &Menu1 );

      KTREE_nodeCtor( &MenuItem3 );
      MenuItem3.text = MenuItem1_3Txt;
      KTREE_addChild( &MenuItem3, &Menu1, &Menu1 );

      KTREE_nodeCtor( &MenuItem4 );
      MenuItem4.text = MenuItem1_4Txt;
      KTREE_addChild( &MenuItem4, &Menu1, &Menu1 );

   /* Add another node at top level - it gets added as a sibling to the first node */
   KTREE_nodeCtor( &Menu2 );
   Menu2.text = Menu2Txt;
   KTREE_addNextSibling( &Menu2, &Menu1, NULL );

      /* Add menu items to it as children  */
      KTREE_nodeCtor( &MenuItem2_1 );
      MenuItem2_1.text = MenuItem1_1Txt;
      KTREE_addChild( &MenuItem2_1, &Menu2, &Menu2 );

      /* Add siblings to that child node */
      KTREE_nodeCtor( &MenuItem2_2 );
      MenuItem2_2.text = MenuItem2_2Txt;
      KTREE_addChild( &MenuItem2_2, &Menu2, &Menu2 );

      KTREE_nodeCtor( &MenuItem2_3 );
      MenuItem2_3.text = MenuItem2_3Txt;
      KTREE_addChild( &MenuItem2_3, &Menu2, &Menu2 );

      KTREE_nodeCtor( &MenuItem2_4 );
      MenuItem2_4.text = MenuItem2_4Txt;
      KTREE_addChild( &MenuItem2_4, &Menu2, &Menu2 );

   /* Add another node at top level - it gets added as a sibling to the first node */
   KTREE_nodeCtor( &Menu3 );
   Menu3.text = Menu3Txt;
   KTREE_addNextSibling( &Menu3, &Menu1, NULL );

      /* Add submenu nodes - it gets added as a sibling to the first node */
      KTREE_nodeCtor( &Menu3_1 );
      Menu3_1.text = Menu3_1Txt;
      KTREE_addChild( &Menu3_1, &Menu3, &Menu3 );

         /* Add menu items to it as children  */
         KTREE_nodeCtor( &MenuItem3_1_1 );
         MenuItem3_1_1.text = MenuItem3_1_1Txt;
         KTREE_addChild( &MenuItem3_1_1, &Menu3_1, &Menu3_1 );

         KTREE_nodeCtor( &MenuItem3_1_2 );
         MenuItem3_1_2.text = MenuItem3_1_2Txt;
         KTREE_addChild( &MenuItem3_1_2, &Menu3_1, &Menu3_1 );

         KTREE_nodeCtor( &MenuItem3_1_3 );
         MenuItem3_1_3.text = MenuItem3_1_3Txt;
         KTREE_addChild( &MenuItem3_1_3, &Menu3_1, &Menu3_1 );

         KTREE_nodeCtor( &MenuItem3_1_4 );
         MenuItem3_1_4.text = MenuItem3_1_4Txt;
         KTREE_addChild( &MenuItem3_1_4, &Menu3_1, &Menu3_1 );

      KTREE_nodeCtor( &Menu3_2 );
      Menu3_2.text = Menu3_2Txt;
      KTREE_addChild( &Menu3_2, &Menu3, &Menu3 );

         /* Add menu items to it as children  */
         KTREE_nodeCtor( &MenuItem3_2_1 );
         MenuItem3_2_1.text = MenuItem3_2_1Txt;
         KTREE_addChild( &MenuItem3_2_1, &Menu3_2, &Menu3_2 );

         KTREE_nodeCtor( &MenuItem3_2_2 );
         MenuItem3_2_2.text = MenuItem3_2_2Txt;
         KTREE_addChild( &MenuItem3_2_2, &Menu3_2, &Menu3_2 );

         KTREE_nodeCtor( &MenuItem3_2_3 );
         MenuItem3_2_3.text = MenuItem3_2_3Txt;
         KTREE_addChild( &MenuItem3_2_3, &Menu3_2, &Menu3_2 );

         KTREE_nodeCtor( &MenuItem3_2_4 );
         MenuItem3_2_4.text = MenuItem3_2_4Txt;
         KTREE_addChild( &MenuItem3_2_4, &Menu3_2, &Menu3_2 );

      KTREE_nodeCtor( &Menu3_3 );
      Menu3_3.text = Menu3_3Txt;
      KTREE_addChild( &Menu3_3, &Menu3, &Menu3 );

         KTREE_nodeCtor( &Menu3_3_1 );
         Menu3_3_1.text = Menu3_3_1Txt;
         KTREE_addChild( &Menu3_3_1, &Menu3_3, &Menu3_3 );

            /* Add menu items to it as children  */
            KTREE_nodeCtor( &MenuItem3_3_1_1 );
            MenuItem3_3_1_1.text = MenuItem3_3_1_1Txt;
            KTREE_addChild( &MenuItem3_3_1_1, &Menu3_3_1, &Menu3_3_1 );

            KTREE_nodeCtor( &MenuItem3_3_1_2 );
            MenuItem3_3_1_2.text = MenuItem3_3_1_2Txt;
            KTREE_addChild( &MenuItem3_3_1_2, &Menu3_3_1, &Menu3_3_1 );

            KTREE_nodeCtor( &MenuItem3_3_1_3 );
            MenuItem3_3_1_3.text = MenuItem3_3_1_3Txt;
            KTREE_addChild( &MenuItem3_3_1_3, &Menu3_3_1, &Menu3_3_1 );

         KTREE_nodeCtor( &Menu3_3_2 );
         Menu3_3_2.text = Menu3_3_2Txt;
         KTREE_addChild( &Menu3_3_2, &Menu3_3, &Menu3_3 );

            /* Add menu items to it as children  */
            KTREE_nodeCtor( &MenuItem3_3_2_1 );
            MenuItem3_3_2_1.text = MenuItem3_3_2_1Txt;
            KTREE_addChild( &MenuItem3_3_2_1, &Menu3_3_2, &Menu3_3_2 );

            KTREE_nodeCtor( &MenuItem3_3_2_2 );
            MenuItem3_3_2_2.text = MenuItem3_3_2_2Txt;
            KTREE_addChild( &MenuItem3_3_2_2, &Menu3_3_2, &Menu3_3_2 );

            KTREE_nodeCtor( &MenuItem3_3_2_3 );
            MenuItem3_3_2_3.text = MenuItem3_3_2_3Txt;
            KTREE_addChild( &MenuItem3_3_2_3, &Menu3_3_2, &Menu3_3_2 );

         KTREE_nodeCtor( &Menu3_3_3 );
         Menu3_3_3.text = Menu3_3_3Txt;
         KTREE_addChild( &Menu3_3_3, &Menu3_3, &Menu3_3 );

            /* Add menu items to it as children  */
            KTREE_nodeCtor( &MenuItem3_3_3_1 );
            MenuItem3_3_3_1.text = MenuItem3_3_3_1Txt;
            KTREE_addChild( &MenuItem3_3_3_1, &Menu3_3_3, &Menu3_3_3 );

            KTREE_nodeCtor( &MenuItem3_3_3_2 );
            MenuItem3_3_3_2.text = MenuItem3_3_3_2Txt;
            KTREE_addChild( &MenuItem3_3_3_2, &Menu3_3_3, &Menu3_3_3 );

            KTREE_nodeCtor( &MenuItem3_3_3_3 );
            MenuItem3_3_3_3.text = MenuItem3_3_3_3Txt;
            KTREE_addChild( &MenuItem3_3_3_3, &Menu3_3_3, &Menu3_3_3 );

         KTREE_nodeCtor( &Menu3_3_4 );
         Menu3_3_4.text = Menu3_3_4Txt;
         KTREE_addChild( &Menu3_3_4, &Menu3_3, &Menu3_3 );

            /* Add menu items to it as children  */
            KTREE_nodeCtor( &MenuItem3_3_4_1 );
            MenuItem3_3_4_1.text = MenuItem3_3_4_1Txt;
            KTREE_addChild( &MenuItem3_3_4_1, &Menu3_3_4, &Menu3_3_4 );

            KTREE_nodeCtor( &MenuItem3_3_4_2 );
            MenuItem3_3_4_2.text = MenuItem3_3_4_2Txt;
            KTREE_addChild( &MenuItem3_3_4_2, &Menu3_3_4, &Menu3_3_4 );

            KTREE_nodeCtor( &MenuItem3_3_4_3 );
            MenuItem3_3_4_3.text = MenuItem3_3_4_3Txt;
            KTREE_addChild( &MenuItem3_3_4_3, &Menu3_3_4, &Menu3_3_4 );

   KTREE_printTree( &Menu1, 0 );
}

ktree.h的代码:

#ifndef KTREE_H_
#define KTREE_H_

#ifdef __cplusplus
extern "C" {
#endif

/* Includes ------------------------------------------------------------------*/
#include "stm32f4xx.h"                                 /* For STM32F4 support */
#include "Shared.h"

/* Exported defines ----------------------------------------------------------*/
/* Exported types ------------------------------------------------------------*/

typedef void (*pMenuFunction) (
      const char* dataBuf,
      uint16_t dataLen,
      CBMsgRoute dst
);

typedef struct treeNode {
   struct treeNode *fakeParentNode;
   struct treeNode *trueParentNode;
   struct treeNode *firstChildNode;
   struct treeNode *firstSiblingNode;
   char *text;
   char *selector;
   pMenuFunction actionToTake;
} treeNode_t;


/* Exported macros -----------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* Exported variables --------------------------------------------------------*/
/* Exported functions --------------------------------------------------------*/


/**
 * @brief   Initialize the menu memory space with the contents of the menu
 *
 * This function initializes the menu application.
 *
 * @param [in]  iBus: I2C_Bus_t identifier for I2C bus to initialize
 *    @arg
 * @return: None
 */
void KTREE_nodeCtor( treeNode_t *node );

/**
 * @brief   Counts the depth (via fakeParentNode pointer) of the passed in
 * pointer to a node.
 *
 * Recursive function that counts it's own depth by traversing the tree up via
 * the fakeParentNode pointer and counting.
 *
 * @param [in]  *node: treeNode_t pointer to the node
 * @parem [in] currDepth: uint8_t value of the current depth.  Unless you want
 * to for some reason offset where you start counting from, pass in 0 here.
 * @return: uint8_t depth of the current node.
 */
uint8_t KTREE_findDepth( treeNode_t *node, uint8_t currDepth );

/**
 * @brief   Adds a child node to a passed in parent node.
 *
 * This function adds a child node to a passed in parent node after doing some
 * initial checking of both nodes.
 *
 * @param [in] childNode: treeNode_t* pointer to the node to be added as a child
 * @parem [in] trueParentNone: treeNode_t* pointer to the node that the child
 * node will be directly attached to because it may appear as a sibling node or
 * an actual child node.
 * @parem [in] fakeParentNone: treeNode_t* pointer to the node that indicates
 * the "regular" tree depth of this child node.
 * @return: None
 */
void KTREE_addChild(
      treeNode_t *childToAdd,
      treeNode_t *trueParentNode,
      treeNode_t *fakeParentNode
);

/**
 * @brief   Adds a sibling node to a passed in parent node.
 *
 * This function adds a sibling node to a passed in parent node by checking if
 * the child node of the trueParentNode is used up and if it is, it recursively
 * calls itself with the used node as a trueParentNode parameter until it finds
 * the last sibling.  It then adds the sibling node there and sets the
 * fakeParentNode.
 *
 * @param [in] childNode: treeNode_t* pointer to the node to be added as a child
 * @parem [in] trueParentNone: treeNode_t* pointer to the node that the child
 * node will be directly attached to because it may appear as a sibling node or
 * an actual child node.
 * @parem [in] fakeParentNone: treeNode_t* pointer to the node that indicates
 * the "regular" tree depth of this child node.
 * @return: None
 */
void KTREE_addNextSibling(
      treeNode_t *siblingToAdd,
      treeNode_t *trueParentNode,
      treeNode_t *fakeParentNode
);

void KTREE_printTree( treeNode_t *node, uint8_t level );

void KTREE_printNode( treeNode_t *node, uint8_t level );

void KTREE_fakeMenuTest( void );

我不想在这里发布其余的代码(它已经很多了)但是请查看我链接中该目录的其余部分,看看它是如何使用的。 menu.c / h使用ktree设置实际菜单并使用它。