Glade 3与GTK+-2入门

本文是用GTK和MySQL完成学生信息管理系统的第一部分

GTK是完全按照面向对象思想设计的一套组件,如果你用过java的Swing那就应该会很容易的理解这个东西。按我现在的水平,我只当GTK就是些图形组件。Glade是可以让你用拖拽的方式来给GTK这些组件进行布局的,用过Netbeans进行Swing设计的应该会明白,当然如果你用过垃圾的VC(ABitNo坚决讨厌这些东西)什么的也会明白。不过不明白也没关系,下面就一切从0开始讲解。

现在ABitNo假设读者会用c,gcc,make。不过不会的话还是没有关系,下面会把每一步需要的命令都列出来。

1、准备开发环境

Linux,GTK+-2,Glade 3.6,gcc,make,Glib2,MySQL

上面这些东西并不是现在就都会用到,是以后的文章中会用到的。由于这些都不是重点,所以就不详细介绍了,如有不明白的就留言,ABitNo愿意帮忙。

2、认识Glade

当你打开Glade3时,会出现一个Unsaved 1的对话框,这个是让你选择现在这个Project的一些基本属性。这里就按照默认的,不要修改。

我们来认识下你看到的Glade窗口,最上面是菜单栏,菜单栏下面的是工具栏;左边那列叫Palette,你所需要的组件都在那里了;中间那个最大的白色空间是你的工作区;右边上部的白色部分叫Inspector,是你添加的组件的一个导航列表;右边下部是Properties,当你点击了某个组件后,在这里会出现它的属性,你可以对它们进行编辑。

3、设计界面

这个应该就不困难了,就是点击Palette里的组件,然后摆放位置,调节属性。如果你不明白应该如何去做,那就按照我给出的这个小示例来一步步走。

  • 在Palette里点击Toplevels下的window组件,这时在中间的空白工作区会出现一个深色方框,这个就是你程序的主窗口。
  • 在Inspector里,用鼠标选中你刚新建的那个窗口,在下面的Properties里进行如下编辑:

    • General标签下,将Name属性改为window,将Window Title改为ABitNo;
    • 在Signals标签下,你可以在GtkWidget那一类中找到个delete-event,为它的Handler选择gtk_main_quit,同样给GtkObject那一类中唯一的destroy选择gtk_main_quit
  • 在Palette里点击Container下的Fixed,在你上一步新建的window中点击,这样就创建好了一个容器,然后按照给window修改名字的方法将其改名为fixed。容器就是一个可以存放其他组件并进行布局的一种组件
  • 在Palette里点击Control and Display下的Label,在Fixed容器上点击,这样你就把label放到了Fixed容器里了,在Properties的General标签下将Name属性改为label,将Label属性里的内容都删除。最后你可以点击工具栏上的那个Drag Resize按钮,然后你就可以选中label进行拖拽,来摆放出一个合适的位置,位置不会影响程序的功能,但是会影响美观(ABitNo做的就很不美观)
  • 在Palette里点击Control and Display下的Button,在Fixed容器上点击,这样你就在Fixed容器里又放置了一个按钮,将其Name属性改为button,Label属性改为ABitNo,同样的你可以通过拖拽来调节它的大小和位置

这样我们的界面就设置完成了,保存为abitno.glade。最后的设计和Inspector里的内容会像下面这样
window-fixed-button-label-inspector

4、编写代码

这一步才是关键,界面设计是次要的,Glade就是把界面与代码分开,这样更便于维护。先不多说了,直接看代码,代码里ABitNo都已经把注释写的很详细了,如果仍然有不明白的可以提出来。
你现在要做的就是打开一个编辑器,如gedit,在abitno.glade所在的文件夹里编辑一个文件abitno.c,内容如下

/*
* File :abitno.c
* Author:  ABitNo
* Email: wolfplanet@gmail.com
* Website: ABitNo.LinPie.com
*/

/***********************************************************************
*           这句include就是简单的包含gtk的头文件                           *
***********************************************************************/
#include <gtk/gtk.h>

/***********************************************************************
*           从名字就可以看出这是一个button被点击时要执行的函数               *
***********************************************************************/
void on_button_clicked(GtkWidget *widget, gpointer label)
{
        /*这是gtk的一个函数,用来给Label设定文字*/
       gtk_label_set_text(GTK_LABEL(label),"I Love ABitNo.LinPie.com");
}

