Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

xCite

Frischling

  • »xCite« ist der Autor dieses Themas

Beiträge: 77

Wohnort: Deutschland

Beruf: Berufsfachschüler

  • Private Nachricht senden

1

12.10.2007, 20:31

[Tutorial] Konsolen Funktionen

Konsolen Funktionen


So habe gedacht ich mache erstmal ein Tutorial für die einfacheren Funktionen der Konsolen Funktionen.

Und gleich vorweg: Das Projekt muss auf Multibyte gestellt sein, dies kann man ändern, indem man in Visual Studio auf das Projekt mit Rechtklick geht, dort auf Eigenschaften klickt und dann den Zeichensatz von Unicode in Multibyte setzt.


Variablen und Includes

Als erstes müssen wir ein Makro definieren um alle Funktionen nutzen zu können:

C-/C++-Quelltext

1
2
#undef _WIN32_WINNT
#define _WIN32_WINNT 0x0500


Als Include Dateien binden wir folgende Dateien ein:

C-/C++-Quelltext

1
2
#include <iostream>
#include <windows.h>


Nun müssen wir ein paar Variablen definieren, mit denen wir arbeiten werden. Als erstes brauchen wir ein Handle für den Output der Konsole, damit die Funktionen, die wir benutzen auch wissen, wo sie was tun sollen. Dazu erstellen wir eine Variable mit dem Makro HANDLE. Diese sollten wir gleich initialisieren, da HANDLE ein Zeiger ist. Dies geht mit der Funktion GetStdHandle, die sehr einfach zu verwenden ist. Die Funktionsdeklaration sieht so aus:

C-/C++-Quelltext

1
HANDLE GetStdHandle(DWORD nStdHandle);


Der Funktion müssen wir lediglich ein Makro übergeben. Folgende kommen in Frage:

STD_INPUT_HANDLE
STD_OUTPUT_HANDLE
STD_ERROR_HANDLE

Da wir den Output haben wollen, übergeben wir STD_OUTPUT_HANDLE.

C-/C++-Quelltext

1
HANDLE Output = GetStdHandle (STD_OUTPUT_HANDLE);


Als nächstes brauchen wir eine Variable von der Struktur CONSOLE_SCREEN_BUFFER_INFO, die Informationen zu dem Screen Buffer beinhält, wenn man sie initialisiert hat. Beispielsweise die Cursorposition. Die Variable wird mit der Funktion GetConsoleScreenBufferInfo initialisiert. Die Funktionsdeklaration sieht wie folgt aus:

C-/C++-Quelltext

1
BOOL GetConsoleScreenBufferInfo(HANDLE hConsoleOutput, PCONSOLE_SCREEN_BUFFER_INFO lpConsoleScreenBufferInfo);


Hier brauchen wir auch schon unser Output Handle, das Handle wird nähmlich als 1. Parameter übergeben. Als 2. Parameter brauchen wir hier nur unsere CONSOLE_SCREEN_BUFFER_INFO Variable zu übergeben.
Da wir die Variable öfters erneuern müssen, können wir auch gleich eine kleine Funktion dazu schreiben, die unter unsere 3 Variablen kommt. Das ganze sähe dann jetzt so aus:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
HANDLE Output = GetStdHandle (STD_OUTPUT_HANDLE);
CONSOLE_SCREEN_BUFFER_INFO csbi;
// Hier kommt gleich die 3. Variable hin


void RefreshCSBI (void)
{
    GetConsoleScreenBufferInfo (Output, &csbi);
}


Die 3. Variable ist von einer Struktur namens COORD. In dieser Struktur befinden sich lediglich 2 Variablen. Einmal X und einmal Y. Wie man sich denken kann, kann man damit ganz gut Position speichern und wir werden diese Struktur verwenden um unsere Cursor Position zu speichern und zu verändern. Diese Variable brauchen wir vorerst nicht initialisieren.

C-/C++-Quelltext

1
COORD CursorPosition;



Konsoleninhalt löschen

Um den Konsoleninhalt löschen zu können brauchen wir die Funktion FillConsoleOutputCharacter. Diese sieht so aus:

C-/C++-Quelltext

1
BOOL FillConsoleOutputCharacter(HANDLE hConsoleOutput, TCHAR cCharacter, DWORD nLength, COORD dwWriteCoord, LPDWORD lpNumberOfCharsWritten);


