本文へスキップ

ビュー

コンポーネントはマウント時に UI を組み立てます。子が状態に応じて現れたり消えたり、並び替えられたりするときは ui.Show と ui.For を使います。

#ビューの仕組み

どのコンポーネントも *ui.Element を返します。子は .Child(...) または .Children(...) で渡します。ラッパーなしの兄弟が複数あるときは ui.Fragment(...) を返します。

func ViewExample() *ui.Element {
	return ui.View().Padding(20).Gap(12).Children(
		ui.Text("Hello from Go"),
		ui.Button().Child("Continue").OnClick(func() {}),
	)
}

普通の Go の if や for は、コンポーネントの構築中にだけ実行されます。あとから更新されることはありません。

#条件付きコンテンツ

状態から子をマウントまたは取り除くには ui.Show を使います。

func DisclosureExample() *ui.Element {
	open, setOpen := ui.CreateSignal(false)
	return ui.View().Children(
		ui.Button().Child("Toggle details").OnClick(func() { setOpen(!open()) }),
		ui.Show(
			open,
			func() *ui.Element { return ui.Text("Details") },
		),
	)
}

#リスト

変化しうるリストには ui.For を使います。各行には安定した一意のキーを付けます。データベースの ID を使い、インデックスは使わないでください。ui.KeyedFor は、その行に現在の項目への accessor も渡します。

type ListPerson struct {
	ID   int
	Name string
}

func KeyedListExample() *ui.Element {
	people, setPeople := ui.CreateSignal([]ListPerson{{1, "Ada"}, {2, "Grace"}})
	return ui.View().Children(
		ui.Button().Child("Reorder and rename").OnClick(func() {
			setPeople([]ListPerson{{2, "Grace"}, {1, "Ada Lovelace"}})
		}),

		ui.KeyedFor(
			people,
			func(person ListPerson) any { return person.ID },
			func(person func() ListPerson, index func() int) *ui.Element {
				return ui.Text(
					index(),
					": ",
					person().Name,
				)
			},
			func() *ui.Element { return ui.Text("No people") },
		),
	)
}

データを編集するときは新しいスライスを渡します。格納済みのスライスをその場で変更しても、購読者には通知されません。長いリストには VirtualList または Table を使います。

#ウィンドウのライフサイクル

各ウィンドウには独自のコンポーネントルートがあります。ウィンドウを閉じると、その UI と effect は破棄されます。クリーンアップは ui.OnCleanup で登録します。ui.Async は UI ゴルーチンの外で作業を実行し、結果を戻し、コンポーネントがなくなっていればキャンセルします。

func LoadingPanel(load func(context.Context) (string, error)) *ui.Element {
	result, setResult := ui.CreateSignal("Loading…")
	ui.Async(
		load,
		func(value string, err error) {
			if err != nil {
				setResult(err.Error())
				return
			}
			setResult(value)
		},
	)
	return ui.Text(result())
}

#現在のウィンドウ

コンポーネントのマウント中に native.CurrentWindow() をキャプチャし、コールバックではそのハンドルを使います。

func CloseButton() *ui.Element {
	window := native.CurrentWindow()
	return ui.Button().Child("Close window").OnClick(func() { window.Close() })
}

#テスト

アプリモジュールから quickgui test を実行します。quickgui fmt --check は書式を検査します。アプリは Go の実行ファイルなので、いつもの Go デバッガーとスタックトレースはソースファイルを指します。