ただのアニメ感想ブログ

主にアニメの感想を書いていきます。

GoLangを触ってみた#その4

本シリーズもこれが最後になります。
最後に簡単なGUIにも手を出して見ようと思います。


と言ってもGoはあまりGUIの機能が充実しておらず、自分の場合はShinyと言う拡張機能を導入しました。
参考にしたのは以下の記事です。
http://qiita.com/tenntenn/items/1ea8750a5668c7595881


まずはAWSの時のようにGoを使ってパッケージ類を落としてきます。

>set GOPATH=<適当なパス>
>go get golang.org/x/exp/shiny/...


サンプルとなるソースコードは"$GOPATH\src\golang.org\x\exp\shiny\example"配下にありました。
それらを参考にして、簡単なGUIのプログラムを書いたのが以下のものになります。

ファイル名:gui.go
package main

import (
    "image"
    "image/color"
    "log"

    "golang.org/x/exp/shiny/driver"
    "golang.org/x/exp/shiny/screen"
    "golang.org/x/mobile/event/key"
    "golang.org/x/mobile/event/lifecycle"
    "golang.org/x/mobile/event/mouse"
    "golang.org/x/mobile/event/paint"
    "golang.org/x/mobile/event/size"
)

const (
    windowWidth  = 640
    windowHeight = 480
    
    modeNone = 0
    modeDrug = 1
)

var (
    red   = color.RGBA{0x7f, 0x00, 0x00, 0x7f}
    white = color.RGBA{0xff, 0xff, 0xff, 0xff}
    
    r = 20
    x = (windowWidth-r)/2
    y = (windowHeight-r)/2
    
    mode = modeNone
    x1 float32 = 0
    y1 float32 = 0
    x2 float32 = 0
    y2 float32 = 0
)

func main() {
    driver.Main(func(s screen.Screen) {
        w, err := s.NewWindow(
            &screen.NewWindowOptions{
                Width:  windowWidth,
                Height: windowHeight,
            },
        )
        if err != nil {
            log.Fatal(err)
        }
        defer w.Release()

        var sz size.Event
        for {
            e := w.NextEvent()
            switch e := e.(type) {
            case lifecycle.Event:
                if e.To == lifecycle.StageDead {
                    return
                }

            case key.Event:
                if e.Code == key.CodeEscape {
                    return
                }

            case mouse.Event:
                if e.Direction == mouse.DirPress {
                    if x <= (int)(e.X) && (int)(e.X) <= x+r && y <= (int)(e.Y) && (int)(e.Y) <= y+r {
                        mode = modeDrug
                        x1 = e.X
                        y1 = e.Y
                    }
                } else if e.Direction == mouse.DirRelease {
                    mode = modeNone
                } else if mode == modeDrug {
                    x2 = e.X
                    y2 = e.Y
                    x += (int)(x2-x1)
                    y += (int)(y2-y1)
                    x1 = x2
                    y1 = y2
                }
                w.Fill(sz.Bounds(), white, screen.Src)
                w.Fill(image.Rect(x, y, x+r, y+r), red, screen.Over)
                w.Publish()

            case paint.Event:
                w.Fill(sz.Bounds(), white, screen.Src)
                w.Fill(image.Rect(x, y, x+r, y+r), red, screen.Over)
                w.Publish()

            case size.Event:
                sz = e

            case error:
                log.Print(e)
            }
        }
    })
}


まずconstではウィンドウのサイズとマウスの状態を記録するための定数を宣言しています。
varでは描画する色と、オブジェクトの位置と大きさを記録する変数を宣言。mode以下のものは大域変数として宣言する必要は無いような気がしますが、適切な場所が思いつかなかったのでここに記載。


main関数ではdriver.Mainの中で関数を宣言します。これはそういう風に書くお約束みたいなものと理解しています。
NewWindowではウィンドウの作成をしています。難しいことは考えずに、こう書いておけば決められたサイズのウィンドウができると思っておけば良いと思います。


for文の中ではイベント(マウスを動かしたり、キーボードを押したり、ウィンドウを閉じたり)をキャッチしてはそれに対応する処理を実行すると言うことを繰り返しています。
lifecycle、key、size、errorに関しては大したことは書いていません。
paintでは描画する内容について記述しています。と言っても、背景を白く塗りつぶし、その上に赤い四角を書いているだけです。
mouseでは赤い四角をドラッグしたときの処理を記載しています。ドラッグ状態にあるかどうかの判定と、ドラッグ状態の場合はマウスの移動した距離を計算して四角の位置を補正する処理を書いています。
また、移動後に画面を再描画する処理も行っています。このあたりを関数で外出しした方が良いのだと思いますが、面倒なので今回は割愛。


で、実行した結果は以下のようになります。

f:id:triobog:20160507010542j:plain

画面内の赤い四角をドラッグするとそれに合わせて動いてくれます。
超簡単なものではありますが、一応これでGUIもやったと言ってよいでしょう。


はっきりいってGUIをやるならGoよりはJavaなどの方が向いていると思います(OpenGLなんかもありますが、自分はそこまで詳しくないので)。
Javaの方がGUIプログラムを作るためのライブラリが豊富ですし、Goだとクラスが無いのでオブジェクトの管理が非常に面倒です。
GoにはGoの強みがあるので、それを活かすような使い方をすれば良いのだと思います。


そんなわけで、今日はこれまで。
それでは、ごきげんよう。