2009-08-17 25 views
28

Có cách nào để tìm chiều rộng của bảng điều khiển mà chương trình Java của tôi đang chạy không?Tôi có thể tìm thấy chiều rộng bàn điều khiển với Java không?

Tôi muốn điều này là nền tảng chéo nếu có thể ...

Tôi không có mong muốn thay đổi chiều rộng của bộ đệm hoặc cửa sổ, tôi chỉ muốn biết chiều rộng của nó vì vậy tôi đúng cách có thể định dạng văn bản đang được in ra màn hình.

Trả lời

23

Không có đáng tin cậy giải pháp đa nền tảng cho vấn đề này. Thật vậy, có những tình huống mà nó không thể biết được chiều rộng bàn điều khiển thực là gì.

Ví dụ: trên hệ thống Linux, bạn thường có thể tìm ra thứ nguyên thiết bị đầu cuối không bình thường từ biến môi trường LINES và COLUMNS. Mặc dù các biến này được tự động cập nhật khi bạn thay đổi kích thước một số cửa sổ trình mô phỏng đầu cuối "" nhưng điều này không phải lúc nào cũng đúng. Thật vậy, trong trường hợp của một giao diện điều khiển từ xa được kết nối thông qua giao thức telnet, không có cách nào để có được kích thước thiết bị đầu cuối thực tế cho vỏ của người dùng.

EDIT: Chỉ cần thêm rằng nếu người dùng thay đổi kích thước xterm của mình trên Linux sau khi khởi chạy ứng dụng Java, ứng dụng Java sẽ không được thông báo và sẽ không thấy các tham số mới được phản ánh trong bản sao của các biến môi trường LINES và COLUMNS!

CHỈNH SỬA 2: Lỗi của tôi, chúng là bash biến trình bao, nhưng không được xuất sang môi trường theo mặc định. Bạn có thể "sửa" điều này bằng cách chạy export COLUMNS LINES trước khi bạn chạy ứng dụng Java của mình.

+0

Tôi đã hy vọng sẽ có một cái gì đó mà sẽ trở lại chiều rộng/chiều cao vv hoặc -1 nếu nó không thể được xác định ... oh well. Chào mừng các hằng số được mã hóa cứng! – masher

+0

@ masher: vấn đề là trên Linux, câu trả lời sẽ gần như luôn luôn là "không thể được xác định với bất kỳ sự chắc chắn nào". –

+0

Tôi đã cố gắng thực hiện việc này với Hệ thống.getenv ("COLUMNS") nhưng nó trả về null. Ubuntu 10.04/GNOME 2.30.2 – jsj

4

Java 6 có lớp java.io.Console, nhưng tiếc là thiếu chức năng bạn đang yêu cầu. Không thể có chiều rộng cửa sổ giao diện điều khiển với thư viện Java chuẩn và Java thuần túy, đa nền tảng.

Dưới đây là một thay thế Java console library cho phép bạn có kích thước màn hình, nhưng nó bao gồm một tệp DLL cụ thể cho Windows. Bạn có thể lấy mã nguồn và biên dịch phần C thành thư viện chia sẻ Linux hoặc Mac OS X, để nó cũng hoạt động trên các nền tảng đó.

+0

Tôi đã tìm thấy API giao diện điều khiển và rất vui mừng; và sau đó tôi đã không ... Đối với những gì tôi muốn làm, học C và làm thế nào để biên dịch chéo là loại giống như búa một móng tay với một quả bóng đắm. – masher

+0

@ Jesper - nó không thực sự là lỗi của Java. Có rất nhiều thứ làm cho nó không thể có được kích thước giao diện điều khiển hiện tại trong mọi trường hợp trên một máy Linux/Unix. –

1

Tôi đã làm việc về vấn đề này trước đây. Tôi sử dụng một vài kỹ thuật khác nhau. Tuy nhiên rất khó để có một giải pháp nền tảng thực sự.

Tôi đã thử làm thử một cái gì đó như thế này:

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

Bạn có thể đọc/kiểm tra và thêm "COLUMNS xuất khẩu" vào file .bashrc trong mỗi thư mục Linux người dùng gia đình với String.contains ("COLUMNS xuất khẩu ") và thuộc tính user.dir.

Điều đó sẽ cho phép bạn tải các cột lên mỗi khi ứng dụng java khởi động.

Sau đó, tôi sẽ chuyển nó sang tệp tạm thời. Như thế này:

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

Một tùy chọn khác bạn có là thực thi yor Java.jar với tập lệnh bash khi khởi động. Bên trong kịch bản, bạn có thể sử dụng "tput cols" để có chiều rộng. Sau đó chuyển giá trị đó cho ứng dụng Java của bạn dưới dạng String [] arg.

Giống như vậy:

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

