Lanterna
Swingライクなコンポーネントベースアプローチを採用した純粋Java TUIライブラリ。ネイティブ依存なしで、開発環境でのSwingターミナルエミュレータを提供。
GitHub概要
スター2,442
ウォッチ65
フォーク260
作成日:2015年6月29日
言語:Java
ライセンス:GNU Lesser General Public License v3.0
トピックス
なし
スター履歴
データ取得日時: 2025/7/25 11:08
Lanterna
Lanternaは、テキスト環境でセミグラフィカルなユーザーインターフェースを作成するためのJavaライブラリです。C言語のcursesライブラリに似ていますが、より多くの機能を提供します。100%純粋Javaで実装されており、ネイティブライブラリに依存しません。
特徴
3層アーキテクチャ
- Terminal層: 最も低レベルの抽象化層
- Screen層: ダブルバッファリングを提供する中間層
- GUI層: 完全なGUIツールキットを提供する最上位層
プラットフォームサポート
- 純粋Java: ネイティブライブラリ依存なし
- Swingエミュレータ: GUI環境での開発用ターミナル
- クロスプラットフォーム: Linux、Windows、macOS対応
- 自動検出: 最適なターミナル実装を自動選択
GUIコンポーネント
- ウィンドウシステム: モーダル/マルチウィンドウ対応
- 基本コンポーネント: Button、Label、TextBox、ComboBox
- レイアウトマネージャー: LinearLayout、GridLayout
- ダイアログ: MessageDialog、FileDialog
入出力機能
- キーボード入力: 特殊キー、修飾キー対応
- マウスサポート: クリック、ドラッグイベント
- カラーサポート: 256色、RGBカラー対応
- Unicodeサポート: 完全なUTF-8サポート
基本的な使用方法
インストール
<!-- Maven -->
<dependency>
<groupId>com.googlecode.lanterna</groupId>
<artifactId>lanterna</artifactId>
<version>3.1.1</version>
</dependency>
// Gradle
implementation 'com.googlecode.lanterna:lanterna:3.1.1'
Hello World(Terminal層)
import com.googlecode.lanterna.terminal.*;
import com.googlecode.lanterna.TerminalSize;
import java.io.IOException;
public class HelloWorldTerminal {
public static void main(String[] args) throws IOException {
// ターミナルの作成
Terminal terminal = new DefaultTerminalFactory().createTerminal();
// プライベートモードに入る
terminal.enterPrivateMode();
terminal.clearScreen();
// カーソルを移動してテキストを出力
terminal.setCursorPosition(10, 5);
terminal.putCharacter('H');
terminal.putCharacter('e');
terminal.putCharacter('l');
terminal.putCharacter('l');
terminal.putCharacter('o');
terminal.putCharacter(',');
terminal.putCharacter(' ');
terminal.putCharacter('W');
terminal.putCharacter('o');
terminal.putCharacter('r');
terminal.putCharacter('l');
terminal.putCharacter('d');
terminal.putCharacter('!');
terminal.flush();
// キー入力を待つ
terminal.readInput();
// プライベートモードを終了
terminal.exitPrivateMode();
terminal.close();
}
}
Screen層の使用
import com.googlecode.lanterna.screen.*;
import com.googlecode.lanterna.terminal.*;
import com.googlecode.lanterna.graphics.*;
import com.googlecode.lanterna.TextColor;
import java.io.IOException;
public class ScreenExample {
public static void main(String[] args) throws IOException {
// ターミナルとスクリーンの作成
Terminal terminal = new DefaultTerminalFactory().createTerminal();
Screen screen = new TerminalScreen(terminal);
screen.startScreen();
screen.clear();
// TextGraphicsを使用した描画
TextGraphics textGraphics = screen.newTextGraphics();
textGraphics.setForegroundColor(TextColor.ANSI.YELLOW);
textGraphics.setBackgroundColor(TextColor.ANSI.BLUE);
// テキストの描画
textGraphics.putString(5, 3, "Lanterna Screen Example");
// ボックスの描画
textGraphics.drawRectangle(
new TerminalPosition(3, 2),
new TerminalSize(25, 5),
'█'
);
// 画面を更新
screen.refresh();
// キー入力を待つ
screen.readInput();
screen.stopScreen();
terminal.close();
}
}
GUI層の使用
import com.googlecode.lanterna.gui2.*;
import com.googlecode.lanterna.screen.*;
import com.googlecode.lanterna.terminal.*;
import java.io.IOException;
import java.util.Arrays;
public class GUIExample {
public static void main(String[] args) throws IOException {
// ターミナルとGUIの初期化
Terminal terminal = new DefaultTerminalFactory().createTerminal();
Screen screen = new TerminalScreen(terminal);
screen.startScreen();
// GUIの作成
MultiWindowTextGUI gui = new MultiWindowTextGUI(screen);
// ウィンドウの作成
BasicWindow window = new BasicWindow("Lanterna GUI Example");
window.setHints(Arrays.asList(Window.Hint.CENTERED));
// パネルの作成
Panel panel = new Panel();
panel.setLayoutManager(new GridLayout(2));
// コンポーネントの追加
panel.addComponent(new Label("名前:"));
TextBox nameBox = new TextBox();
panel.addComponent(nameBox);
panel.addComponent(new Label("年齢:"));
TextBox ageBox = new TextBox().setValidationPattern("[0-9]*");
panel.addComponent(ageBox);
panel.addComponent(new EmptySpace());
Button submitButton = new Button("Submit", new Runnable() {
@Override
public void run() {
MessageDialog.showMessageDialog(
gui,
"入力内容",
"名前: " + nameBox.getText() + "\n" +
"年齢: " + ageBox.getText()
);
}
});
panel.addComponent(submitButton);
// ウィンドウにパネルを設定
window.setComponent(panel);
// GUIを表示
gui.addWindowAndWait(window);
// クリーンアップ
screen.stopScreen();
terminal.close();
}
}
カスタムコンポーネント
import com.googlecode.lanterna.gui2.*;
import com.googlecode.lanterna.TerminalSize;
import com.googlecode.lanterna.TextColor;
public class ProgressBar extends AbstractComponent<ProgressBar> {
private double progress = 0.0;
private String label = "";
public ProgressBar() {
setPreferredSize(new TerminalSize(20, 1));
}
public void setProgress(double progress) {
this.progress = Math.max(0.0, Math.min(1.0, progress));
invalidate();
}
public void setLabel(String label) {
this.label = label;
invalidate();
}
@Override
protected ComponentRenderer<ProgressBar> createDefaultRenderer() {
return new ComponentRenderer<ProgressBar>() {
@Override
public TerminalSize getPreferredSize(ProgressBar component) {
return new TerminalSize(20, 1);
}
@Override
public void drawComponent(TextGUIGraphics graphics, ProgressBar component) {
TerminalSize size = graphics.getSize();
int width = size.getColumns();
int filledWidth = (int)(width * component.progress);
// 進捗バーの描画
graphics.setForegroundColor(TextColor.ANSI.GREEN);
for (int i = 0; i < filledWidth; i++) {
graphics.setCharacter(i, 0, '█');
}
graphics.setForegroundColor(TextColor.ANSI.WHITE);
for (int i = filledWidth; i < width; i++) {
graphics.setCharacter(i, 0, '░');
}
// ラベルの描画
if (!component.label.isEmpty()) {
String text = component.label + " " +
(int)(component.progress * 100) + "%";
int textX = (width - text.length()) / 2;
graphics.putString(textX, 0, text);
}
}
};
}
}
テーマのカスタマイズ
import com.googlecode.lanterna.gui2.*;
import com.googlecode.lanterna.TextColor;
import com.googlecode.lanterna.graphics.*;
public class CustomTheme extends SimpleTheme {
public CustomTheme() {
// ウィンドウのスタイル
setWindowBackgroundColor(TextColor.ANSI.BLUE);
setWindowForegroundColor(TextColor.ANSI.WHITE);
// ボタンのスタイル
addOverride(Button.class, new ComponentRenderer<Button>() {
@Override
public TerminalSize getPreferredSize(Button component) {
return new TerminalSize(
component.getLabel().length() + 4, 3
);
}
@Override
public void drawComponent(TextGUIGraphics graphics, Button button) {
ThemeDefinition themeDefinition = button.getThemeDefinition();
if (button.isFocused()) {
graphics.applyThemeStyle(themeDefinition.getActive());
} else {
graphics.applyThemeStyle(themeDefinition.getNormal());
}
// ボタンの枠を描画
graphics.drawRectangle(
TerminalPosition.TOP_LEFT_CORNER,
graphics.getSize(),
'█'
);
// ラベルを中央に描画
graphics.putString(
2, 1,
button.getLabel()
);
}
});
}
}
高度な機能
マルチウィンドウアプリケーション
// 非モーダルウィンドウの作成
BasicWindow window1 = new BasicWindow("Window 1");
window1.setHints(Arrays.asList(
Window.Hint.NO_DECORATIONS,
Window.Hint.FIXED_POSITION
));
window1.setPosition(new TerminalPosition(5, 3));
BasicWindow window2 = new BasicWindow("Window 2");
window2.setHints(Arrays.asList(
Window.Hint.NO_DECORATIONS,
Window.Hint.FIXED_POSITION
));
window2.setPosition(new TerminalPosition(25, 8));
// 両方のウィンドウを追加
gui.addWindow(window1);
gui.addWindow(window2);
非同期入力処理
// 非ブロッキング入力
KeyStroke keyStroke = screen.pollInput();
if (keyStroke != null) {
if (keyStroke.getKeyType() == KeyType.Escape) {
// ESCキーが押された
}
}
アニメーション
public class AnimatedLabel extends Label {
private String fullText;
private int currentIndex = 0;
public AnimatedLabel(String text) {
super("");
this.fullText = text;
// アニメーションタイマー
new Timer().scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
if (currentIndex <= fullText.length()) {
setText(fullText.substring(0, currentIndex));
currentIndex++;
} else {
currentIndex = 0;
}
}
}, 0, 100);
}
}
エコシステム
サポートされるターミナル
- Linux: xterm、gnome-terminal、konsole
- Windows: cmd.exe、PowerShell、Windows Terminal
- macOS: Terminal.app、iTerm2
- エミュレータ: PuTTY、MinTTY
関連プロジェクト
- CHARVA: Lanternaをバックエンドとして使用
- ゲーム開発: ローグライクゲームなどで利用
- ツール開発: TUIベースの開発ツール
利点
- 純粋Java: ネイティブ依存なしでポータビリティが高い
- 3層アーキテクチャ: 柔軟な抽象化レベル
- Swingライク: Java開発者に親しみやすいAPI
- 開発環境: GUI環境でのデバッグが容易
- アクティブ開発: 継続的なメンテナンス
制約事項
- パフォーマンス: ネイティブ実装より遅い場合がある
- 機能限定: 高度なグラフィックス機能は限定的
- 学習曲線: 3層アーキテクチャの理解が必要
- ドキュメント: 日本語資料が少ない
他のライブラリとの比較
項目 | Lanterna | Jexer | CHARVA |
---|---|---|---|
純粋Java | ○ | ○ | ×(JNI使用) |
APIスタイル | Swingライク | Turbo Visionライク | Swing互換 |
機能 | 中程度 | 高度 | 基本的 |
開発の活発度 | 高 | 中 | 低 |
学習コスト | 中 | 高 | 低 |
まとめ
Lanternaは、JavaでTUIアプリケーションを開発するための優れたライブラリです。純粋Java実装による高いポータビリティ、3層アーキテクチャによる柔軟性、SwingライクなAPIによる学習のしやすさが特徴です。特に、GUI環境での開発からヘッドレスサーバーへのデプロイまで、同じコードで対応できる点は大きな利点です。