Eingabemaske für die Konsole
-
Salve,
da hier ab und an komplexe Eingaben in der Konsole gemacht werden sollen, habe ich mich mal drangesetzt, und versucht, ein Hilfsmittel dafür zu schreiben.
Es ist sicher weder vollständig noch fehlerfrei, aber Ihr seid aufgerufen, es weiterzuentwickeln.
Test:#include "eingabe.h" #include <iostream> int main() { eingabe::inFeld inName("Name", 20); eingabe::inFeld inVname("Vorname", 20); eingabe::inFeld inStrasse("Strasse", 20); eingabe::inFeld inOrt("Ort", 20); { eingabe::inMask mask; mask.addFeld(&inName); mask.addFeld(&inVname); mask.addFeld(&inStrasse); mask.addFeld(&inOrt); mask.setPositions(); mask.showMask(); } ConsoleFunctions::ClearScreen(); std::cout << "Eingegeben wurde: \n" << inName.getInhalt() << '\n' << inVname.getInhalt() << '\n' << inStrasse.getInhalt() << '\n' << inOrt.getInhalt() << '\n'; }
Es werden ein paar Felder vom Typ inFeld erstellt, der Konstruktor braucht mindestens einen Bezeichner und eine Feldlänge.
Dann wird eine Maske inMask erstellt, der die Adressen der Felder hinzugefügt werden. setPositions errechnet anhand der Felderanzahl ein paar Positionen (können auch mittels inFeld-Methode von Hand gesetzt werden).
showMask zeigt dann die Felder an, man kann sie editieren, die Enter-Taste wechselt von Feld zu Feld, und die Eingabe beendet wird durch die ENDE-Taste auf der PC-Tastatur.
Die eingegebenen Werte können dann mit der inFeld-Methode getInhalt ausgelesen werden.Die Header-Datei:
#ifndef eingabe_h #define eingabe_h #include <windows.h> #include <string> #include <vector> #include <clocale> namespace someHelpers { std::string rTrim(const std::string &in); std::string lTrim(const std::string &in); std::string trim(const std::string &in); } namespace ConsoleFunctions { void DruckSimpleText(int x, int y, char const *text); void invert(int spalte,int zeile, int anz); void SetTextAttributes(int x, int y, int zahl, WORD attrib); WORD GetTextAttribute(int x, int y); void SetCursorPosition(int x, int y); void ClearScreen(void); void SetWindowExt(int x, int y, int yMulti = 1); } namespace eingabe { enum taste { PGDWN = 401, PGUP, INSERT = 501, BCKSPC, ENTF, CSRLFT = 601, CSRRGT, CSRUP, CSRDWN, ENDE, ESC, RETURN }; class inFeld { public: inFeld(std::string bezeichnung, unsigned groesse, std::string inhalt = ""); virtual ~inFeld(){} void show() const; int bearbeite(); void setPosition(int spalte, int reihe){x = spalte; y = reihe;} int getSpace() const {return space;} void setSpace(int s){if(s > nam.size() + len + 1) space = s;} std::string getInhalt() const {return value;} protected: virtual bool zeichenErlaubt(int zeichen) const; private: std::string value; std::string nam; int x; int y; int len; int space; void invert() const; int holZeichen() const; int pruefZeichen(int c) const; int verarbeite(int c, int pos); }; class inMask { public: inMask() : c(80), r(25){} virtual ~inMask(){} void addFeld(inFeld *feld){felder.push_back(feld);} void setPositions() const; void showMask() const; protected: private: std::vector<inFeld*> felder; unsigned c; unsigned r; void bearbeite() const; }; } #endif
und die Implementierung:
#include <conio.h> #include "eingabe.h" using namespace someHelpers; using namespace ConsoleFunctions; using namespace std; namespace someHelpers { string rTrim(const string &in) { if(in.empty()) return in; string res(in); size_t i; for(i = res.size(); i > 0; --i) if(!isspace(res[i - 1])) break; if(i < res.size()) res.erase(i); return res; } string lTrim(const string &in) { if(in.empty()) return in; string res(in); size_t i; for(i = 0; i < res.size(); ++i) if(!isspace(res[i])) break; return res.erase(0, i); } string trim(const string &in) { return(lTrim(rTrim(in))); } } namespace ConsoleFunctions { void SetWindowExt(int x, int y, int yMulti) { SMALL_RECT sr_window = {0, 0, x - 1, y - 1}; COORD extension; CONSOLE_SCREEN_BUFFER_INFO csbi; GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi); extension.X = max(x, csbi.dwMaximumWindowSize.X); extension.Y = max(y, csbi.dwMaximumWindowSize.Y); SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), extension); SetConsoleWindowInfo(GetStdHandle(STD_OUTPUT_HANDLE), TRUE, &sr_window); extension.X = x; extension.Y = y * yMulti; SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), extension); } void ClearScreen(void) { CONSOLE_SCREEN_BUFFER_INFO csbi; COORD target = {0, 0}; DWORD written; GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi); FillConsoleOutputCharacter(GetStdHandle(STD_OUTPUT_HANDLE), ' ', csbi.dwSize.X * csbi.dwSize.Y, target, &written); FillConsoleOutputAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7, csbi.dwSize.X * csbi.dwSize.Y, target, &written); SetCursorPosition(0, 0); } void SetCursorPosition(int x, int y) { COORD pos = {x, y}; SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos); } WORD GetTextAttribute(int x, int y) { COORD target; DWORD gelesen; WORD attrib; target.X = x; target.Y = y; ReadConsoleOutputAttribute(GetStdHandle(STD_OUTPUT_HANDLE), &attrib, 1, target, &gelesen); return attrib; } void SetTextAttributes(int x, int y, int zahl, WORD attrib) { COORD target; DWORD written; WORD *buffer; int i; buffer = new WORD[zahl]; for (i = 0; i < zahl; i++) buffer[i] = attrib; target.X = x; target.Y = y; WriteConsoleOutputAttribute(GetStdHandle(STD_OUTPUT_HANDLE), buffer, zahl, target, &written); delete[] buffer; } void DruckSimpleText(int x, int y, char const *text) { COORD target = {x, y}; DWORD written; WriteConsoleOutputCharacter(GetStdHandle(STD_OUTPUT_HANDLE), text, strlen(text), target, &written); } void invert(int spalte,int zeile, int anz) { WORD attrib_alt, attrib_neu; attrib_alt = GetTextAttribute(spalte, zeile); attrib_neu = (attrib_alt & 0xFF00) | ((attrib_alt & 0xF) << 4) | ((attrib_alt & 0xF0) >> 4); SetTextAttributes(spalte, zeile, anz, attrib_neu); } } namespace eingabe { inFeld::inFeld(string bezeichnung, unsigned groesse, string inhalt) : value(inhalt), nam(trim(bezeichnung)), x(0), y(0), len(groesse) { value.resize(groesse, ' '); space = nam.size() + 2 + groesse; } void inFeld::show() const { string txt = nam + ':'; DruckSimpleText(x, y, txt.c_str()); DruckSimpleText(x + space - len, y, value.c_str()); } int inFeld::bearbeite() { invert(); int pos = 0; bool go = true; int zeichen; while(go) { SetCursorPosition(x + pos + space - len, y); zeichen = holZeichen(); switch(zeichen) { case 0: break; case CSRLFT: if(pos) --pos; break; case CSRRGT: if(pos < len - 1) ++pos; break; case ENDE: case RETURN: go = false; break; default: pos = verarbeite(zeichen, pos); show(); if(pos == len) pos = 0; } } invert(); return zeichen; } bool inFeld::zeichenErlaubt(int zeichen) const { if(zeichen >= 'a' && zeichen <= 'z') return true; if(zeichen >= 'A' && zeichen <= 'Z') return true; if(zeichen >= '0' && zeichen <= '9') return true; switch(zeichen) { case CSRLFT: case CSRRGT: case RETURN: case ENDE: case BCKSPC: case ENTF: case ' ': case 132: case 148: case 129: case 142: case 153: case 154: return true; } return false; } int inFeld::verarbeite(int c, int pos) { switch(c) { case BCKSPC: if(!pos) return pos; --pos; case ENTF: value.erase(pos, 1); value.push_back(' '); break; default: if(pos < len) value[pos++] = c; break; } return pos; } int inFeld::holZeichen() const { int zeichen = getch() & 0xFF; if (zeichen == 224) { zeichen = getch(); switch (zeichen) { case 82 : zeichen = INSERT; break; case 83 : zeichen = ENTF; break; case 75 : zeichen = CSRLFT; break; case 77 : zeichen = CSRRGT; break; case 72 : zeichen = CSRUP; break; case 80 : zeichen = CSRDWN; break; case 79 : zeichen = ENDE; break; case 81 : zeichen = PGDWN; break; case 73 : zeichen = PGUP; break; default : zeichen = NULL; } } else switch (zeichen) { case 8 : zeichen = BCKSPC; break; case 27 : zeichen = ESC; break; case 13 : zeichen = RETURN; } zeichen = pruefZeichen(zeichen); return (zeichen); } void inFeld::invert() const { WORD attrib_alt, attrib_neu; int myX = x + space - len; attrib_alt = GetTextAttribute(myX, y); attrib_neu = (attrib_alt & 0xFF00) | ((attrib_alt & 0xF) << 4) | ((attrib_alt & 0xF0) >> 4); SetTextAttributes(myX, y, len, attrib_neu); } int inFeld::pruefZeichen(int c) const { if(zeichenErlaubt(c)) return c; else return 0; } void inMask::setPositions() const { int anz = felder.size() * 2; int first = (r - anz) / 2; int maxSpace = 0; for(int i = 0; i < felder.size(); ++i) { felder[i]->setPosition(2, first + 2 * i); if(felder[i]->getSpace() > maxSpace) maxSpace = felder[i]->getSpace(); } for(int i = 0; i < felder.size(); ++i) felder[i]->setSpace(maxSpace); } void inMask::showMask() const { SetWindowExt(c, r); ClearScreen(); for(int i = 0; i < felder.size(); ++i) felder[i]->show(); bearbeite(); } void inMask::bearbeite() const { int i = 0; int result; do { result = felder[i]->bearbeite(); if(result == RETURN) { ++i; if(i >= felder.size()) i = 0; } }while(result != ENDE); } }