int main(int argc, char *argv[])
{
    /*这些語句声明了一些组件变量,由于GTK是面向对象的,
    所以都可以声明为GtkWidget,这也是习惯作法 */
    GtkBuilder *builder;
    GtkWidget *window;
    GtkWidget *button;
    GtkWidget *label;

    /*每一个gtk程序都会用到这一句,用来初始化*/
    gtk_init(&argc, &argv);

    /*这个builder就是用来读取我们用Glade设计的界面的一个东西*/
    builder = gtk_builder_new();

    /*用下面这个gtk函数把abitno.glade的内容给builder*/
    gtk_builder_add_from_file(builder, "abitno.glade", NULL);

   /*通过名字从abitno.glade中读取我们需要使用的组件*/
    window = GTK_WIDGET(gtk_builder_get_object(builder, "window"));
    button=GTK_WIDGET(gtk_builder_get_object(builder,"button"));
    label=GTK_WIDGET(gtk_builder_get_object(builder,"label"));
    
    /*这是glib里的一个函数,用来把一个组件与一个函数关联起来,下面
    这句就是把button和我们上面的那个on_button_clicked给关联了*/
    g_signal_connect( G_OBJECT(button), "clicked", 
    		G_CALLBACK(on_button_clicked), (gpointer)label);
    
    /*这条語句就是自动把所有人信号处理函数都关联好*/
    gtk_builder_connect_signals(builder, NULL);

    /*因为我们已经不需要builder了,就释放builder的空间*/
    g_object_unref(G_OBJECT(builder));

    /*将window内所有的组件都显示出来,这们我们才能看见*/
    gtk_widget_show_all(window);

    /*这也是每一个gtk程序都要有的*/
    gtk_main();

    return 0;
}

5、编译运行

当你的代码都写完了,那就保存,准备编译了,用下面的命令

gcc -o abitno abitno.c `pkg-config --cflags --libs gtk+-2.0` -export-dynamic

要注意,pkg-config前后的那个不是单引号,而是ESC下面那个键。

然后通过下面的命令来运行

./abitno

如果一切顺利的话,就会出现一个窗口,上面只显示一个ABitNo按钮,你点击它就会出现一句话“I Love ABitNo.LinPie.com“,如下图
abitno-gtk-demo

TAGS:C,Glade,GTK

