読者です 読者をやめる 読者になる 読者になる

レガシーコード生産ガイド

私に教えられることなら

FactorでGUI

factorcode 学習記録

Re: Factor: Calculator with GUI がものすごくわかりやすかった上に、Factorの「力」を使ってるカンジがしていい。(最後のcalc-uiが必見!)

十分わかりやすいんだけど、更にミニマムなステップを書いておく。

最初の最初のGUI

USING: ui ui.gadgets.labels ;
"fuuuuuuuuuuuu!" <label>
"hyo" open-window

これでfuuuuuuuuuuuu!というラベルが貼ってあるhyoというタイトルのウインドウが開く。<label>がgadgetを生成して、open-windowはそれを開く。gadgetを入れ子にしたりして組み立てて行くらしい。

ラベルの方は"ラベルの内容" <label>と単純だ。

open-windowには、文字列か、world-attributesというものを渡せる。タイトルやステータスバーの表示/非表示、ウインドウのボタンや、 world-classで更に詳細な設定ができるみたいだ。

並べる

gadgetを並べるコンテナgadgetが<track>だ。

USING: ui ui.gadgets.labels ui.gadgets.tracks ;

vertical <track>
1 >>fill
{ 5 6 } >>gap

"日本語も" <label>
1 track-add

"表示できる" <label>
1 track-add

"hoge" open-window

<track>はui.gadgetsで定義されているvertical/horizontalを引数に取り、並べる方向を決める。

fillはよくわからない…それぞれ並べる方向に対して垂直方向へのサイズを埋めるかどうか、かな……?

gapは { 水平方向 垂直方向 } の要素同士の間隔。単位はピクセルかな?

<track>を作ったら、<track> 対象ガジェット constraint track-add で対象ガジェットをtrackの列に追加できる。このconstraintもfillと同じようなものなのだろうか?とりあえず等間隔で縦横並べるときはfillもconstraintも1にするっぽい。

Concatenativeに使ってみる

combinators.smartのoutput>arrayを使うと、quotを評価して、その結果をスタックに積むのではなく、配列に格納してスタックに積める。

[ 3 4 + 5 6 + ] output>arrayを評価すると、{ 7 11 }がスタックに積まれる。

これを利用して、quotでそのままシーケンスを表現できる。

上の

"日本語も" <label>
1 track-add

"表示できる" <label>
1 track-add

の代わりに、

[ "日本語も" <label> "表示できる" <label> ]
output>array
[ 1 track-add ] each

で追加できる。

これを利用したのが参考ページの<col><row>で、それぞれquotを取って評価し、gadgetの配列を作り、<track>に格納する。

Re: Factor: Calculator with GUI より引用

: <row> ( quot -- track )
    vertical <track> 1 >>fill { 5 5 } >>gap
    swap output>array [ 1 track-add ] each ; inline

: <row> ( quot -- track )
    horizontal <track> 1 >>fill { 5 5 } >>gap
    swap output>array [ 1 track-add ] each ; inline

<track>を入れ子にしてみる。

[
  [ "ほげ" <label> "ふが" <label> ] <row>
  [ "ほげ" <label> "ふが" <label> ] <row>
] <col>

これで

ほげ ふが
ほげ ふが

と表示されるgadgetが作られる。

ボタン

ui.gadgets.buttonsの<border-button>を使ってみる。labelとquotをとってボタンgadgetを作る。ボタンが押されるとquotが評価され、その際ボタン自身がquotに渡される(積まれる)。何もしないボタンは次のように作れる。

USING: ui ui.gadgets.buttons ;

"yo!" [ drop ] <border-button>

"hey!" open-window

close-windowを使うと、そのガジェットが含まれるウインドウが閉じられる。上のコードで押したときに閉じるようにするには、単純にborder-buttonに対してclose-windowを適用すればいい。

USING: ui ui.gadgets.buttons ;

"yo!" [ close-window ] <border-button>

"hey!" open-window

感想と罠

  • やっぱりFactor触ってて楽しい。壊れない感がすごくいい。エラーメッセージがわかりやすいのがいいのかもしれない。
  • わかってくるとBrowserの記述は簡潔でいいんだけど、わからないところはさっぱりわからない。誰かえらい人本出してクレ……
  • 開発中にListenerでdupしたりコンテキストメニュー→pushしたりしてgadgetを複製してtrackに追加しようとしたんだけど上手くいかなかった。どっちも同じgadgetへのポインタを複製してるだけで、表示するためには別のオブジェクトでないといけないんだろうか。同じものを二回書いて別のオブジェクトとして生成すると普通に表示できた。
  • 本来ならSS貼りまくるタイプの記事なんだろうけど、めんどい……そういうツールをfactorで作るの目標にするか。
広告を非表示にする