2009-08-17 6 views
28

Gibt es eine Möglichkeit, die Breite der Konsole zu finden, in der mein Java-Programm ausgeführt wird?Kann ich die Konsolenbreite mit Java finden?

Ich möchte diese Cross-Plattform sein, wenn möglich ...

ich keine Lust haben, die Breite des Puffers oder des Fensters zu ändern, ich will nur seine Breite, also kann ich richtig Textformat, wird auf dem Bildschirm gedruckt.

Antwort

23

Es gibt keine zuverlässige Cross-Plattform-Lösungen für dieses Problem. Tatsächlich gibt es Situationen, in denen es nicht möglich ist zu wissen, wie groß die tatsächliche Konsolenbreite ist.

Beispielsweise können Sie auf einem Linux-System in der Regel die fiktiven Terminaldimensionen aus den Umgebungsvariablen LINES und COLUMNS herausfinden. Während diese Variablen automatisch aktualisiert werden, wenn Sie die Größe einiger "Terminal-Emulator" -Fenster ändern, ist dies nicht immer der Fall. Bei einer Remote-Konsole, die über das Telnet-Protokoll verbunden ist, gibt es keine Möglichkeit, die tatsächlichen Terminal-Dimensionen in der Shell des Benutzers abzurufen.

EDIT: Wenn der Benutzer die Dimensionen seines xterm unter Linux nach dem Start einer Java-App ändert, wird die Java-App nicht benachrichtigt und die neuen Dimensionen werden nicht angezeigt in seiner Kopie der LINES- und COLUMNS-Umgebungsvariablen!

EDIT 2: Mein Fehler, sie sind bash Shell-Variablen, werden aber nicht standardmäßig in die Umgebung exportiert. Sie können dies beheben, indem Sie export COLUMNS LINES ausführen, bevor Sie Ihre Java-Anwendung ausführen.

+0

Ich hatte gehofft, es würde etwas geben, das die Breite/Höhe usw. zurückgeben würde oder -1, wenn es nicht bestimmt werden kann ... na ja. Willkommen fest codierte Konstanten! – masher

+0

@masher: Das Problem ist, dass unter Linux die Antwort fast immer "nicht mit Bestimmtheit bestimmt werden kann". –

+0

Ich habe versucht, dies mit System zu tun.getenv ("COLUMNS") aber es gab null zurück. Ubuntu 10.04/GNOME 2.30.2 – jsj

4

Java 6 hat eine Klasse java.io.Console, aber es fehlt Ihnen leider die Funktionalität, nach der Sie fragen. Die Breite des Konsolenfensters ist mit der Standard-Java-Bibliothek und reinem, plattformübergreifendem Java nicht möglich.

Hier ist eine Alternative Java console library, die Ihnen ermöglicht, die Bildschirmgröße zu erhalten, aber es enthält eine Windows-spezifische DLL. Möglicherweise können Sie den Quellcode verwenden und den C-Teil in einer gemeinsam genutzten Linux- oder Mac OS X-Bibliothek kompilieren, damit er auch auf diesen Plattformen funktioniert.

+0

Ich fand die Console API und war aufgeregt; und dann war ich nicht ... Für das, was ich tun möchte, ist das Lernen von C und wie man Cross-Compiling macht, so wie man einen Nagel mit einer Abrissbirne hämmert. – masher

+0

@Jesper - es ist nicht wirklich Javas Schuld. Es gibt viele Dinge, die es unmöglich machen, die aktuelle Konsolengröße in allen Fällen auf einem Linux/Unix-Rechner zu erhalten. –

1

Ich habe an diesem Problem schon gearbeitet. Ich benutze ein paar verschiedene Techniken. Es ist jedoch schwierig, eine wirklich plattformübergreifende Lösung zu haben.

Ich habe versucht zu tun versuchen, etwas wie folgt aus:

String os = System.getProperty("os.name").toLowerCase(); 

    //Windows 
    if(os.contains("win")){ 
     System.out.append("Windows Detected"); 
     //set Windows Dos Terminal width 80, height 25 
     Process p = Runtime.getRuntime().exec("mode 80, 25"); 
    } 
    //Mac 
    if(os.contains("mac")){ 
     System.out.println("Macintosh Detected"); 
     //... I dont know...try Google 
    } 
    //Linux 
    if(os.contains("linux")){ 
     System.out.println("Linux Detected"); 

Sie können/Test lesen und "export Columns" in die Datei .bashrc in jeder Linux-Anwender mit den String.contains Home-Verzeichnis anhängen ("Export SÄULEN ") Methode und die Eigenschaft user.dir.

Damit können Sie die Spalten jedes Mal laden, wenn die Java-App gestartet wird.

Dann würde ich es in eine temporäre Datei übergeben. Wie folgt aus:

try { 
    ProcessBuilder pb = new ProcessBuilder("bash","-c","echo $COLUMNS >/home/$USER/bin/temp.txt"); 
     pb.start(); 

    }catch (Exception e) { 
     System.out.println("exception happened - here's what I know: "); 
     e.printStackTrace(); 
     System.exit(-1); 
    } 
} 

Eine weitere Option, die Sie haben, ist yor Java.jar mit einem Bash-Skript beim Start auszuführen. Innerhalb des Skripts können Sie "tput cols" verwenden, um die Breite zu erhalten. Übergeben Sie diesen Wert als String [] arg an Ihre Java-App.

Wie so:

//#!/bin/bash 

//#clear the screen 

clear 

//#get the console width and height 

c=$[$(tput cols)] 

l=$[$(tput lines)] 

//#pass the columns, lines and an optional third value as String[] args. 

java -jar ~/bin/Plus.jar $c $l $1 

warum ist das so eine schwierige Aufgabe mit Java? Offensichtlich ein guter Ort, um eine gute API zu schreiben. Ich denke, wir könnten Apache.commons.exec auch versuchen?

+2

Wenn 'export COLUMNS' vor dem Start des Java-Prozesses aufgerufen wurde, können Sie' System.getenv ("COLUMNS") ''; Es ist nicht notwendig, einen Subprozess mit 'ProcessBuilder' zu starten. – dimo414

8

Bearbeiten: Siehe @ dave_thompson_085's Kommentar über ProcessBuilder, wie das ist fast sicher ein besserer Ansatz.

Eine andere Antwort erwähnt tput cols in einem Skript ausgeführt, bevor Sie Ihren Befehl starten. Aber wenn Sie das ausführen möchten, nachdem Java bereits gestartet wurde, indem Sie Runtime.getRuntime().exec() verwenden, werden Sie feststellen, dass tput nicht mit Ihrem Terminal sprechen kann, da Java stdout und stderr umgeleitet hat. Als Workaround, bei dem es sich nicht um eine portable Lösung handelt, können Sie das magische Gerät /dev/tty verwenden, das sich auf das Terminal des aktuellen Prozesses bezieht. Das können Sie so etwas wie dies auszuführen:

Process p = Runtime.getRuntime().exec(new String[] { 
    "bash", "-c", "tput cols 2> /dev/tty" }); 
// Read the output of this process to get your terminal width 

Dies funktioniert für mich auf Linux, aber ich würde nicht erwarten, dass es überall zu arbeiten. Es wird hoffentlich auf Mac funktionieren. Es wird definitiv nicht mit Windows funktionieren, obwohl es mit Cygwin möglich ist.

+2

Funktioniert auch auf dem Mac – pascal

+0

Dies ist die einzige Lösung, die für mich funktioniert. – Panayotis

+1

'ProcessBuilder' seit Java7 (2011) kann den eigenen stdin/out/err von Java an einen untergeordneten Prozess anstelle der standardmäßig umgeleiteten Pipes übergeben; siehe 'inheritIO()' und 'redirect * (Redirect.INHERIT)' - was nicht hilft, wenn 'java' selbst vom Benutzer umgeleitet wurde, aber in diesem Fall interessiert dich die Breite eines I/O Gerät, das du nicht benutzt? –

0

Python scheint eine gute Lösung zu haben: 11.9.3. Querying the size of the output terminal. Ich würde nicht den Atem anhalten und darauf warten, dass dies in Core-Java verfügbar ist, aber Sie können möglicherweise Jython verwenden, um die Python-Funktionalität verfügbar zu machen.

+0

Wie die 'shuthil'-Dokumente erwähnen, fällt dies auf [' os.get_terminal_size() '] (https://docs.python.org/3.5/library/os.html#os.get_terminal_size) zurück, was OS- spezifisch und [implementiert] (https://hg.python.org/cpython/file/3.5/Modules/posixmodule.c#l11128) in C. Die Verwendung von Jython könnte für einige Anwendungsfälle funktionieren, aber es ist ein ziemlich schwerer Hammer. – dimo414

13

Tatsächlich existiert bereits eine Java-Bibliothek, um dies in Java zu tun: JLine 2. (Es gibt eine alte Version auf SourceForce, aber diese Verbindung zu GitHub scheint die neueste zu sein.)

Dies funktionierte für mich unter Linux (Mint 14) und Windows (ich weiß nicht welche Version), mit JLine 2.11:

terminalWidth = jline.TerminalFactory.get().getWidth(); 

JLine verspricht auch auf dem Mac zu arbeiten.

Ich habe festgestellt, dass es schlechte Breiten (wie 1!) Unter der Eclipse-Konsole (aber sogar Java native Konsole funktioniert nicht unter Eclipse!), Und leider unter Cygwin. Aber ich habe mit Code gearbeitet, der nach unangemessenen Werten sucht (< 10) und in diesen Fällen nur 80 verwendet.

+3

Unter Unix ruft JLine einfach 'stty -a' in ['TerminalLineSetting'] auf (https://github.com/jline/jline2/blob/master/src/main/java/jline/internal/TerminalLineSettings.java), Unter Windows hakt es sich über 'org.fusesource.jansi.internal.WindowsSupport' in einen Closed-Source-Teil der JAnsi-Bibliothek ein. – dimo414

0

Für mich ist der einzige Weg, eine Vorstellung von der Terminal-Fenster zu erhalten (noch nicht korrekt, wenn das Fenster passt die Größe) ist wie

einen Befehl verwenden
ProcessBuilder pb = new ProcessBuilder("cmd.exe", "/c", "mode con"); 
pb.redirectError(ProcessBuilder.Redirect.INHERIT); 

Wenn ohne den Teil cmd.exe laufen, es zeigt, dass Der Befehl konnte nicht gefunden werden. Beachten Sie auch den redirectError Teil. Wenn nicht verwendet, wird die Java-Ausgabegröße verwendet, nicht die tatsächliche. Nur mit dieser Kombination war es möglich, die tatsächliche Größe zu erfassen.

Verwandte Themen