Als 1. Parameter übergeben wir hier natürlich unser Output Handle. Als 2. geben wir das Zeichen an, mit welchem wir die Konsole füllen wollen, dies ist hier natürlich ' ' (Leerzeichen). Als 3. Parameter übergeben wir die Größe des Fensters. Diese kriegen wir über unsere csbi Variable raus. Die Struktur besitzt eine Variable der Struktur COORD. Diese Variable heißt dwSize. Und da wir wissen, dass COORD 2 Variablen namens X und Y besitzt, können wir damit die Größe angeben. Einfach auf die X und Y Variablen zugreifen und beide * nehmen, dadurch geben wir die Größe des Fensters an. Als 4. Parameter übergeben wir die Position von wo die Funktion mit dem befüllen beginnen soll. Dazu brauchen wir eine COORD Variable, deshalb werden wir einfach die Cursor Variable verwenden. Als letztes müssen wir nur noch eine Variable vom Typen LPDWORD übergeben. Dies ist ein Zeiger auf vom Typen unsigned long. Dieser Parameter ist für uns eher irrelevant. Unsere Funktion sieht jetzt ungefähr so aus:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
void cls (void)
{
    CursorPosition.X = 0; // Cursor Poisitionsvariable definieren

    CursorPosition.Y = 0;
    unsigned long Count; // Die für uns eher irrelevante Variable ;)

    RefreshCSBI(); // Muss aktualisiert werden, wegen den Fensterkoordinaten

    FillConsoleOutputCharacter (Output, ' ', csbi.dwSize.X * csbi.dwSize.Y, CursorPosition, &Count);
    SetConsoleCursorPosition (Output, CursorPosition); // Als letztes Cursor zurücksetzen, aber dazu gleich mehr

}



Cursor positionieren

Den Cursor zu setzen ist wirklich einfach. Dazu verwenden wir die Funktion von eben SetConsoleCursorPosition. Diese Funktion ist folgendermaßen aufgebaut:

C-/C++-Quelltext

1
BOOL SetConsoleCursorPosition(HANDLE hConsoleOutput, COORD dwCursorPosition);


Als 1. Parameter übergeben wir wieder Output und als 2. die Koordinaten, wo der Cursor hingesetzt werden soll. Dazu verwenden wir unsere CursorPosition Variable. Die CursorPosition Variable wird von 2 Parametern in unserer Funktion initialisiert.

C-/C++-Quelltext

1
2
3
4
5
6
void SetCursorPosition (unsigned short x, unsigned short y)
{
    CursorPosition.X = x;
    CursorPosition.Y = y;
    SetConsoleCursorPosition (Output, CursorPosition);
}


Hier habe ich unsigned für die Parameter genommen, da die Variablen nicht unter 0 gehen und short, weil die übergebene Zahl immer sehr gering ausfallen wird.


Cursor Position ermitteln

Um die Cursor Position zu ermitteln brauch es auch nicht viel. Als erstes updaten wir unsere csbi Variable und holen uns daraus die Position des Cursors und speichern diese in unsere CursorPosition Variable. Diese wird dann via return zurückgegeben.

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
COORD GetCursorPosition (void)
{
    RefreshCSBI ();

    CursorPosition.X = csbi.dwCursorPosition.X;
    CursorPosition.Y = csbi.dwCursorPosition.Y;

    return CursorPosition;
}



Text- und Hintergrundfarbe setzen

Um die Text- und Hintergrundfarben zu setzen, benötigen wir die Funktion SetConsoleTextAttribute, die so aufgebaut ist:

C-/C++-Quelltext

1
BOOL SetConsoleTextAttribute(HANDLE hConsoleOutput, WORD wAttributes);


Als ersten wird wieder mal unser Handle übergeben, Output. Als 2. müssen wir ein Makro übergeben. Hier stehen folgende zur Auswahl:

Quellcode

1
2
3
4
5
6
7
8
FOREGROUND_BLUE
FOREGROUND_GREEN
FOREGROUND_RED
FOREGROUND_INTENSITY
BACKGROUND_BLUE
BACKGROUND_GREEN
BACKGROUND_RED
BACKGROUND_INTENSITY


FOREGROUND steht im Grunde für TEXT und BACKGROUND sollte klar sein. Dahinter steht dann die jeweilige Farbe, die sich auch durch | kombinieren lassen. Daraus formen wir uns jetzt ein paar Makros, die das ganze vereinfachen und übersichtlicher machen. Das Ganze kommt dann ganz an den Anfang unserer Datei direkt unter den Includes.

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// Textfarben

#define TEXT_BLUE               FOREGROUND_BLUE                // Blauer Text

#define TEXT_GREEN             FOREGROUND_GREEN               // Grüner Text

#define TEXT_RED                 FOREGROUND_RED                 // Roter Text

#define TEXT_TURQUOISE         TEXT_BLUE | TEXT_GREEN           // Türkiser Text

#define TEXT_PURPLE           TEXT_BLUE | TEXT_RED            // Lila Text

#define TEXT_YELLOW           TEXT_GREEN | TEXT_RED          // Gelber Text

#define TEXT_GREY               TEXT_BLUE | TEXT_GREEN | TEXT_RED // Grauer Text (Default)

#define TEXT_WHITE             TEXT_GREY | TEXT_INTENSIFY       // Weißer Text

#define TEXT_INTENSIFY         FOREGROUND_INTENSITY           // Intensivierter Text

#define TEXT_BLUE_INTENSIFY      TEXT_BLUE | TEXT_INTENSIFY     // Intensivierter blauer Text

