golangのrivo/tviewで、Listの要素を参照しつつselectedの関数を定義したい

January 17, 2021

暇だったのでrss Readerを作っていました。 “github.com/rivo/tview”というパッケージの使い方でハマったところがあったのでメモ

やりたいこと

github.com/rivo/tviewのListにAddItemする際に、selectedという関数を定義する必要があるのですが、それで、Listの番号を参照したかったのです。 機能としては、Listを選択したら隣のtextViewに本文が表示される感じです。 調べたところ、空のselected functionを定義したあとに、 List.SetSelectionFunc(func(int, string, string, rune)) を呼び出せば良さそうです。

こうやって解決しました

var list = tview.NewList()
var textview tview.NewTextView()
var texts = []string{"foo", "bar", "fizz", "buzz"}

for _, t := range texts {
	list.AddItem(txt0, txt1, 's', func() {})
  list.SetSelectedFunc(func(i int, _ string, _ string, _ rune) {
    textview.Clear()
    textview.SetText(texts[i])
  })
}

誤った例

var list = tview.NewList()
var textview tview.NewTextView()
var texts = []string{"foo", "bar", "fizz", "buzz"}

for _, t := range texts {
	list.AddItem(txt0, txt1, 's', func() {
    textview.Clear()
    textview.SetText(t)
  })
}

この無名関数は、goroutineで動くため、このままだと良くないことがおきます。 簡略化するとこれ。 下の関数を実行すると50を50回出力しますからね。

func main() {
	for i := 0; i < 50; i++ {
		do(func() {
			time.Sleep(time.Second)
			fmt.Println(i)
		})
	}
	time.Sleep(4 * time.Second)
}

func do(f func()) {
	go f()
}

まとめ

だいたいドキュメントに書いてある。


Written by aimof
Goプログラマ。PythonやJSなどもちょくちょく触る。最近はGatsbyのカスタマイズが楽しい。 Twitter