|
 |
|
 |
10-14-2006, 01:37 PM
|
#1 (permalink)
|
|
krisl100
Join Date: Oct 2006
Location: Montreal
Posts: 34
|
C++ Menu
Ok, this is not even covered in the book I have, but someone was telling me about creating a menu system, & each menu item would then run a different or part of the same program. Example:
Menu
A
B
C
D
X: Quit program (go back to DOS/Windows)
He said you could write the menu as a seperate function, I have no clue where to even begin, so if someone could just help get started with the menu system, that would be great. Thanks.
(I still remember doing this in batch files using CHOICE 
|
|
|
10-14-2006, 05:18 PM
|
#2 (permalink)
|
|
Senior Contributor
Join Date: Mar 2005
Posts: 677
|
Code:
typedef void (*menufunc)();
typedef struct {
char *title;
char hotkey;
menufunc *func;
} menuitem
void Aclicked()
{
// do something
}
menuitem menuitems[5];
menuitems[0].title = "Choose A";
menuitems[0].hotkey = 'A';
menuitems[0].func = Aclicked;
__________________

UT: Ultra-kill... God like!
|
|
|
10-14-2006, 08:06 PM
|
#3 (permalink)
|
|
[code][/code] enforcer
Join Date: Mar 2003
Location: Netherlands
Posts: 1,544
|
Or how about something truly object oriented programming. This is the command design pattern. A menu can also hold menus, therefore it enables sub-menus to be created. A bit more advanced, I know, but this my style of making something really object oriented, like a menu subsystem.
And watch it. Strange things is happening to code here when copying and pasting... use your common sense.
main.cpp
Code:
#include "MenuManager.h"
int main()
{
//Setup main menu first. Add submenu's here later.
MenuManager MainMenu("Main Menu");
//Setup a single sub menu.
MenuManager* FileMenu = new MenuManager("File Menu");
//Add concrete menu's to the sub menu.
FileMenu->add(new PrintCmd);
FileMenu->add(new ReturnCmd);
//And add the sub menu to the main menu.
MainMenu.add(FileMenu);
//Also let's add a concrete quit command to the main menu to exit the app.
MainMenu.add(new QuitCmd);
//Run the menu.
MainMenu.execute();
return 0;
}
MenuCommand.h
Code:
#ifndef COMMAND_H
#define COMMAND_H
#include <vector>
#include <string>
using std::string;
using std::vector;
//Abstract.
class MenuCommand
{
public:
MenuCommand(const string name);
virtual ~MenuCommand();
virtual bool execute() = 0;
string get_name();
private:
//Protect copy ctor and assignment.
MenuCommand(const MenuCommand&);
MenuCommand& operator=(const MenuCommand& rho);
const string _sName;
};
//
class QuitCmd : public MenuCommand
{
public:
QuitCmd();
bool execute();
private:
QuitCmd(const QuitCmd&);
QuitCmd& operator=(const QuitCmd& rho);
};
//
class ReturnCmd : public MenuCommand
{
public:
ReturnCmd();
// if bool = false: return to previous level.
//If top level then quit app.
bool execute();
private:
ReturnCmd(const ReturnCmd&);
ReturnCmd& operator=(const ReturnCmd& rho);
};
//
class PrintCmd : public MenuCommand
{
public:
PrintCmd();
bool execute();
private:
PrintCmd(const PrintCmd&);
PrintCmd& operator=(const PrintCmd& rho);
};
//
#endif //COMMAND_H
MenuCommand.cpp
Code:
#include "MenuCommand.h"
#include "MenuManager.h"
#include <iostream>
using std::cout;
using std::endl;
using std::cin;
//---- CLASS MENUCOMMAND ----
MenuCommand::MenuCommand(const string name) :
_sName(name)
{ }
MenuCommand::~MenuCommand()
{ }
string MenuCommand::get_name()
{
return _sName;
}
//---- CLASS QUITCMD ----//
QuitCmd::QuitCmd() :
MenuCommand("Quit Application")
{}
bool QuitCmd::execute()
{
return false;
}
// CLASS RETURNCMD //
ReturnCmd::ReturnCmd() :
MenuCommand("Return To Previous Menu")
{ }
bool ReturnCmd::execute()
{
return false;
}
// CLASS PRINTCMD //
PrintCmd::PrintCmd() :
MenuCommand("Print")
{}
bool PrintCmd::execute()
{
cout<<"I am printing stuff :)"<<endl;
return true;
}
MenuManager.h
Code:
#ifndef MENUMANAGER_H
#define MENUMANAGER_H
#include "MenuCommand.h"
#include <vector>
#include <string>
using std::vector;
using std::string;
class MenuManager : public MenuCommand
{
public:
MenuManager(const string name);
~MenuManager();
void add(MenuCommand* pCommand);
bool execute();
private:
MenuManager(const MenuManager&);
MenuManager& operator=(const MenuManager& rho);
MenuCommand* select(int index);
void show();
int get_user_input();
vector<MenuCommand*> _vecMenuItemCommands;
};
#endif //MENUMANAGER_H
MenuManager.cpp
Code:
#include "MenuManager.h"
#include <algorithm>
#include <cstdlib> //size_t
#include <iostream>
#include <ios>
using std::cout;
using std::endl;
using std::cin;
//#define VERBOSE
//
MenuManager::MenuManager(const string name) :
MenuCommand(name)
{ }
//
void MenuManager::add(MenuCommand* pCommand)
{
_vecMenuItemCommands.push_back( pCommand );
}
//
bool MenuManager::execute()
{
MenuCommand* pCmd;
do
{
show();
int userInput = get_user_input();
pCmd = select( userInput );
}
while( pCmd->execute() );
return true;
}
//
void MenuManager::show()
{
cout << endl << "*** " << get_name() << " ***" << endl;
std::size_t size = _vecMenuItemCommands.size();
for(std::size_t i=0; i < size; ++i)
{
cout << i+1 << ". " << _vecMenuItemCommands[i]->get_name() << endl;
}
}
//
MenuCommand* MenuManager::select(int index)
{
return _vecMenuItemCommands[index-1];
}
//
int MenuManager::get_user_input()
{
unsigned input = 0;
while(input < 1 || input > ( _vecMenuItemCommands.size() ) )
{
cout << "Please select an item 1-" << (_vecMenuItemCommands.size()) << endl << ">";
cin >> input;
}
return input;
}
//
struct Delete
{
template <typename T>
void operator()(const T* ptr) const
{
#ifdef VERBOSE
std::cout << "\tDeleting address: " << std::ios::hex << ptr << std::endl;
#endif //VERBOSE
delete ptr;
}
};
//
MenuManager::~MenuManager()
{
#ifdef VERBOSE
std::cout<<"Deleting: "<<get_name()<<std::endl;
#endif //VERBOSE
std::for_each(_vecMenuItemCommands.begin(), _vecMenuItemCommands.end(), Delete() );
}
__________________
|
|
|
10-15-2006, 05:14 AM
|
#4 (permalink)
|
|
krisl100
Join Date: Oct 2006
Location: Montreal
Posts: 34
|
I tried typing both of these manually into my compiler, but I got errors. For the .h files, do I save those in my include directory?
|
|
|
10-15-2006, 10:28 AM
|
#5 (permalink)
|
|
[code][/code] enforcer
Join Date: Mar 2003
Location: Netherlands
Posts: 1,544
|
No, you save both your cpp and h files in the project folder.
Currently, the bb code messed the c++ code up. Just copy and paste the code, but manuallly add the newlines.
__________________
|
|
|
10-15-2006, 10:35 AM
|
#6 (permalink)
|
|
[code][/code] enforcer
Join Date: Mar 2003
Location: Netherlands
Posts: 1,544
|
I have a better idea: I'll upload the files in a zip for you to download. See edit later.
---
edit
---
Link below:
http://home.tiscali.nl/valmont/cpp/d...manddesign.zip
- Create an empty project.
- Unpack these 5 files in your project folder.
- Add them to your project.
- Compile and run.
________________________
Don't post this code elsewhere without referring to this site and my name. Respect works both ways.
__________________
|
|
|
10-16-2006, 06:34 AM
|
#7 (permalink)
|
|
C++ Beginner
Join Date: Jul 2005
Location: Ottawa
Posts: 73
|
Hey Valmont, I was just looking through your menu lib that you made, i haven't had a chance to unpack it and see what it actually does, just had a couple questions for you.
I notice in MenuCommand.h you make a destructor and the execute() command both virtual...could you elaborate on what the purpose of using virtual functions is (I've never covered this topic).
Second, going down to the MenuManager.cpp,
Code:
#ifdef VERBOSE
std::cout "something...or another"
#endif
I'm assuming this is placed in there because we don't know what type of application our user is building. If he/she were writing their program to accept command line arguments, and their program supported the -v (verbose) option (I'm not even sure if MS has such an option), then the menu could still operate under such an environment, and handle those options respectively?
|
|
|
10-16-2006, 10:36 AM
|
#8 (permalink)
|
|
Code Monkey
Join Date: Aug 2002
Location: Boston, MA
Posts: 79
|
The #ifdef he is using is for debugging. If you have VERBOSE defined in your make or what ever MS has then it will include that code when you compile. If it is not set then it will nto be included during compilation.
__________________
|
|
|
10-16-2006, 10:41 AM
|
#9 (permalink)
|
|
Code Monkey
Join Date: Aug 2002
Location: Boston, MA
Posts: 79
|
I think the virtual destructor is used to call the derived classes destructor as well as it's own to make sure everything is cleaned up. This is of course a wild stab at a guess it has been a while since I did any C++.
__________________
|
|
|
10-16-2006, 03:01 PM
|
#10 (permalink)
|
|
C++ Beginner
Join Date: Jul 2005
Location: Ottawa
Posts: 73
|
I think I found it:
Quote:
|
A virtual function is a function member of a class, declared using the "virtual" keyword. ...If the function is virtual and occurs both in the base class and in derived classes, then the right function will be picked up based on what the base class pointer "really" points at.
|
I guess in that example there were several execute() functions for the multiple classes
|
|
|
10-17-2006, 09:23 AM
|
#11 (permalink)
|
|
[code][/code] enforcer
Join Date: Mar 2003
Location: Netherlands
Posts: 1,544
|
I was typing my fingers off, then I pressed my 5th mouse button and now I lost my big post!!
I need a cappucino first, then I start again.
But on the virtual destructors, I'll make a seperate "Quick Tutorial" in a new thread. Should serve as a "pilot" tutorial for the tutorial section when it passed the critical eye of our students and contributors  .
When it comes to the zip file with the code:
Just compile it and run it. It's here only to demonstrate my own style. It's a nested Command Design Pattern. Some hate it, I love it, although it's right now clearly "over-engineering".
When it comes to the "VERBOSE" macro:
Remove the comment so the macro becomes active:
Code:
//#define VERBOSE //
becomes
Compile and run again. Quit program. What do you see? Why would I want to see such feedback?
__________________
|
|
|
| Thread Tools |
|
|
| Display Modes |
Linear Mode
|
Posting Rules
|
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
HTML code is Off
|
|
|
All times are GMT -8. The time now is 09:20 AM.
|
Copyright © 2000-2008, Milano Interactive
Web Hosting provided by Portal 360 Web Hosting
|
 |
|