#define TEXT_GREEN_INTENSIFY     TEXT_GREEN | TEXT_INTENSIFY       // Intensivierter grüner Text

#define TEXT_RED_INTENSIFY     TEXT_RED | TEXT_INTENSIFY         // Intensivierter roter Text

#define TEXT_TURQUOISE_INTENSIFY TEXT_TURQUOISE | TEXT_INTENSIFY   // Intensivierter türkiser Text

#define TEXT_PINK_INTENSIFY   TEXT_PURPLE | TEXT_INTENSIFY    // Intensivierter pinker Text

#define TEXT_YELLOW_INTENSIFY   TEXT_YELLOW | TEXT_INTENSIFY      // Intensivierter gelber Text


// Hintergrundfarben

#define BACK_BLUE               BACKGROUND_BLUE                // Blauer Hintergrund

#define BACK_GREEN             BACKGROUND_GREEN               // Grüner Hintergrund

#define BACK_RED                 BACKGROUND_RED                 // Roter Hintergrund

#define BACK_TURQUOISE         BACK_BLUE | BACK_GREEN           // Türkiser Hintergrund

#define BACK_PURPLE           BACK_BLUE | BACK_RED            // Lila Hintergrund

#define BACK_YELLOW           BACK_GREEN | BACK_RED          // Gelber Hintergrund

#define BACK_GREY               BACK_BLUE | BACK_GREEN | BACK_RED // Grauer Hintergrund

#define BACK_WHITE             BACK_GREY | BACK_INTENSIFY       // Weißer Hintergrund

#define BACK_INTENSIFY         BACKGROUND_INTENSITY           // Hintergrundfarbe intensivieren (verstärken)

#define BACK_BLUE_INTENSIFY   BACK_BLUE | BACK_INTENSIFY        // Intensivierter blauer Hintergrund

#define BACK_GREEN_INTENSIFY     BACK_GREEN | BACK_INTENSIFY       // Intensivierter grüner Hintergrund

#define BACK_RED_INTENSIFY     BACK_RED | BACK_INTENSIFY         // Intensivierter roter Hintergrund

#define BACK_TURQUOISE_INTENSIFY BACK_TURQUOISE | BACK_INTENSIFY   // Intensivierter türkiser Hintergrund

#define BACK_PINK_INTENSIFY   BACK_PURPLE | BACK_INTENSIFY    // Intensivierter rosa Hintergrund

#define BACK_YELLOW_INTENSIFY   BACK_YELLOW | BACK_INTENSIFY      // Intensivierter gelber Hintergrund


Die Funktion sieht jetzt wie folgt aus und es muss als 2. Parameter lediglich nur noch einer unserer Makros übergeben werden oder um Hintergrund + Textfarbe zu setzen können auch 2 mit | kombiniert werden.

C-/C++-Quelltext

1
2
3
4
void SetColor (unsigned short Color)
{
    SetConsoleTextAttribute (Output, Color);
}



Konsolentitel setzen

Um den Konsolentitel zu setzen brauchen wir mal wieder nicht viel. Lediglich die Funktion SetConsoleTitle und einen String, der über einen Parameter übergeben wird. Die Funktion SetConsoleTitle sieht so aus:

C-/C++-Quelltext

1
BOOL SetConsoleTitle(LPCTSTR lpConsoleTitle);


Und unsere Funktion dann so:

C-/C++-Quelltext

1
2
3
4
void SetTitle (const char* Title)
{
    SetConsoleTitle (Title);
}



Cursor Sichtbarkeit setzen

Um den Cursor anzuzeigen und auszublenden brauchen wir einmal eine Struktur namens CONSOLE_CURSOR_INFO und 2 Funktionen, nähmlich GetConsoleCursorInfo und SetConsoleCursorInfo. GetConsoleCursorInfo initialisiert unsere Variable von der Struktur und SetConsoleCursorInfo setzt dann unsere leicht veränderte Variable. Zuerst füllen wir unsere Variable mit GetConsoleCursorInfo und anschließend ändern wir den Wert von bVisible aus unserer Variablen via Parameter. Dort braucht dann nur noch TRUE oder FALSE der Funktion übergeben werden oder 0 für ausblenden und 1 für anzeigen. Am Ende unserer Funktion brauch dann nur noch unsere Variable neu gesetzt werden, womit der Cursor dann ein- oder ausgeblendet wird. Die Funktion sieht dann so aus:

C-/C++-Quelltext

1
2
3
4
5
6
7
void SetCursorVisibility (unsigned short Visible)
{
    CONSOLE_CURSOR_INFO CursorInfo;
    GetConsoleCursorInfo (Output, &CursorInfo);
    CursorInfo.bVisible = Visible;
    SetConsoleCursorInfo (Output, &CursorInfo);
}



Fenstergröße ändern

Die Fenstergröße ändert man mit der Funktion SetConsoleWindowInfo, die so aussieht:

C-/C++-Quelltext

1
BOOL SetConsoleWindowInfo(HANDLE hConsoleOutput, BOOL bAbsolute, const SMALL_RECT* lpConsoleWindow);


