#Go言語でGUIしたいかー?! おー!!
とまあ、そんなノリで始まります。
##Go言語でGUIするには?
Go言語でGUIするライブラリは意外と色々あります。
-
go-ui
「Go言語 GUI」でググった時に、おそらく一番情報の多いライブラリ。ただ情報はあるけど大して気合の入ったライブラリではない模様。
__go-ui__なんて大層な名前をしてるけど、その実態はQtバインディングだったりする。
開発はもう終わったみたいで、 GoQt というのが後継らしいけど、 GoQt の方はまだリポジトリを作っただけのような状態だった。
Windowsで導入するのがほぼ無理ゲー。(最重要事案) -
go-gtk
mattn氏が開発の中心となっているGo言語のGtk+バインディング。多分Go言語のGUIライブラリで一番開発が活発。
_Windowsでも動くらしい_けれど、Win64な環境ではしったこっちゃないし、そもそもGtkベースだからLGPLなわけで、嫌LGPLな現代っ子の僕には向いてない。 -
wxGo
名前の通りwxWidgetsのGoバインディング。SWIGを使っている。
既に二年近くメンテされてないし、どうしてもwxWidgets使いたい人向け。
他にもいくつかある。ここら辺を参照。
ここまで見た感じだと、まともに開発されているライブラリはgo-gtkしかない気がします。でもなぁ、Gtkなんだよなぁ…。
##そんなあなたに、WALKはいかが?
__WALK__という、Windows向けのGUIライブラリがあります。これは、何かのGo言語バインディングというわけではなくて、Go言語から直接Win32APIを叩くことでGUIを作るライブラリです。
開発は盛んな方だと思います。600コミット以上されていて、最近もコミットされ続けていますし。 go-gtk ほどじゃないのが残念ですが。
どれだけの人に伝わるかわかりませんが、Rubyで言えばVisualRubyみたいなものです、多分。
ぶっちゃけたことを言ってしまえばただWin32APIのラッパなのですが、うまい具合に抽象化されていて、結構使いやすいです。
あと、完全にWindows向けかつGo言語単体で完結しているので、Windowsならインストールが楽ちんです。
##なにはともあれインストール
僕の環境はWindows 8上のgo version 1.1.1 windows/amd64ですが、Windowsならおそらくはうまくいくと思います。
インストール方法は、コンソール上で、
go get github.com/lxn/walk
を叩くだけ。簡単ですよね?
何も出力されなければ成功です。Go言語は怖いぐらいに 「沈黙は成功なり」 の法則を順守している気がします。せめて依存関係ぐらい出力してくれてもいいのに…。
ちなみに、何か出力されていたら十中八九エラーだと思います。恐らく一番多いエラーは、バージョン1.1.x未満のGo言語を使っていることによるので。とりあえず最新版のGo言語をインストールしてきてください。
他にも、環境変数GOPATH
が設定されていなかったり、Gitがインストールされていなかったりするとエラーが出ます。注意してください。
##それでは使ってみよう
テキストエリアの文字列を検索する、というプログラムを作ることにします。名前はsearchbox
です。
まずは、mkdir searchbox && cd searchbox
で、新しいディレクトリを作って、移動してください。ここに必要なファイルを置いていきます。
(なぜわざわざディレクトリを掘る必要があるの? って感じですが、あとあとgo build
して実行可能ファイルを作ることになるので、ディレクトリを分けておいたほうが都合がいいのです)
次に、プログラムの主役ソースコードを書きます。
とりあえず僕が書いたコードを載せておきます。(このコードのGist)
package main
//WALK関連のライブラリ
import (
"github.com/lxn/walk"
. "github.com/lxn/walk/declarative"
)
//その他標準ライブラリ
import (
"fmt"
"log"
"strings"
)
func main() {
mw := &MyMainWindow {}
if _, err := (MainWindow {
AssignTo: &mw.MainWindow,
Title: "SearchBox",
MinSize: Size {300, 400},
Layout: VBox {},
Children: []Widget {
GroupBox {
Layout: HBox {},
Children: []Widget {
LineEdit {
AssignTo: &mw.searchBox,
},
PushButton {
Text: "検索",
OnClicked: mw.clicked,
},
},
},
TextEdit {
AssignTo: &mw.textArea,
},
ListBox {
AssignTo: &mw.results,
Row: 5,
},
},
}.Run()); err != nil {
log.Fatal(err)
}
}
//structにまとめることで、グローバル変数を作らない
type MyMainWindow struct {
*walk.MainWindow
searchBox *walk.LineEdit
textArea *walk.TextEdit
results *walk.ListBox
}
func (mw *MyMainWindow) clicked() {
word := mw.searchBox.Text()
text := mw.textArea.Text()
model := []string {}
for _, i := range search(text, word) {
model = append(model, fmt.Sprintf("%d文字目に発見", i))
}
log.Print(model)
mw.results.SetModel(model)
}
//textからwordを検索して、位置をUnicode単位で返す
func search(text ,word string) (result []int) {
result = []int {}
i := 0
for j, _ := range text {
if strings.HasPrefix(text[j:], word) {
log.Print(i)
result = append(result, i)
}
i += 1
}
return
}
簡単にこのコードを説明すると、最初のimport
でWALK関連のパッケージを読み込み、
//WALK関連のライブラリ
import (
"github.com/lxn/walk"
. "github.com/lxn/walk/declarative"
)
main関数の中でWindowの構造を作り(この部分がかなり宣言的でイケてると思います)、Runメソッドを呼びGUIを初めています。
if _, err := (MainWindow {
AssignTo: &mw.MainWindow,
Title: "SearchBox",
MinSize: Size {300, 400},
Layout: VBox {},
Children: []Widget {
GroupBox {
Layout: HBox {},
Children: []Widget {
LineEdit {
AssignTo: &mw.searchBox,
},
PushButton {
Text: "検索",
OnClicked: mw.clicked,
},
},
},
TextEdit {
AssignTo: &mw.textArea,
},
ListBox {
AssignTo: &mw.results,
Row: 5,
},
},
}.Run()); err != nil {
AssignToで実施のWidgetとの結びつけをするのですね。
で、その後のclickedメソッドが「検索」ボタンを押した時に呼ばれるものです。
func (mw *MyMainWindow) clicked() {
word := mw.searchBox.Text()
text := mw.textArea.Text()
model := []string {}
for _, i := range search(text, word) {
model = append(model, fmt.Sprintf("%d文字目に発見", i))
}
log.Print(model)
mw.results.SetModel(model)
}
search関数は、本当はindex/suffixarray
パッケージを使いたかったのですが、suffixarrayがbyteにしか対応していなかったため、byte位置を教えられてもなあ、という気がしたので定義したものです。
あとはまあ、雰囲気で察してください。
ソースコードができたら、マニフェストファイルを書きます。書かないと起動しないので注意してください。
マニフェストファイルは実行可能ファイル名.manifest
という名前で保存します。
この場合はsearchbox.exe.manifest
で問題ないでしょう。
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity version="1.0.0.0" processorArchitecture="*" name="SomeFunkyNameHere" type="win32"/>
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"/>
</dependentAssembly>
</dependency>
</assembly>
ここまできたら、あとはbuildしてコンパイルするだけです。
go build
(起動時にコマンドプロンプトが表示されないようにするには、
go build -ldflags="-H windowsgui"
として下さい)
でオーケーです。
早速、起動してみましょう。
searchbox.exe
こんな画面が立ち上がれば、無事成功です。
青空文庫から適当に文章を引っ張ってきて「検索」をしてみると、こんな風になります。
良い感じじゃないでしょうか?
##最後に
説明をかなり簡略化したため、わかりにくいところ(コードの意味とか)は多いと思います。そこはWALKのexamplesやgodocを見て補完してください。(他力本願ですみません)
Go言語でGUIをする、という記事はあまり無くて、しかも大抵は環境がOS XかLinuxという状況だったので、この記事がWindowsでGo言語やろうとしてる人の支えに、またGo言語を始める切っ掛けになったらいいな、なんて思ってみたりもしています。
それではっ。
#イヤッッホォォォオオォオウ!Go言語最高ー!!
この前AIRをやったばかりなんです。叫びたい年頃なんです。