一步一步学习GTK

时间:2022-10-21 08:19:49

完成课设,偶然碰到GTK,索性学习一遍
转载自ikoDotA の BLOG

(一)、一步一步学GTK+之开篇

一、什么是GTK+

GTK+ 是一种函数库是用来帮助制作图形交互界面的。整个函数库都是由C 语言来编写的。 GTK+函数库通常也叫做 GIMP 工具包。因为,一开始GTK+是用来编写“GIMP”–这个图形处理软件的。从那以后, GTK+就逐渐成为了Linux and BSDUnix 下最受欢迎的用于图形交互界面(GUI)设计的工具包之一。时至今日,大多数的Linux 下的GUI 软件(有图形交互界面)都是由GTK+或者QT 来编写的。GTK+是一种面向对象式的API(applicationprogramming interface)。Glib 是GTK+的基础,而这种“面向对象系统”正是由“Glib”来提供的。GObject 也就是这种面向对象的机制可以为 GTK+绑定很多种开发语言。目前存在的语言有:C++, Python, Perl, Java, C#,PHP,等其他高级语言。

GTK+ 和以下“函数库”存在着依赖关系
• Glib
• Pango
• ATK
• GDK
• GdkPixbuf
• Cairo
Glib 是一种通用的函数库。她提供了各种各样的语言特性,譬如说:各种数据类型,字符串函数,错误通知,消息队列和线程。Pango 是一种函数库,用来实现国际化和本地化的功能。ATK是一种平易近人的工具函数包,她提供了快捷键服务为肢体有缺陷的人使用电脑提供了便利。GDK 是一种函数库,她为整个GTK+图形库系统提供了一些底层的“图形实现”和“窗口实现”的方法。在Linux 中GDK 是位于X 服务器和GTK+函数库之间的。在最近的GTK+发行版本中,越来越多的功能性函数,都交给了Cairo 函数库来处理。GdkPixbuf 函数库是一种函数库工具包用于加载图像和维护图像“缓存”的(pixel buffer)。Cairo 是一种函数库用于制作二维图像。从GTK+2.8 版本以后,Cairo 就正式成为GTK+系统中的一员了。Gnome and XFce 桌面环境系统都是用GTK+来编程实现的. SWT and wxWidgets 是种很著名的编程框架,也是用GTK+来编程实现的。最杰出的GTK+软件的代表是Firefox (火狐浏览器)和 Inkscape。

二、GTK安装

此部分未自主创作内容,非转载,主要面向linux系统,笔者系统Ubuntu 17.10
1、安装codeblocks
自主上网下载或者Ubuntu软件商店中下载
2、安装GTK+
(1)安装gcc/g++/gdb/make 等基本编程工具

$sudo apt-get install build-essential

(2)安装 libgtk2.0-dev libglib2.0-dev 等开发相关的库文件

$sudo apt-get install gnome-core-devel

(3)用于在编译GTK程序时自动找出头文件及库文件位置  

$sudo apt-get install pkg-config

(4)安装 devhelp GTK文档查看程序

$sudo apt-get install devhelp

(5)安装 gtk/glib 的API参考手册及其它帮助文档

$sudo apt-get install libglib2.0-doc libgtk2.0-doc

(6)安装基于GTK的界面GTK是开发Gnome窗口的c/c++语言图形库
sudoaptgetinstallgladelibglade2dev sudo apt-get install glade-gnome glade-common glade-doc

(7)安装gtk2.0 或者 将gtk+2.0所需的所有文件统通下载安装完毕

sudoaptgetinstalllibgtk2.0dev sudo apt-get install libgtk2.0*

查看GTK库版本
(1)查看 2.x 版本

$pkg-config –modversion gtk+-2.0

(2)查看pkg-config的版本

$pkg-config –version

(3)查看是否安装了gtk

$pkg-config –list-all grep gtk

注意:在测试是否装成功的时候,注意Codeblocks不能有中文路径名称

