I am coding my way to the last project of the semester and I have a code duplication issue.
I am using ncurses or pdcurses to make a menu to interact with the user.
The problem: For each choice of the menu(Five in total) I need a submenu. The submenu's only difference from the main menu is, the array of Items to be printed, and the parameters that go into some functions, as a result of the Items array size. Since I need five submenus, I need five times the same code(six if you add the main menu).
Could any of you help me make a function that does the same thing, which I'll then call six times to create my menu?
Here's my code
void Menu(){
const char* Items[]={
"[1]...New tax declaration",
"[2]...Modify tax declaration",
"[3]...Cancel tax declaration",
"[4]...Additional Information",
"[5]...Exit"
};
int Cur=0;
int ch, i;
int flag=0;
do{
werase(wm);
mvwaddstr(wm, 2, 16, "MENU");
for(int i=0; i<5;i++){
if(i==Cur)
wattr_on(wm, A_REVERSE, 0);
mvwaddstr(wm, 4+i, 4, Items[i]);
wattr_off(wm, A_REVERSE, 0);
}
mvwaddstr(wm, 14, 3, "Choice: ");
wprintw(wm, "%1d", Cur+1);
wrefresh(wm);
ch=wgetch(wm);
switch(ch){
case '1':Cur=0;Sub2();break;
case '2':Cur=1;Sub1();break;
case '3':Cur=2;break;
case '4':Cur=3;break;
case '5':flag=1;break;
case KEY_UP:
case KEY_LEFT: Cur--; if (Cur<0) Cur=4; break;
case KEY_DOWN:
case KEY_RIGHT: Cur++; if(Cur>4) Cur=0; break;
case 27: flag=1; break;
case 32:
case 13:
switch (Cur){
case 0:Sub2();break;
case 1:Sub1();break;
case 2:break;
case 3:break;
case 4:flag=1;break;
}
}
}while(!flag);
}
Thank you.
p.s The code is from a book. I have little experience with ncurses
A simple menu-driven program. This is based on using std::map instead of conditional logic. This map stores a list of menuitem structures that define what the menu looks like and what each option does.
This is best explained as we work through the code, so let's dive in!
// headers for everything used in this example
#include <iostream>
#include <string>
#include <map>
#include <functional>
#include <cctype>
// function to perform menu option B sub option 1
void optionB1()
{
std::cout << "perfoming B1" << std::endl;
}
// function to perform menu option B sub option 2
void optionB2()
{
std::cout << "perfoming B2" << std::endl;
}
// function to perform menu option A
void optionA()
{
std::cout << "perfoming A" << std::endl;
}
// defines a menu item. Good naming can often save the need to comment
struct menuitem
{
std::function<void()> doIt; // function to run if option chosen
std::string description; // pretty message describing option
};
// draw menu and wait for the user to select an option.
void domenu(const std::map<char, menuitem> & menu)
{
while (true) // loop until user gives a good option. Or use a retry count.
// You decide.
{
for (auto &items : menu)
{ // for all items in the menu, print out the item and it's description text
// for what first and second mean, read up on std::map and std::pair
std::cout << items.first << ") " << items.second.description << std::endl;
}
char ch;
std::cin >> ch; // get the user's choice
// often you may want to eliminate one of the cases to reduce the amount
// of possible inputs you need to provide handling code for.
// the line below allows us to use the same code for input of A and a.
ch = std::tolower(ch); // convert input to lower case
try
{
menu.at(ch).doIt(); // call the function mapped to user's choice.
// this may do produce something or it may
// display another menu. It could end the wor--
return; // done.
}
catch (...)
{ // print error message on unsupported input
std::cout << "Error. Invalid option!" << std::endl;
}
}
}
// the B menu
std::map<char, menuitem> bmenu
{ // User input doIt function Description
{'1', {optionB1, "Option B1"}},
{'2', {optionB2, "Option B2"}}
// add more options here. Or don't. Up to you.
};
// the main menu
std::map<char, menuitem> mainmenu
{ // User input doIt function Description
{'a', {optionA, "Option A"}},
{'b', {std::bind(domenu, bmenu), "Option B"}}
// OK, so that last one was a bit weird. std::bind makes a function and
// specifies the arguments with which it will be called. This takes
// domenu binds it with bmenu so that std::function<void()> is
// satisfied. As far as the world is concerned, the bound function
// returns nothing and takes no parameters. Very complicated functions
// can be bound so long as the end result returns nothing and requires
// no parameters.
// what it's doing here is allowing us to call domenu to draw the B
// submenu, wait for valid input, and call the chosen function.
};
// good 'ol trusty main so we can test that the above code isn't utter BS.
int main()
{
while (true) // loop forever. Or use whatever exit logic is required.
{
domenu(mainmenu); // kick-start by calling do menu to run the main menu
}
return(0);
}
This will keep the code down to a minimum. All of the duplicated code is reduced to the domenu function and a smurfload of code hidden from sight in the standard library and written by folks who likely have far more experience in getting this stuff right than you or I. Whenever possible, stand on the shoulders of giants.
domenu is driven by lists of options and execution instructions for the option. Want another option? Add an item to a list and possibly provide a new function to fulfill the obligations of that option.
All you have to do is fill in the blanks.
Related
I have a loop running that displays data read from a serial port on a console screen, the same screen lists some options for the user, such as the option to enter a file name that data would be logged to, or exit. The user presses the required key to enter the desired option.
After the key press and the option function entered any key presses can be ignored/discarded but I am not able to find a way to discard the key presses/ clear the cin buffer resulting in the key press being shown on the console.
Is there any way to clear the cin buffer without the user having to take any action? Or possibly some better way to provide the same functionality?
A stripped down version of code here:
(this should display the local time while giving the user the option to enter a "file name" or exit, no serial port stuff included)
#include <iostream>
#include <limits>
#include <chrono>
#include <windows.h>
using namespace std;
// global variables
char SavedFileName[20];
HANDLE hConsole;
CONSOLE_SCREEN_BUFFER_INFO csbi;
// functions
void GetTime(void){
char buffer [20];
time_t now = time(NULL);
strftime(buffer , 20, "%H:%M:%S %d/%m/%Y", localtime(&now));
cout << "local time: " << buffer << endl;
}
bool is1keypressed(void){
if(GetAsyncKeyState(49) & 0x8000){
return true;
}
return false;
}
bool is9keypressed(void){
if(GetAsyncKeyState(57) & 0x8000){
return true;
}
return false;
}
int ClearConsole(void){
hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
SMALL_RECT scrollRect;
COORD scrollTarget;
CHAR_INFO fill;
// Get the number of character cells in the current buffer.
if (!GetConsoleScreenBufferInfo(hConsole, &csbi))
return 0;
// Scroll the rectangle of the entire buffer.
scrollRect.Left = 0;
scrollRect.Top = 0;
scrollRect.Right = csbi.dwSize.X;
scrollRect.Bottom = csbi.dwSize.Y;
// Scroll it upwards off the top of the buffer with a magnitude of the entire height.
scrollTarget.X = 0;
scrollTarget.Y = (SHORT)(0 - csbi.dwSize.Y);
// Fill with empty spaces with the buffer's default text attribute.
fill.Char.UnicodeChar = TEXT(' ');
fill.Attributes = csbi.wAttributes;
// Do the scroll
ScrollConsoleScreenBuffer(hConsole, &scrollRect, NULL, scrollTarget, &fill);
return 0;
}
int main(){
bool exit = false;
// clear the console
ClearConsole();
// main loop
while(!exit){
// Move the cursor to the top left corner too.
csbi.dwCursorPosition.X = 0;
csbi.dwCursorPosition.Y = 0;
SetConsoleCursorPosition(hConsole, csbi.dwCursorPosition);
// prints the local time each on iteration of loop
GetTime();
// user options
cout << "\npress (1) enter file name - saved file name is: " << SavedFileName;
cout << "\npress (9) to exit." << endl;
// test user options
if(is1keypressed()){
cout << "option 1 - press ENTER to proceed " << endl;
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
bool validentry = false;
while(!validentry){
cout << "Enter a file name, max 19 characters: ";
cin.getline(SavedFileName, 20, '\n');
if(cin.fail()){
validentry = false;
cout << endl << "File name is too large, enter 19 characters or less. " << endl;
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
}else
validentry = true;
}
ClearConsole();
}
exit = is9keypressed();
}
cout << "\n end program" << endl;
return 0;
}
I have experimented with cin.ignore, this leaves the user to press Enter to proceed. Without cin.ignore the user has to delete the "option" characters themselves.
Okay, Windows console stuff. Only works on Windows.
Playing with this stuff is never as easy as advertised, but for what you want to do, we can make some pretty stripped-down Windows-only code. (If, at some future point, you wish to port to Linux, the design here can be pretty easily swapped-out for similar code on Linux.)
Minimal Windows Console Functions
#include <ciso646>
#include <utility>
#include <windows.h>
namespace console
{
inline auto hStdIn () { return GetStdHandle( STD_INPUT_HANDLE ); }
inline auto hStdOut() { return GetStdHandle( STD_OUTPUT_HANDLE ); }
auto CSBI()
{
CONSOLE_SCREEN_BUFFER_INFO _csbi;
GetConsoleScreenBufferInfo( hStdOut(), &_csbi );
return _csbi;
}
void clear_screen()
// Function
// Clears the screen to blanks using the current text color and puts the
// cursor in the upper-left cell.
{
DWORD _count;
DWORD _cell_count;
COORD _home_coords = { 0, 0 };
auto _csbi = CSBI();
_cell_count = _csbi.dwSize.X * _csbi.dwSize.Y;
if (!FillConsoleOutputCharacter( hStdOut(), (TCHAR)' ', _cell_count, _home_coords, &_count )) return;
if (!FillConsoleOutputAttribute( hStdOut(), _csbi.wAttributes, _cell_count, _home_coords, &_count )) return;
SetConsoleCursorPosition( hStdOut(), _home_coords );
}
void goto_xy( int x, int y )
// Function
// Position the text cursor on the screen.
//
// Arguments
// x - column coordinate, starting at zero from the left.
// y - row coordinate, starting at zero from the top.
{
COORD _coords = { (SHORT)x, (SHORT)y };
SetConsoleCursorPosition( hStdOut(), _coords );
}
bool is_key_pressed( int timeout_ms = 0 )
// Function
// Wait for key input to become available.
//
// Argument
// The maxiumum amount of time to wait, expressed in milliseconds.
// May also be one of the following:
// 0 - return immediately.
// -1 - wait indefinitely.
//
// Returns
// true : If key input is available
// false : If not
{
auto is_key_event_waiting = []()
{
DWORD _n;
INPUT_RECORD _rec;
while (PeekConsoleInputW( hStdIn(), &_rec, 1, &_n) and _n)
{
if (_rec.EventType != KEY_EVENT) continue;
if (_rec.Event.KeyEvent.bKeyDown) return true;
if ((_rec.Event.KeyEvent.wVirtualKeyCode == VK_MENU) and _rec.Event.KeyEvent.uChar.UnicodeChar)
return true;
ReadConsoleInputW( hStdIn(), &_rec, 1, &_n );
}
return false;
};
// Get rid of all unwanted events
if (is_key_event_waiting()) return true;
// Else wait until event available or timeout
if (WaitForSingleObject( hStdIn(), (DWORD)timeout_ms ) != WAIT_OBJECT_0) return false;
// We only want key events
return is_key_event_waiting();
}
char32_t read_key()
// Function
// Wait for and return the next key input available.
//
// Returns
// 0 : next read_key() returns a Windows Virtual Key Code, like `VK_F1` or `VK_UP`
// Unicode code point : any normal input key
{
static char32_t _vkey = 0;
if (_vkey) return std::exchange( _vkey, 0 );
DWORD _n;
INPUT_RECORD _rec;
while (true)
{
ReadConsoleInputW( hStdIn(), &_rec, 1, &_n );
if (_rec.EventType == KEY_EVENT)
{
// Key release events for the ALT/MENU key where UnicodeChar != 0
// means an Alt-code was entered on the numeric keypad. We'll report that.
// All other key release events are ignored.
if (!_rec.Event.KeyEvent.bKeyDown)
if ((_rec.Event.KeyEvent.wVirtualKeyCode != VK_MENU) or !_rec.Event.KeyEvent.uChar.UnicodeChar)
continue;
// Normal Unicode code point
if (_rec.Event.KeyEvent.uChar.UnicodeChar)
return _rec.Event.KeyEvent.uChar.UnicodeChar;
// Special keys and function keys
_vkey = _rec.Event.KeyEvent.wVirtualKeyCode;
return 0;
}
}
}
} // namespace console
Notes:
It works on both the Windows Terminal and on both current and past versions of the Windows Console.
There is no initialization or finalization necessary to use this particular magic.
Assumes a human is present. More robust code would check that the standard streams are attached to a console/terminal at initialization and complain (and quit) if not.
Only one thread should ever be messing with the console, so if you are doing anything multi-threaded, only console:: from one of them, ever. (This is pretty much true of any user-application UI.)
Your program, updated
#include <ctime>
#include <iostream>
#include <string>
std::string SavedFileName;
void DrawMenu(){
console::clear_screen();
console::goto_xy(0, 1);
std::cout << "\npress (1) enter file name - saved file name is: " << SavedFileName;
std::cout << "\npress (9) to exit.\n";
}
void DrawTime(){
char buffer [20];
time_t now = time(NULL);
strftime(buffer , 20, "%H:%M:%S %d/%m/%Y", localtime(&now));
console::goto_xy(0, 0);
std::cout << "local time: " << buffer << " ";
}
int main(){
DrawMenu();
bool done = false;
while(!done){
DrawTime();
if (console::is_key_pressed(500))
switch (console::read_key()){
case '1':
console::goto_xy(0, 5);
std::cout << "option 1\nEnter a file name: ";
getline(std::cin, SavedFileName);
DrawMenu();
break;
case '9':
console::goto_xy(0, 5);
std::cout << "option 2\nReally quit (y/[n])? ";
{
auto c = console::read_key();
if (!c) console::read_key();
else done = (c == 'y') or (c == 'Y');
}
if (!done) DrawMenu();
break;
case 0:
// Ignore special and function keys
console::read_key();
break;
}
}
std::cout << "\n\nGood-bye\n";
}
Notes:
I tend to alphabetize #includes, which makes it easier when the list gets long. Also, <chrono> is for time-based C++ functions, but you use the C date-time stuff from <ctime>. Be careful to include the correct headers.
It is a good idea to get used to writing std:: in front of everything. It is generally a bad idea to simply dump the entire Standard Library into your program’s namespace[citation needed].
Strings in C++ are, in general, best handled with the std::string class. Please use it. It’ll make your life infinitely easier.
The Draw*() functions are carefully organized to work together. This requires you to have a good idea of how your output is going to look.
DrawMenu() clears the screen and draws only the menu options
DrawTime() only draws the time
We do not clear the display every frame. Clearing the console is an expensive operation, often producing a noticeable blink. Avoid it if possible. In our case, we only want to update the time every frame, and redraw everything only after we have finished with some user interaction.
The frame rate is set by how long we are willing to wait for input to be available. In this example I choose 500 ms, which is a reasonably snappy response time. Avoid going below 150–250 ms, as that bogs the processor down with your wait loop. (This is why we don’t use _kbhit() from <conio.h>.)
Be careful with names. The way you name things makes a difference.
DrawTime() is a better name than GetTime() because it better informs you what it is doing — drawing the time for the user. It doesn’t actually get (and return) the time (to the caller).One way to think about it is that the fact that getting the time is a subtask of showing the time.
done is a better name than exit because it is a nominative state, not an action. (And also because it does not clash with the Standard Library exit() function name.)
The general rule of thumb is to use nouns for objects and verbs for functions.
Commentary should only exist to clarify code, not to describe it. For example, commentary in the console:: namespace describes how user functions are to be used. The only commentary in the main program reminds us why we are calling console::get_key() again, which is otherwise non-obvious.
Compiling and running the code is as easy as concatenating the two code-blocks together and running it through the compiler.
MSVC
cl /EHsc /W4 /Ox /std=c++17 example.cpp /D_CRT_SECURE_NO_WARNINGS
Clang (or MinGW)
clang++ -Wall -Wextra -Werror -pedantic-errors -O3 -std=c++17 example.cpp -o example.exe -D_CRT_SECURE_NO_WARNINGS
I'm trying to make a basic console menu using switch-case with C++. Said menu gives the option to select between different filters implemented using opencv. I'm fairly new to both opencv and C++, so I'm sure the code could be more efficent or nicely implemented.
Part of the code for the menu looks like:
void updateMenu(void){
cin >> opc;
switch (opc)
{
case 1:
cout << "Media \n";
media(image, res1, 5);
imshow("Media", res1);
break;
While the main looks like:
int main(){
image = imread("image.jpg", IMREAD_GRAYSCALE);
menu();
while (open)
{
updateMenu();
}
return 0;
}
menu() prints the options. open is a boolean defaulted to true that changes to false when 0 is pressed.
media is declared:
void media(Mat& imagen, Mat& returnMat, int var)
being the first Mat the source, the second one the destiny where the result will be saved to, and var the value for the median filter.
This code results in this image. As seen, it displays a grey screen with nothing on it. If I change the main to contain only the code inside the main (shown below) the image will be filtered, resulting in this.
int main()
{
image = imread("image.jpg", IMREAD_GRAYSCALE);
media(image, res1, 5);
imshow("Media", res1);
waitKey(0);
return 0;
}
I'm trying to understand what the error might be. No error messages are shown. Is there something wrong about using switch cases this way, or is there a more effective way of doing the same menu without switch?
Thanks!
UPDATE
I found my mistake. For anyone facing similar issues, all I had to do is turn the boolean open to false before the switch case, and turn it true again after.
Also, I had to create and later destroy a window:
case 1:
cout << "Media \n";
media(image, aux, 5);
hconcat(image, aux, res);
namedWindow("Media", WINDOW_AUTOSIZE);
imshow("Media", res);
waitKey(0);
destroyWindow("Media");
break;
If I understand well what you want, or what problem you have,
obviously your opc variable(you did not provide type of it in your code sample), after you entered its value and press enter, has no value 1 which is of type int, so code for 1 case, is not executed. When you call Media func directly with var=5, it all goes well, so clearly, case 1 is missed.
Sometimes we did not entered value and pressed enter, when we have no clear console message what is expected to be done.
So, to be sure, what is happening, try to change your code to something like this
void updateMenu(void) {
cout << "please enter 1 for filter 5, or any other value and press enter\n";
cin >> opc; // we can suppose that opc is declared out side
switch (opc)
{
case 1:
cout << "Media \n";
media(image, res1, 5);
imshow("Media", res1);
break;
Recently I've been working on an inventory system for a text-based game that uses a global array for the inventory system and a corresponding function to read true or false in said array. The problem I've run into is this, the function I'm using to modify the array
void playerGet(bool items[], int itemNumber) //this function takes an assigned argument of the array indices variable, and changes that array indices from true, to false.
{
items[itemNumber] = true;
}
only modifies the array within the scope of the function its housed in. The array is defined in a .cpp file like this:
void inventoryArray(bool items[]) //This function establishes all the items in the game, the true false statement expresses whether or not the item is in the player's inventory.
{
items[WEAPON_RELIC_RIFLE] = false;
items[WEAPON_SCALPEL] = false;
items[MISC_ACTION_FIGURE] = false;
items[MISC_FIRE_EXTINGUISHER] = false;
items[MISC_LIFE_RAFT] = false;
}
and is then declared in a .h file like this:
void inventoryArray(bool items[]);
the enums used in the array are defined in a header file like this:
enum equipment //This declares a list of enums for each item in the game, consumables, not included.
{
WEAPON_RELIC_RIFLE, // = 0
WEAPON_SCALPEL, // = 1
MISC_ACTION_FIGURE, // = 2
MISC_FIRE_EXTINGUISHER, // = 3
MISC_LIFE_RAFT, // = 4
MAX_EQUIPMENT
};
the function that reads the inventory array is this:
void twoScavengerCombat(bool items[])
{
for (int item = 0; item < MAX_EQUIPMENT; ++item)
{
if (items[item] == true) //if true proceed
{
switch (item)
{
case 0: //if array indices identifier = 0, print relic rifle
cout << "1: Use the Relic Rifle\n";
break;
case 1:
cout << "2: Use the Scalpel\n";
break;
case 2:
break;
case 3:
cout << "3: Use the Fire Extingusher\n";
break;
case 4:
cout << "4: Use the Life Raft\n";
break;
default:
cout << "Error";
break;
}
}
else
cout << "Option Unavailible\n"; //if false print Option Unavailible
}
compiled, with the array and enums headers declared the main file would look like this:
int toolSearch()
{
bool items[MAX_EQUIPMENT];
inventoryArray(items);
playerGet(items, 0);
}
void twoScavengerCombat(bool items[])\\ declared in this file, but since its just above here i left it as a forward declaration to save space
int main()
{
toolSearch();
twoScavengerCombat(items);
return 0;
}
Ideally this would produce the result: Use Relic Rifle
Option Unavailable
Option Unavailable
Option Unavailable
Option Unavailable
but instead it produces 5 Option Unavailable's. What am I missing?
You would want
//bunch of #include<> directives
bool items[MAX_EQUIPMENT];
int toolSearch()
{
inventoryArray();
playerGet( 0);
}
void twoScavengerCombat()
...
// other functions here
int main()
{
toolSearch();
twoScavengerCombat();
return 0;
}
Note that bool items[MAX_EQUIPMENT]; is not defined in a function. It is off on it's own at the top of the file in plain view of anything defined below it. This is what it means to be global. Anyone and everyone can access it, if they know where it is or you tell them where it is with an extern statement. It is created when the program starts (even before main and that can cause some really fun debugging if the initialization logic of the variable is faulty) and dies only when the program does.
Lightness Races in Orbit delves a bit deeper here, but is more concerned with making a global variable extend past a single file
There is no need to pass items into any function because everyone can see items The downside is there is one and only one items so if you have multiple players each with different item lists, you're going to have problems.
You might want to look into std::vector (resizable array) and std::map (which will allow you to look items up by name items["sword"].attackFoe(foe);) and std::set (which makes it really easy to see what a player has (if (items.find("Vorpal Hand Grenade") != items.end()) BlowStuffUp();) rather than having to search through each item every time.
I am willing to write a code of a tennis score keeper in C++ that keeps track of the score, but there are 2 problems that occur when I run the program:
I can't quit the loop with while(cin!="q")
The functions wouldn't initialize the variables
#include<iostream>
#include<string>
using namespace std;
int points1=0, points2=0;
int set1=0, set2=0;
int games1=0, games2=0;
string in="";
void score(int point,int set,int game);
int main()
{
do
{
cout<<"POINTS: "<<points1<<":"<<points2<<endl<<"SETS: "<<set1<<":"<<set2<<endl<<"GAMES: "<<games1<<":"<<games2<<endl;
cout<<"Who scored - player 1 or player 2? (p1/p2) : ";
cin>>in;
if(in=="p1")
{
void score(int points1,int set1,int games1);
}
else if(in=="p2")
{
void score(int points2,int set2,int games2);
}
else {cout<<endl<<"Error!"<<endl<<endl;}
}
while(cin!="q");
system("pause");
return 0;
}
void score(int& point,int& set,int& game){
if(set<5)
{
switch(point)
{
case '30':
point=point+10;
case '40':
set++;
point=0;
default:
point=point+15;
}
}
else game++;
}
while(cin!="q");
should be
while(in!="q");
In your function, your switch is on an integer value, so your cases should use an integer value as well:
case '30':
should be
case 30:
The others as well.
This is a function prototype:
void score(int points1,int set1,int games1);
This is a function call:
score(points1,set1,games1);
Make sure you have function calls where you want to execute the function. You have a lot of prototypes where they don't belong.
Some Tennis tips: you need to be two points ahead to win a set, two sets ahead to win a match. You may want to take that into account in your functions. Points and sets of a single player will not be enough to decide who won a set or game.
Edit:
In addition, if you want variables you pass to a function to change outside of this function, you need to pass them by reference.
void score(int& points1, int& set1, int& games1);
Note the ampersands.
Passing parameters to a function will make a [b]copy[/b] of the parameters. This is refered to as pass-by-value, because the value is passed. You can pass-by-reference, which means you don't create a copy but instead pass the location of the actual variable. Changes to it will then be reflected back to your main program.
You want an infinite while loop with a break, also get rid of type defs in function calls -- something like:
while (true) {
cin >> in;
if (in == "p1") {
score(points1, set1, games1);
}
else if (in == "p2") {
score(points2, set2, games2);
}
else if (in == "q") {
break;
} else {
cout << endl << "Error!" << endl << endl;
}
}
The following line is wrong: while(cin!="q");
Instead of cin you need to use in!="q"
The second issue is because you're calling the function in the wrong way.
When you call a function, you just write its name and pass the specified arguments, you don't need to write the function return type when calling it. Also you don't need to specify the types of the arguments you're passing. Your function call should be :
score(points2, set2, games2)
And finally you're switching on an integer, so your cases should check for integers.
I am trying to make a C++ Button class in which the user inputs a function to execute when the button is pressed. So far, this is my code:
class Button {
public:
char* text;
void* buttonclick();
Button (char* constext, void* consbuttonclick()) {
text = constext;
//What do I do here?
}
};
I am trying to make the constructor pass on the value of consbuttonclick() to buttonclick(). I believe there is a way to do this using function pointers, but I have been having trouble with them, so I would greatly appreciate some help on how to proceed.
What you've declared is a function returning a void *. You want a pointer to function returning void. So to start with you need to change the prototype: In place of void * foo() you want void (*foo)(). (You'll have to sort out exactly what you want, but that's the idea.)
Once you have it, you call it simply by using the function invocation operator (), so you'l get something like
class Button {
public:
char* text;
void* buttonclick();
Button (char* constext, void(* consbuttonclick())) {
text = constext;
consbuttonclick();
}
};
Better yet, though, is to create what's called a functor class, like:
class ClickFunctor {
public:
void doIt(){
// code
}
}
then pass a ClickFunctor object.
class Button {
public:
char* text;
Button (char* constext, ClickFunctor cf) {
text = constext;
cf.doIt();
}
};
Now, go read the C++ FAQ book on these things. (Update: Marshall calls these things "functionoids" rather than "functors", just to warn you.)
Sorry to burst your bubble, but there's no sane way of doing that. Function names only exist for easy writing. As soon as the compiler gets hold of them, the names become garbled and then turned into function addresses only. The names (at least in C++) are meaningless at runtime.
Your best bet is either a long chain of if / else statements OR possibly a dictionary that maps a string to a function pointer. But you'd have to set up that dictionary manually.
Look, if you are trying to make a button in a c++ ms-dos window, it can't be done unless you have a library that I don't about. But I found a way around that (which is long but gets the job done). What I did was I found the top left position of a button drawn out with simple cout<<"whatevergoeshere";, and the bottom right. Then, by creating a function that returns true when the left button is pressed and if the click is within the arguments provided for the top left corner and bottom right corner, control will move on. It is a pretty complicated process, but I can give you the source code I used in another answer.
(If you wan't me to explain any of this code, I will. I didn't know how to do this either until recently. One thing that is important though is keeping the window in the same place everytime. In the environment I'm using (code::blocks), the window stays in the same place, but moving it can mess up the button. Also remember to continuosly use the system("cls"); to clear the screen so stuff doesn't change position. (system"cls" is located in the cstdio or cstdlib libraries.)
Here is the code I used:
#include <iostream>
#include <windows.h>
#include <cstdlib>
#include <cstdio>
#include <stdio.h>
#ifndef MOUSE_HWHEELED
#define MOUSE_HWHEELED 0x0008
#endif
using namespace std;
int main()
{
POINT point;
HANDLE csbiHandle;
CONSOLE_SCREEN_BUFFER_INFO csbi;
int counter = 0;
DWORD cNumRead, i,fdwMode, fdwSaveOldMode;
INPUT_RECORD irInputBuffer[128];
HANDLE stdHandle;
stdHandle = GetStdHandle(STD_INPUT_HANDLE);
MOUSE_EVENT_RECORD mer;
cout << "|-------------|" << endl
<< "| A |" << endl
<< "|-------------|" << endl;
buttonpress:
ReadConsoleInput(stdHandle, irInputBuffer,128, &cNumRead);
GetCursorPos(&point);
for(i=0; i<cNumRead; i++)
{
switch(irInputBuffer[i].EventType)
{
case MOUSE_EVENT:
{
mer = irInputBuffer[i].Event.MouseEvent;
if(mer.dwButtonState == FROM_LEFT_1ST_BUTTON_PRESSED)
{
cout << "left button press" << endl;
cout << point.x << " " << point.y << endl;
if(point.x>=16&&point.x<=182&&point.y>=30&&point.y<=63){cout << "You clicked A!!" << endl;}
}
else
{
goto buttonpress;
}
break;
}
default:{
printf("unknown\n");
break;}
}
}
goto buttonpress;
return 0;
}