大概我这样的人还是超少见的,或者你可以称之为傲娇。
于是这个是我自己写Gtk程序的心得。我个人的主力发行版是一个几乎无Gtk的发行版,平时唯一用于测试gtk的程序其实是gtk-demo。不过即使如此我也照样开发着Gtk程序,不过由于发行版没有Glade,虽然用下也不会少块肉,不过界面大部分还是靠手写。反正就是省点事情。
本文基于 Gtk3 和 up to date 的 Glib。
另外我对于所有动态语言抱有一种不信任的态度,另外就是写C比较熟悉,所以还是写C。
那么开始第一个程序吧。
在最新的GLib中,GLib终于也诞生了一个称为Application的概念,对于Gtk2时代的人来说这大概是个没听过的概念。用了有什么好处呢?
1、支持单实例
2、支持Application Menu
说道Application Menu,这究竟又是个什么东西呢?可以理解为“属于这个程序的”菜单,例如Firefox,Opera的大按钮等等。
当然不幸的是,我最近唯一写的Gtk程序是不需要Menu的,而且反正这个功能在非GNOME3环境下惨不忍睹(显示为只有一项的菜单栏,要多难看有多难看),所以这里带过不提。
那么第一个GtkApplication就从这里开始:
https://github.com/fcitx/fcitx-configtool/blob/b68086d4b6773845065e44956875d90bca195eba/gtk3/main.c
(该死的WP贴代码不方便)
如果你用过 Qt 的话,大概就看出了
QApplication app(argc, argv); app.exec();
的影子,总之就是差不多的东西。
这里还实现了一个函数,activate,这个函数会在执行程序的时候被调用,而且是交给主进程的程序,于是里面的内容很简单,如果有窗口,那就显示出来,如果没有,那就创建一个。
关于 GObject 的 Signal,在下不才其实并不十分了解,你可以参考:
http://nanjingabcdefg.is-programmer.com/posts/24116.html
activate 本身其实也是一个 signal,具体你要实现activate被调用的效果其实有很多方式,在这个小地方怎么实现其实都并无所谓,你可以自己g_signal_connect 一个上去,或者采用别的方式。
但总之单实例就是这么简单就可以用上了。
里面的window部分是我自己实现的window,你如果想要随便测试玩玩的话,可以用 gtk_window_new 随便搞一个简单的出来。这里和Qt的一个差别是,top level的需要是GtkWindow,而Qt里面Toplevel的只要是Widget就可以了。
那么另一个可能的需求就是,你想要处理参数,这里让我当年好是头疼了一会。
那么再来看代码吧。
https://github.com/fcitx/fcitx-configtool/blob/1837cdf9bd0e03e05569c899e09ac9c4e024eb6a/gtk3/main.c
这里我处理参数处理的很简单,就是打开了一个fcitx对应addon的配置窗口。
这段代码存在了许多非常magic的地方,首先是创建Gtk程序的FLAGS变了,变成了,
G_APPLICATION_HANDLES_COMMAND_LINE
首先说明你需要command-line的支持。
其次,由于程序变成了单实例,于是就出现了local-command-line和command-line两个signal,其一,是在当前进程处理的,第二个则是在单实例的程序那边处理的。
这里我们并不需要local处理,于是跳过。然后这里就是magic的地方,当这个flag存在时,activate是不会被自动调用的,于是可以看到我在 fcitx_config_app_handle_command_line 手动调用了activate,然后进行了打开addon窗口的处理,第一次写这个的时候我迷惑了好半天……不如说是默认处理command line的行为就是activate,如果使用了这个flag的话这个行为将被discard而需要自己操作。
至于具体的参数处理,虽然glib也给了一些函数进行处理,不过我还是不善于此道,就直接用了第一个参数。
P. S.
至于这些和浆糊一样的内容究竟是有用还是没用呢?谁知道啊。
有没有2呢,谁知道啊。
~~ 好一篇傲娇文章 ~~~
依然怨念的gtk3啊~
参数处理那里好别扭……
用惯c++/qt再看 init class_init new finalize ref-count 感觉gobject真是讨厌!!
@nihui
乃真的知道ref和unref的意义何在么……
@SuperCat Qt 的开始就指定感觉写起代码来更舒服,主要是你写代码的时候一开始就很清楚哪些对象不用你继续操心了。用 GObject 的时候看见一个api也不能确定你是否把ref转移过去了,非得去查文档不可。
@cssplayer: 首先作为C这个也是没有办法的事情,没有C++里面那些自动销毁栈内类实例的能力。其次是GObject是要为其它脚本语言服务的(GObject Introspection),这个设计和上层的语言比较合的来。嘛,其实更蛋疼的是文档里面没说,非要去查源码(如果不是开源的就只有自己想办法测ref数了)。如果Qt用C实现的话说不定会比GObject做得更糟糕呢。
@csslayer 呃,不小心打错名字了……
@SuperCat ……“如果Qt用C实现的话说不定会比GObject做得更糟糕呢。”……这算啥?Qt没用C……
(另外那有个“回复”……点那个就行了)
@SuperCat 理论上来讲函数有没有/需不需要`ref()/unref()`文档里面会用[transfer]参数说明的 (如果它真的作好了gir支持的话) (虽然有好多是默认, 然后默认的有时又蛮诡异)
@yyc gtk的文档注释是写在c里面的(也就是说不会安装到header里面给你看)……所以还是必须查文档。蛮纠结的。
@csslayer gtk-doc 里面会注上 (虽然超级不显眼~~ T_T) .gir里面会更靠谱一点, gobject系的头文件~~~~ 那种东西怎么样都好了~~
完全看不懂。。。在写什么啊~~
呼~ 一起床就看到GoogleReader的blog分类里多了四篇傲娇文~
其实用GtkBuilder那个组件就可以自己用XML写出界面了,不一定非要Glade不可。
@SuperCat gtkbuilder在我看来这就是glade二代而已……
再者你是让我手写xml吗……我是说我发行版没有glade的那个gui拖拖画画的工具
那个 GApplication,严格的说,它个是 gio 库里提供的一个类。
GOptionContext 的用法,如果用的话,可以参考一下这里:https://github.com/liyanrui/cikada/blob/master/src/cikada.c
不过,这一些列tutorial,看名字让我激动了一下,总算又有中文用户来写一些尘封已久的 gtk 文章了。但是看过之后,发现只是 cookbook 🙂
gtk+ 的教材真是比 qt 少的可怜。
@garfileo 因为要用dbus嘛……否则库依赖就搞不定了。
不擅长写这些东西……