Programas basados en consola con Java usando Lanterna

Escrito por picodotdev el .
java planeta-codigo
Enlace permanente Comentarios

Java

Todavía hoy en día la terminal no ha desaparecido, y no lo hará, aún habiendo pasado ya algunas décadas de la aparición de las interfaces gráficas. Algunas ventajas de la terminal es que conociendo los comandos es más fácil realizar una tarea que con un programa basado en una ventana con botones que hay que pulsar usando el ratón, además las tareas usando comandos se pueden automatizar con scripts y combinar varios donde la entrada de uno sea la salida de otros dando lugar a funcionalidades mucho más complejas que las que realizan los comandos individualmente. También los comandos son más eficientes al no requerir tantos recursos del sistema. Por todo ello los comandos y programas basados en la consola o terminal no van a desaparecer.

En GNU/Linux la terminal es una parte importante del sistema con la que es posible realizar muchas de las tareas, es más fácil y habitual para tareas repetitivas. ncurses es una librería para desarrollar programas basados en texto pero simulando una interfaz gráfica. Se pueden crear ventanas, botones, mensajes de texto, paneles, gestores de disposición o layouts, etiquetas, cajas de texto, selectores, botones check y radio, diálogos, etc…

En Java está la librería Lanterna que proporciona similar funcionalidad que ncurses, y quizá más, sirve para el mismo propósito pero con una implementación completamente basada en Java y sin necesidad de recurrir a código nativo. En la documentación de Lanterna hay varios ejemplos y guías de las clases principales que forman la API.

Un ejemplo de uso posible para Lanterna es realizar un instalador basado en texto para el script de instalación de Arch Linux que implementé y mantengo desde hace un tiempo. Con Lanterna es posible crear el instalador o configurador para la instalación desatendida y automatizada que junto con jlink para crear un runtime distribuible de Java es posible ejecutar sin necesidad de instalar Java previamente en el sistema y utilizando la imagen que proporciona Arch Linux sin necesidad de modificarla.

El siguiente código muestra lo que podría ser la pantalla inicial de este instalador usando Lanterna.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
package io.github.picodotdev.blogbitix.lanterna;

import java.util.Arrays;

import com.googlecode.lanterna.SGR;
import com.googlecode.lanterna.TerminalSize;
import com.googlecode.lanterna.TextColor;
import com.googlecode.lanterna.graphics.SimpleTheme;
import com.googlecode.lanterna.gui2.BasicWindow;
import com.googlecode.lanterna.gui2.BorderLayout;
import com.googlecode.lanterna.gui2.Button;
import com.googlecode.lanterna.gui2.DefaultWindowManager;
import com.googlecode.lanterna.gui2.EmptySpace;
import com.googlecode.lanterna.gui2.GridLayout;
import com.googlecode.lanterna.gui2.Label;
import com.googlecode.lanterna.gui2.MultiWindowTextGUI;
import com.googlecode.lanterna.gui2.Panel;
import com.googlecode.lanterna.gui2.Window;
import com.googlecode.lanterna.screen.Screen;
import com.googlecode.lanterna.screen.TerminalScreen;
import com.googlecode.lanterna.terminal.DefaultTerminalFactory;
import com.googlecode.lanterna.terminal.Terminal;

public class Main {

    public static void main(String[] args) throws Exception {
        Terminal terminal = new DefaultTerminalFactory().createTerminal();
        Screen screen = new TerminalScreen(terminal);
        screen.startScreen();

        Panel titlePanel = new Panel();
        titlePanel.addComponent(new Label(" "));
        titlePanel.addComponent(new Label(" Arch Linux Installation").addStyle(SGR.BOLD));

        Panel buttonsPanel = new Panel(new GridLayout(2).setHorizontalSpacing(1));
        buttonsPanel.addComponent(new Button("Continue", () -> System.exit(0)));
        buttonsPanel.addComponent(new Button("Exit", () -> System.exit(0)));
        buttonsPanel.setLayoutData(GridLayout.createLayoutData(GridLayout.Alignment.END, GridLayout.Alignment.CENTER, false, false));

        Panel contentPanel = new Panel(new GridLayout(1).setLeftMarginSize(1).setRightMarginSize(1));
        contentPanel.addComponent(new EmptySpace(new TerminalSize(0, 1)));
        contentPanel.addComponent(new Label("Welcome to Arch Linux Install Script.\n\nThis automated, unnatended and configurable script\nwill install Arch Linux on your system."));
        contentPanel.addComponent(new EmptySpace(new TerminalSize(0, 1)));
        contentPanel.addComponent(new Label("Warning!\n\nThis script deletes all partitions of the persistent\nstorage and continuing all your data in it will be lost.").setForegroundColor(TextColor.ANSI.RED));
        contentPanel.addComponent(new EmptySpace(new TerminalSize(0, 1)));
        buttonsPanel.setLayoutData(GridLayout.createLayoutData(GridLayout.Alignment.END, GridLayout.Alignment.CENTER,false,false)).addTo(contentPanel);

        Panel mainPanel = new Panel(new BorderLayout());
        mainPanel.addComponent(titlePanel, BorderLayout.Location.TOP);

        BasicWindow mainWindow = new BasicWindow();
        mainWindow.setHints(Arrays.asList(Window.Hint.FULL_SCREEN, Window.Hint.NO_DECORATIONS));
        mainWindow.setTheme(new SimpleTheme(TextColor.ANSI.WHITE, TextColor.ANSI.BLUE));
        mainWindow.setComponent(mainPanel);

        BasicWindow window = new BasicWindow("Arch Linux Installation");
        window.setHints(Arrays.asList(Window.Hint.CENTERED));
        window.setComponent(contentPanel);

        MultiWindowTextGUI gui = new MultiWindowTextGUI(screen, new DefaultWindowManager(), new EmptySpace(TextColor.ANSI.BLUE));
        gui.addWindow(mainWindow);
        gui.addWindow(window);
        gui.waitForWindowToClose(mainWindow);
        gui.setActiveWindow(window);
    }
}
Main.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
plugins {
    id 'application'
}

repositories {
    mavenCentral()
}

dependencies {
    implementation 'com.googlecode.lanterna:lanterna:3.1.1'
}

application {
    mainClass = 'io.github.picodotdev.blogbitix.lanterna.Main'
    sourceCompatibility = '11'
}

build.gradle

Hola Mundo con Lanterna

Hola Mundo con Lanterna
Terminal

El código fuente completo del ejemplo puedes descargarlo del repositorio de ejemplos de Blog Bitix alojado en GitHub y probarlo en tu equipo ejecutando siguiente comando:
./gradlew distZip && unzip -o -d app/build/distributions/ app/build/distributions/app.zip && ./app/build/distributions/app/bin/app

Comparte el artículo: