Fyne   ToDo

ホーム   Goチュートリアル

ToDo


この章では、ToDoアプリを作ります。この章には、多くのことを詰め込みました。

  1. リストでのアイテム(item、項目)の表示方法
  2. Fyneに用意されている、theme(テーマ)アイコンの使い方
  3. Entry(入力フィールド)付きのダイアログの作成方法
  4. リストのデータとなるスライスの各種操作方法
  5. ハードディスクからのファイル(データ)の読み込みと書き込み


アプリケーションディレクトリの作成

ターミナルもしくはコマンドプロンプトを起動して、次のようにしてアプリケーション作成の下準備をします。 ディレクトリはどこでも構いませんが、Documents などに go か fyne などのディレクトリを作り、さらに次のようにディレクトリを作るのが良いでしょう。


mkdir ToDo
cd ToDo
go mod init example.com/ToDo

// 通常は、example.com の部分を、あなたが持っているURLにします。
// デフォルトでは、スラッシュ(/)の次の名前がアプリの名前になります。
    


コードの記述

次のファイルを記述します。main 関数を記述しているファイルは、 main.go とするのが一般的ですが、好きなファイル名にしても構いません。

todo.go


package main

import (
	"bufio"
	"fyne.io/fyne/v2"
	"fyne.io/fyne/v2/app"
	"fyne.io/fyne/v2/container"
	"fyne.io/fyne/v2/dialog"
	"fyne.io/fyne/v2/layout"
	"fyne.io/fyne/v2/theme"
	"fyne.io/fyne/v2/widget"
	"os"
)

var data = []string{}

// Windows と macOS の場合は、次のようなパスを設定します。
const path string = "/Users/ユーザー名/Documentsなどのディレクトリ名/todo.txt"

/* Linux の場合は、次のようなパスを設定します。
const path string = "/home/ユーザー名/Documentsなどのディレクトリ名/todo.txt"
*/

func read(filename string) error {
	file, _ := os.Open(filename)
	defer file.Close()
	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		line := scanner.Text()
		data = append(data, line)
	}
	return nil
}

func save(filename string) error {
	file, _ := os.Create(path)
	defer file.Close()
	for _, line := range data {
		file.WriteString(line + "\n")
	}
	return nil
}

func main() {
	read(path)
	row := -1
	app := app.New()
	app.Settings().SetTheme(&myTheme{})
	win := app.NewWindow("ToDo")
	list := widget.NewList(
		func() int {
			return len(data)
		},
		func() fyne.CanvasObject {
			return widget.NewLabel("template")
		},
		func(i widget.ListItemID, o fyne.CanvasObject) {
			o.(*widget.Label).SetText(data[i])
		},
	)
	list.OnSelected = func(id int) { row = id }
	add := widget.NewButtonWithIcon("", theme.ContentAddIcon(),
		func() {
			entry := widget.NewEntry()
			dialog.ShowForm("ToDoを追加", "追加", "キャンセル",
				[]*widget.FormItem{
					widget.NewFormItem("入力...", entry)},
				func(b bool) {
					if b && entry.Text != "" {
						data = append([]string{entry.Text}, data...)
						list.Refresh()
						save(path)
					}
				}, win)
		})
	edit := widget.NewButtonWithIcon("", theme.DocumentCreateIcon(),
		func() {
			if row != -1 {
				entry := widget.NewEntry()
				entry.SetText(data[row])
				dialog.ShowForm("ToDoを編集", "編集", "キャンセル",
					[]*widget.FormItem{
						widget.NewFormItem("入力...", entry)},
					func(b bool) {
						if b && row != -1 {
							data[row] = entry.Text
							list.Refresh()
							save(path)
						}
					}, win)
			}
		})
	remove := widget.NewButtonWithIcon("", theme.ContentRemoveIcon(),
		func() {
			if row != -1 {
				dialog.ShowConfirm("ToDoの削除",
					"本当に削除してもよろしいですか?",
					func(b bool) {
						if b {
							data = append(data[:row], data[row+1:]...)
							list.Unselect(row)
							list.Refresh()
							save(path)
						}
					}, win)
			}
		})
	up := widget.NewButtonWithIcon("", theme.MoveUpIcon(),
		func() {
			if row != 0 && row != -1 {
				temp := data[row]
				data = append(data[:row], data[row+1:]...)
				data = append(data[:row-1],
					append([]string{temp}, data[row-1:]...)...)
				row -= 1
				list.Select(row)
				list.Refresh()
				save(path)
			}
		})
	down := widget.NewButtonWithIcon("", theme.MoveDownIcon(),
		func() {
			if row != len(data)-1 && row != -1 {
				temp := data[row]
				data = append(data[:row], data[row+1:]...)
				data = append(data[:row+1],
					append([]string{temp}, data[row+1:]...)...)
				row += 1
				list.Select(row)
				list.Refresh()
				save(path)
			}
		})
	buttons := container.New(layout.NewVBoxLayout(),
		add, edit, up, down, layout.NewSpacer(), remove)
	content := container.New(layout.NewBorderLayout(nil, nil, nil, buttons),
		buttons, list)
	win.SetContent(content)
	win.Resize(fyne.NewSize(400, 200))
	win.ShowAndRun()
}
	


  1. 次の bundle.go と theme.go はアプリケーションで日本語を表示したり、日本語を入力できるようにするために必要です。
  2. bundle.go はフォントファイルからリソース(resource、資源)を取り出したものです。
  3. その取り出したリソースを theme.go で設定します。
  4. ビルドする場合は、3つのGoファイルを指定して、
    go run todo.go bundle.go theme.go もしくは、got run *.go とします。
  5. パッケージ化(ダブルクリックで実行できるアプリケーション)にする場合は、
    fyne package -os darwin -icon leaf.png などとします。
  6. -os のところは Windows の場合は windows、Mac の場合は darwin、 Linux の場合は linux とします。
  7. Icon ファイルは、png しか指定できないみたいです。
  8. 指定した png ファイルは、それぞれの OS の正しい Icon ファイルに変換されます。