tại sao là một nhiệm vụ khó khăn như thế này với Java? Rõ ràng là một nơi tốt để viết một API tốt. Tôi đoán chúng ta có thể thử Apache.commons.exec?

+2

Nếu 'xuất COLUMNS' được gọi trước khi bắt đầu quá trình Java, bạn có thể chỉ cần thực hiện' System.getenv ("COLUMNS") '; không cần phải khởi chạy tiến trình con với 'ProcessBuilder'. – dimo414

8

Chỉnh sửa: Xem nhận xét của @ dave_thompson_085 về ProcessBuilder, vì đó gần như chắc chắn là một cách tiếp cận tốt hơn.

Một câu trả lời khác được đề cập khi chạy tput cols trong tập lệnh trước khi bạn bắt đầu lệnh. Nhưng nếu bạn muốn chạy nó sau khi Java đã bắt đầu, sử dụng Runtime.getRuntime().exec(), bạn sẽ thấy rằng tput không thể nói chuyện với thiết bị đầu cuối của bạn, bởi vì Java đã chuyển hướng stdout và stderr. Như một giải pháp không cần thiết, bạn có thể sử dụng thiết bị huyền diệu /dev/tty, trong đó đề cập đến thiết bị đầu cuối của quá trình hiện tại. Điều đó cho phép bạn chạy một cái gì đó như thế này:

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 

Điều này làm việc cho tôi trên Linux, nhưng tôi không mong đợi nó hoạt động ở mọi nơi. Nó hy vọng sẽ hoạt động trên Mac. Nó chắc chắn sẽ không hoạt động trên Windows, mặc dù nó có thể với Cygwin.

+2

Hoạt động trên Mac cũng như – pascal

+0

Đây là giải pháp duy nhất phù hợp với tôi. – Panayotis

+1

'ProcessBuilder' kể từ Java7 (2011) có thể vượt qua riêng của stdin/out/err của Java cho một tiến trình con thay vì các đường dẫn mặc định được chuyển hướng; xem 'inheritIO()' và 'redirect * (Redirect.INHERIT)' - không giúp ích gì nếu bản thân 'java' đã được chuyển hướng bởi người dùng, nhưng trong trường hợp đó, tại sao bạn quan tâm đến chiều rộng của một I/O thiết bị bạn không sử dụng? –

0

Python dường như có giải pháp tốt: 11.9.3. Querying the size of the output terminal. Tôi sẽ không giữ hơi thở của tôi chờ đợi cho điều này để có sẵn trong lõi Java, nhưng bạn có thể sử dụng Jython để làm cho các chức năng Python có sẵn.

+0

Khi tài liệu 'shutil' đề cập đến, điều này trở lại [' os.get_terminal_size() '] (https://docs.python.org/3.5/library/os.html#os.get_terminal_size), là OS- cụ thể và [thực hiện] (https://hg.python.org/cpython/file/3.5/Modules/posixmodule.c#l11128) trong C. Sử dụng Jython có thể làm việc cho một số trường hợp sử dụng, nhưng nó là một cái búa khá nặng. – dimo414

13

Thực ra, một thư viện Java đã tồn tại để thực hiện việc này trong Java: JLine 2. (Có một phiên bản cũ trên SourceForce, nhưng liên kết đó với GitHub có vẻ là mới nhất.)

Điều này làm việc cho tôi dưới Linux (Mint 14) và Windows (Tôi không biết phiên bản nào), sử dụng JLine 2.11:

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

JLine cũng hứa sẽ hoạt động trên Mac.

Tôi thấy rằng nó trả về độ rộng xấu (như 1!) Trong bảng điều khiển Eclipse (nhưng ngay cả Bàn điều khiển gốc của Java không hoạt động trong Eclipse!), Và, thật không may, dưới Cygwin. Nhưng tôi đã làm việc xung quanh điều này với mã kiểm tra các giá trị không hợp lý (< 10) và chỉ sử dụng 80 trong những trường hợp đó.

+3

Trên Unix, JLine chỉ cần gọi 'stty -a' trong [' TerminalLineSetting'] (https://github.com/jline/jline2/blob/master/src/main/java/jline/internal/TerminalLineSettings.java), trên Windows, nó nối vào một phần mã nguồn mở của thư viện JAnsi thông qua 'org.fusesource.jansi.internal.WindowsSupport'. – dimo414

0

Đối với tôi, cách duy nhất để có được một ý tưởng về cửa sổ terminal (vẫn không chính xác khi cửa sổ thay đổi kích thước) là sử dụng một lệnh như

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

Khi chạy mà không cần phần cmd.exe, nó cho thấy rằng không thể tìm thấy lệnh. Cũng lưu ý phần redirectError. Nếu không được sử dụng thì kích thước đầu ra Java sẽ được sử dụng, không phải kích thước thực tế. Chỉ với sự kết hợp này mới có thể lấy được kích thước thực tế.

Các vấn đề liên quan