Ich habe es mittlerweile aufgegeben eigene Funktionen für farbige Ausgaben oder Konsolenhandling (Konsole leeren, Cursor bewegen usw) in Java (unter Windows) zu schreiben. Fehlendes ANSI Verständnis von Windows sorgt dafür, dass ANSI Steuerzeichen nicht umgesetzt werden; damit sind Farben, Formatting und Handling in der Konsole schier unerreichbar.
Aber glücklicherweise gibt es dutzende Java Bibliotheken, die solche Dinge realisieren: Jansi, JCurses, Charva, uvm.
Ich habe bisher nur Jansi getestet und es klappt ganz gut. Jansi installiert das Ansi Verständnis in die Konsole und ermöglicht somit die ordnungsgemäße Nutzung dieser Steuerzeichen sowohl mit der eigenen Funktion AnsiConsole.out als auch mit der normalen Funktion System.out.
Ich habe die Farbgestaltung und ein paar Handlingsachen mal in einem Beispiel zusammengepackt.
Den Code könnt ihr bequem mit den Links/Rechts Pfeiltasten horizontal bewegen.
import java.io.IOException; import java.io.*; // Jansi Bibliothekbestandteile importieren, logischerweise muss das sein. // Diese imports befinden sich in der jansi.jar, die dann beim kompilieren und ausführen mit eingebunden werden muss // siehe http://hannes-schurig.de/17/04/2012/java-2-farbige-formatierte-konsolenausgaben-in-windows-einfache-beispiele/ import org.fusesource.jansi.AnsiConsole; import org.fusesource.jansi.*; public class Farben { /* Author: Hannes Schurig Created: 16.4.2012 Changed: 16.4.2012 Version: 1.0 Changelog: v1.0: Farbige Ausgaben und Konsolenhandling dank jansi.jar, verschiedene Beispiele Title: Farben Quellen: jansi Doku: http://jansi.fusesource.org/documentation/api/index.html http://en.wikipedia.org/wiki/ANSI_escape_code */ public static final String CLS = "\u001b[2J"; public static final String TOP = "\u001b[H"; public static final String UP = "\u001b[1F"; public static final String LEFT = "\u001b[1G"; public static final String DEL = "\u001b[2K"; public static final String DEL_LEFT = "\u001b[1K"; public static final String DEL_RIGHT = "\u001b[0K"; public static final String BOLD = "\u001b[1m"; public static final String RESET = "\u001b[0m"; public static final String SPLASH = "\u001b[1;37;44m"; public static final String f1 = "\u001b[1;37;46m"; public static final String f2 = "\u001b[1;34;41m"; public static final String f3 = "\u001b[1;31;45m"; public static final String f4 = "\u001b[1;36;42m"; public static final String f5 = "\u001b[1;35;43m"; public static void main(String[] args) throws IOException, InterruptedException { try { // Installation der AnsiConsole und Einbetttung der Funktionalitäten in die System.out Funktion AnsiConsole.systemInstall(); }catch(Exception e){} // muss nicht in einer try catch stehen, würde ich persönlich aber bevorzugen // Ansi Objekt erstellen Ansi ansi=Ansi.ansi(); // AnsiConsole.out wird für ANSI Steuerzeichenausgaben genutzt // Farb- oder Formatierungsanweisungen immer vor den Text, den es betreffen soll. // Diese Formatierungen bleiben so lange aktiv, bis sie neu gesetzt werden. Also auch über mehrere Ausgabebefehle hinweg. // Ein Zurücksetzen der Farb- und Formatierungsanweisungen kann mit [0m oder [m erfolgen (hier in RESET gespeichert). AnsiConsole.out.println( f1 + " Dies ist ein Test " + RESET ); AnsiConsole.out.println( f2 + " Dies ist ein Test " + RESET ); AnsiConsole.out.println( f3 + " Dies ist ein Test " + RESET ); AnsiConsole.out.println( f4 + " Dies ist ein Test " + RESET ); AnsiConsole.out.println( f1 + " Dies ist ein Test " + RESET ); AnsiConsole.out.println( f2 + " Dies ist ein Test " + RESET ); AnsiConsole.out.println( f3 + " Dies ist ein Test " + RESET ); AnsiConsole.out.println( f4 + " Dies ist ein Test " + RESET ); AnsiConsole.out.println( SPLASH + " Dies ist ein Test " ); AnsiConsole.out.println( " Eine Zeile ohne RESET davor ist wie die vorherige. " + RESET ); AnsiConsole.out.println( " Wieder normal " ); // Pause von 5 Sekunden (main Funktion braucht throws InterruptedException und import java.io.*; nötig) Thread.sleep(10000); // Ausgabe von ANSI [2J und [H ( auch: [1;1H ) für 'Clear Screen' und 'Cursor to top left cornor' AnsiConsole.out.print( CLS + TOP ); // weiterhin kann man System.out und System.console() verwenden System.console().printf( " CLS löscht zwar die Zeichen aber nicht farbige Überreste, " ); System.console().printf( " daher müssen diese Zeile für Zeile gelöscht werden. " ); Thread.sleep(10000); // echter CLS Befehl mit mehrfachem Zeile Löschen und erneutem Hochspringen am Ende for(int i=0;i<50;i++) { AnsiConsole.out.println( RESET + DEL); } AnsiConsole.out.print( CLS + TOP ); // echter CLS Ende AnsiConsole.out.print(ansi.cursor(10,10) + SPLASH + " Positionieren des Cursors kann auf 2 verschiedene Wege passieren: " ); AnsiConsole.out.print(ansi.cursor(11,10) + " Entweder generiert man sich das Ansi Objekt (siehe oben) und nutzt " ); AnsiConsole.out.print(ansi.cursor(12,10) + " dann die ansi.cursor(row, column) Funktion oder man nutzt direkt die " ); AnsiConsole.out.print( "\u001b[13;10H entsprechenden ANSI Steuerzeichen dafür. Also [row;columnH " ); AnsiConsole.out.print( "\u001b[14;10H wie in den letzten beiden Zeilen hier zu sehen. " + RESET ); // System.out bietet nach der AnsiConsole.systemInstall die gleichen Funktionalität System.out.print( "\u001b[16;10H\u001b[1;37;41m Grundsätzlich brauch man sich also gar keine Variablen für Formatierungen setzen\u001b[m " ); System.out.print( "\u001b[17;10H\u001b[1;37;41m und kann alle Steuerzeichen händisch eingeben. Variablen sind aber zu empfehlen ;)\u001b[0m " ); Thread.sleep(10000); // echter CLS Befehl mit mehrfachem Zeile Löschen und erneutem Hochspringen am Ende for(int i=0;i<50;i++) { AnsiConsole.out.println( RESET + DEL); } AnsiConsole.out.print( CLS + TOP ); // echter CLS Ende AnsiConsole.out.println("\n\n" + BOLD + "Choose a menu item with the specified number key" +"\n"+ "or press another key to exit." +"\n\n"+ " >> " + RESET); try {System.in.read();}catch(Exception e){} } }
In diesem Beispiel nutze ich eigens definierte Variablen mit Ansi Steuercodes und die ansi.cursor() Funktion. Vermutlich bietet Jansi weitere fertig ausprogrammierte Lösungen in Form von Funktionen für Dinge, die ich hier noch manuell gemacht habe (ein richtiges Clear Screen z.B.). Für weitere fertige Lösungen schaut bitte die Jansi Dokumentation durch.
Ausführung in Notepad++:
(Vorbereitung hier) NppExec Plugin installieren, Batch erstellen mit folgendem Inhalt (oder unten downloaden):
Den Code könnt ihr bequem mit den Links/Rechts Pfeiltasten horizontal bewegen.
@echo off :: jar(s) specified? if not [%4]==[] goto jars :: compile and run without externals jars if not [%1]==[] javac %1 if not [%2]==[] if not [%3]==[] start cmd.exe /c java -classpath %2 %3 :jars setlocal enabledelayedexpansion set /a N=0 :: reads up to 6 externals jars for /f "tokens=1,2,3 delims=;" %%a in ("%~4") do ( set /a N+=1 set j1=%%a set j2=%%b set j3=%%c ) set classpath=%~2 set jarpath=%~2 if not [%5]==[] set jarpath=%~5 set jars=. if not [%j1%]==[] set jars=%jars%;%jarpath%\%j1% if not [%j2%]==[] set jars=%jars%;%jarpath%\%j2% if not [%j3%]==[] set jars=%jars%;%jarpath%\%j3% :: compile and run with external jars if not [%1]==[] javac -cp "%jars%" %1 if not [%2]==[] if not [%3]==[] start cmd /c ""c:\Program Files\Java\jre7\bin\java" -cp "%jars%;%classpath%" %3" endlocal :: usage: :: just compile :: executor.bat "C:\Pfad\zur\Javadatei\MeinProgramm.java" :: compile with 1 external .jar :: executor.bat "C:\Pfad\zur\Javadatei\MeinProgramm.java" "lib1.jar" :: compile with 1 external .jar :: executor.bat "C:\Pfad\zur\Javadatei\MeinProgramm.java" "lib1.jar;lib2.jar" :: just run java code :: executor.bat "C:\Pfad\zur\Javadatei\MeinProgramm.java" "C:\Pfad\zur\Javadatei" "MeinProgramm" :: run java code with one or multiple external jars :: executor.bat "C:\Pfad\zur\Javadatei\MeinProgramm.java" "C:\Pfad\zur\Javadatei" "MeinProgramm" "lib1.jar" :: run java code with one or multiple external jars - up to 3 jars supported (change lines 15-28 [if you know batch] for more) :: usage: executor.bat "C:\Pfad\zur\Javadatei\MeinProgramm.java" "C:\Pfad\zur\Javadatei" "MeinProgramm" "lib1.jar;lib2.jar;jcurse.jar" :: Notepad++ F6 Code: :: NPP_SAVE :: ?:\path\to\executor.bat "$(FULL_CURRENT_PATH)" "$(CURRENT_DIRECTORY)" "$(NAME_PART)" "one_or_multiple_external.jar"
Batch, .java Code und alle nötigen .jars (jansi.jar in diesem Fall) in ein Verzeichnis, in Notepad++ F6 drücken, folgenden Code (erst anpassen!) einfügen:
NPP_SAVE t:\Dropbox\Programmierung\Java\executor.bat "$(FULL_CURRENT_PATH)" "$(CURRENT_DIRECTORY)" "$(NAME_PART)" "jansi.jar"
(bei mir liegen also .java, .jar und .bat in T:\Dropbox\Programmierung\Java\)
und dann sollte das funktionieren. Weitere Nutzungshinweise zur executor.bat befinden sich als Kommentar am Ende. Die Batch kann mittlerweile nur kompilieren (ohne und mit jars) und ausführen (ohne und mit jars).
Beachte: javac.exe und java.exe müssen in der Windows Umgebungsvariablen PATH eingetragen sein! siehe Vorbereitungen oder Google.
Unschön an Jansi ist die Zeichencodierung in der Konsole. Selbst wenn ich den Outputstream auf CP850 umbiege und Jansi diesen Stream übergebe, werden Umlaute noch immer nicht korrekt dargestellt.
Aktuell ist ebenfalls die JANSI Homepage nicht mehr erreichbar. Wird das Projekt noch aktiv supportet?