1. Parameter ist klar und der 2. Parameter gibt an, ob die Fenstergröße komplett verändert werden soll (TRUE) oder ob die angegeben Größe zu der momentanen Größe dazuaddiert werden soll (FALSE). Der 3. Parameter verlangt ein SMALL_RECT (eine Struktur), welches die Fenstergröße angibt. Die SMALL_RECT Variable wird folgendermaßen definiert und die Funktion folgendermaßen aufgerufen:

C-/C++-Quelltext

1
2
SMALL_RECT WindowSize = {0, 0, x, y}; // x und y sind übergebene Parameter

SetConsoleWindowInfo (Output, TRUE, &WindowSize);


Dazu müssen wir einen neuen Screen Buffer setzen, sonst hat die Änderung der Fenstergröße keine sonderlich großen Auswirkungen, da darin der Text ausgegeben wird. Um den Screen Buffer neu zu setzen brauchen wir eine COORD Variable und die Funktion SetConsoleScreenBufferSize, die so aufgebaut ist:

C-/C++-Quelltext

1
BOOL SetConsoleScreenBufferSize(HANDLE hConsoleOutput, COORD dwSize);


Als 2. Parameter übergeben wir unsere COORD Variable. Die Screen Buffer Größe muss immer mind. eine Zeile und ein Zeichen größer sein als die Fenster Größe. D.h. wir initialisieren unsere COORD Variable so und rufen so unsere Funktion auf:

C-/C++-Quelltext

1
2
COORD BufferSize = {x+1, y+1};
SetConsoleScreenBufferSize (Output, BufferSize);


Als Funktion sieht das ganze so aus:

C-/C++-Quelltext

1
2
3
4
5
6
7
void SetWindowSize (unsigned short x, unsigned short y)
{
    SMALL_RECT WindowSize = {0, 0, x, y};
    SetConsoleWindowInfo (Output, TRUE, &WindowSize);
    COORD BufferSize = {x+1, y+1};
    SetConsoleScreenBufferSize (Output, BufferSize);
}



Ein Zeichen aus der Konsole auslesen

Um ein vorhandenes Zeichen aus der Konsole auszulesen brauchen wir eine char Variable für das Zeichen, welches am Ende via return zurückgegeben wird, unsere CursorPosition Variable und eine unsigned long Variable um die gelesene Anzahl der Zeichen zu ermitteln, die gelesen worden, was wir aber im Grunde nicht benötigen. Um das Ganze dann zu verarbeiten benötigen wir die Funktion ReadConsoleOutputCharacter, die so aufgebaut ist:

C-/C++-Quelltext

1
BOOL ReadConsoleOutputCharacter(HANDLE hConsoleOutput, LPTSTR lpCharacter, DWORD nLength, COORD dwReadCoord, LPDWORD lpNumberOfCharsRead);


Als 2. Parameter übergeben wir unsere char Variable, als 3. die Länge der zu lesenden Zeichen, also 1, als 4. Parameter unsere CursorPosition Variable und als 5. unsere unsigned long Variable. Unsere Funktion sieht nun so aus:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
char ReadChar (unsigned short x, unsigned short y)
{
    char Character;
    CursorPosition.X = x;
    CursorPosition.Y = y;
    unsigned long length;

    ReadConsoleOutputCharacter (Output, &Character, 1, CursorPosition, &length);

    return Character;
}


Wenn wir die Funktion aufrufen, brauchen wir nur noch die Koordinaten angeben, wo sich das Zeichen befindet, welches wir auslesen wollen.


Alles zusammen + Sample

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#undef _WIN32_WINNT
#define _WIN32_WINNT 0x0500

#include <iostream>
#include <windows.h>

using std::cout; // Für die main, ist besser als using namespace std, da wir ja nur cout benötigen


// Textfarben

#define TEXT_BLUE                FOREGROUND_BLUE                   // Blauer Text

#define TEXT_GREEN               FOREGROUND_GREEN                  // Grüner Text

#define TEXT_RED                 FOREGROUND_RED                    // Roter Text

#define TEXT_TURQUOISE           TEXT_BLUE | TEXT_GREEN            // Türkiser Text

#define TEXT_PURPLE              TEXT_BLUE | TEXT_RED              // Lila Text

#define TEXT_YELLOW              TEXT_GREEN | TEXT_RED             // Gelber Text

#define TEXT_GREY                TEXT_BLUE | TEXT_GREEN | TEXT_RED // Grauer Text (Default)

#define TEXT_WHITE               TEXT_GREY | TEXT_INTENSIFY        // Weißer Text

#define TEXT_INTENSIFY           FOREGROUND_INTENSITY              // Intensivierter Text

#define TEXT_BLUE_INTENSIFY      TEXT_BLUE | TEXT_INTENSIFY        // Intensivierter blauer Text

#define TEXT_GREEN_INTENSIFY     TEXT_GREEN | TEXT_INTENSIFY       // Intensivierter grüner Text

#define TEXT_RED_INTENSIFY       TEXT_RED | TEXT_INTENSIFY         // Intensivierter roter Text

#define TEXT_TURQUOISE_INTENSIFY TEXT_TURQUOISE | TEXT_INTENSIFY   // Intensivierter türkiser Text

#define TEXT_PINK_INTENSIFY      TEXT_PURPLE | TEXT_INTENSIFY      // Intensivierter pinker Text

#define TEXT_YELLOW_INTENSIFY    TEXT_YELLOW | TEXT_INTENSIFY      // Intensivierter gelber Text


// Hintergrundfarben

#define BACK_BLUE                BACKGROUND_BLUE                   // Blauer Hintergrund

#define BACK_GREEN               BACKGROUND_GREEN                  // Grüner Hintergrund

#define BACK_RED                 BACKGROUND_RED                    // Roter Hintergrund

#define BACK_TURQUOISE           BACK_BLUE | BACK_GREEN            // Türkiser Hintergrund

#define BACK_PURPLE              BACK_BLUE | BACK_RED              // Lila Hintergrund

#define BACK_YELLOW              BACK_GREEN | BACK_RED             // Gelber Hintergrund

#define BACK_GREY                BACK_BLUE | BACK_GREEN | BACK_RED // Grauer Hintergrund

#define BACK_WHITE               BACK_GREY | BACK_INTENSIFY        // Weißer Hintergrund

#define BACK_INTENSIFY           BACKGROUND_INTENSITY              // Hintergrundfarbe intensivieren (verstärken)

#define BACK_BLUE_INTENSIFY      BACK_BLUE | BACK_INTENSIFY        // Intensivierter blauer Hintergrund

#define BACK_GREEN_INTENSIFY     BACK_GREEN | BACK_INTENSIFY       // Intensivierter grüner Hintergrund

#define BACK_RED_INTENSIFY       BACK_RED | BACK_INTENSIFY         // Intensivierter roter Hintergrund

#define BACK_TURQUOISE_INTENSIFY BACK_TURQUOISE | BACK_INTENSIFY   // Intensivierter türkiser Hintergrund

#define BACK_PINK_INTENSIFY      BACK_PURPLE | BACK_INTENSIFY      // Intensivierter rosa Hintergrund

#define BACK_YELLOW_INTENSIFY    BACK_YELLOW | BACK_INTENSIFY      // Intensivierter gelber Hintergrund


HANDLE Output = GetStdHandle (STD_OUTPUT_HANDLE);
CONSOLE_SCREEN_BUFFER_INFO csbi;
COORD CursorPosition;

void RefreshCSBI (void)
{
    GetConsoleScreenBufferInfo (Output, &csbi);
}

void cls (void)
{
    CursorPosition.X = 0;
    CursorPosition.Y = 0;
    unsigned long Count;
    RefreshCSBI();
    FillConsoleOutputCharacter (Output, ' ', csbi.dwSize.X * csbi.dwSize.Y, CursorPosition, &Count);
    SetConsoleCursorPosition (Output, CursorPosition);
}

void SetCursorPosition (unsigned short x, unsigned short y)
{
    CursorPosition.X = x;
    CursorPosition.Y = y;
    SetConsoleCursorPosition (Output, CursorPosition);
}

COORD GetCursorPosition (void)
{
    RefreshCSBI ();

    CursorPosition.X = csbi.dwCursorPosition.X;
    CursorPosition.Y = csbi.dwCursorPosition.Y;

    return CursorPosition;
}

void SetColor (unsigned short Color)
{
    SetConsoleTextAttribute (Output, Color);
}

void SetTitle (const char* Title)
{
    SetConsoleTitle (Title);
}

void SetCursorVisibility (unsigned short Visible)
{
    CONSOLE_CURSOR_INFO CursorInfo;
    GetConsoleCursorInfo (Output, &CursorInfo);
    CursorInfo.bVisible = Visible;
    SetConsoleCursorInfo (Output, &CursorInfo);
}

void SetWindowSize (unsigned short x, unsigned short y)
{
    SMALL_RECT WindowSize = {0, 0, x, y};
    SetConsoleWindowInfo (Output, TRUE, &WindowSize);
    COORD BufferSize = {x+1, y+1};
    SetConsoleScreenBufferSize (Output, BufferSize);
}

char ReadChar (unsigned short x, unsigned short y)
{
    char Character;
    CursorPosition.X = x;
    CursorPosition.Y = y;
    unsigned long length;

    ReadConsoleOutputCharacter (Output, &Character, 1, CursorPosition, &length);

    return Character;
}

