RGtk2入門編

今回はもう少し進んで,簡単な機能を実装したいと思います。さっそく実例です。

例1

f:id:phosphor_m:20100211233722p:image:right

win <- gtkWindowNew(show=FALSE)
btn <- gtkButtonNew()

win$setDefaultSize(50, 50)
btn$setLabel("OK")

win$add(btn)

gSignalConnect(btn, "clicked", quote(cat("Hello, world!")))

win$showAll()

ありがちですね。ボタンを押すとコンソールにHello, world!と表示されます。widgetは,それぞれ固有のイベントを持っています。発生したイベントに応じて,signalが発行されます。今回だと,ボタンが"クリックされた"("clicked")というsignalが発行されました。そのsignalと,cat("Hello, world!")を前もってgSignalConnect()で結び付けているわけです。

signalもproperty同様RGtk2のヘルプには載っていないことが多いです。Gtk本体のリファレンスをみましょう。

http://library.gnome.org/devel/gtk/unstable/GtkButton.html#GtkButton.signals

日本語はこちら。

http://mikeforce.net/documents/gtk+-2.8.x-refs/gtk/html/GtkButton.html#id2901269

GtkButtonは"activate","clicked","enter","leave","pressed","released"という6つのsignalを持っていることがわかります。

quote(cat("Hello, world!"))というふうにquote()で括ってある理由ですが,あまり深く考えず,他のオブジェクトと関わらない単体の処理を行いたいときに使ってください。ただ,実行時に大局的環境にない関数を入れるとエラーになります。この方法はあまり使わないほうがいいかもしれません。詳しくはこちら。

http://d.hatena.ne.jp/phosphor_m/20100127/1264607315

例2

次に,もう少し進んだ機能を実装します。ボタンのON,OFFでwidgetの内容が書き換わるようにします。

f:id:phosphor_m:20100211233723p:image:right

win  <- gtkWindowNew(show=FALSE)
hbox <- gtkHBoxNew()
lab  <- gtkLabelNew("Button is OFF")
btn  <- gtkToggleButtonNew()

win$setDefaultSize(120, 30)
btn$setLabel("ON")

hbox$packStart(lab)
hbox$packStart(btn)

win$add(hbox)

onClicked <- function(btn, lab){
  lab$setText (ifelse(btn$getActive(), "Button is ON", "Button is OFF"))
  btn$setLabel(ifelse(btn$getActive(), "OFF", "ON"))
}

gSignalConnect(btn, "toggled", onClicked, data=lab)
win$showAll()

GtkHBoxは新しく出てきたクラスです。GtkHBoxはwidgetを横に順に格納していくwidgetで,GtkVBoxは縦に格納していくクラスです。なぜこのようなクラスが必要かというと,GtkWindowは1つのwidgetしか格納することができないからです。GtkHBox,GtkVBoxは,いくらでもwidgetを格納することができます。widgetの配置についてはいろいろとややこしいのでここでは詳細を省きます。上ではPackStartというメソッドを使っていますが,これはGtkHBox,GtkVBoxの一つ上位のクラスであるGtkBoxのメソッドです。widgetを順に前から詰めるというメソッドです。逆に後ろから詰めるメソッドはPackEndです。

GtkToggleButtonも初めて出てきました。ほとんどGtkButtonと同じですが,GtkToggleButtonは押したら押し込まれたままで戻ってきません。もう一度押すと戻ってきます。説明するより動かしてみればすぐわかると思います。GtkToggleButtonはGtkButtonの持つsignalに加えて"toggled"というsignalを持っています。これは元の状態と押し込まれた状態が順次入れ替わったときに発行されます。今回はこのsignalを使っています。

最後から二行目のgSignalConnectですが,"toggled"signalにonClickedという関数を結び付けています。signalに結び付けられる関数は,コールバック関数と呼ばれます。コールバック関数には通常signalを発行したobjectが渡されますが,signalによってはそれ以外のものも渡します。それに加えて,任意のオブジェクトをコールバック関数に渡すことができます。コールバック関数に何が渡されるかは,リファレンスのsignalの項に書かれています。

http://library.gnome.org/devel/gtk/unstable/GtkToggleButton.html#GtkToggleButton-toggled

今回使う"toggled"で渡されるのは,GtkToggleButton *togglebuttonとgpointer user_dataと書かれているので,signalを発行したGtkToggleButtonオブジェクトと設定した任意のデータだけです。コールバック関数に渡したい任意のデータは,引数のdataで設定します。今回はGtkLabelであるlabを渡しています。渡せるデータは形式上は1つのオブジェクトだけなのですが,複数のオブジェクトを渡したい場合はlistでまとめて渡します。

onClicked関数ではbtnとlabのテキストを書き換えています。gtkToggleButtonGetActive()は,ボタンが押し込まれているかどうかを判断し,押し込まれていればTRUE,そうでなければFALSEを返します。その真偽によって,書き換えるテキストの内容を切り替えています。ここらへんでRを熟知している人は何かおかしいことに気づくと思いますが,関数内での独立した操作のはずがその外にも反映されています。実はRGtk2のオブジェクトは参照渡しです。Rは原則的に値渡しなので,RGtk2のオブジェクトはちょっと不思議な動作になりますが,関数内の操作も全て元のオブジェクトに反映されます。

さて,ここまでで重要なことはほとんど終わっています。あとは個々のwidgetの扱い方をそれぞれ覚えていけばだいたいなんでも作れます。widgetも,全て必要なわけではないので,5,6種類ぐらい覚えれば十分実用的なアプリケーションを作れると思います。次は,もう少し実用的なものを作ってみます。