Improving my code

This is a discussion on Improving my code within the C++ Programming forums, part of the General Programming Boards category; I have created a class to allow user input of multiple variables, displaying each prompt ont the screen at once ...

  1. #1
    Master of Puppets rwmarsh's Avatar
    Join Date
    Feb 2006
    Location
    Texas
    Posts
    96

    Improving my code

    I have created a class to allow user input of multiple variables, displaying each prompt ont the screen at once and allowing the user to 'tab' between each prompt and 'enter' to record all the input into variables. Here is the code :
    Code:
    File : ConsoleIOBox.h
    #ifndef IOBOX_H_INCLUDED
    #define IOBOX_H_INCLUDED
    
    #include <string>
    #include <windows.h>
    #include <iostream>
    #include <conio.h>
    
    typedef enum { // System key codes
        ENTER       = 13,    BACKSPACE   = 8,     TAB         = 9,
        CTRL_TAB    = 404,   ESC         = 27,    UP_ARROW    = 328,
        DOWN_ARROW  = 336,   LEFT_ARROW  = 331,   RIGHT_ARROW = 333,
        PAGE_UP     = 329,   PAGE_DOWN   = 337,   F1          = 315,
        F2          = 316,   F3          = 317,   F4          = 318,
        F5          = 319,   F6          = 320,   F7          = 321,
        F8          = 322,   F9          = 323,   F10         = 324,
        F11         = 325,   F12         = 326
    } SYSTEMKEYCODES;
    
    
    typedef struct {
        short X, // X and
              Y, // Y coords for the start position of the box
              Z; // length (in characters) of the box
    } BOXCOORDS;
    
    
    class ConsoleInputBox {
        public :  // Functions
            ConsoleInputBox() {};
            ~ConsoleInputBox() {};
            void SetBox(const BOXCOORDS, const std::string, const char, const char);
            std::string Display();
            std::string Display(const std::string);
            std::string Read();
            wchar_t Get(SYSTEMKEYCODES);
        
        private :  // Functions
            static int GetCode() {
                int ch = getch();
                if ( ch == 0 || ch == 224 ) ch = 256 + getch();
                return ch;
            }
            void RemoveTrailingSpaces(std::string&);
            
        private :  // Variables
            BOXCOORDS box_coords;
            short current_x_pos;
            char front_border,
                 rear_border;
            std::string title;
    };
    
    // Set the Coords, Prompt message, and border characters for the box
    void ConsoleInputBox::SetBox(const BOXCOORDS set_coords,
                                 const std::string s,
                                 const char front,
                                 const char rear ) {
        box_coords    = set_coords;
        title         = s;
        front_border  = front;
        rear_border   = rear;
        return;
    }
    
    // Display the box
    std::string ConsoleInputBox::Display() {
        HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
        COORD Position;
          Position.X = ( (box_coords.X - 1) - title.length() );
          Position.Y = box_coords.Y;
          SetConsoleCursorPosition(hOut, Position);
        std::string space(box_coords.Z, ' ');
        std::string str = title + front_border + space + rear_border;
        return str;
    }
    
    // Display the box with optional information already in the box
    std::string ConsoleInputBox::Display(const std::string s) {
        std::string s2 = s;
        HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
        COORD Position;
          Position.X = ( (box_coords.X - 1) - title.length() );
          Position.Y = box_coords.Y;
          SetConsoleCursorPosition(hOut, Position);
        std::string space( (box_coords.Z - s.length() ), ' ');
        if (s.length() > box_coords.Z)
            s2 = s.substr(0, box_coords.Z);
        std::string str = title + front_border + s2 + space + rear_border;
        return str;
    }
    
    // Read the information from the box into a variable
    std::string ConsoleInputBox::Read() {
        char tempchar[box_coords.Z];
        std::string tempstring;
        COORD Position;
        DWORD NumRead;
        HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
        Position.X = box_coords.X; Position.Y = box_coords.Y;
          ReadConsoleOutputCharacter(hOut, tempchar, box_coords.Z, 
                                     Position, &NumRead);
        tempstring.assign(tempchar, 0, box_coords.Z);
        std::string space(tempstring.size(), ' ');
        if (tempstring == space)
            tempstring.clear();
        else
            RemoveTrailingSpaces(tempstring);
        return tempstring;
    }
    
    // Get user input into the box
    wchar_t ConsoleInputBox::Get(SYSTEMKEYCODES syscodes) {
        HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
        COORD Position;
          Position.X = box_coords.X;
          Position.Y = box_coords.Y;
        SetConsoleCursorPosition(hOut, Position);
        int current_x_pos = 0;
        bool loop = true;
        const int length = ( (box_coords.X + box_coords.Z) - 1);
        char ch;
        wchar_t wch;
        while(loop) {
            wch = GetCode();
            if (wch >= 32 && wch <= 126) {
                if (current_x_pos < box_coords.Z) {
                    ch = wch;
                    std::cout<<ch;
                    ++current_x_pos;
                }
            } else switch (wch) {
                 case LEFT_ARROW :
                     if (current_x_pos > 0) {
                         current_x_pos--;
                         Position.X = (box_coords.X + current_x_pos);
                         SetConsoleCursorPosition(hOut, Position);
                     }
                     break;
                 case RIGHT_ARROW :
                     if (current_x_pos < box_coords.Z) {
                         current_x_pos++;
                         Position.X = (box_coords.X + current_x_pos);
                         SetConsoleCursorPosition(hOut, Position);
                     }
                     break;
                 case BACKSPACE :
                     if (current_x_pos > 0) {
                         std::cout<<"\b \b";
                         current_x_pos--;
                     }
                     break;
                 default :
                     loop = false;
                     break;
            }
        }
        return wch;
    }
    
    // Remove the trailing spaces in the variable
    void ConsoleInputBox::RemoveTrailingSpaces(std::string& str) {
        std::string::size_type length = str.length();
        std::string::iterator iter;
        for (iter = (str.end() - 1); iter != str.begin(); --iter) {
            if (*iter == ' ')
                --length;
            else
                break;
        }
        str.assign(str, 0, length);
        return;
    }
        
    #endif
    and a small program to test it :
    Code:
    #include "iobox.h"
    #include <iostream>
    #include <string>
    #include <vector>
    
    using namespace std;
    
    int main() {
        // Create an instance of the ConsoleInputBox
        ConsoleInputBox cBox;
    
        // Create typedef's for the box coords and system key codes
        BOXCOORDS BoxCoords;
        SYSTEMKEYCODES SysCodes;
    
        // Create a vector to hold the ConsoleInputBoxes and an iterator
        //    to access them
        vector<ConsoleInputBox> Boxes;
        vector<ConsoleInputBox>::iterator iter;
    
        // Load vector with coords for the three ConsoleInputBoxes
        BoxCoords.X = 15;
        BoxCoords.Y = 0;
        BoxCoords.Z = 15;
          cBox.SetBox(BoxCoords, "First Name ", '[', ']');
          Boxes.push_back(cBox);
        BoxCoords.X = 15;
        BoxCoords.Y = 1;
        BoxCoords.Z = 15;
          cBox.SetBox(BoxCoords, "Middle Name ", '[', ']');
          Boxes.push_back(cBox);
        BoxCoords.X = 15;
        BoxCoords.Y = 2;
        BoxCoords.Z = 20;
          cBox.SetBox(BoxCoords, "Last Name  ", '[', ']');
          Boxes.push_back(cBox);
    
        // Display the three ConsoleInputBoxes
        for (iter = Boxes.begin(); iter != Boxes.end(); ++iter) {
            cout<<iter->Display() <<endl;
        }
        
        // User enters information into the ConsoleInputBoxes here
        //   User can TAB between the boxes or ENTER to read the 
        //    information typed in into variables and exit out
        iter = Boxes.begin();
        wchar_t option;
        bool loop = true;
        do {
            option = iter->Get(SysCodes);
            switch (option) {
                case TAB :
                    ++iter;
                    if (iter == Boxes.end() )
                        iter = Boxes.begin();
                    break;
                case ENTER :
                    loop = false;
                    break;
            }
        } while (loop);
        
        // Display what the user typed in, just to make sure it worked
        iter = Boxes.begin();
        string first = iter->Read();
        ++iter;
        string middle = iter->Read();
        ++iter;
        string last = iter->Read();
        cout<<"\n\n\n\n\n" <<first <<" " <<middle <<" " <<last;
        
        cin.get();
        return 0;
    }
    I've been playing with this for a while now and I was wondering if there was any way I can improve on it (less code, better syntax, ect...)
    The one thing I don't like is the use of <iostream> in the header. I have been looking for another way to do this and have toyed with the WriteConsole function but have not been able to make it work.
    Thanks for any suggestions

    Oh, and in case you were wondering about all the codes in the SYSTEMKEYCODES enum, thats so I can use this with any other program I create and to allow flexability in choosing what keys the user can hit to get different results. For instance, I might want to use 'enter' to tab around, 'F8' to save and 'F3' to exit out and not save......
    Using DEV-C++ Under Windows XP
    +------------------------------+

    "No! Do, or Do Not. There is no Try..."

  2. #2
    ZuK
    ZuK is offline
    Registered User
    Join Date
    Aug 2005
    Location
    Austria
    Posts
    1,990
    Since this is C++ you don't need the typedef on your struct BOXCOORDS
    I would give it a constructor
    Code:
    struct BOXCOORDS {
        BOXCOORDS( int x, y, z ):X(x),Y(y),Z(z) {}
        short X, // X and
              Y, // Y coords for the start position of the box
              Z; // length (in characters) of the box
    };
    this way you could call the functions that take BOXCOORDS as a parameter with a temporary object like this.
    Code:
    cBox.SetBox(BOXCOORDS(15,1,15), "Middle Name ", '[', ']');
    BTW: I don't like struct or classnames with all uppercase characters ( just a matter of taste )
    Kurt

  3. #3
    Registered User
    Join Date
    Jan 2005
    Posts
    7,317
    >> char tempchar[box_coords.Z];
    This code is illegal in C++ even though some compilers allow it as an extension. To make your code more portable, consider switching that to a vector. When you call ReadConsoleOutputCharacter with the vector, pass it with &tempchar[0] and it should work the same.

    Your RemoveTrailingSpaces function could be done more easily with find_last_not_of and substr.

  4. #4
    Master of Puppets rwmarsh's Avatar
    Join Date
    Feb 2006
    Location
    Texas
    Posts
    96
    OK, That simplifies things a bit. I remember reading about that somewhere, but did not think about it.
    I also added a bit of error checking in the SetBox function and managed to get rid of the <iostream> in the header, here are the revisions :
    Code:
    header file
    #ifndef IOBOX_H_INCLUDED
    #define IOBOX_H_INCLUDED
    
    #include <string>
    #include <windows.h>
    #include <conio.h>
    
    typedef enum { // System key codes
        ENTER       = 13,    BACKSPACE   = 8,     TAB         = 9,
        CTRL_TAB    = 404,   ESC         = 27,    UP_ARROW    = 328,
        DOWN_ARROW  = 336,   LEFT_ARROW  = 331,   RIGHT_ARROW = 333,
        PAGE_UP     = 329,   PAGE_DOWN   = 337,   F1          = 315,
        F2          = 316,   F3          = 317,   F4          = 318,
        F5          = 319,   F6          = 320,   F7          = 321,
        F8          = 322,   F9          = 323,   F10         = 324,
        F11         = 325,   F12         = 326
    } SYSTEMKEYCODES;
    
    
    struct BOXCOORDS {
        BOXCOORDS() {}; // Default constructor
        BOXCOORDS(int x, int y, int z):X(x),Y(y),Z(z) {} //constructor to load coords
        int X, // X and
            Y, // Y coords for the start position of the box
            Z; // length (in characters) of the box
    };
    
    
    class ConsoleInputBox {
        public :  // Functions
            ConsoleInputBox() {};
            ~ConsoleInputBox() {};
            bool SetBox(const BOXCOORDS, const std::string, const char, const char);
            std::string Display();
            std::string Display(const std::string);
            std::string Read();
            wchar_t Get(SYSTEMKEYCODES);
        
        private :  // Functions
            static int GetCode() {
                int ch = getch();
                if ( ch == 0 || ch == 224 ) ch = 256 + getch();
                return ch;
            }
            void RemoveTrailingSpaces(std::string&);
            
        private :  // Variables
            BOXCOORDS box_coords;
            short current_x_pos;
            char front_border,
                 rear_border;
            std::string title;
    };
    
    // Set the Coords, Prompt message, and border characters for the box
    bool ConsoleInputBox::SetBox(const BOXCOORDS set_coords,
                                 const std::string s,
                                 const char front,
                                 const char rear ) {
        HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
        COORD ConsoleSize = GetLargestConsoleWindowSize(hOut);
        // Error checking for coord out-of-bounds
        int left_side    = set_coords.X - s.length(),
            right_side   = set_coords.X + set_coords.Z;
        if (left_side >= 0    && right_side <= ConsoleSize.X &&
            set_coords.Y >= 0 && set_coords.Y <= ConsoleSize.Y) {
                box_coords    = set_coords;
                title         = s;
                front_border  = front;
                rear_border   = rear;
                return true;
        } else {
            // Display error message
            std::string str = "Prompt \'" + s + "\' puts coordinates past margin!!";
            COORD pos;
              pos.X = 0; pos.Y = 0;
            LPDWORD NumWritten;
            WriteConsoleOutputCharacter(hOut, "ERROR!!", 7, pos, NumWritten);
            ++pos.Y;
            WriteConsoleOutputCharacter(hOut, str.c_str(), str.length(), 
                                        pos, NumWritten);
            getch();
            return false;
        }
    }
    
    // Display the box
    std::string ConsoleInputBox::Display() {
        HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
        COORD Position;
          Position.X = ( (box_coords.X - 1) - title.length() );
          Position.Y = box_coords.Y;
          SetConsoleCursorPosition(hOut, Position);
        std::string space(box_coords.Z, ' ');
        std::string str = title + front_border + space + rear_border;
        return str;
    }
    
    // Display the box with optional information already in the box
    std::string ConsoleInputBox::Display(const std::string s) {
        std::string s2 = s;
        HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
        COORD Position;
          Position.X = ( (box_coords.X - 1) - title.length() );
          Position.Y = box_coords.Y;
          SetConsoleCursorPosition(hOut, Position);
        std::string space( (box_coords.Z - s.length() ), ' ');
        if (s.length() > box_coords.Z)
            s2 = s.substr(0, box_coords.Z);
        std::string str = title + front_border + s2 + space + rear_border;
        return str;
    }
    
    // Read the information from the box into a variable
    std::string ConsoleInputBox::Read() {
        char tempchar[box_coords.Z];
        std::string tempstring;
        COORD Position;
        DWORD NumRead;
        HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
        Position.X = box_coords.X; Position.Y = box_coords.Y;
          ReadConsoleOutputCharacter(hOut, tempchar, box_coords.Z, 
                                     Position, &NumRead);
        tempstring.assign(tempchar, 0, box_coords.Z);
        std::string space(tempstring.size(), ' ');
        if (tempstring == space)
            tempstring.clear();
        else
            RemoveTrailingSpaces(tempstring);
        return tempstring;
    }
    
    // Get user input into the box
    wchar_t ConsoleInputBox::Get(SYSTEMKEYCODES syscodes) {
        HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
        LPDWORD NumWritten;
        COORD Position;
          Position.X = box_coords.X;
          Position.Y = box_coords.Y;
        SetConsoleCursorPosition(hOut, Position);
        int current_x_pos = 0;
        bool loop = true;
        const int length = ( (box_coords.X + box_coords.Z) - 1);
        char ch;
        wchar_t wch;
        while(loop) {
            wch = GetCode();
            if (wch >= 32 && wch <= 126) {
                if (current_x_pos < box_coords.Z) {
                    ch = wch;
                    WriteConsole(hOut, &ch, 1, NumWritten, NULL);
                    ++current_x_pos;
                }
            } else switch (wch) {
                 case LEFT_ARROW :
                     if (current_x_pos > 0) {
                         current_x_pos--;
                         Position.X = (box_coords.X + current_x_pos);
                         SetConsoleCursorPosition(hOut, Position);
                     }
                     break;
                 case RIGHT_ARROW :
                     if (current_x_pos < box_coords.Z) {
                         current_x_pos++;
                         Position.X = (box_coords.X + current_x_pos);
                         SetConsoleCursorPosition(hOut, Position);
                     }
                     break;
                 case BACKSPACE :
                     if (current_x_pos > 0) {
                         WriteConsole(hOut, "\b \b", 3, NumWritten, NULL);  
                         current_x_pos--;
                     }
                     break;
                 default :
                     loop = false;
                     break;
            }
        }
        return wch;
    }
    
    // Remove the trailing spaces in the variable
    void ConsoleInputBox::RemoveTrailingSpaces(std::string& str) {
        std::string::size_type length = str.length();
        std::string::iterator iter;
        for (iter = (str.end() - 1); iter != str.begin(); --iter) {
            if (*iter == ' ')
                --length;
            else
                break;
        }
        str.assign(str, 0, length);
        return;
    }
        
    #endif
    and the updated part of the main :
    Code:
    int main() {
        // Create an instance of the ConsoleInputBox
        ConsoleInputBox cBox;
    
        // Create typedef's for the system key codes
        SYSTEMKEYCODES SysCodes;
    
        // Create a vector to hold the ConsoleInputBoxes and an iterator
        //    to access them
        vector<ConsoleInputBox> Boxes;
        vector<ConsoleInputBox>::iterator iter;
    
        // Load vector with coords for the three ConsoleInputBoxes
        if (cBox.SetBox(BOXCOORDS(15, 0, 150), "First Name  ", '[', ']') )
          Boxes.push_back(cBox);
        if (cBox.SetBox(BOXCOORDS(15, 1, 15), "Middle Name ", '[', ']') )
          Boxes.push_back(cBox);
        if (cBox.SetBox(BOXCOORDS(15, 2, 20), "Last Name   ", '[', ']') )
          Boxes.push_back(cBox);
    
        // Display the three ConsoleInputBoxes
        for (iter = Boxes.begin(); iter != Boxes.end(); ++iter) {
            cout<<iter->Display() <<endl;
        }
    ect....
    Thanks in advance for any other ideas, comments, criticism, approvals.....
    Using DEV-C++ Under Windows XP
    +------------------------------+

    "No! Do, or Do Not. There is no Try..."

  5. #5
    and the hat of wrongness Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    32,344
    > Z; // length (in characters) of the box
    Not exactly a meaningful name is it?

    > char tempchar[box_coords.Z];
    I don't think standard C++ supports var-arrays
    http://david.tribble.com/text/cdiffs.htm#C99-vla

    > case LEFT_ARROW :
    I think I would decouple the key from the action.
    So for example, you would have
    case PREV_FIELD:

    Then it becomes relatively easy to provide a simple translate function to convert key-codes into actions in a configurable way.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.
    I support http://www.ukip.org/ as the first necessary step to a free Europe.

  6. #6
    (?<!re)tired Mario F.'s Avatar
    Join Date
    May 2006
    Location
    Portugal
    Posts
    7,383
    Quote Originally Posted by Salem
    > char tempchar[box_coords.Z];
    I don't think standard C++ supports var-arrays
    It does not. Quiet surprising he was able to compile. MinGW (The OP seems to be using it) certainly doesn't allow it.

    EDIT: As a side note, I would perhaps review the option of using conio. If portability is not an issue, then by all means stick to it. But download conio2. If portability may be an issue, I'd suggest PDCurses. In fact I'd suggest PDCurses in any case
    Last edited by Mario F.; 07-01-2006 at 03:06 PM.
    The programmer’s wife tells him: “Run to the store and pick up a loaf of bread. If they have eggs, get a dozen.”
    The programmer comes home with 12 loaves of bread.


    Originally Posted by brewbuck:
    Reimplementing a large system in another language to get a 25% performance boost is nonsense. It would be cheaper to just get a computer which is 25% faster.

  7. #7
    Registered User
    Join Date
    Mar 2006
    Posts
    725
    Quite the contrary. GCC (ie. MinGW) is one of the few compilers which allow it. GCC will display a warning when -pedantic is set and stop compilation when -pedantic-errors is set.
    Code:
    #include <stdio.h>
    
    void J(char*a){int f,i=0,c='1';for(;a[i]!='0';++i)if(i==81){
    puts(a);return;}for(;c<='9';++c){for(f=0;f<9;++f)if(a[i-i%27+i%9
    /3*3+f/3*9+f%3]==c||a[i%9+f*9]==c||a[i-i%9+f]==c)goto e;a[i]=c;J(a);a[i]
    ='0';e:;}}int main(int c,char**v){int t=0;if(c>1){for(;v[1][
    t];++t);if(t==81){J(v[1]);return 0;}}puts("sudoku [0-9]{81}");return 1;}

  8. #8
    (?<!re)tired Mario F.'s Avatar
    Join Date
    May 2006
    Location
    Portugal
    Posts
    7,383
    True. Didn't know about that, since I compile with -pedantic on all the time. I apologize.
    However -pedantic alone will already issue an error, not a warning, under gcc 3.4.2 (MinGW).
    The programmer’s wife tells him: “Run to the store and pick up a loaf of bread. If they have eggs, get a dozen.”
    The programmer comes home with 12 loaves of bread.


    Originally Posted by brewbuck:
    Reimplementing a large system in another language to get a 25% performance boost is nonsense. It would be cheaper to just get a computer which is 25% faster.

  9. #9
    Master of Puppets rwmarsh's Avatar
    Join Date
    Feb 2006
    Location
    Texas
    Posts
    96
    > char tempchar[box_coords.Z];
    I don't think standard C++ supports var-arrays
    Did not even realize what I did I have been playing with this for a while now and I guess it got lost in the shuffle.... Anyway, I have been trying to fix this little oversight and have come to another problem. The ReadConsoleutputCharacter function that I have been using requires a LPTSTR as its second parameter, which as I understand is a pointer to a char array. If I use a variable of type LPTSTR then my compiler will not let me convert to a std::string (which is what the rest of the program uses). So if I just use a char array (as I did here) would it be better to use a const int to initialize it like this
    Code:
    std::string ConsoleInputBox::Read() {
        const int ArraySize = box_coords.Length;
        char tempchar[ArraySize];
        COORD Position;
        DWORD NumRead;
        HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
        Position.X = box_coords.X; Position.Y = box_coords.Length;
          ReadConsoleOutputCharacter(hOut, tempchar, box_coords.Length, 
                                     Position, &NumRead);
        std::string tempstring = tempchar;
        std::string space(tempstring.size(), ' ');
        if (tempstring == space)
            tempstring.clear();
        else
            RemoveTrailingSpaces(tempstring);
        return tempstring;
    }
    Or am I making it more difficult than it really is?
    Using DEV-C++ Under Windows XP
    +------------------------------+

    "No! Do, or Do Not. There is no Try..."

  10. #10
    and the hat of wrongness Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    32,344
    > std::string tempstring = tempchar;
    Does ReadConsoleOutputCharacter() always append a \0 ?

    > char tempchar[ArraySize];
    The normal way would be to have a fixed length buffer, and have a loop of some sort which reads characters until you've read all that you want.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.
    I support http://www.ukip.org/ as the first necessary step to a free Europe.

  11. #11
    Master of Puppets rwmarsh's Avatar
    Join Date
    Feb 2006
    Location
    Texas
    Posts
    96
    Since this is C++ you don't need the typedef on your struct BOXCOORDS
    I would give it a constructor
    Done.
    Your RemoveTrailingSpaces function could be done more easily with find_last_not_of and substr.
    Ok.
    > Z; // length (in characters) of the box
    Not exactly a meaningful name is it?
    No, its not... I renamed that one and a couple others.
    > case LEFT_ARROW :
    I think I would decouple the key from the action.
    So for example, you would have
    case PREV_FIELD:
    Not sure I understand completely but what I did instead was I created a separate enum that defines only the arrow keys and the backspace. These are the only keys that the function needs to operate. This way the caller can define whatever key in whatever way it wants to. I kept the original enum in as well so the caller can use it as a 'default'.
    > char tempchar[ArraySize];
    The normal way would be to have a fixed length buffer, and have a loop of some sort which reads characters until you've read all that you want.
    Instead of using a loop I just declared a string using the char[] to initialize it.

    as far as the <conio.h> goes, I am comfortable with it right now, but I am sure I will want to cange that in the future. I am looking int PDcurses now, as well as conio2 and some other things.

    Anything else would be apreciated. I am fairly confident with my knowledge of c++, its all the tricks and shortcuts I am trying to figure out.
    Updated code:
    Code:
    #ifndef IOBOX_H_INCLUDED
    #define IOBOX_H_INCLUDED
    
    #include <string>
    #include <windows.h>
    #include <conio.h>
    
    typedef enum { // System key codes
        ENTER       = 13,    BACKSPACE   = 8,     TAB         = 9,
        CTRL_TAB    = 404,   ESC         = 27,    UP_ARROW    = 328,
        DOWN_ARROW  = 336,   LEFT_ARROW  = 331,   RIGHT_ARROW = 333,
        PAGE_UP     = 329,   PAGE_DOWN   = 337,   F1          = 315,
        F2          = 316,   F3          = 317,   F4          = 318,
        F5          = 319,   F6          = 320,   F7          = 321,
        F8          = 322,   F9          = 323,   F10         = 324,
        F11         = 325,   F12         = 326
    } SYSTEMKEYCODES;
    
    
    struct BOXCOORDS {
        BOXCOORDS() {}; // Default constructor
        BOXCOORDS(int x, int y, int l):Xpos(x),Ypos(y),Length(l) {} //constructor to load coords
        int Xpos,   // X and
            Ypos,   // Y coords for the start position of the box
            Length; // length (in characters) of the box
    };
    
    
    class ConsoleInputBox {
        public :  // Functions
            ConsoleInputBox(char front, char rear):front_border(front),
                                                   rear_border(rear) {};
            ~ConsoleInputBox() {};
            bool SetBox(const BOXCOORDS, const std::string);
            std::string Display();
            std::string Display(const std::string);
            std::string Read();
            wchar_t Get();
        
        private :  // Functions
            static int GetCode() {
                int ch = getch();
                if ( ch == 0 || ch == 224 ) ch = 256 + getch();
                return ch;
            }
            void RemoveTrailingSpaces(std::string&);
            
        private :  // Variables
            BOXCOORDS box_coords;
            short current_x_pos;
            char front_border,
                 rear_border;
            std::string title;
    };
    
    // Set the Coords, Prompt message, and border characters for the box
    bool ConsoleInputBox::SetBox(const BOXCOORDS set_coords,
                                 const std::string s) {
        HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
        COORD ConsoleSize = GetLargestConsoleWindowSize(hOut);
        // Error checking for coord out-of-bounds
        int left_side    = set_coords.Xpos - s.length(),
            right_side   = set_coords.Xpos + set_coords.Length;
        if (left_side       >= 0             && 
            right_side      <= ConsoleSize.X &&
            set_coords.Ypos >= 0) {
                box_coords    = set_coords;
                title         = s;
                return true;
        } else {
            // Display error message
            std::string str = "Prompt \'" + s + "\' puts coordinates past margin!!";
            COORD pos;
              pos.X = 0; pos.Y = 0;
            LPDWORD NumWritten;
            WriteConsoleOutputCharacter(hOut, "ERROR!!", 7, pos, NumWritten);
            ++pos.Y;
            WriteConsoleOutputCharacter(hOut, str.c_str(), str.length(), 
                                        pos, NumWritten);
            getch();
            return false;
        }
    }
    
    // Display the box
    std::string ConsoleInputBox::Display() {
        HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
        COORD Position;
          Position.X = ( (box_coords.Xpos - 1) - title.length() );
          Position.Y = box_coords.Ypos;
          SetConsoleCursorPosition(hOut, Position);
        std::string space(box_coords.Length, ' ');
        std::string str = title + front_border + space + rear_border;
        return str;
    }
    
    // Display the box with optional information already in the box
    std::string ConsoleInputBox::Display(const std::string s) {
        std::string s2 = s;
        HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
        COORD Position;
          Position.X = ( (box_coords.Xpos - 1) - title.length() );
          Position.Y = box_coords.Ypos;
          SetConsoleCursorPosition(hOut, Position);
        std::string space( (box_coords.Length - s.length() ), ' ');
        if (s.length() > box_coords.Length)
            s2 = s.substr(0, box_coords.Length);
        std::string str = title + front_border + s2 + space + rear_border;
        return str;
    }
    
    // Read the information from the box into a variable
    std::string ConsoleInputBox::Read() {
        char chStr[100];
        COORD Pos;
        DWORD NumRead;
        HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
        Pos.X = box_coords.Xpos; Pos.Y = box_coords.Ypos;
          ReadConsoleOutputCharacter(hOut, chStr, box_coords.Length, Pos, &NumRead);
        std::string str(chStr, 0, box_coords.Length);
        std::string space(box_coords.Length, ' ');
        if (str == space)
            str.clear();
        else
            RemoveTrailingSpaces(str);
        return str;
    }
    
    // Get user input into the box
    wchar_t ConsoleInputBox::Get() {
        enum {
            _Key_BACKSPACE_   = 8,
            _KEY_LEFT_ARROW_  = 331,
            _KEY_RIGHT_ARROW_ = 333
        };
        HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
        LPDWORD NumWritten;
        COORD Position;
          Position.X = box_coords.Xpos;
          Position.Y = box_coords.Ypos;
        SetConsoleCursorPosition(hOut, Position);
        int current_x_pos = 0;
        bool loop = true;
        const int length = ( (box_coords.Xpos + box_coords.Length) - 1);
        char ch;
        wchar_t wch;
        while(loop) {
            wch = GetCode();
            if (wch >= 32 && wch <= 126) {
                if (current_x_pos < box_coords.Length) {
                    ch = wch;
                    WriteConsole(hOut, &ch, 1, NumWritten, NULL);
                    ++current_x_pos;
                }
            } else switch (wch) {
                 case _KEY_LEFT_ARROW_ :
                     if (current_x_pos > 0) {
                         current_x_pos--;
                         Position.X = (box_coords.Xpos + current_x_pos);
                         SetConsoleCursorPosition(hOut, Position);
                     }
                     break;
                 case _KEY_RIGHT_ARROW_ :
                     if (current_x_pos < box_coords.Length) {
                         current_x_pos++;
                         Position.X = (box_coords.Xpos + current_x_pos);
                         SetConsoleCursorPosition(hOut, Position);
                     }
                     break;
                 case _KEY_BACKSPACE_ :
                     if (current_x_pos > 0) {
                         WriteConsole(hOut, "\b \b", 3, NumWritten, NULL);  
                         current_x_pos--;
                     }
                     break;
                 default :
                     loop = false;
                     break;
            }
        }
        return wch;
    }
    
    // Remove the trailing spaces in the variable
    void ConsoleInputBox::RemoveTrailingSpaces(std::string& str) {
        std::string::size_type index = str.find_last_not_of (" " , str.length() );
        str.assign(str, 0, index + 1);
        return;
    }
        
    #endif
    Using DEV-C++ Under Windows XP
    +------------------------------+

    "No! Do, or Do Not. There is no Try..."

  12. #12
    Registered User
    Join Date
    Jan 2005
    Posts
    7,317
    >> Did not even realize what I did.
    That was what I was referring to in my post above. Switch to a vector. When you call ReadConsoleOutputCharacter with the vector, pass it with &tempchar[0] and it should work the same.

  13. #13
    Sanity is for the weak! beene's Avatar
    Join Date
    Jul 2006
    Posts
    321
    i thought that u had to get rid of the extension in C++ and place a c at the beginning of the word?
    example:
    Code:
    #include <windows.h> = #include <cwindows>

  14. #14
    (?<!re)tired Mario F.'s Avatar
    Join Date
    May 2006
    Location
    Portugal
    Posts
    7,383
    That is true for standard headers. But not for non-standard ones.
    The programmer’s wife tells him: “Run to the store and pick up a loaf of bread. If they have eggs, get a dozen.”
    The programmer comes home with 12 loaves of bread.


    Originally Posted by brewbuck:
    Reimplementing a large system in another language to get a 25% performance boost is nonsense. It would be cheaper to just get a computer which is 25% faster.

  15. #15
    Sanity is for the weak! beene's Avatar
    Join Date
    Jul 2006
    Posts
    321
    oh, right, my bad

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Improving Code Interface
    By helloamuro in forum C Programming
    Replies: 20
    Last Post: 05-02-2008, 04:34 AM
  2. Proposal: Code colouring
    By Perspective in forum A Brief History of Cprogramming.com
    Replies: 28
    Last Post: 05-14-2007, 07:23 AM
  3. Values changing without reason?
    By subtled in forum C Programming
    Replies: 2
    Last Post: 04-19-2007, 10:20 AM
  4. Interface Question
    By smog890 in forum C Programming
    Replies: 11
    Last Post: 06-03-2002, 05:06 PM
  5. Replies: 0
    Last Post: 02-21-2002, 05:05 PM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21