我对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]);
}
}
答案 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设置实际菜单并使用它。