GolangでGUIのクロスプラットフォームアプリを作る
fyne-io/fyne というOpenGLを使うライブラリを使います。 この間1.0が出たみたいです。 僕はGolang Weeklyのツイートで知りました。
Fyne 1.0: A Cross Platform GUI Development Toolkit – https://t.co/Ag2EK2wkwA
— Golang Weekly (@golangweekly) 2019年3月22日
簡単なタイマーを作ってみる
こんな感じのものを作ります。
リポジトリ
コード
OpenGLを触ったことがないのでC++とかで使うOpenGLがどうなのかはわからないですが、 Canbasを作ってその上にWidgetを乗せてくみたいな感じでとてもわかりやすいなと思います 雰囲気Flutterぽいなと思いました。
package main
import (
"fmt"
"time"
"fyne.io/fyne"
"fyne.io/fyne/app"
"fyne.io/fyne/widget"
"github.com/nozo-moto/pomodoro_timer/timer"
)
var (
showTimeLabel widget.Label
)
const (
countTime = time.Second * 10
)
func init() {
showTimeLabel.Alignment = fyne.TextAlignCenter
}
func main() {
showTimeChan := make(chan time.Duration)
timer := timer.New(countTime, showTimeChan)
go timer.Run()
go func() {
for {
select {
case showtime := <-showTimeChan:
showTimeLabel.SetText(formatTime(showtime))
}
}
}()
startButton := &widget.Button{
Text: "Start", OnTapped: func() { timer.Start() },
}
stopButton := &widget.Button{
Text: "Stop", OnTapped: func() { timer.Stop() },
}
a := app.New()
w := a.NewWindow("Timer")
w.Resize(fyne.Size{Width: 150, Height: 150})
canvasObjects := []fyne.CanvasObject{
&widget.Label{Text: "Timer", Alignment: fyne.TextAlignCenter},
&showTimeLabel,
startButton,
stopButton,
}
w.SetContent(&widget.Box{Children: canvasObjects})
timer.Initialize(countTime)
w.ShowAndRun()
}
func formatTime(t time.Duration) string {
h := t / time.Hour
m := (t - h*time.Hour) / time.Minute
s := (t - h*time.Hour - m*time.Minute) / time.Second
return fmt.Sprintf("%d:%d:%d", h, m, s)
}
timer.go
package timer
import (
"time"
)
const timerTime = 1 * time.Second
type Timer struct {
startTime time.Time
showTimeChan chan time.Duration
CountTime time.Duration
}
func New(countTime time.Duration, showTime chan time.Duration) *Timer {
return &Timer{
startTime: time.Time{},
showTimeChan: showTime,
CountTime: countTime,
}
}
func (t *Timer) Run() {
timeTicker := time.NewTicker(timerTime)
for {
select {
case <-timeTicker.C:
if t.startTime != (time.Time{}) {
showtime := t.CountTime - time.Now().Sub(t.startTime)
if showtime < 0 {
t.Stop()
break
}
t.showTimeChan <- showtime
}
}
}
}
func (t *Timer) Start() {
t.startTime = time.Now()
}
func (t *Timer) Stop() {
t.startTime = time.Time{}
t.showTimeChan <- 0
}
func (t *Timer) Initialize(initalTimer time.Duration) {
t.showTimeChan <- initalTimer
}
その他
タイマーが終ったのを通知させたり、音楽鳴らしたりしたかったができなかった。
音楽再生と、通知はRoadmapに乗ってるのでそのうちできるんじゃないかなと思います 。
ロードマップには
- Higher level interaction and workflow definitions – navigation, app scaffold, notifications etc
- Web-service integration for working with cloud services etc
- Multimedia integration
- Interoperability with other applications or UI providers (file pickers, document viewers etc)
- Payment integration
とあるので後々実装されそうです。
音楽は
https://www.nozograph.com/2019/07/09/453/
の記事で書いたやり方を試したがこれに組み込むのは無理でした。
雑感
GUIクロスプラットフォームアプリだとElectronくらいしかなさそうな上に、大変なのでサクッと作るならこっちの方が楽だなといった印象です。