46 COMMENTS >>LEAVE<<

  1. gcell
  2. ABitNo
    @gcell

    谢谢,ABitNo会感激你的。。。ABitNo会继续努力的。。。

  3. xbox

    不错的文章。国内关于GTK和Glade 3的文章太少了,没有地方学习,以后会常来看看的。

  4. ABitNo
    @xbox

    谢谢关注。ABitNo会努力的。。。

  5. nix

    文章很好,我会多多关注!

  6. Xhacker

    恩,不错!现在glade文章确实少。

  7. ABitNo
    @nix

    谢谢,我会多多努力。。。

  8. ABitNo
    @Xhacker

    是的,而且都还比较旧,估计用的人不是很多吧。。。那些大牛估计会习惯写代码,刚开始学的说不定还不知道这个东西呢。。。

  9. Feng

    使用fixed layout是windows遗留思想

  10. ABitNo
    @Feng

    那倒不是,我还真没Windows过。。。主要的问题是我不会用GTK,我要好好学习才行。。。

  11. AzureSky

    教程么,http://www.zetcode.com/ 这个网站里面有很多教程

  12. ABitNo
    @AzureSky

    对,就是那,我就在那学了很多。。。

  13. 邱焜

    我真会YY, 东西是这样命名的xx-clothes-bra

  14. ABitNo
    @邱焜

    不明白是什么意思。。。

  15. 海贼阿D

    那首歌叫什么名字?

  16. ABitNo
    @海贼阿D

    阿沁的那个南极星。。。里面那女声真好听。。。

  17. JackalDire

    这两天也在看Glade, 带着看点gtkmm,主要是觉得用C写Gtk界面太痛苦了,函数名老长,还要加各种宏,各种box,加得自己都乱了。添加一个widget、设定属性、连接回掉函数、添加到某个box,然后show(), 程序代码基本没法看。

  18. ABitNo
    @JackalDire

    我也是这么觉得,我觉得C语言就没法看,用起来也痛苦,C++东西就太多了,我也不想学了,还是学我的Ruby和Java,C语言还是一定要学的,虽然让我很痛苦

  19. ExclusivePig

    请问楼主,gtk_builder_add_from_file是动态加载吧?就是说.glade文件要和程序放在一起的吧?那样的话,界面不就不保密了?只要得到你的软件包,用同样方式加载你的.glade,改下callback,不就直接用你的界面了?

    我在网上搜的方法都是这样(来到你在这也要谢谢GOOGLE),不过听说有种静态加载方式,请问你知道吗?

    还有,你写GTK的代码,用vi还是什么?能自动提示吗?我在windows或者linux下,gtk的自动提示不能解决,很是头疼,健忘的我尤其痛苦

  20. ABitNo
    @ExclusivePig

    是的,上面说的是动态加载的,要把glade文件和程序放到一起。

    至于要静态加载,我也没考虑过,不过肯定是会有这种方法的。我这个暑假要好好学Linux编程,现在还只是大体了解,等我知道了,一定会告诉你,大家一起学习。。。

    写GTK的用vi就行,可以自动提示的,当然还可以用一些ide,不过这些都是默认不扫描gtk的东西的,都要自己配置一下,我只会设置vi和netbeans的,其实这样设置了提示也不好,gtk的东西实在是太多了,那么长的提示列表。。。

    gtk的命名也很规律的,只要大体明白是个什么就能記住了。。。

    我现在不是很在行,过了这个假期或许我会比现在知道的更多。。。

  21. graint

    glade很多地方都是用GladeXML获得界面的,但是的 我用的时候会加载失败,不知道为什么
    然后我用你这里的这种方法的话,每个控件的消息响
    应都要自己去g_signal_connect么?除非是系统自
    带的函数么?

  22. ABitNo
    @graint

    不是每个都用的,你可以直接在做设计的时候就关联好,然后

    gtk_builder_connect_signals
    

    就能把所有你在设计中关联的东西自己关联的

    不过我现在对这些还不是很了解,主要是很长时间没看了,这个暑假后会好一点,我会专心学习Linux编程的。。。

    谢谢你的关注

  23. graint
    @ABitNo

    在glade中消息响应函数,比如一个BUTTON,我设置响应clicked消息的函数叫on_button1_clicked,然后在C文件里声明这个函数,但是在gtk_builder_connect_signals的时候仍然说on_button1_clicked不存在,那设置的函数名应该怎么用啊

  24. ABitNo
    @graint

    这个我刚刚又自己写了个简单的小例子看了下,发现是没有问题的,看看今晚我有没有时间,你把你的文件发给我,我看一下呢。。。

  25. graint
    @ABitNo

    是我编译的时候少加了个参数。。我的错

    我发现gtk_builder_get_object这样拿出来的控件不能直接显示之类的?
    比如我拿出一个image,然后在对一个button进行点击的时候把image作为参数传给button的响应函数,然后调用gtk_widget_hide,然后程序就崩了。。

    或者我在gtk_widget_show_all后面直接对image进行gtk_widget_hide操作,仍然没有任何效果啊

  26. ABitNo
    @graint

    graint says:
    2009/07/28 at 16:45 (Edit)

    是我编译的时候少加了个参数。。我的错

    我发现gtk_builder_get_object这样拿出来的控件不能直接显示之类的?
    比如我拿出一个image,然后在对一个button进行点击的时候把image作为参数传给button的响应函数,然后调用gtk_widget_hide,然后程序就崩了。。

    或者我在gtk_widget_show_all后面直接对image进行gtk_widget_hide操作,仍然没有任何效果啊

    这个我也接着试验了一下,发现是可以的,你仔细看看是不是写错了名字还是什么的,C语言的细节问题要细心的。。。

  27. graint
    @ABitNo

    老大有没QQ之类即时聊天的。。~很希望能直接请教一下。。

  28. graint
    @ABitNo

    我QQ262009627 老大加下指导指导。。感激不尽呃

  29. ABitNo
    @graint

    我没有QQ,看不起腾讯这种企业。。。
    Gtalk: wolfplanet@gmail.com
    MSN : wolfplanet@live.cn

    先去吃饭去了。。。

    话说我现在对这些东西都忘了,刚做完那些项目,正准备再好好学一下。。。

  30. snyh

    用gtk_builder_connect_signals 的时候编译的时候必须加上
    gccgtk x.c -Wl,--export-dynamic

    这样就行了
    不过如果在glade里面传递user_data 注意callback函数 第一个参数才是user_data

    gccgtk是我用的一个别名 gccgtk=gcc 'pkg-config --cflags --libs gtk+2.0'后面还有一堆

    要不让每次测试简单的程序写make麻烦了 打命令又要加一堆pkg-config

    要保密 我觉得没必要。。。不过如果应要 就把glade文件写在代码里面当作一个
    const char* 就是了 然后用gtk_builder_add_from_string

  31. ABitNo
    @snyh

    非常感谢,以后多向你学习了。。。

  32. snyh
    @ABitNo

    ..
    谈不上学习 手册上都写着。。。

    就usr_data 传递的时候是第一个参数比较雷人。。。
    而且似乎没地方写着。。。

  33. 崇拜

    感谢楼主,找了很久终于找到好文。
    不然还不知道怎么使用glade,希望楼主继续造福我们这些菜鸟。
    多谢了!

  34. ABitNo
    @崇拜

    多谢夸奖。。。
    我也是刚学习一点

  35. ReeChou

    那个用glade可以直接生成GUI的框架代码吧?

  36. 轩痕

    我也是极度讨厌vc,完全搞不明白那东西在搞毛阿,但是gtk+ 很可爱,很容易学习理解

  37. ABitNo
    @ReeChou

    真抱歉,最近忙得没时间回复留言。。。
    glade只是生成了界面,应该就是你所说的GUI的框架代码吧

  38. ABitNo
    @轩痕

    哈哈,对,我一直在期待着gtk3呢,到时候一定好好研究一下

  39. joeguan2

    我运行之后程序不能正常运行,提示:
    GTK-CRITICAL**:gtk_widget_show_all: assertion `GTK_IS_WIDGET(widget)` failed.
    我调试了一下,发现window = GTK_WIDGET(gtk_builder_get_object(builder, "window"));这一语句没有正确获得window,其他的widge也是如此。不知道为什么。

  40. ABitNo
    @joeguan2

    你的glade文件里window的名字是不是window啊~~~
    你要注意名字一致

  41. joeguan2
    @ABitNo

    the names are identical.
    the following codes are from .c file and .glade file.
    /* gui.c */
    #include <gtk></gtk>

    int main(int argc, char *argv[])

    {

    GtkBuilder *builder;

    GtkWidget *window;

    gtk_init(&argc, &argv);

    builder = gtk_builder_new();

    gtk_builder_add_from_file(builder, "gui.glade", NULL);

    window = GTK_WIDGET(gtk_builder_get_object(builder, "window"));

    gtk_builder_connect_signals(builder, NULL);

    g_object_unref(G_OBJECT(builder));

    gtk_widget_show_all(window);

    gtk_main();

    return 0;

    }

    /* gui.glade */
    <?xml version="1.0" encoding="UTF-8" standalone="no"?>

    <!--Generated with glade3 3.4.3 on Wed Mar 10 16:42:23 2010 -->
    <glade-interface><br><widget class="GtkWindow" id="window"><br></widget></glade-interface>

    <property name="title" translatable="yes">glade window</property><signal name="delete_event" handler="gtk_main_quit"></signal>
    <child><br><placeholder></placeholder><p></p></child>

  42. joeguan2
    @ABitNo

    两个文件的window是一致的,上一个回复不能显示gui.glade的代码。

  43. ABitNo
    @joeguan2

    嗯,我的blog程序还有问题。。。

    如果是一致的不可能找不到,除非你哪个地方写错了

    你确定你完全按照示例来的吗

  44. Ted
    @ABitNo

    我出现了和joeguan2 一样的问题 我是大一的不懂怎么解决 能帮帮我吗? 我有的是window的系统 不是linux的 这有关系吗? 还有你先得glade教程真的很通俗 我找了好久终于找到这篇经典的了

  45. ABitNo
    @Ted

    先谢谢夸奖

    你说的这个问题我不清楚啊,我没在windows上尝试过,我对windows上都可以用glade表示惊讶和欣慰

    可以加我gtalk说说看

  46. YuriX

    按照你的例子做了下,编译完后运行程序报错内容如下:
    (abitno:28984): GLib-GObject-WARNING **: invalid (NULL) pointr instance

    (abitno:28984): GLib-GObject-CRITICAL **: g_signal_connect_daa: assertion `G_TYPE_CHECK_INSTANCE (instance)' failed

    (abitno:28984): Gtk-CRITICAL **: gtk_widget_show_all: assertin `GTK_IS_WIDGET (widget)' failed

    这是怎么回事?

LEAVE A RESPONSE >>CANCEL<<

loader