bundle.go


fyne bundle Osaka.ttf > bundle.go


// 上記のようにコマンドするとフォントをリソースに変換した bundle.go が出来上がります。
// Osaka.ttf のところは、フォントフォルダからコピーしてきた任意の日本語フォントを指定します。
// フォントファイルをコピーせずに、フォントファイルまでのフルパスを指定することもできます。
// この bundle.go は、大変大きなファイルになりますので、ほとんどのテキストエディタでは開けません。
// 私の場合は、ターミナル版 Emacs とデスクトップ版 CotEditor では、フリーズしてしまいました。
// デスクトップ版のEmacsでは開くことができました。
// フォントのサイズがそのままアプリケーションのサイズになることはありませんが、大きなサイズのフォントほど大きなアプリケーションのサイズになります。
// サイズを気にしないのであれば、Mac の場合 Arial Unicode.ttf などが探しやすくて良いでしょう。


var resourceOsakaTtf = &fyne.StaticResource{
	StaticName: "Osaka.ttf",
	StaticContent: []byte(
		"\x00\x01\x00\x00\x00\x19\x01\x00\x00\x04\x01\x80OS/2V\x82p}\x00\x00\x02\xf0\x00"・・・
		

// bundle.go を大きなサイズのファイルを開くことができるテキストエディタで開くと上記のように書かれています。末尾はフォントを定義した数値が続きます。
// ここで必要となるのは var の次に書かれている resourceOsakaTtf というリソース名です。
// このリソース名は読み込んだフォントによって変わります。
	


theme.go


// 15行目の return に先程のフォントリソース名を指定します。

package main

import (
	"fyne.io/fyne/v2"
	"fyne.io/fyne/v2/theme"
	"image/color"
)

type myTheme struct{}

var _ fyne.Theme = (*myTheme)(nil)

// return bundled font resource
func (*myTheme) Font(s fyne.TextStyle) fyne.Resource {
	return resourceOsakaTtf
}

func (*myTheme) Color(n fyne.ThemeColorName, v fyne.ThemeVariant) color.Color {
	return theme.DefaultTheme().Color(n, v)
}

func (*myTheme) Icon(n fyne.ThemeIconName) fyne.Resource {
	return theme.DefaultTheme().Icon(n)
}

func (*myTheme) Size(n fyne.ThemeSizeName) float32 {
	return theme.DefaultTheme().Size(n)
}
    


パッケージの読み込み

コードの記述が完了しましたら、次のようにして実行します。


go run todo.go bundle.go theme.go

// 次のようにパッケージをインストールしてくださいという表示が出ます。
todo.go:4:8: no required module provides package fyne.io/fyne/v2; to add it:
	go get fyne.io/fyne/v2
todo.go:5:8: no required module provides package fyne.io/fyne/v2/app; to add it:
	go get fyne.io/fyne/v2/app
todo.go:6:8: no required module provides package fyne.io/fyne/v2/container; to add it:
	go get fyne.io/fyne/v2/container
todo.go:7:8: no required module provides package fyne.io/fyne/v2/dialog; to add it:
	go get fyne.io/fyne/v2/dialog
todo.go:8:8: no required module provides package fyne.io/fyne/v2/layout; to add it:
	go get fyne.io/fyne/v2/layout
goto.go:9:8: no required module provides package fyne.io/fyne/v2/theme; to add it:
	go get fyne.io/fyne/v2/theme
todo.go:10:8: no required module provides package fyne.io/fyne/v2/widget; to add it:
	go get fyne.io/fyne/v2/widget

// 指示のとおりインストールします。
go get fyne.io/fyne/v2
go get fyne.io/fyne/v2/app
go get fyne.io/fyne/v2/container
go get fyne.io/fyne/v2/dialog
go get fyne.io/fyne/v2/layout
go get fyne.io/fyne/v2/theme
go get fyne.io/fyne/v2/widget

// もう一度実行してみます。
go run todo.go bundle.go theme.go
    


実行方法

  1. ビルドする場合は、3つのGoファイルを指定して、
    go run todo.go bundle.go theme.go もしくは、got run *.go とします。
  2. パッケージ化(ダブルクリックで実行できるアプリケーション)にする場合は、
    fyne package -os darwin -icon leaf.png などとします。
  3. -os のところは Windows の場合は windows、Mac の場合は darwin、 Linux の場合は linux とします。
  4. Icon ファイルは、png しか指定できないみたいです。
  5. 指定した png ファイルは、それぞれの OS の正しい Icon ファイルに変換されます。


実行結果

Fyne のリストでは、選択されている項目は、色が反転するのではなく、 項目の左隅に青い縦線が表示されるだけです、注意してくだい。

デフォルトでは、Windowsの場合は白いウィンドウ、macOSとLinuxの場合は、 黒いウィンドウになります。


これからの予定

いきなり、ToDo というチュートリアルでやるべき最後のサンプルのようなことから初めてしまいました。 ここから続けるとすれば、テキストエディタか画像ビューワになると思いますが、その前に Fyne のインストールと簡単なサンプルを前に戻って説明しようと思います。


25012 visits
Posted: Jun. 21, 2021
Update: Jun. 25, 2021

ホーム   Goチュートリアル   目次