2009-08-17 11 views
28

C'è un modo per trovare la larghezza della console in cui è in esecuzione il mio programma Java?Posso trovare la larghezza della console con Java?

vorrei che questo è cross platform, se possibile ...

non ho alcun desiderio di cambiare la larghezza del buffer o la finestra, voglio solo sapere la sua larghezza in modo da poter correttamente formattare il testo che viene stampato sullo schermo.

risposta

23

Non ci sono soluzioni affidabili per per questo problema. In effetti, ci sono situazioni in cui non è possibile sapere qual è la larghezza della console reale.

Ad esempio, su un sistema Linux è possibile in genere rilevare le dimensioni del terminale teorico dalle variabili di ambiente LINES e COLUMNS. Mentre queste variabili vengono aggiornate automaticamente quando ridimensionate alcune finestre di "emulatore di terminale", questo non è sempre il caso. Infatti, nel caso di una console remota collegata tramite protocollo telnet, non c'è modo di ottenere le dimensioni del terminale effettivo nella shell dell'utente.

EDIT: Solo per aggiungere che se l'utente modifica le dimensioni del proprio xterm su Linux dopo aver lanciato un'app Java, l'app Java non verrà notificata e non vedrà le nuove dimensioni riflesse nella sua copia delle variabili di ambiente LINES e COLUMNS!

MODIFICA 2: Errore mio, sono variabili di shell bash, ma non vengono esportate nell'ambiente per impostazione predefinita. È possibile "risolvere" questo eseguendo export COLUMNS LINES prima di eseguire l'applicazione Java.

+0

Speravo che ci fosse qualcosa che avrebbe restituito la larghezza/altezza ecc o -1 se non può essere determinato ... vabbè. Benvenuto costanti hard-coded! – masher

+0

@masher: il problema è che su Linux, la risposta dovrebbe essere quasi sempre "non può essere determinata con certezza". –

+0

Ho provato a farlo con System.getenv ("COLUMNS") ma ha restituito null. Ubuntu 10.04/GNOME 2.30.2 – jsj

4

Java 6 ha una classe java.io.Console, ma sfortunatamente manca della funzionalità richiesta. Ottenere la larghezza della finestra della console non è possibile con la libreria Java standard e Java puro multipiattaforma.

Questa è un'alternativa Java console library che consente di ottenere le dimensioni dello schermo, ma include una DLL specifica per Windows. Potresti essere in grado di prendere il codice sorgente e compilare la parte C in una libreria condivisa Linux o Mac OS X, in modo che funzioni anche su quelle piattaforme.

+0

Ho trovato l'API della console ed ero eccitato; e poi non ero ... Per quello che voglio fare, imparare C e come compilarlo è come martellare un chiodo con una palla da demolizione. – masher

+0

@Jesper: non è proprio colpa di Java. Ci sono molte cose che rendono impossibile ottenere la dimensione attuale della console in tutti i casi su una macchina Linux/Unix. –

1

Ho lavorato a questo problema prima. Io uso un paio di tecniche diverse. Tuttavia è difficile avere una soluzione veramente cross-platform.

Ho provato a fare provare qualcosa di simile:

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"); 

Si può leggere/test e aggiungere "colonne di esportazione" al file .bashrc in ogni home directory degli utenti Linux con le String.contains ("colonne d'esportazione ") metodo e la proprietà user.dir.

Ciò consentirebbe di caricare le colonne ogni volta che viene avviata l'app java.

Quindi lo passerei a un file temporaneo. Come questo:

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); 
    } 
} 

Un'altra opzione che avete è quello di eseguire yor Java.jar con uno script bash all'avvio. All'interno dello script puoi usare "tput cols" per ottenere la larghezza. Quindi passa quel valore alla tua app Java come argomento String [] arg.

Come così:

//#!/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 

perché questo è un compito così difficile con Java? Ovviamente un buon posto per scrivere una buona API. Suppongo che potremmo provare anche Apache.commons.exec?

