Windows-Konsolenanwendungen (Farbe, Double Buffering, Event Loops und mehr)

Es liegt in der Natur der Dinge, dass man sich beim Erlernen einer neuen Programmiersprache wie C++ zunächst einmal lediglich auf die Entwicklung einfacher Konsolenanwendungen konzentriert und solche „Kleinigkeiten“ wie die grafische Ausgestaltung der einzelnen Programme oder das Input-Handling auf einen späteren Zeitpunkt verschiebt. Allerdings wirkt die für eine Konsolenanwendung typische winzig kleine graue Schrift vor schwarzem Hintergrund auf Dauer ein wenig demotivierend. Denn sein wir doch mal ehrlich, ohne Farbe macht das Leben und das Lernen einfach keinen Spaß!
Wenn Sie jetzt der Meinung sind, dass die Grafikprogrammierung ein Thema für fortgeschrittenere Programmierer ist, dann will ich Ihnen da gar nicht widersprechen. Was ich jedoch im Sinn habe, sind einfach zu nutzende Funktionen, mit deren Hilfe sich ein tristes Windows-Konsolenfenster (unter Windows Vista oder neuer) ohne großen Aufwand verschönen und an die jeweilen Programmanforderungen anpassen lässt. Mit den von Windows bereitgestellten Konsolen-API-Funktionen wäre es sogar problemlos möglich, die alten 2D-Spieleklassiker (Klötzchengrafik, 16 Farben) wieder zu neuem Leben zu erwecken!
Mit Hilfe der in den nachfolgenden Programmbeispielen zum Einsatz kommenden Helper-Klasse sollte es für Sie problemlos möglich sein, Ihre eigenen Konsolenanwendungen im Handumdrehen ein wenig aufzuhübschen. Schauen wir uns doch gleich einmal an, bei welchen Aufgaben uns die CWinConsoleHelperClass so alles behilflich sein kann:

  • Änderung der Fenstergröße.
  • Änderung des Titels.
  • Änderung der Schriftart, Schriftgröße und Schriftdicke.
  • Änderung der Hintergrundfarbe des kompletten Konsolenfensters (RGB-Farbschema).
  • Mehrfarbige Textausgabe (16 Schriftfarben + 16 Hintergrundfarben) an beliebigen Positionen.
  • Einzelne Zeichen, Pixel oder komplette Text-Strings (16 Schriftfarben + 16 Hintergrundfarben) lassen sich in einem sogenannten Back Buffer zwischenspeichern und zu einem späteren Zeitpunkt auf dem Bildschirm präsentieren (Double Buffering).
  • Abfrage von Keyboard- und Maus-Nachrichten.
  • Exakte Zeitmessung (mit Hilfe des Performance Counters) als Grundlage für die Implementierung eigener Ereignisschleifen (Event Loop).



Download Link: WindowsConsoleRendering.zip 


Beispiel 1 – Eine „Hallo Welt“-Anwendung:


int main(void)
{
CWinConsoleHelperClass WinConsole(
    /*Titel:*/ "Demo Program",
    /*Scrollbar:*/ true,
    /*Zeichen/Pixel pro Zeile:*/ 30,
    /*Zeichen/Pixel pro Spalte:*/ 20,
    /*Keyboard und Maus Input:*/ true,
    /*Schriftart:*/ "Consolas",
    /*Schriftbreite:*/ 15, /*Schrifthöhe*/ 15,
    /*Schriftdicke:*/ 2);

WinConsole.Set_BackgroundColor(RGB(0, 75, 0));

WinConsole.Set_CursorVisibilityAndSize(FALSE);

WinConsole.Set_CursorPosition(2, 10);

WinConsole.Set_Color_For_AdditionalText(
           lightgreen, consoleBackground);

cout << "Hello World!" << endl;

getchar();
return 0;
}

Beispiel 2 – Eine einfache Event Loop:


int main(void)
{
CWinConsoleHelperClass WinConsole(
    "Demo Program", false, 30, 20, true,
    "Consolas", 15, 15, 2);

WinConsole.Set_Color_For_AdditionalText(
           lightgreen, consoleBackground);

WinConsole.Set_BackgroundColor(RGB(0, 75, 0));

WinConsole.Set_CursorVisibilityAndSize(FALSE);

double FrameTime_LastFrame = 0.0;

uint32_t LoopCounter = 0;

bool EventLoopRunning = true;

// Ereignis-Schleife starten:
while (EventLoopRunning == true)
{
WinConsole.Start_TimeMeasurement();

// nach jeweils 10 Frames (Schleifendurchgängen):
if (LoopCounter % 10 == 0)
{
WinConsole.Clear_Screen();
WinConsole.Set_BackgroundColor(
           RGB(LoopCounter % 100, 75, 0));
}

if(KEYDOWN(VK_ESCAPE) == true)
    EventLoopRunning = false;

cout << "FrameTime: " << FrameTime_LastFrame << endl;

WinConsole.Stop_TimeMeasurement(&FrameTime_LastFrame,
    /*kleinstmögliches Zeitintervall pro Frame:*/ 0.125);

LoopCounter++;

} // Ereignis-Schleife beenden

WinConsole.Set_BackgroundColor(RGB(0, 0, 75));

WinConsole.Set_Color_For_AdditionalText(
           lightred, consoleBackground);

cout << "Event Loop Stopped!";

getchar();
return 0;
}

Beispiel 3 – Event Loop + Double Buffering:


int main(void)
{
CWinConsoleHelperClass WinConsole(
    "Demo Program", false, 30, 20, true,
    "Consolas", 15, 15, 2);

WinConsole.Set_Color_For_AdditionalText(
           lightgreen, consoleBackground);

WinConsole.Set_BackgroundColor(RGB(0, 75, 0));

WinConsole.Set_CursorVisibilityAndSize(FALSE);

double FrameTime_LastFrame = 0.0;

uint32_t LoopCounter = 0;

uint32_t IntValue;

bool EventLoopRunning = true;

// Ereignis-Schleife starten:
while (EventLoopRunning == true)
{
WinConsole.Start_TimeMeasurement();

IntValue = LoopCounter % 10;

// nach jeweils 10 Frames (Schleifendurchgängen):
if (IntValue == 0)
{
WinConsole.Clear_BackBuffer();
}

WinConsole.Set_BackgroundColor(
           RGB(LoopCounter % 100, 75, 0));

if (KEYDOWN(VK_ESCAPE) == true)
    EventLoopRunning = false;

WinConsole.Write_String_Into_BackBuffer(
    /*PosX:*/ 4, /*PosY:*/ IntValue+3,
     "Test Output", lightgreen, consoleBackground);

WinConsole.Write_Pixel_Into_BackBuffer(/*PosX:*/ 2,
           /*PosY:*/ IntValue + 3, lightred);

WinConsole.Write_Pixel_Into_BackBuffer(/*PosX:*/ 16,
           /*PosY:*/ IntValue + 3, lightred);

WinConsole.Present_BackBuffer();

WinConsole.Stop_TimeMeasurement(&FrameTime_LastFrame,
    /*kleinstmögliches Zeitintervall pro Frame:*/ 0.125);

LoopCounter++;

} // Ereignis-Schleife beenden

WinConsole.Set_BackgroundColor(RGB(0, 0, 75));

WinConsole.Set_Color_For_AdditionalText(
           lightred, consoleBackground);

WinConsole.Set_CursorPosition(0, 18);

cout << "Event Loop Stopped!";

getchar();
return 0;
}