int main (void)
{
    cls(); // Konsoleninhalt löschen

    SetCursorPosition (5, 5); // Cursor versetzen

    cout << "Cursor verschoben!";

    SetCursorPosition (5, 7);
    COORD Position = GetCursorPosition (); // Cursor Position auslesen

    cout << "Cursor an Position: x = " << Position.X << "; y = " << Position.Y;

    SetCursorPosition (5, 9);
    SetColor (TEXT_RED_INTENSIFY); // Textfarbe ändern

    cout << "Roter Text";

    SetTitle ("Konsolen Tutorial"); // Konsolentitel setzen

    SetWindowSize (120, 90); // Fenstergröße setzen

    SetCursorVisibility (FALSE); // Cursor ausblenden

    SetCursorPosition (5, 11);
    cout << "Titel gesetzt, Fenstergroesse veraendert und Cursor unsichtbar gemacht!";

    char Character = ReadChar (5, 11); // Zeichen auslesen (das T von "Titel gesetzt, ...")

    SetCursorPosition (5, 13);
    cout << "Char an Position x = 5; y = 11 ausgelesen. Ergebnis: " << Character;

    getchar();
    return 0;
}



Abschluss

So, ich hoffe ich konnte einigen helfen. Wer noch Wünsche für weitere Funktionen hat, kann sich gerne melden, werde dieses Tutorial dann möglichst schnell erweitern. Freue mich auch über Feedback, weil ich sicherlich noch ein paar dumme Fehler drin habe. Hoffe, dass meine Sätze alle sinnvoll sind, bei soviel Text kann ich auch schonmal durcheinander kommen, wenn das der Fall ist, dann bitte melden.

Dann kann ich den Leuten, mit denen ich durch dieses Tutorial geholfen habe nur noch viel Spaß wünschen und hoffe es war alles verständlich genug.
[01.10.2007 - 19:36:05] babelfish: weiss jemand einen Algo um witzige Sprüche zu erkennen? will das einbauen xD
[01.10.2007 - 19:36:07] |bubble|: War diese Frage ernst gemeint?!?

(Insider!) xD

P.S.: goto ruleZ! :D

SirForce

Alter Hase

Beiträge: 802

Wohnort: Süddeutschland

  • Private Nachricht senden

2

12.10.2007, 21:52

Sorry, ich konnte es noch nicht intensiv durchlesen sondern habs (vorerst) nur kurz überflogen, sieht bis jetzt aber ziemlich gut aus.

Nur ne Frage, sollte das nicht eigentlich unter die Kategorie Tutorials?!
Nichts behindert so sehr die Entwicklung der Intelligenz wie ihre vollständige Abwesenheit.

Michail Genin

3

12.10.2007, 22:04

1. Globale Variablen raus.
2. Es geht dich NICHTS an wie der User gerade _WIN32_WINNT definieren will!
3.

Zitat

Und gleich vorweg: Das Projekt muss auf Multibyte gestellt sein, dies kann man ändern, indem man in Visual Studio auf das Projekt mit Rechtklick geht, dort auf Eigenschaften klickt und dann den Zeichensatz von Unicode in Multibyte setzt.
... was wohl eindeutig auf deinen ("schlechten") Programmierstil zurück zu führen ist. Würdest du nicht unnötig typedefs auflösen usw. wäre das alles kein Problem.

C-/C++-Quelltext

1
BOOL SetConsoleTitle(LPCTSTR lpConsoleTitle);
und dann:

C-/C++-Quelltext

1
2
3
4
void SetTitle (const char* Title)
{
    SetConsoleTitle (Title);
}
...
viel besser:

C-/C++-Quelltext

