GtkBuilderとPython(pygtk) JavaScript(Seed) C#(Vala) C そして Mono gtkmm gjs
libgladeからGtkBuilderへの移行の時期が近づいてますが、対応状況がバラバラなので、ある程度の割り切りが必要になりそうです。
当然C言語では問題ないですが、C++(gtkmm)は対応が中途半端みたいです。pygtkは問題なく動作中。C# と JavaScriptはValaとSeedに軍配があがりました。MonoはGladeのみの対応ですし、gjsはドキュメントが見つからない。。。
ということで、いつものプログラムを書いたんだけど、今回からボタンではなくメニューにしてみました。
GtkBuilder用のuiファイルは以下の通り'hello.ui'。glade-3はLANG=Cで起動しないと、uiに日本語が入ってしまうので、今後の課題です。
<?xml version="1.0"?> <interface> <requires lib="gtk+" version="2.16"/> <!-- interface-naming-policy project-wide --> <object class="GtkWindow" id="window1"> <child> <object class="GtkVBox" id="vbox1"> <property name="visible">True</property> <property name="orientation">vertical</property> <child> <object class="GtkMenuBar" id="menubar1"> <property name="visible">True</property> <child> <object class="GtkMenuItem" id="menuitem1"> <property name="visible">True</property> <property name="label" translatable="yes">アプリケーション(_A)</property> <property name="use_underline">True</property> <child type="submenu"> <object class="GtkMenu" id="menu1"> <property name="visible">True</property> <child> <object class="GtkImageMenuItem" id="imagemenuitem1"> <property name="label">gtk-quit</property> <property name="visible">True</property> <property name="use_underline">True</property> <property name="use_stock">True</property> <signal name="activate" handler="on_imagemenuitem1_activate"/> </object> </child> </object> </child> </object> </child> </object> <packing> <property name="expand">False</property> <property name="position">0</property> </packing> </child> <child> <object class="GtkLabel" id="label1"> <property name="visible">True</property> <property name="xalign">0.4699999988079071</property> <property name="label" translatable="yes">Hello</property> <attributes> <attribute name="size" value="100000"/> </attributes> </object> <packing> <property name="position">1</property> </packing> </child> </object> </child> </object> </interface>
それではCから
#include <gtk/gtk.h> #include <stdlib.h> G_MODULE_EXPORT void on_imagemenuitem1_activate(GtkAction *action) { gtk_main_quit(); } int main (int argc, char* argv[]) { GtkWidget *window; GtkBuilder *builder; GError *err = NULL; gtk_init(&argc, &argv); builder = gtk_builder_new(); gtk_builder_add_from_file(builder, "hello.ui", &err); if (err) { g_error ("ERROR: %s\n", err->message); return EXIT_FAILURE; } gtk_builder_connect_signals(builder, NULL); window = GTK_WIDGET(gtk_builder_get_object(builder, "window1")); gtk_widget_show_all (window); gtk_main(); }
EXIT_FAILUREのためだけにstdlib.hをincludeしてます。シグナル名と関数名を同じにすると、gtk_builder_connect_signals()で自動的に割り当てられるのが便利です。
次は、vala
using Gtk; public void on_imagemenuitem1_activate(Menu source) { Gtk.main_quit (); } public class Hello { static void main(string [] args) { new Hello(args); } public Hello(string [] args) { Gtk.init (ref args); try { var builder = new Builder(); builder.add_from_file("hello.ui"); builder.connect_signals(null); var window = builder.get_object ("window1") as Window; window.show_all(); Gtk.main(); } catch (Error e) { stderr.printf ("Could not load UI: %s\n", e.message); } } }
こちらは、メソッドをpublicにする必要はありますが、builder.connect_signals()できるのはCと同じです。
pygtkも同様に
#!/usr/bin/env python import gtk class hello: def __init__(self): self.builder = gtk.Builder() self.builder.add_from_file('hello.ui') self.builder.connect_signals(self) self.builder.get_object('window1').show_all() def on_imagemenuitem1_activate(self, data): gtk.main_quit() if __name__ == "__main__": app = hello() gtk.main()
self.builder.connect_signals(self)のように非常にすっきりとした書き方になります。
残念ながらJavaScriptのSeedはオブジェクトとして渡す必要があります。しかし、JSON形式で書くので問題ないかな?
#! /usr/bin/env seed const Gtk = imports.gi.Gtk; const GtkBuilder = imports.gtkbuilder; Gtk.init(Seed.argv); builder = new Gtk.Builder(); builder.add_from_file("hello.ui"); builder.connect_signals({on_imagemenuitem1_activate:function(){Seed.quit();}}); win = builder.get_object("window1"); win.show_all(); Gtk.main();
Seedが素晴らしいのは、builderをSeed独自に対応しているところ、こうなるとGjsは使い難いですね。
上記のソースの問題は、window の destory シグナルを処理していないところです。右上のバッテンをクリックすると window は閉じるけどプロセスは死なないのです。。。
hideするか、main_quit()につなげるか、どちらかが必要です。一般的なアプリを作るなら、別途関数を作るべきでしょうね。