Go言語(golang)でTUIアプリを作ろう ( その3 tviewの基本構造 )
tviewのWidgetとEventを理解しよう。
tviewの基本機能を理解するには、まず、下記のドキュメンテーションを見ることが第一歩でしょう。
(1) Widget一覧
画面を下に少しスクロールしたところに、”Widgets”という項目があります。基本的な部品は揃っているように見えますが、細部を見ていくと気になる点も少なくありません。それは後で述べるとして、とりあえずWidget一覧を見ていきましょう。
Widget | 概要 | 利用 |
---|---|---|
TextView | 表示フィールド。マルチライン可。 | ○ |
Table | テーブル形式のデータ。スクロール化。 | |
TreeView | ツリー形式の表示 | |
List | 一覧表示 | ○ |
InputField | 入力フィールド。マルチラインをサポートしていないようだ。 | ○ |
DropDown | ドロップダウン形式の表示 | |
Checkbox | チェックボックス | |
Button | ボタン | ○ |
Form | 入力フォーム。Widgetというより雛形で再利用性に乏しい。 | |
Modal | 単なるメッセージボックス。再利用性に乏しい。 | |
Grid | 二次元のコンテナ。 | |
Flex | 一次元のコンテナ。縦、横の方向を選択する。 | ○ |
Pages | 画面に複数ページを切り替えて表示できるコンテナ。 | ○ |
なお、これからの開発に使用する予定のWidgetには、「○」を付けておきました。
(2) オブジェクト構造
オブジェクトの構造について重要なポイントが、上記ドキュメント中盤に”Type Hierarchy”として記述されています。
All widgets listed above contain the Box type. All of Box’s functions are therefore available for all widgets, too.
All widgets also implement the Primitive interface.
というところです。
要するに、すべてのWidgetは、Primitiveインターフェースを実装、Boxオブジェクトを継承しているということです。下記に概念図を示しておきます。
(3) WidgetとEvent
次に、WidgetとEventの関係ですが、最上部のWidgetを、ApplicationオブジェクトのSetRootメソッドにセットすることでアプリケーションが開始されます。
入力Eventは、各WidgetのSetInputCaptureメソッドや、SetDoneFuncメソッドで処理されることになります。これも概念図を示しておきます。
プログラミング例も示しておきましょう。
下記のプログラムでは、WidgetはinputField一つだけですので、このインスタンスをApplicationのSetRootメソッドにセットしています。また、入力完了イベントは、SetDoneFuncメソッドで処理しています。
func main() {
app := tview.NewApplication()
inputField := tview.NewInputField().
SetLabel("文字を入力: ").
SetFieldWidth(10).
SetDoneFunc(func(key tcell.Key) {
app.Stop()
})
if err := app.SetRoot(inputField, true).EnableMouse(true).Run(); err != nil {
panic(err)
}
Python Urwidでは、各Widgetで処理されないイベントを一括でハンドリングできるunhandled inputが用意されていましたが、tviewでは、appにもSetInputCaptureメソッドがありますので、ここで処理すれば良さそうです。
(4) 問題点
先にも少し触れましたが、tviewのWidgetには気になる点が複数あります。
- データ入力を司るinputFieldが、複数行入力をサポートしていないこと。
これは、最も大きな問題です。 - ダイアログ関係がないこと。
Modalが一見その様に見えますが、実はメッセージボックスそのもので応用が効きません。これでは、Widgetとは言えないでしょう - Formも同様。
入力画面をサポートするものですが、作成できる画面フォーマットは決まっており、汎用性がありません。
こんなところでしょうか。前途多難が懸念されますが、その予想は....外れませんでしたね(笑)。