1
2
3
4
5
namespace console
{
    void set_title(basic_string<TCHAR> const & title) { set_title(title.c_str()); }
    void set_title(LPCTSTR title) { if (::SetConsoleTitle(title) == FALSE) throw std::runtime_error("could not set console title"); }
};
...
4. Überleg mal bei GetCursorPosition, was csbi.dwCursorPosition für ein Type ist... wofür willst du die verdammten Daten noch in eine Globale Struktur packen?
5. Warum machst du da nicht einen Header draus(in dem dann using nicht vorkommt|_WIN32_WINNT < 0x0500 durch #pragma message abfangen ...) damit man es auch wiederverwenden kann?

Zitat

Nur ne Frage, sollte das nicht eigentlich unter die Kategorie Tutorials?!
Sollte man nicht erst die Beschreibung von etwas lesen bevor man es sich anguckt?!

usw ...
Devil Entertainment :: Your education is our inspiration
Der Spieleprogrammierer :: Community Magazin
Merlin - A Legend awakes :: You are a dedicated C++ (DirectX) programmer and you have ability to work in a team? Contact us!
Siedler II.5 RttR :: The old settlers-style is comming back!

Also known as (D)Evil

xCite

Frischling

  • »xCite« ist der Autor dieses Themas

Beiträge: 77

Wohnort: Deutschland

Beruf: Berufsfachschüler

  • Private Nachricht senden

4

12.10.2007, 22:18

1. Und was statt globalen Variablen? Es wurden nach Funktionen verlangt und das hier ist aus einer Klasse und immer die Variablen neu initialisieren halte ich hier eh für unnötig. Die Variablen speichern keine Texturen sondern lediglich kleine Werte und für Anfänger ist das in Ordnung denke ich.

2. Was soll das denn heißen? Ohne diese Definition kannst du bestimmte Funktionen nicht aufrufen und warum sollte das jemand höher definieren wollen, wenn das Programm doch auf möglichst vielen Systemen laufen soll?

3. Deine bessere Lösung ist aber nicht gerade Einsteigerfreundlich...

4. Weil COORD da passender ist

5. #pragma message kenn ich bisher nicht und Anfänger mit Sicherheit auch nicht...

[edit] @SirForce, schau mal in dem Forum "Tutorials" unter "Wichtig: Bitte lesen"[/edit]
[01.10.2007 - 19:36:05] babelfish: weiss jemand einen Algo um witzige Sprüche zu erkennen? will das einbauen xD
[01.10.2007 - 19:36:07] |bubble|: War diese Frage ernst gemeint?!?

(Insider!) xD

P.S.: goto ruleZ! :D

grek40

Alter Hase

Beiträge: 1 491

Wohnort: Dresden

  • Private Nachricht senden

5

12.10.2007, 22:35

Also ich hab jetzt noch nicht alles durchgelesen sondern eher stichprobenartig typische Probleme angeschaut... es gibt noch einiges zu verbessern, wenn das hier nen ordentliches Tut werden soll. Anfangen solltest du am besten gleich mit dem was Deviloper geschrieben hat.

zu 2.: zumindest solltest du ein #if !defined _WIN32_WINNT || _WIN32_WINNT < 0x0500
einsetzen bevor du mit #undef usw zuschlägst.

-------

Zu cls gehört mMn. auch ein Aufruf von FillConsoleOutputAttribute(...) damit beim Löschen die aktuelle Farbe gesetzt wird.


SetWindowSize hat einige Schnitzer drin.
1. Wo hast du das her, dass der Screenbuffer in Höhe und Breite +1 sein muss?

2. Bedenke, dass beim vergrößern des Fensters zuerst der Screenbuffer wachsen muss, beim verkleinern muss zuerst das Fenster schrumpfen. Denn wenn der Buffer zu klein für das Fenster wird dann gibt die Funktion einfach nen Fehler zurück und alles bleibt beim alten.


Wo wir grad bei Fehlern sind - es wäre das mindeste, die Funktionen auf Fehlschläge zu testen und per bool Rückgabewert dem Nutzer mitzuteilen wenn was schief ging.


*genug geschrieben fürs erste*

// €dit:
das mit 4. solltest du wirklich nochmal genauer anschaun

xCite

Frischling

  • »xCite« ist der Autor dieses Themas

Beiträge: 77

Wohnort: Deutschland

Beruf: Berufsfachschüler

  • Private Nachricht senden

6

12.10.2007, 22:40

Okay, werde es morgen noch einmal überarbeiten, hat sich schon deutlich freundlicher und konstruktiver angehört. ;) Danke.
[01.10.2007 - 19:36:05] babelfish: weiss jemand einen Algo um witzige Sprüche zu erkennen? will das einbauen xD
[01.10.2007 - 19:36:07] |bubble|: War diese Frage ernst gemeint?!?

(Insider!) xD

P.S.: goto ruleZ! :D

SirForce

Alter Hase

Beiträge: 802

Wohnort: Süddeutschland

  • Private Nachricht senden

7

12.10.2007, 23:13

Zitat

@SirForce, schau mal in dem Forum "Tutorials" unter "Wichtig: Bitte lesen"


Ok, tut mir leid... :roll: habe ich nicht gewusst. Danke für den Hinweis :D !!!
Nichts behindert so sehr die Entwicklung der Intelligenz wie ihre vollständige Abwesenheit.

Michail Genin

8

12.10.2007, 23:27

Zitat

4. Weil COORD da passender ist
Hmm vllt hat mein VC++2005 ne andere Implementierung als dein Compiler von der Struktur Aber bei mir ist csbi.dwCursorPosition vom Type COORD ... d.h. ist es vollkommen unnötig das alles erstmal noch in eine !globale! Struktur zu packen und dann eine Kopie zurück zu geben.

Zitat

, hat sich schon deutlich freundlicher und konstruktiver angehört.
Ehm. ok ist hätte etwas freundlicher sein können ... aber wenn du das alles umänderst, ist das sehr konstruktiv.

Zitat

1. Und was statt globalen Variablen? Es wurden nach Funktionen verlangt und das hier ist aus einer Klasse und immer die Variablen neu initialisieren halte ich hier eh für unnötig. Die Variablen speichern keine Texturen sondern lediglich kleine Werte und für Anfänger ist das in Ordnung denke ich.
Was ist das für eine lächerliche Begründung? :P Nee mal im ernst ... mach es raus und fertig ... bevor ich hier noch eine wirklich "unfreundliche" Artikulation wähle ...

Zitat

5. #pragma message kenn ich bisher nicht und Anfänger mit Sicherheit auch nicht...
... Dann kennst du es jetzt :P Ist ganz nützlich um bsw. in so einem Fall dem Benutzer deines Headers klar machen zu können, wo sein Fehler liegt, damit er sich nicht bei dir beschweren kommt ....

Zitat

3. Deine bessere Lösung ist aber nicht gerade Einsteigerfreundlich...
Na ok wenn du die Funktionsvariante mit std::basic_string<TCHAR> rauslässt ... dann schon ... und korrekt!.

Zitat

2. Was soll das denn heißen? Ohne diese Definition kannst du bestimmte Funktionen nicht aufrufen und warum sollte das jemand höher definieren wollen, wenn das Programm doch auf möglichst vielen Systemen laufen soll?
1. Steht es nicht zur Debatte warum das jemand machen will
2. Um bsw. Features der WinAPI zu nutzen, die nur unter noch höheren Windows-Versionen zur Verfügung stehen.
Devil Entertainment :: Your education is our inspiration
Der Spieleprogrammierer :: Community Magazin
Merlin - A Legend awakes :: You are a dedicated C++ (DirectX) programmer and you have ability to work in a team? Contact us!
Siedler II.5 RttR :: The old settlers-style is comming back!

Also known as (D)Evil

xCite

Frischling

  • »xCite« ist der Autor dieses Themas

Beiträge: 77

Wohnort: Deutschland

Beruf: Berufsfachschüler

  • Private Nachricht senden

9

12.10.2007, 23:36

Zitat

Hmm vllt hat mein VC++2005 ne andere Implementierung als dein Compiler von der Struktur Aber bei mir ist csbi.dwCursorPosition vom Type COORD ... d.h. ist es vollkommen unnötig das alles erstmal noch in eine !globale! Struktur zu packen und dann eine Kopie zurück zu geben.


Okay da hast du schonmal Recht.

Zitat

Ehm. ok ist hätte etwas freundlicher sein können ... aber wenn du das alles umänderst, ist das sehr konstruktiv.


War eher provokant als freundlich, trotzdem hilfreich. Aber je freundlicher, desto mehr geht jemand darauf ein, solltest du dir angewöhnen. ;)

Zitat

Was ist das für eine lächerliche Begründung? :P Nee mal im ernst ... mach es raus und fertig ... bevor ich hier noch eine wirklich "unfreundliche" Artikulation wähle ...


Schon wieder provokant, aber ich hasse normalerweise auch globale Variablen, aber was soll ich machen? So ist es deutlich einfacher für Einsteiger und sie lernen nicht alles gleich tausend mal in jeder Funktion neu zu definieren. Hätte sowieso alles in eine Klasse gepackt, aber es wurden halt Funktionen bevorzugt und damit ist global meiner Meinung sinvoller für Anfänger, auch wenn es unschöner ist. Und nenn mir einen Grund, warum ich in diesem Fall nicht mit globalen Variablen arbeiten sollte, außer, dass es unschön ist.

Zitat

... Dann kennst du es jetzt :P Ist ganz nützlich um bsw. in so einem Fall dem Benutzer deines Headers klar machen zu können, wo sein Fehler liegt, damit er sich nicht bei dir beschweren kommt ....


Gut sollte nicht sonderlich schwer sein, werde ich morgen einbauen und erklären, aber ist wieder etwas neues für Anfänger und dieses Kapitel der Programmierung ist für Einsteiger sicherlich nicht gerade einfach.

Zitat

Na ok wenn du die Funktionsvariante mit std::basic_string<TCHAR> rauslässt ... dann schon ... und korrekt!.


Werd morgen nochmal schauen, wie ich es Einsteigerfreundlich und sauber gestalten kann.

Zitat

1. Steht es nicht zur Debatte warum das jemand machen will
2. Um bsw. Features der WinAPI zu nutzen, die nur unter noch höheren Windows-Versionen zur Verfügung stehen.


Ich weiß, aber besser Einsteigern etwas vorgeben als sie auf dem Trockenem sitzen zu lassen.
[01.10.2007 - 19:36:05] babelfish: weiss jemand einen Algo um witzige Sprüche zu erkennen? will das einbauen xD
[01.10.2007 - 19:36:07] |bubble|: War diese Frage ernst gemeint?!?

(Insider!) xD

P.S.: goto ruleZ! :D

grek40

Alter Hase

Beiträge: 1 491

Wohnort: Dresden

  • Private Nachricht senden

10

13.10.2007, 00:34

Zitat von »"xCite"«


Zitat

1. Steht es nicht zur Debatte warum das jemand machen will
2. Um bsw. Features der WinAPI zu nutzen, die nur unter noch höheren Windows-Versionen zur Verfügung stehen.


Ich weiß, aber besser Einsteigern etwas vorgeben als sie auf dem Trockenem sitzen zu lassen.

Was is denn da gegen meinen Vorschlag einzuwenden^^

C-/C++-Quelltext

1
2
3
4
#if !defined _WIN32_WINNT || _WIN32_WINNT < 0x0500
#undef _WIN32_WINNT
#define  _WIN32_WINNT 0x500
#endif

Werbeanzeige