• 全部
  • 问答

如何用c++实现多级交互菜单?

redsprite 2007-03-05 04:12:35
自己做了下,发现问题很多,想不到办法解决。向做过的朋友请教下,谢谢!任务紧,时间得加快了。

具体要求是:控制台界面的,采用竖式列表菜单项,如:

1)Item1;
2)Item2;
... ...
5)Item5;

Please input your choice(1-5):

菜单是多级的,也就是每一项下面还有类似的菜单项。下级菜单里面包括返回上一级菜单的项目和退出的项目。输入选择的时候,支持单选和多选。

非常感谢!
...全文
547 点赞 收藏 11
写回复
11 条回复
切换为时间正序
当前发帖距今超过3年,不再开放新的回复
发表回复
redsprite 2007-03-20
输入的错误处理没能很好的包括,例如输入1)就会死循环。不过已经基本完成了,谢谢!给分咯!
回复
boxban 2007-03-15
//Menu.cpp
#include <assert.h>
#include <iostream>
#include "Menu.h"
#include "MenuWidget.h"


Menu* Menu::m_sActiveMenu = NULL;

Menu::Menu() : m_pParentMenu(NULL)
{
}
Menu::Menu(const std::string& strName, Menu* pParentMenu /* = NULL */)
: MenuWidget(strName), m_pParentMenu(pParentMenu)
{
}


Menu::~Menu()
{
for(size_t i = 0; i < m_vWidgets.size(); ++i)
delete m_vWidgets[i];
}

//return item index (zero-based)
size_t Menu::appendMenuWidget(MenuWidget* pMenuWidget)
{
m_vWidgets.push_back(pMenuWidget);
return (m_vWidgets.size() - 1);
}

MenuWidget* Menu::getMenuWidget(size_t idx)
{
return ((idx < m_vWidgets.size()) ? m_vWidgets[idx] : NULL);
}

void Menu::onClick(size_t idx, void* arg /* = NULL */)
{
if (getActiveMenu() != this){
//this is a sub-menu
setActiveMenu(this);
return;
}

if (idx < m_vWidgets.size()){
MenuWidget* pWidget = m_vWidgets[idx];
if (pWidget)
pWidget->onClick(idx, arg);
}
}

void Menu::draw()
{
using namespace std;

cout << getName() << endl;
cout << "=============================================" << endl;

MenuWidget* pWidget = NULL;
for(size_t i = 0; i < m_vWidgets.size(); ++i){
pWidget = m_vWidgets[i];
if (pWidget != NULL){
cout << i << ")\t" << pWidget->getName() << endl;
}else{ // treat it as a seperator
cout << i <<")\t-----------------------------------" << endl;
}
}
cout << "=============================================" << endl << endl;

}


//####################################################################

//====================================================================
//main.cpp

#include <iostream>
#include <assert.h>

#include "Menu.h"
#include "MenuItem.h"

using namespace std;

void handlerReturnToParentMenu(void* arg, MenuItem* pItem)
{
Menu* pMenu = Menu::getActiveMenu();
assert(pMenu->getParentMenu() != NULL);
Menu::setActiveMenu(pMenu->getParentMenu());
}

void handlerNormalItem(void* arg, MenuItem* pItem)
{
cout << "MenuItem " << pItem->getName() << " clicked:" << pItem->getItemData() << endl;
}

void handlerExit(void* arg, MenuItem* pItem)
{
cout << "MenuItem " << pItem->getName() << " clicked:" << pItem->getItemData() << endl;
Menu::setActiveMenu(NULL);
}

Menu* createMenu()
{
Menu* mainMenu = new Menu("Main menu");

MenuItem* item = new MenuItem("item-1", &handlerNormalItem, 1);

mainMenu->appendMenuWidget(item);
item = new MenuItem("item-2", &handlerNormalItem, 2);
mainMenu->appendMenuWidget(item);
item = new MenuItem("item-3", &handlerNormalItem, 3);
mainMenu->appendMenuWidget(item);

Menu* submenu = new Menu("sub-menu", mainMenu);
submenu->appendMenuWidget(new MenuItem("sub-item-11", &handlerNormalItem, 11));
submenu->appendMenuWidget(new MenuItem("sub-item-12", &handlerNormalItem, 12));
submenu->appendMenuWidget(new MenuItem("sub-item-13", &handlerNormalItem, 13));
submenu->appendMenuWidget(new MenuItem("return to up-level", &handlerReturnToParentMenu, 0));

mainMenu->appendMenuWidget(submenu);

mainMenu->appendMenuWidget(NULL); //add a seperator

item = new MenuItem("Exit", &handlerExit, 0);
mainMenu->appendMenuWidget(item);


return mainMenu;
}