3.配置code::blocks中的GTK+编译器
现在安装了gtk后,可以用pkg-config –list-all 查看,其中应该包含一个gtk+-2.0.
在code::blocks中 默认的编译器是GNU GCC Compiler,我们为 GTK单独设置一个编译器:
Settings -> Compiler settings ,选择GNU GCC Compiler 然后点击 copy ,输入一个gtk编译器的名称:GUN GCC Compiler GTK2.0,并设置为默认编译器,点击 set as default .然后在 Compiler settings -> Other options -> 添加pkg-config --cflags gtk+-2.0(目的是添加include),在linker settings -> Other linker options 中也添加 pkg-config –libs gtk+-2.0`(目的是添加lib),如果在windows下运行时候可能会报错,如果缺少zlib1.dll ,放在 工程/bin/Debug下即可。

4.测试一下环境是否正确
在codeblocks中新建一个工程,选择上面新添加的编译器(GUN GCC Compiler GTK2.0),然后在main.c中添加代码:

#include <gtk/gtk.h>
int main( int argc, char *argv[])
{
    GtkWidget *window;
    gtk_init(&argc, &argv);
    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_widget_show(window);
    gtk_main();
    return 0;
}

编译并执行出现一个空白窗体(linux下在命令行下执行),即代表gtk+的开发环境配置成功了。
顺便说下可以直接用gcc命令行生成:

gcc -o hello-world main.c  `pkg-config --cflags --libs gtk+-2.0`

(二)、一步一步学GTK+之窗口

本系列不准备对GTK+的各个组件分别介绍,这会让人觉得很无趣,采用开发一个小软件作为演示,该软件的功能就是演示GTK+的控件应用,以达到学习目的。在上一篇的最后我给出了一段代码来测试环境——显示了一个空白的窗口,代码如下:

#include <gtk/gtk.h>
int main( int argc, char *argv[])
{
    GtkWidget *window;
    /*初始化整个GTK+程序,是每一个GTK+程序必不可少的部分*/
    gtk_init(&argc, &argv);
    /*这里生成了一个窗口构件——GtkWindow,GTK_WINDOW_TOPLEVEL包含窗口的标题栏和边框,同意用窗口管理器来进行管理*/
    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);

    /*开始显示窗口*/
    gtk_widget_show(window);
    gtk_main();
    return 0;
}

现在我们来给窗口做一些改进工作:

一、添加一个标题、设置默认大小以及显示位置。

#include <gtk/gtk.h>
int main( int argc, char *argv[])
{
    GtkWidget *window;
    /*初始化整个GTK+程序,是每一个GTK+程序必不可少的部分*/
    gtk_init(&argc, &argv);
    /*这里生成了一个窗口构件——GtkWindow,GTK_WINDOW_TOPLEVEL包含窗口的标题栏和边框,同意用窗口管理器来进行管理*/
    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    /*设置窗口标题*/
    gtk_window_set_title(GTK_WINDOW(window), "一步一步学GTK+ DEMO");
    /*设置窗口默认大小*/
    gtk_window_set_default_size(GTK_WINDOW(window), 500, 400);
    /* * 设置窗口在显示器中的位置为居中。 * GTK_WIN_POS_NONE :不固定 * GTK_WIN_POS_CENTER : 居中 * GTK_WIN_POS_MOUSE : 出现在鼠标位置 * GTK_WIN_POS_CENTER_ALWAYS : 窗口改变大小的时候仍然居中 */
    gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);

    /*开始显示窗口*/
    gtk_widget_show(window);
    gtk_main();
    return 0;
}

二、设置应用程序的图标

#include <gtk/gtk.h>

/* @Description: 从一个图片中获取信息得到pixbuf @param: gchar filename */
GdkPixbuf *create_pixbuf(const gchar * filename)
{
    GdkPixbuf *pixbuf;
    GError *error = NULL;
    /* * 函数gdk_pixbuf_new_from_file() 从一个图片文件中加载图象数据,从而生成一个新的 pixbuf, * 至于文件中包含图象的格式,是由系统自动检测的。如果该函数返回值是NULL 的话,程序就会出现错误。 */
    pixbuf = gdk_pixbuf_new_from_file(filename, &error);
    if(!pixbuf) {
        fprintf(stderr, "%s\n", error->message);
        g_error_free(error);
    }
    return pixbuf;
}

int main( int argc, char *argv[])
{
    GtkWidget *window;
    /*初始化整个GTK+程序,是每一个GTK+程序必不可少的部分*/
    gtk_init(&argc, &argv);
    /*这里生成了一个窗口构件——GtkWindow,GTK_WINDOW_TOPLEVEL包含窗口的标题栏和边框,同意用窗口管理器来进行管理*/
    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    /*设置窗口标题*/
    gtk_window_set_title(GTK_WINDOW(window), "一步一步学GTK+ DEMO");
    /*设置窗口默认大小*/
    gtk_window_set_default_size(GTK_WINDOW(window), 500, 400);
    /* * 设置窗口在显示器中的位置为居中。 * GTK_WIN_POS_NONE :不固定 * GTK_WIN_POS_CENTER : 居中 * GTK_WIN_POS_MOUSE : 出现在鼠标位置 * GTK_WIN_POS_CENTER_ALWAYS : 窗口改变大小的时候仍然居中 */
    gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);

    /*函数gtk_window_set_icon() 是为窗口设置图标用的,函数create_pixbuf是我们自定义的,目的是从一个图片中获取信息得到pixbuf。*/
    gtk_window_set_icon(GTK_WINDOW(window), create_pixbuf("./images/bear.png"));

    /*开始显示窗口*/
    gtk_widget_show(window);
    gtk_main();
    return 0;
}

三、当点击关闭窗口(X)时,应该结束程序
在命令行下运行这个demo,点击右上角的X时候,窗口虽然关闭了,但是程序还在运行,需要按ctrl+C(linux下 ctrl+D)来结束程序运行。我们希望点击X的时候就结束程序的运行。我们必须要明确为这个例子程序连接一个关闭的信号(destroy signal),然后调用回调函数gtk_main_quit() 实现结束程序。这里涉及到事件和信号会在日后讲到。

#include <gtk/gtk.h>

/* @Description: 从一个图片中获取信息得到pixbuf @param: gchar filename */
GdkPixbuf *create_pixbuf(const gchar * filename)
{
    GdkPixbuf *pixbuf;
    GError *error = NULL;
    /* * 函数gdk_pixbuf_new_from_file() 从一个图片文件中加载图象数据,从而生成一个新的 pixbuf, * 至于文件中包含图象的格式,是由系统自动检测的。如果该函数返回值是NULL 的话,程序就会出现错误。 */
    pixbuf = gdk_pixbuf_new_from_file(filename, &error);
    if(!pixbuf) {
        fprintf(stderr, "%s\n", error->message);
        g_error_free(error);
    }
    return pixbuf;
}

int main( int argc, char *argv[])
{
    GtkWidget *window;
    /*初始化整个GTK+程序,是每一个GTK+程序必不可少的部分*/
    gtk_init(&argc, &argv);
    /*这里生成了一个窗口构件——GtkWindow,GTK_WINDOW_TOPLEVEL包含窗口的标题栏和边框,同意用窗口管理器来进行管理*/
    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    /*设置窗口标题*/
    gtk_window_set_title(GTK_WINDOW(window), "一步一步学GTK+ DEMO");
    /*设置窗口默认大小*/
    gtk_window_set_default_size(GTK_WINDOW(window), 500, 400);
    /* * 设置窗口在显示器中的位置为居中。 * GTK_WIN_POS_NONE :不固定 * GTK_WIN_POS_CENTER : 居中 * GTK_WIN_POS_MOUSE : 出现在鼠标位置 * GTK_WIN_POS_CENTER_ALWAYS : 窗口改变大小的时候仍然居中 */
    gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);

    /*函数gtk_window_set_icon() 是为窗口设置图标用的,函数create_pixbuf是我们自定义的,目的是从一个图片中获取信息得到pixbuf。*/
    gtk_window_set_icon(GTK_WINDOW(window), create_pixbuf("./images/bear.png"));

    /***********************************以下是信号处理部分************************************/

    /*关闭窗口时退出主循环*/
    g_signal_connect_swapped(G_OBJECT(window),"destroy",G_CALLBACK(gtk_main_quit), NULL);

    /***********************************以下是显示控件部分************************************/
    /*开始显示窗口*/
    gtk_widget_show(window);


    gtk_main();
    return 0;
}

(三)、一步一步学GTK+之布局

本来想接上篇把关于窗口方面的写的更详尽一点,但因为我做软件的习惯来说还暂时用不不到、我们先跳过,然后先说说窗口中的布局。跟大多数软件界面一样,一般包含标题栏、菜单栏、工具栏、状态栏和工作区等。

首先,我必须要有一个初步的规划,因为是自己设计一些软件,我只需要问我自己几个问题(why/how),而不需要跟设计部进行沟通。
1.Q:为什么要设计这个demo?
A:初步认识GTK+的构件并应用到实际开发中,实现掌握GTK+的能力并能分享给大家。

2.Q:如何分享?demo有什么功能?
A:我通过逐步添加代码的方式,高亮显示能看到代码进化的过程,让本系列读者达到学习的目的;要全面接触到所有的GTK+的构建,那么只有把demo做成GTK+构件演示软件才能满足了。

3.Q:demo的界面大致是怎么样的?
A:基本的软件界面,通过菜单、工具栏等方式逐步演示界面上显示不到的功能。

4.Q:怎么样去划分demo的功能?
A:根据Glade 3中的划分,GTK+构建分为Toplevels、Containers、Controls and Display、Composite Widgets等类型。所以在菜单设计中可以按这个分类去设计。

好了,现在应该基本知道未来的demo大概是个什么样的了吧。

一、添加简单菜单栏,以后在逐步完善

 在添加菜单栏之前、还需要用一个容器来将窗体划分为多个区域,以供放工具栏、状态栏等.我们从上到下分4栏,最上面是菜单栏,紧接着是工具栏,然后是工作区,最下面是状态栏。我们先添加一个容器vbox来划分区域,并加入toggle菜单。这个菜单的功能是让用户可以操作划分区域的显示和隐藏。
#include <gtk/gtk.h>

/* @Description: 从一个图片中获取信息得到pixbuf @param: gchar filename */
GdkPixbuf *create_pixbuf(const gchar * filename)
{
    GdkPixbuf *pixbuf;
    GError *error = NULL;
    /* * 函数gdk_pixbuf_new_from_file() 从一个图片文件中加载图象数据,从而生成一个新的 pixbuf, * 至于文件中包含图象的格式,是由系统自动检测的。如果该函数返回值是NULL 的话,程序就会出现错误。 */
    pixbuf = gdk_pixbuf_new_from_file(filename, &error);
    if(!pixbuf) {
        fprintf(stderr, "%s\n", error->message);
        g_error_free(error);
    }
    return pixbuf;
}


int main( int argc, char *argv[])
{
    GtkWidget *window;
    GtkWidget *vbox;            //盒装容器
    GtkWidget *menubar;         //菜单栏
    GtkWidget *menutoggle, *menu_tog_toggle,*menu_tog_toolbar, *menu_tog_statusbar;  //界面开关菜单
    //GtkWidget *menu_about, *menu_about_us; //帮助菜单

    /*初始化整个GTK+程序,是每一个GTK+程序必不可少的部分*/
    gtk_init(&argc, &argv);
    /*这里生成了一个窗口构件——GtkWindow,GTK_WINDOW_TOPLEVEL包含窗口的标题栏和边框,同意用窗口管理器来进行管理*/
    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    /*设置窗口标题*/
    gtk_window_set_title(GTK_WINDOW(window), "一步一步学GTK+ DEMO");
    /*设置窗口默认大小*/
    gtk_window_set_default_size(GTK_WINDOW(window), 500, 400);
    /* * 设置窗口在显示器中的位置为居中。 * GTK_WIN_POS_NONE :不固定 * GTK_WIN_POS_CENTER : 居中 * GTK_WIN_POS_MOUSE : 出现在鼠标位置 * GTK_WIN_POS_CENTER_ALWAYS : 窗口改变大小的时候仍然居中 */
    gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);

    /*函数gtk_window_set_icon() 是为窗口设置图标用的,函数create_pixbuf是我们自定义的,目的是从一个图片中获取信息得到pixbuf。*/
    gtk_window_set_icon(GTK_WINDOW(window), create_pixbuf("./images/bear.png"));

    /*创建一个盒装容器并添加到窗口中*/
    vbox = gtk_vbox_new(FALSE, 0);
    gtk_container_add(GTK_CONTAINER(window), vbox);

    /*创建菜单*/
    menubar = gtk_menu_bar_new();   //代表整个菜单,是一个menu shell

    menutoggle = gtk_menu_new();   //这里代表第一列菜单toggle ,也是一个menu shell
    menu_tog_toggle = gtk_menu_item_new_with_label("widget toggle");
    menu_tog_toolbar = gtk_menu_item_new_with_label("show Toolbar"); //toggle 菜单中子项
    menu_tog_statusbar = gtk_menu_item_new_with_label("show Statusbar");

    gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_tog_toggle), menutoggle);  //widget toggle菜单加入 menutoggle menu shell
    gtk_menu_shell_append(GTK_MENU_SHELL(menutoggle), menu_tog_toolbar);
    gtk_menu_shell_append(GTK_MENU_SHELL(menutoggle), menu_tog_statusbar);

    gtk_menu_shell_append(GTK_MENU_SHELL(menubar), menu_tog_toggle);


    /*把菜单加入盒子容器*/
    gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 3);
    /***********************************以下是信号处理部分************************************/

    /*关闭窗口时退出主循环*/
    g_signal_connect_swapped(G_OBJECT(window),"destroy",G_CALLBACK(gtk_main_quit), NULL);

    /***********************************以下是显示控件部分************************************/
    /*开始显示窗口*/
    //gtk_widget_show(window);
    gtk_widget_show_all(window);


    gtk_main();
    return 0;
}

二、添加状态栏,并点击任意菜单的时候在状态来显示内容

#include <gtk/gtk.h>

/* @Description: 从一个图片中获取信息得到pixbuf @param: gchar filename */
GdkPixbuf *create_pixbuf(const gchar * filename)
{
    GdkPixbuf *pixbuf;
    GError *error = NULL;
    /* * 函数gdk_pixbuf_new_from_file() 从一个图片文件中加载图象数据,从而生成一个新的 pixbuf, * 至于文件中包含图象的格式,是由系统自动检测的。如果该函数返回值是NULL 的话,程序就会出现错误。 */
    pixbuf = gdk_pixbuf_new_from_file(filename, &error);
    if(!pixbuf) {
        fprintf(stderr, "%s\n", error->message);
        g_error_free(error);
    }
    return pixbuf;
}

/*点击菜单时,状态栏显示*/
void menu_pressed(GtkWidget *widget, gpointer window)
{
    gchar *str;
    str = g_strdup_printf("you clicked one menu item");
    gtk_statusbar_push(GTK_STATUSBAR(window),gtk_statusbar_get_context_id(GTK_STATUSBAR(window), str), str);
    g_free(str);
}


int main( int argc, char *argv[])
{
    GtkWidget *window;
    GtkWidget *vbox;            //盒装容器
    GtkWidget *menubar;         //菜单栏
    GtkWidget *menutoggle, *menu_tog_toggle,*menu_tog_toolbar, *menu_tog_statusbar;  //界面开关菜单
    //GtkWidget *menu_about, *menu_about_us; //帮助菜单
    GtkWidget *statusbar;       //状态栏

    /*初始化整个GTK+程序,是每一个GTK+程序必不可少的部分*/
    gtk_init(&argc, &argv);
    /*这里生成了一个窗口构件——GtkWindow,GTK_WINDOW_TOPLEVEL包含窗口的标题栏和边框,同意用窗口管理器来进行管理*/
    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    /*设置窗口标题*/
    gtk_window_set_title(GTK_WINDOW(window), "一步一步学GTK+ DEMO");
    /*设置窗口默认大小*/
    gtk_window_set_default_size(GTK_WINDOW(window), 500, 400);
    /* * 设置窗口在显示器中的位置为居中。 * GTK_WIN_POS_NONE :不固定 * GTK_WIN_POS_CENTER : 居中 * GTK_WIN_POS_MOUSE : 出现在鼠标位置 * GTK_WIN_POS_CENTER_ALWAYS : 窗口改变大小的时候仍然居中 */
    gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);

    /*函数gtk_window_set_icon() 是为窗口设置图标用的,函数create_pixbuf是我们自定义的,目的是从一个图片中获取信息得到pixbuf。*/
    gtk_window_set_icon(GTK_WINDOW(window), create_pixbuf("./images/bear.png"));

    /*创建一个盒装容器并添加到窗口中*/
    vbox = gtk_vbox_new(FALSE, 0);
    gtk_container_add(GTK_CONTAINER(window), vbox);

    /*创建菜单*/
    menubar = gtk_menu_bar_new();   //代表整个菜单,是一个menu shell

    menutoggle = gtk_menu_new();   //这里代表第一列菜单toggle ,也是一个menu shell
    menu_tog_toggle = gtk_menu_item_new_with_label("widget toggle");
    menu_tog_toolbar = gtk_menu_item_new_with_label("show Toolbar"); //toggle 菜单中子项
    menu_tog_statusbar = gtk_menu_item_new_with_label("show Statusbar");

    gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_tog_toggle), menutoggle);  //widget toggle菜单加入 menutoggle menu shell
    gtk_menu_shell_append(GTK_MENU_SHELL(menutoggle), menu_tog_toolbar);
    gtk_menu_shell_append(GTK_MENU_SHELL(menutoggle), menu_tog_statusbar);

    gtk_menu_shell_append(GTK_MENU_SHELL(menubar), menu_tog_toggle);


    /*把菜单加入盒子容器*/
    gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 4);

    statusbar = gtk_statusbar_new();
    gtk_box_pack_end(GTK_BOX(vbox), statusbar, FALSE, TRUE, 1);
    /***********************************以下是信号处理部分************************************/

    /*关闭窗口时退出主循环*/
    g_signal_connect_swapped(G_OBJECT(window),"destroy",G_CALLBACK(gtk_main_quit), NULL);
    g_signal_connect(G_OBJECT(menu_tog_toolbar),"activate",G_CALLBACK(menu_pressed), G_OBJECT(statusbar));
    g_signal_connect(G_OBJECT(menu_tog_statusbar),"activate",G_CALLBACK(menu_pressed), G_OBJECT(statusbar));

    /***********************************以下是显示控件部分************************************/
    /*开始显示窗口*/
    //gtk_widget_show(window);
    gtk_widget_show_all(window);


    gtk_main();
    return 0;
}

状态栏的相关函数:

函数
guint gtk_statusbar_push (GtkStatusbar *statusbar, guint context_id, const gchar*text);
void gtk_statusbar_pop (GtkStatusbar *statusbar, guint context_id);
void gtk_statusbar_remove (GtkStatusbar *statusbar, guint context_id, guint message_id);
void gtk_statusbar_remove_all (GtkStatusbar *statusbar, guint context_id);

三、添加工具栏,并给“退出”按钮加入信号

#include <gtk/gtk.h>

/* @Description: 从一个图片中获取信息得到pixbuf @param: gchar filename */
GdkPixbuf *create_pixbuf(const gchar * filename)
{
    GdkPixbuf *pixbuf;
    GError *error = NULL;
    /* * 函数gdk_pixbuf_new_from_file() 从一个图片文件中加载图象数据,从而生成一个新的 pixbuf, * 至于文件中包含图象的格式,是由系统自动检测的。如果该函数返回值是NULL 的话,程序就会出现错误。 */
    pixbuf = gdk_pixbuf_new_from_file(filename, &error);
    if(!pixbuf) {
        fprintf(stderr, "%s\n", error->message);
        g_error_free(error);
    }
    return pixbuf;
}

/*点击菜单时,状态栏显示*/
void menu_pressed(GtkWidget *widget, gpointer window)
{
    gchar *str;
    str = g_strdup_printf("you click one menu item");
    gtk_statusbar_push(GTK_STATUSBAR(window),gtk_statusbar_get_context_id(GTK_STATUSBAR(window), str), str);
    g_free(str);
}


int main( int argc, char *argv[])
{
    GtkWidget *window;
    GtkWidget *vbox;            //盒装容器
    GtkWidget *menubar;         //菜单栏
    GtkWidget *menutoggle, *menu_tog_toggle,*menu_tog_toolbar, *menu_tog_statusbar;  //界面开关菜单
    //GtkWidget *menu_about, *menu_about_us; //帮助菜单
    GtkWidget *toolbar;         //工具栏
    GtkToolItem *tool_exit, *tool_sep,*tool_about;
    GtkWidget *statusbar;       //状态栏

    /*初始化整个GTK+程序,是每一个GTK+程序必不可少的部分*/
    gtk_init(&argc, &argv);
    /*这里生成了一个窗口构件——GtkWindow,GTK_WINDOW_TOPLEVEL包含窗口的标题栏和边框,同意用窗口管理器来进行管理*/
    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    /*设置窗口标题*/
    gtk_window_set_title(GTK_WINDOW(window), "一步一步学GTK+ DEMO");
    /*设置窗口默认大小*/
    gtk_window_set_default_size(GTK_WINDOW(window), 500, 400);
    /* * 设置窗口在显示器中的位置为居中。 * GTK_WIN_POS_NONE :不固定 * GTK_WIN_POS_CENTER : 居中 * GTK_WIN_POS_MOUSE : 出现在鼠标位置 * GTK_WIN_POS_CENTER_ALWAYS : 窗口改变大小的时候仍然居中 */
    gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);

    /*函数gtk_window_set_icon() 是为窗口设置图标用的,函数create_pixbuf是我们自定义的,目的是从一个图片中获取信息得到pixbuf。*/
    gtk_window_set_icon(GTK_WINDOW(window), create_pixbuf("./images/bear.png"));

    /*创建一个盒装容器并添加到窗口中*/
    vbox = gtk_vbox_new(FALSE, 0);
    gtk_container_add(GTK_CONTAINER(window), vbox);

    /*创建菜单*/
    menubar = gtk_menu_bar_new();   //代表整个菜单,是一个menu shell

    menutoggle = gtk_menu_new();   //这里代表第一列菜单toggle ,也是一个menu shell
    menu_tog_toggle = gtk_menu_item_new_with_label("View");
    menu_tog_toolbar = gtk_menu_item_new_with_label("show Toolbar"); //toggle 菜单中子项
    menu_tog_statusbar = gtk_menu_item_new_with_label("show Statusbar");

    gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_tog_toggle), menutoggle);  //widget toggle菜单加入 menutoggle menu shell
    gtk_menu_shell_append(GTK_MENU_SHELL(menutoggle), menu_tog_toolbar);
    gtk_menu_shell_append(GTK_MENU_SHELL(menutoggle), menu_tog_statusbar);

    gtk_menu_shell_append(GTK_MENU_SHELL(menubar), menu_tog_toggle);


    //创建工具栏
    toolbar = gtk_toolbar_new();
    gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS); //设置工具栏样式为图标
    gtk_container_set_border_width(GTK_CONTAINER(toolbar), 0);      //工具栏边框大小

    tool_exit = gtk_tool_button_new_from_stock(GTK_STOCK_QUIT);     //工具栏中的 “退出” 按钮
    gtk_toolbar_insert(GTK_TOOLBAR(toolbar), tool_exit, -1);

    tool_sep = gtk_separator_tool_item_new();                       //工具栏中按钮之间的分割线
    gtk_toolbar_insert(GTK_TOOLBAR(toolbar), tool_sep, -1);

    tool_about = gtk_tool_button_new_from_stock(GTK_STOCK_HELP);    //工具栏中的“关于” 按钮
    gtk_toolbar_insert(GTK_TOOLBAR(toolbar), tool_about, -1);


    statusbar = gtk_statusbar_new();
    /*把菜单加入盒子容器*/
    gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 1);
    /*把工具栏加入盒子容器*/
    gtk_box_pack_start(GTK_BOX(vbox), toolbar, FALSE, FALSE, 0);
    /*把状态栏加入盒子最下面*/
    gtk_box_pack_end(GTK_BOX(vbox), statusbar, FALSE, TRUE, 1);


    /***********************************以下是信号处理部分************************************/
    /*关闭窗口时退出主循环*/
    g_signal_connect_swapped(G_OBJECT(window),"destroy",G_CALLBACK(gtk_main_quit), NULL);
    g_signal_connect(G_OBJECT(tool_exit), "clicked",G_CALLBACK(gtk_main_quit), NULL);

    g_signal_connect(G_OBJECT(menu_tog_toolbar),"activate",G_CALLBACK(menu_pressed), G_OBJECT(statusbar));
    g_signal_connect(G_OBJECT(menu_tog_statusbar),"activate",G_CALLBACK(menu_pressed), G_OBJECT(statusbar));

    /***********************************以下是显示控件部分************************************/
    /*开始显示窗口*/
    //gtk_widget_show(window);
    gtk_widget_show_all(window);


    gtk_main();
    return 0;
}

四、选择(Check)菜单选项(menu item)

移除刚才菜单点时候状态栏显示的功能,新增功能——控制工具栏和状态栏的显示/隐藏。

#include <gtk/gtk.h>

/* @Description: 从一个图片中获取信息得到pixbuf @param: gchar filename */
GdkPixbuf *create_pixbuf(const gchar * filename)
{
    GdkPixbuf *pixbuf;
    GError *error = NULL;
    /* * 函数gdk_pixbuf_new_from_file() 从一个图片文件中加载图象数据,从而生成一个新的 pixbuf, * 至于文件中包含图象的格式,是由系统自动检测的。如果该函数返回值是NULL 的话,程序就会出现错误。 */
    pixbuf = gdk_pixbuf_new_from_file(filename, &error);
    if(!pixbuf) {
        fprintf(stderr, "%s\n", error->message);
        g_error_free(error);
    }
    return pixbuf;
}

/*点击菜单时,状态栏显示*/
/* void menu_pressed(GtkWidget *widget, gpointer window) { gchar *str; str = g_strdup_printf("you click one menu item"); gtk_statusbar_push(GTK_STATUSBAR(window),gtk_statusbar_get_context_id(GTK_STATUSBAR(window), str), str); g_free(str); } */
//根据菜单栏的选择(check)控制一些构件的显示和隐藏
void toggle_display(GtkWidget *widget, gpointer oneofwidget)
{
    if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))) {
        gtk_widget_show(oneofwidget);
    } else {
        gtk_widget_hide(oneofwidget);
    }
}


int main( int argc, char *argv[])
{
    GtkWidget *window;
    GtkWidget *vbox;            //盒装容器
    GtkWidget *menubar;         //菜单栏
    GtkWidget *menutoggle, *menu_tog_toggle,*menu_tog_toolbar, *menu_tog_statusbar;  //界面开关菜单
    //GtkWidget *menu_about, *menu_about_us; //帮助菜单
    GtkWidget *toolbar;         //工具栏
    GtkToolItem *tool_exit, *tool_sep,*tool_about;
    GtkWidget *statusbar;       //状态栏

    /*初始化整个GTK+程序,是每一个GTK+程序必不可少的部分*/
    gtk_init(&argc, &argv);
    /*这里生成了一个窗口构件——GtkWindow,GTK_WINDOW_TOPLEVEL包含窗口的标题栏和边框,同意用窗口管理器来进行管理*/
    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    /*设置窗口标题*/
    gtk_window_set_title(GTK_WINDOW(window), "一步一步学GTK+ DEMO");
    /*设置窗口默认大小*/
    gtk_window_set_default_size(GTK_WINDOW(window), 500, 400);
    /* * 设置窗口在显示器中的位置为居中。 * GTK_WIN_POS_NONE :不固定 * GTK_WIN_POS_CENTER : 居中 * GTK_WIN_POS_MOUSE : 出现在鼠标位置 * GTK_WIN_POS_CENTER_ALWAYS : 窗口改变大小的时候仍然居中 */
    gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);

    /*函数gtk_window_set_icon() 是为窗口设置图标用的,函数create_pixbuf是我们自定义的,目的是从一个图片中获取信息得到pixbuf。*/
    gtk_window_set_icon(GTK_WINDOW(window), create_pixbuf("./images/bear.png"));

    /*创建一个盒装容器并添加到窗口中*/
    vbox = gtk_vbox_new(FALSE, 0);
    gtk_container_add(GTK_CONTAINER(window), vbox);

    /*创建菜单*/
    menubar = gtk_menu_bar_new();   //代表整个菜单,是一个menu shell

    menutoggle = gtk_menu_new();   //这里代表第一列菜单toggle ,也是一个menu shell
    menu_tog_toggle = gtk_menu_item_new_with_label("View");
    //menu_tog_toolbar = gtk_menu_item_new_with_label("show Toolbar"); //toggle 菜单中子项
    //menu_tog_statusbar = gtk_menu_item_new_with_label("show Statusbar");
    menu_tog_toolbar = gtk_check_menu_item_new_with_label("show Toolbar");
    gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu_tog_toolbar),TRUE);
    menu_tog_statusbar = gtk_check_menu_item_new_with_label("show Statusbar");
    gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu_tog_statusbar),TRUE);

    gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_tog_toggle), menutoggle);  //widget toggle菜单加入 menutoggle menu shell
    gtk_menu_shell_append(GTK_MENU_SHELL(menutoggle), menu_tog_toolbar);
    gtk_menu_shell_append(GTK_MENU_SHELL(menutoggle), menu_tog_statusbar);


    gtk_menu_shell_append(GTK_MENU_SHELL(menubar), menu_tog_toggle);


    //创建工具栏
    toolbar = gtk_toolbar_new();
    gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS); //设置工具栏样式为图标
    gtk_container_set_border_width(GTK_CONTAINER(toolbar), 0);      //工具栏边框大小

    tool_exit = gtk_tool_button_new_from_stock(GTK_STOCK_QUIT);     //工具栏中的 “退出” 按钮
    gtk_toolbar_insert(GTK_TOOLBAR(toolbar), tool_exit, -1);

    tool_sep = gtk_separator_tool_item_new();                       //工具栏中按钮之间的分割线
    gtk_toolbar_insert(GTK_TOOLBAR(toolbar), tool_sep, -1);

    tool_about = gtk_tool_button_new_from_stock(GTK_STOCK_HELP);    //工具栏中的“关于” 按钮
    gtk_toolbar_insert(GTK_TOOLBAR(toolbar), tool_about, -1);


    statusbar = gtk_statusbar_new();
    /*把菜单加入盒子容器*/
    gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 1);
    /*把工具栏加入盒子容器*/
    gtk_box_pack_start(GTK_BOX(vbox), toolbar, FALSE, FALSE, 0);
    /*把状态栏加入盒子最下面*/
    gtk_box_pack_end(GTK_BOX(vbox), statusbar, FALSE, TRUE, 1);


    /***********************************以下是信号处理部分************************************/
    /*关闭窗口时退出主循环*/
    g_signal_connect_swapped(G_OBJECT(window),"destroy",G_CALLBACK(gtk_main_quit), NULL);
    g_signal_connect(G_OBJECT(tool_exit), "clicked",G_CALLBACK(gtk_main_quit), NULL);

    //g_signal_connect(G_OBJECT(menu_tog_toolbar),"activate",G_CALLBACK(menu_pressed), G_OBJECT(statusbar));
    //g_signal_connect(G_OBJECT(menu_tog_statusbar),"activate",G_CALLBACK(menu_pressed), G_OBJECT(statusbar));
    g_signal_connect(G_OBJECT(menu_tog_toolbar), "activate",G_CALLBACK(toggle_display), toolbar);
    g_signal_connect(G_OBJECT(menu_tog_statusbar), "activate",G_CALLBACK(toggle_display), statusbar);

    /***********************************以下是显示控件部分************************************/
    /*开始显示窗口*/
    //gtk_widget_show(window);
    gtk_widget_show_all(window);


    gtk_main();
    return 0;
}

(四)、一步一步学GTK+之多窗口

一、按照一定的逻辑去切割代码并实现多窗口

上一篇中完成了一个简单的软件界面,考虑到这个软件主要的目的是在软件中容纳很多控件,一个窗口中不可能全部包含进去的。所以这篇内容是我们一起来学下多窗口。既然我们要实现多窗口,那么就不能把所有代码放到一个文件中,这样会很混乱的,一个文件来放一个窗口,然后用main.c的入口文件来调度它们。使用我先把文件的结构分为:
main.c——入口文件
window_main.c——主窗口文件
window_test.c——测试用的子窗口文件
common_func.c——各个窗口调用的公共函数文件
既然涉及到公共函数会被其他窗口调用,我们还需要建立一些头文件,在其中加入一些宏来防止重复包含文件。
common_func.h

#ifndef __COMMON_FUNC_H__
#define __COMMON_FUNC_H__

#include <gtk/gtk.h>
GdkPixbuf *create_pixbuf(const gchar * filename);
void toggle_display(GtkWidget *widget, gpointer oneofwidget);

#endif // __COMMON_FUNC_H__

common.c


#include "common_func.h"
/*  @Description: 从一个图片中获取信息得到pixbuf  @param: gchar filename */
GdkPixbuf *create_pixbuf(const gchar * filename)
{
    GdkPixbuf *pixbuf;
    GError *error = NULL;
    /* * 函数gdk_pixbuf_new_from_file() 从一个图片文件中加载图象数据,从而生成一个新的 pixbuf, * 至于文件中包含图象的格式,是由系统自动检测的。如果该函数返回值是NULL 的话,程序就会出现错误。 */
    pixbuf = gdk_pixbuf_new_from_file(filename, &error);
    if(!pixbuf) {
        fprintf(stderr, "%s\n", error->message);
        g_error_free(error);
    }
    return pixbuf;
}


//根据菜单栏的选择(check)控制一些构件的显示和隐藏
void toggle_display(GtkWidget *widget, gpointer oneofwidget)
{
    if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))) {
        gtk_widget_show(oneofwidget);
    } else {
        gtk_widget_hide(oneofwidget);
    }
}

以上只是把原来的两个函数提取出来,并添加了头文件。

window_main.h

#ifndef __WINDOW_MAIN_H__
#define __WINDOW_MAIN_H__

#include <gtk/gtk.h>
#include "common_func.h"
GtkWidget *create_main_window();

#endif // __WINDOW_MAIN_H__

window_main.c

#include "common_func.h"
#include "window_main.h"


GtkWidget *create_main_window()
{//创建主窗口
    GtkWidget *window;
    GtkWidget *vbox;            //盒装容器
    GtkWidget *menubar;         //菜单栏
    GtkWidget *menutoggle, *menu_tog_toggle,*menu_tog_toolbar, *menu_tog_statusbar;  //界面开关菜单
    //GtkWidget *menu_about, *menu_about_us; //帮助菜单
    GtkWidget *toolbar;         //工具栏
    GtkToolItem *tool_exit, *tool_sep,*tool_about;
    GtkWidget *statusbar;       //状态栏


    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_title(GTK_WINDOW(window), "一步一步学GTK+ DEMO");
    gtk_window_set_default_size(GTK_WINDOW(window), 500, 400);
    gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);

    /*函数gtk_window_set_icon() 是为窗口设置图标用的,函数create_pixbuf是我们自定义的,目的是从一个图片中获取信息得到pixbuf。*/
    gtk_window_set_icon(GTK_WINDOW(window), create_pixbuf("./images/bear.png"));

    /*创建一个盒装容器并添加到窗口中*/
    vbox = gtk_vbox_new(FALSE, 0);
    gtk_container_add(GTK_CONTAINER(window), vbox);

    /*创建菜单*/
    menubar = gtk_menu_bar_new();   //代表整个菜单,是一个menu shell

    menutoggle = gtk_menu_new();   //这里代表第一列菜单toggle ,也是一个menu shell
    menu_tog_toggle = gtk_menu_item_new_with_label("View");

    menu_tog_toolbar = gtk_check_menu_item_new_with_label("show Toolbar");
    gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu_tog_toolbar),TRUE);
    menu_tog_statusbar = gtk_check_menu_item_new_with_label("show Statusbar");
    gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu_tog_statusbar),TRUE);

    gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_tog_toggle), menutoggle);  //widget toggle菜单加入 menutoggle menu shell
    gtk_menu_shell_append(GTK_MENU_SHELL(menutoggle), menu_tog_toolbar);
    gtk_menu_shell_append(GTK_MENU_SHELL(menutoggle), menu_tog_statusbar);


    gtk_menu_shell_append(GTK_MENU_SHELL(menubar), menu_tog_toggle);


    //创建工具栏
    toolbar = gtk_toolbar_new();
    gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS); //设置工具栏样式为图标
    gtk_container_set_border_width(GTK_CONTAINER(toolbar), 0);      //工具栏边框大小

    tool_exit = gtk_tool_button_new_from_stock(GTK_STOCK_QUIT);     //工具栏中的 “退出” 按钮
    gtk_toolbar_insert(GTK_TOOLBAR(toolbar), tool_exit, -1);

    tool_sep = gtk_separator_tool_item_new();                       //工具栏中按钮之间的分割线
    gtk_toolbar_insert(GTK_TOOLBAR(toolbar), tool_sep, -1);

    tool_about = gtk_tool_button_new_from_stock(GTK_STOCK_HELP);    //工具栏中的“关于” 按钮
    gtk_toolbar_insert(GTK_TOOLBAR(toolbar), tool_about, -1);


    statusbar = gtk_statusbar_new();
    /*把菜单加入盒子容器*/
    gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 1);
    /*把工具栏加入盒子容器*/
    gtk_box_pack_start(GTK_BOX(vbox), toolbar, FALSE, FALSE, 0);
    /*把状态栏加入盒子最下面*/
    gtk_box_pack_end(GTK_BOX(vbox), statusbar, FALSE, TRUE, 1);

     /***********************************以下是信号处理部分************************************/
    /*关闭窗口时退出主循环*/
    g_signal_connect_swapped(G_OBJECT(window),"destroy",G_CALLBACK(gtk_main_quit), NULL);
    g_signal_connect(G_OBJECT(tool_exit), "clicked",G_CALLBACK(gtk_main_quit), NULL);

    g_signal_connect(G_OBJECT(menu_tog_toolbar), "activate",G_CALLBACK(toggle_display), toolbar);
    g_signal_connect(G_OBJECT(menu_tog_statusbar), "activate",G_CALLBACK(toggle_display), statusbar);

    /***********************************以下是显示控件部分************************************/
    /*开始显示窗口*/
    //gtk_widget_show_all(window);

    //gtk_main();
    //return 0;
    return window;


}

这段也只是原来的代码中,把显示窗口的部分放在了一个函数中(create_main_window()),并把显示窗口语句gtk_widget_show_all(window); 注释掉,放在入口文件中调用,并注释掉gtk_main()主循环,主循环我们应该放在入口文件中,让这个函数返回创建的窗口, return window;

window_test.h

#ifndef __WINDOW_TEST_H__
#define __WINDOW_TEST_H__

#include <gtk/gtk.h>
#include "common_func.h"
GtkWidget *create_test_window();

#endif // __WINDOW_TEST_H__

window_test.c

#include "window_test.h"

 GtkWidget *create_test_window()
 { //创建一个测试窗口


    GtkWidget *window_test;

    window_test = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_widget_show(window_test);
    //gtk_main();
    //return 0;
    return window_test;
 }

这里只用了个函数创建了一个空白的测试窗口,并返回窗口。
main.c

#include <gtk/gtk.h>
#include "common_func.h"
#include "window_main.h"
#include "window_test.h"

int main( int argc, char *argv[])
{
    GtkWidget *main_window ,*test_window;
    gtk_init(&argc, &argv);

    main_window=create_test_window(); //创建主窗口
    test_window=create_main_window(); //创建测试窗口

    gtk_widget_show_all(main_window); //显示主窗口
    gtk_widget_show_all(test_window); //显示测试窗口
    gtk_main();
    return 0;

}

在入口文件中,我们开始执行创建窗口并显示它们,这样看起来就很简洁,如果还有其他窗口我们用同样的方法去增加就好了。在main.c中同一控制其他窗口的调度是很方便的。这样分开后,代码结构清晰,审查代码也很方便了。
以上的代码仅仅是显示了2个窗口,但点击任意窗口右上角的X就会全部关闭.下面我们来实现2个窗口的交互。

二、主窗口与子窗口的交互

在主窗口中的2个按钮分别控制子窗口的显示和隐藏(没有使用摧毁和重新创建的方法),并在点击子窗口的按钮,改变主窗口的label控件中的文字。顺便也简单介绍下 按钮(GtkButton)和标签控件(GtkLabel).以及非盒装容器GtkFixed。

注意:由于本人能力有限,且暂时不想引入在结构体中包含函数指针的方法,姑且采用几个全局变量,这样其他文件中可通过extern修饰符进行引用。

修改main.c

#include <gtk/gtk.h>
#include "common_func.h"
#include "window_main.h"
#include "window_test.h"

//Global
GtkWidget *window_test = NULL;  //子窗口本身
GtkWidget *label = NULL;        //主窗口中的label


int main( int argc, char *argv[])
{
    GtkWidget *window_main;     //主窗口不会在子窗口中使用,故不用声明为全局变量

    gtk_init(&argc, &argv);

    window_main=create_main_window(); //创建主窗口
    window_test=create_test_window(); //创建测试窗口

    gtk_widget_show_all(window_main); //显示主窗口
    //gtk_widget_show_all(window_test); //显示测试窗口


    gtk_main();
    return 0;

}

window_main.c

#include "common_func.h"
#include "window_main.h"

extern GtkWidget *window_test;
extern GtkWidget *label;

//显示子窗口
void show_test_window(GtkWidget *widget)
{

    gchar *msg="子窗口打开了";
    gtk_label_set_text(GTK_LABEL(label),msg);
    gtk_widget_show_all(window_test);
}

//隐藏子窗口
void hide_test_window(GtkWidget *widget)
{
    gchar *msg="子窗口关闭了";
    gtk_label_set_text(GTK_LABEL(label),msg);
    gtk_widget_hide_all(window_test);
}


GtkWidget *create_main_window()
{//创建主窗口
    GtkWidget *window;
    GtkWidget *vbox;            //盒装容器
    GtkWidget *menubar;         //菜单栏
    GtkWidget *menutoggle, *menu_tog_toggle,*menu_tog_toolbar, *menu_tog_statusbar;  //界面开关菜单
    //GtkWidget *menu_about, *menu_about_us; //帮助菜单
    GtkWidget *toolbar;         //工具栏
    GtkToolItem *tool_exit, *tool_sep,*tool_about;
    GtkWidget *statusbar;       //状态栏
    GtkWidget *fixed;

    GtkWidget *test_button;
    GtkWidget *test2_button;

    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_title(GTK_WINDOW(window), "一步一步学GTK+ DEMO");
    gtk_window_set_default_size(GTK_WINDOW(window), 500, 400);
    gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);

    /*函数gtk_window_set_icon() 是为窗口设置图标用的,函数create_pixbuf是我们自定义的,目的是从一个图片中获取信息得到pixbuf。*/
    gtk_window_set_icon(GTK_WINDOW(window), create_pixbuf("./images/bear.png"));

    /*创建一个盒装容器并添加到窗口中*/
    vbox = gtk_vbox_new(FALSE, 0);
    gtk_container_add(GTK_CONTAINER(window), vbox);

    /*创建菜单*/
    menubar = gtk_menu_bar_new();   //代表整个菜单,是一个menu shell

    menutoggle = gtk_menu_new();   //这里代表第一列菜单toggle ,也是一个menu shell
    menu_tog_toggle = gtk_menu_item_new_with_label("View");

    menu_tog_toolbar = gtk_check_menu_item_new_with_label("show Toolbar");
    gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu_tog_toolbar),TRUE);
    menu_tog_statusbar = gtk_check_menu_item_new_with_label("show Statusbar");
    gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu_tog_statusbar),TRUE);

    gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_tog_toggle), menutoggle);  //widget toggle菜单加入 menutoggle menu shell
    gtk_menu_shell_append(GTK_MENU_SHELL(menutoggle), menu_tog_toolbar);
    gtk_menu_shell_append(GTK_MENU_SHELL(menutoggle), menu_tog_statusbar);


    gtk_menu_shell_append(GTK_MENU_SHELL(menubar), menu_tog_toggle);


    //创建工具栏
    toolbar = gtk_toolbar_new();
    gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS); //设置工具栏样式为图标
    gtk_container_set_border_width(GTK_CONTAINER(toolbar), 0);      //工具栏边框大小

    tool_exit = gtk_tool_button_new_from_stock(GTK_STOCK_QUIT);     //工具栏中的 “退出” 按钮
    gtk_toolbar_insert(GTK_TOOLBAR(toolbar), tool_exit, -1);

    tool_sep = gtk_separator_tool_item_new();                       //工具栏中按钮之间的分割线
    gtk_toolbar_insert(GTK_TOOLBAR(toolbar), tool_sep, -1);

    tool_about = gtk_tool_button_new_from_stock(GTK_STOCK_HELP);    //工具栏中的“关于” 按钮
    gtk_toolbar_insert(GTK_TOOLBAR(toolbar), tool_about, -1);


    statusbar = gtk_statusbar_new();
    fixed = gtk_fixed_new();
    /*把菜单加入盒子容器*/
    gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 1);
    /*把工具栏加入盒子容器*/
    gtk_box_pack_start(GTK_BOX(vbox), toolbar, FALSE, FALSE, 0);
    /*把fixed加入主工作区*/
    gtk_box_pack_start(GTK_BOX(vbox), fixed, FALSE, FALSE, 0);
    /*在fixed中放入一些按钮和label*/
    test_button=gtk_button_new_with_label("打开测试窗口");
    gtk_fixed_put(GTK_FIXED(fixed), test_button, 150, 50);
    gtk_widget_set_size_request(test_button, 150, 35);

    test2_button=gtk_button_new_with_label("关闭测试窗口");
    gtk_fixed_put(GTK_FIXED(fixed), test2_button, 300, 50);
    gtk_widget_set_size_request(test2_button, 80, 35);

    label = gtk_label_new("这里的文字会通过子窗口的操作来改变。");
    gtk_fixed_put(GTK_FIXED(fixed), label, 100, 100);
    gtk_widget_set_size_request(label, 300, 100);

    /*把状态栏加入盒子最下面*/
    gtk_box_pack_end(GTK_BOX(vbox), statusbar, FALSE, TRUE, 1);

     /***********************************以下是信号处理部分************************************/
    /*关闭窗口时退出主循环*/
    g_signal_connect_swapped(G_OBJECT(window),"destroy",G_CALLBACK(gtk_main_quit), NULL);
    g_signal_connect(G_OBJECT(tool_exit), "clicked",G_CALLBACK(gtk_main_quit), NULL);


    g_signal_connect(G_OBJECT(menu_tog_toolbar), "activate",G_CALLBACK(toggle_display), toolbar);
    g_signal_connect(G_OBJECT(menu_tog_statusbar), "activate",G_CALLBACK(toggle_display), statusbar);

    g_signal_connect(G_OBJECT(test_button), "clicked",G_CALLBACK(show_test_window), NULL);
    g_signal_connect(G_OBJECT(test2_button), "clicked",G_CALLBACK(hide_test_window), NULL);


    return window;


}

window_test.c

#include "window_test.h"
//
extern GtkWidget *window_test;
extern GtkWidget *label;

static gint delete_event()
{
    /* 如果你的 "delete_event" 信号处理函数返回 FALSE,GTK 会发出 "destroy" 信号。 * 返回 TRUE,你不希望关闭窗口。 * 当你想弹出“你确定要退出吗?”对话框时它很有用。*/
    gtk_widget_hide_all(window_test);

    return TRUE; //注意必须为TRUE,否则子窗口点击关闭按钮后,就摧毁了,而不是隐藏了。
}


static void change_label_text()
{
    char *text="我是子窗口的动作改变的";
    gtk_label_set_text(GTK_LABEL(label),text);
}



 GtkWidget *create_test_window()
 { //创建一个测试窗口

    GtkWidget *window_test;
    GtkWidget *fixed;
    GtkWidget *button;

    window_test = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_default_size(GTK_WINDOW(window_test), 300, 200);
    fixed = gtk_fixed_new();

    button=gtk_button_new_with_label("改变主窗口label文字");
    gtk_fixed_put(GTK_FIXED(fixed), button, 50, 50);
    gtk_widget_set_size_request(button, 80, 65);

    gtk_container_add(GTK_CONTAINER(window_test), fixed);

    //gtk_widget_show(window);
    g_signal_connect(G_OBJECT(window_test),"delete_event",G_CALLBACK(delete_event), NULL); //注意这里不是“destroy” 事件
    g_signal_connect(G_OBJECT(button),"clicked",G_CALLBACK(change_label_text), NULL);

    //gtk_main();
    //return 0;
    return window_test;
 }

运行如下:
点击“打开测试窗口”——子窗口打开了,点击关闭测试窗口——子窗口关闭了(隐藏了),并主窗口中有对应的文字显示(label)

点击子窗口中的按钮,主窗口中的label标签文字改变了

说明:本方法只是测试多窗口的交互而已,是很拙劣的方法。在我看来如果能实现下面这种就更好了,可我不会。
1.入口文件中,通过其他2个文件创建并返回了2个窗口。
2.那么如果能在入口文件中操作其他所有窗口以及窗口中的控件和信号就好了。