+2

Se è stato chiamato 'export COLUMNS' prima dell'avvio del processo Java, è sufficiente eseguire' System.getenv ("COLUMNS") '; non è necessario avviare un sottoprocesso con 'ProcessBuilder'. – dimo414

8

Modifica: vedi il commento di @ dave_thompson_085 su ProcessBuilder, poiché è quasi certamente un approccio migliore.

Un'altra risposta citata in esecuzione tput cols in uno script prima di iniziare il comando. Ma se si desidera eseguirlo dopo l'avvio di Java, utilizzando Runtime.getRuntime().exec(), è possibile che tput non possa parlare con il terminale, poiché Java ha reindirizzato stdout e stderr. Come soluzione alternativa non completamente portatile, puoi utilizzare il magico dispositivo /dev/tty, che fa riferimento al terminale del processo corrente. Che consente di eseguire qualcosa di simile:

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 

Questo funziona per me su Linux, ma non mi aspetto di lavorare ovunque. Speriamo che funzionerà su Mac. Sicuramente non funzionerà su Windows, anche se potrebbe funzionare con Cygwin.

+2

Funziona anche su Mac – pascal

+0

Questa è l'unica soluzione che funziona per me. – Panayotis

+1

'ProcessBuilder' poiché Java7 (2011) può passare lo stdin/out/err di Java a un processo figlio anziché le pipe reindirizzate di default; vedi 'inheritIO()' e 'redirect * (Redirect.INHERIT)' - che non aiuta se 'java' stesso è stato reindirizzato dall'utente, ma in tal caso perché ti preoccupi della larghezza di un I/O dispositivo che non stai utilizzando? –

0

Python sembra avere una buona soluzione: 11.9.3. Querying the size of the output terminal. Non terrei il respiro aspettando che fosse disponibile nel core Java, ma potresti essere in grado di usare Jython per rendere disponibile la funzionalità Python.

+0

Come menzionano i documenti 'shutil', questo torna a [' os.get_terminal_size() '] (https://docs.python.org/3.5/library/os.html#os.get_terminal_size), che è OS- specifico e [implementato] (https://hg.python.org/cpython/file/3.5/Modules/posixmodule.c#l11128) in C. L'uso di Jython potrebbe funzionare per alcuni casi d'uso, ma è un martello piuttosto pesante. – dimo414

13

In realtà, esiste già una libreria Java per eseguire questa operazione in Java: JLine 2. (C'è una vecchia versione su SourceForce, ma quel collegamento a GitHub sembra essere l'ultimo.)

Questo ha funzionato per me sotto Linux (Mint 14) e Windows (non so quale versione), usando JLine 2.11:

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

JLine promette di lavorare anche su Mac.

Ho trovato che restituisce larghezze errate (come 1!) Sotto la console Eclipse (ma anche la console nativa di Java non funziona con Eclipse!), E, ​​purtroppo, sotto Cygwin. Ma ho lavorato su questo con il codice che controlla i valori irragionevoli (< 10) e usa solo 80 in questi casi.

+3

Su Unix, JLine chiama semplicemente 'stty -a' in [' TerminalLineSetting'] (https://github.com/jline/jline2/blob/master/src/main/java/jline/internal/TerminalLineSettings.java), su Windows si aggancia a una parte closed-source della libreria JAnsi tramite 'org.fusesource.jansi.internal.WindowsSupport'. – dimo414

0

Per me, l'unico modo per avere un'idea della finestra del terminale (ancora non è corretta quando ridimensiona la finestra) è quello di utilizzare un comando come

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

Quando viene eseguito senza la parte cmd.exe, mostra che il comando non è stato trovato. Si noti inoltre la parte redirectError. Se non utilizzato, verrà utilizzata la dimensione dell'output Java, non quella effettiva. Solo con questa combinazione è stato possibile afferrare le dimensioni reali.

Problemi correlati