void main()
{
Menu::setActiveMenu(createMenu());
int i;
while(Menu::getActiveMenu()){
Menu::getActiveMenu()->draw();
cout << "input item" << endl;
cin >> i;
Menu::getActiveMenu()->onClick(i);
}
}


回复
boxban 2007-03-15
//MenuWidget.h

#pragma once

#include <stdlib.h>
#include <string>

class MenuWidget
{
public:
MenuWidget() {}
MenuWidget(const std::string& strName) : m_strName(strName) {}
virtual ~MenuWidget() {}

public:
const std::string& getName() const { return m_strName; }
void setName(const std::string& strName) { m_strName = strName;}

public: //interface
virtual void onClick(size_t idx, void* arg = NULL) = 0;

private:
std::string m_strName;
};

#endif

//####################################################################

//====================================================================
//MenuItem.h

#pragma once

#include <string>
#include "MenuWidget.h"

class MenuItem;

typedef unsigned int ITEMDATA;
typedef void (*ITEM_HANDLER)(void* arg, MenuItem* pItem);

class MenuItem : public MenuWidget
{
public:
MenuItem() : m_pfHandler(NULL), m_itemData(0) {}
MenuItem(const std::string& strName, ITEM_HANDLER pfHandler = NULL, ITEMDATA itemData = 0)
: MenuWidget(strName), m_pfHandler(pfHandler), m_itemData(itemData)
{}

public:
const ITEM_HANDLER getHandler() const { return m_pfHandler;}
void setHandler(ITEM_HANDLER pfHandler) { m_pfHandler = pfHandler;}

ITEMDATA getItemData() const { return m_itemData; }
void setItemData(ITEMDATA data) { m_itemData = data; }

virtual void onClick(size_t idx, void* arg = NULL)
{
if(m_pfHandler != NULL)
(*m_pfHandler)(arg, this);
}

private:
ITEM_HANDLER m_pfHandler;
ITEMDATA m_itemData;
};

//####################################################################

//====================================================================
//Menu.h

#pragma once

#include <string>
#include <vector>

#include "MenuWidget.h"


class Menu : public MenuWidget
{
public:
Menu();
Menu(const std::string& strName, Menu* pParentMenu = NULL);
~Menu();

public:
//return item index (zero-based)
size_t appendMenuWidget(MenuWidget* pMenuWidget);

//insert item at postion idx
bool insertMenuWidget(MenuWidget* pMenuWidget, int idx);

MenuWidget* getMenuWidget(size_t idx);

// interface from MenuWidget
virtual void onClick(size_t idx, void* arg = NULL);

public:
void draw();

void setParentMenu(Menu* pMenu) { m_pParentMenu = pMenu; }
Menu* getParentMenu() { return m_pParentMenu; }

static void setActiveMenu(Menu* pMenu) { m_sActiveMenu = pMenu;}
static Menu* getActiveMenu() { return m_sActiveMenu; }

private:
std::vector<MenuWidget*> m_vWidgets;
Menu* m_pParentMenu;

static Menu* m_sActiveMenu;
};

回复
todototry 2007-03-14
mark
回复
redsprite 2007-03-14
还是没有有价值的结果啊。再等等,没有就结贴咯!
回复
jixingzhong 2007-03-06
打印菜单,
等待用户输入,
然后执行相应的功能就是了 ~
回复
taodm 2007-03-06
C/C++没有提供标准清屏接口。所以,在windows下和unix下必须要2调不同接口函数的,无法使用完全相同的代码的。
当然,如果你不介意输出无数的退格键(\b)来实现清屏的话,代码可以统一。
回复
redsprite 2007-03-06
程序需要在windows和unix下都能清屏,该怎么实现呢?
回复
redsprite 2007-03-06
我已经实现了,不过代码感觉比较累赘,还没有想到什么简单方便的方法来做。

清屏的问题,使用宏定义来区分不同平台,windows下调用system('cls');unix下面则调用system("clear");

虽然做完了,但是感觉还是有点不满意,继续征求更好的实现方法,比如可以作为类来方便增加,减少菜单项和层级。最好是层级和数量不限的。最为一个可以经常调用的工具类。这样会方便大家啊!谢谢楼上的回帖。
回复
redsprite 2007-03-05
界面是字符的,需要完整的代码。谢谢!
回复
taodm 2007-03-05
输出,等待输入,清屏,重新输出。
这没难度呀。
回复
相关推荐
发帖
C++ 语言
创建于2007-09-28

5.9w+

社区成员

C++ 语言相关问题讨论,技术干货分享,前沿动态等
申请成为版主
帖子事件
创建了帖子
2007-03-05 04:12
社区公告
暂无公告