转载请注明:http://blog.csdn.net/hubbybob1/article/details/49466979
本文主要是针对 GTK+2.0编程范例–宋国伟老师的书内的代码做一些注释,兼并讨论一下GTK+3.0与2.0的区别.其安装,在网上有很多讲解.
查看各个函数的的说明,就得看说明文档,下面这个网址很好,是GTK+3.0API的目录:
https://developer.gnome.org/gtk3/stable/
或者下载我上传的3.0说明文档,查看:
http://download.csdn.net/detail/hubbybob1/9219553
第2章 菜单与工具栏
2.1添加菜单
本节程序menu.c如下:
/*添加菜单menu.c*/
#include <gtk/gtk.h>
void on_menu_activate(GtkMenuItem* item, gpointer data)
{
g_print("菜单项 %s 被激活\n",(gchar*)data);
// g_print("menuitem %s is press!\n ",(gchar*)data);
}
int main (int argc, char* argv[])
{
GtkWidget* window;
GtkWidget* box;
GtkWidget* menubar;//定义菜单条
GtkWidget* menu;//定义文件菜单
GtkWidget* editmenu;//编辑菜单
GtkWidget* helpmenu;//帮助菜单
GtkWidget* rootmenu;//主菜单,其他菜单要附加到这里面
GtkWidget* menuitem;//菜单项
GtkAccelGroup* accel_group;
gtk_init(&argc,&argv);
//创建window
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window),"菜单测试程序");
gtk_window_set_default_size(GTK_WINDOW(window),200,200);//如果不设置大小的话会出现,窗口很小的问题
g_signal_connect(G_OBJECT(window),"destroy",G_CALLBACK(gtk_main_quit),NULL);
accel_group = gtk_accel_group_new();//创建快捷键集
gtk_window_add_accel_group(GTK_WINDOW(window),accel_group);
box = gtk_vbox_new(FALSE,0);//非均匀排放
gtk_container_add(GTK_CONTAINER(window),box);
///////////////////////////////////////////////////////////////////////////////////////
//创建 "文件"菜单
menu = gtk_menu_new();//创建菜单
//https://developer.gnome.org/gtk3/stable/gtk3-Stock-Items.html#GTK-STOCK-NEW:CAPS
//这识函数gtk_image_menu_item_new_from_stock的中的stock_id的定义,可以自己看看,也是快捷键
//在gtkstock.h文件中定义
menuitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_NEW,accel_group);//快捷键 CTRL + N,带系统图像
gtk_menu_shell_append(GTK_MENU_SHELL(menu),menuitem);//把新建子菜单挂到 他的上一级菜单上去
g_signal_connect(G_OBJECT(menuitem),"activate",//调用回调函数,打印新建
G_CALLBACK(on_menu_activate),(gpointer)("新建"));//(gpointer)("New")
menuitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_OPEN,accel_group);//创建快捷键 CTRL + O,并带系统图像
gtk_menu_shell_append(GTK_MENU_SHELL(menu),menuitem);//
g_signal_connect(G_OBJECT(menuitem),"activate",
G_CALLBACK(on_menu_activate),(gpointer)("打开"));//(gpointer)("Open")
menuitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_SAVE,accel_group);//CTRL + S ,并带有系统图标
gtk_menu_shell_append(GTK_MENU_SHELL(menu),menuitem);
g_signal_connect(G_OBJECT(menuitem),"activate",
G_CALLBACK(on_menu_activate),(gpointer)("保存"));//(gpointer)("Save")
menuitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_SAVE_AS,accel_group);
gtk_menu_shell_append(GTK_MENU_SHELL(menu),menuitem);
g_signal_connect(G_OBJECT(menuitem),"activate",
G_CALLBACK(on_menu_activate),(gpointer)("另存为"));//(gpointer)("Save As")
menuitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT,accel_group);
gtk_menu_shell_append(GTK_MENU_SHELL(menu),menuitem);
g_signal_connect(G_OBJECT(menuitem),"activate",
G_CALLBACK(on_menu_activate),(gpointer)("退出"));//(gpointer)("Exit")
rootmenu = gtk_menu_item_new_with_label(" 文件 ");//创建只带文字的菜单项, "文件"跟菜单
gtk_menu_item_set_submenu(GTK_MENU_ITEM(rootmenu),menu);//menu作为rootmenu的子菜单
menubar = gtk_menu_bar_new();//创建菜单条
gtk_menu_shell_append(GTK_MENU_SHELL(menubar),rootmenu);//把"文件"根菜单放到才单条上
////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
//创建"编辑"菜单
rootmenu = gtk_menu_item_new_with_label(" 编辑 ");
editmenu = gtk_menu_new();//编辑菜单
menuitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_CUT,accel_group);
gtk_menu_shell_append(GTK_MENU_SHELL(editmenu),menuitem);
g_signal_connect(G_OBJECT(menuitem),"activate",
G_CALLBACK(on_menu_activate),(gpointer)("剪切"));//(gpointer)("Cut")
menuitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_COPY,accel_group);
gtk_menu_shell_append(GTK_MENU_SHELL(editmenu),menuitem);
g_signal_connect(G_OBJECT(menuitem),"activate",
G_CALLBACK(on_menu_activate),(gpointer)("复制"));//(gpointer)("Copy")
menuitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_PASTE,accel_group);
gtk_menu_shell_append(GTK_MENU_SHELL(editmenu),menuitem);
g_signal_connect(G_OBJECT(menuitem),"activate",
G_CALLBACK(on_menu_activate),(gpointer)("粘贴"));//(gpointer)("Paste")
menuitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_FIND,accel_group);
gtk_menu_shell_append(GTK_MENU_SHELL(editmenu),menuitem);
g_signal_connect(G_OBJECT(menuitem),"activate",
G_CALLBACK(on_menu_activate),(gpointer)("查找"));//(gpointer)("Find")
gtk_menu_item_set_submenu(GTK_MENU_ITEM(rootmenu),editmenu);
gtk_menu_shell_append(GTK_MENU_SHELL(menubar),rootmenu);
////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////
//创建"帮助"菜单
rootmenu = gtk_menu_item_new_with_label(" 帮助 ");
helpmenu = gtk_menu_new();//帮助菜单
menuitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_HELP,accel_group);
gtk_menu_shell_append(GTK_MENU_SHELL(helpmenu),menuitem);
g_signal_connect(G_OBJECT(menuitem),"activate",
G_CALLBACK(on_menu_activate),(gpointer)("帮助"));//(gpointer)("Help")
menuitem = gtk_image_menu_item_new_with_label(" 关于...");
gtk_menu_shell_append(GTK_MENU_SHELL(helpmenu),menuitem);
g_signal_connect(G_OBJECT(menuitem),"activate",
G_CALLBACK(on_menu_activate),(gpointer)("关于"));//(gpointer)("About")
gtk_menu_item_set_submenu(GTK_MENU_ITEM(rootmenu),helpmenu);
gtk_menu_shell_append(GTK_MENU_SHELL(menubar),rootmenu);
///////////////////////////////////////////////////////////////////////////////////////////
/*
根据上面的阐述我们总结一下这个过程:
1.首先要创建window->box,这就不讲了,创建快捷键集, accel_group = gtk_accel_group_new();注意这个是绑定到window上的
2.要创建菜单条:使用menubar = gtk_menu_bar_new(),菜单条包括"文件","编辑","帮助"这些根菜单(rootmenu)
3.创建根菜单:rootmenu = gtk_menu_item_new_with_label(" 编辑 "),(需要把打包好的子菜单放到跟菜单上,这一点后面做)
4.创建菜单项,就是 editmenu = gtk_menu_new(),这个的作用就是打包所有的子菜单
5.创建子菜单:menuitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_CUT,accel_group),已编辑根菜单为例,子菜单为,复制粘贴剪切等
6.把子菜单放到菜单项中,就是打包gtk_menu_shell_append(GTK_MENU_SHELL(editmenu),menuitem);
7.把打包好的菜单项如editmenu放到根菜单上:gtk_menu_item_set_submenu(GTK_MENU_ITEM(rootmenu),editmenu);
8.再把根菜单放到菜单条上:gtk_menu_shell_append(GTK_MENU_SHELL(menubar),rootmenu);
这就是创建菜单的过程,其中回调函数最常用的信号为"activate",就是菜单被激活(被点击)
*/
gtk_box_pack_start(GTK_BOX(box),menubar,FALSE,FALSE,0);
gtk_widget_show_all(window); //显示
gtk_main();
return FALSE;
}//makefile
CC=gcc
all:
$(CC) -o menu menu.c `pkg-config --cflags --libs gtk+-3.0`
其运行的结果如下,可以使用快捷键.
到这里大家也许会发现两个问题:
1,为什么我运行的结果中菜单并没有系统图标,而在程序中使用的函数明明是gtk_image_menu_item_new_from_stock函数?
2.仔细观察,我们的对话框内的子菜单是中文的,为什么会是中文呢,千万不要以为中文,来自函数g_signal_connect()内的中文,这只是一个回调函数,中文作为参数用在on_menu_activate上,在终端打印的也就是上面的第二章图片?
这两个问题值得思考,我会在以后慢慢说明这一点.
2.2创建菜单快捷方法
这一节是上一节的简化,程序itemfact.c如下:
/*创建菜单的快捷方法itemfact.c*/
#include <gtk/gtk.h>
void on_menu_activate(GtkMenuItem* item, gpointer data);
static GtkItemFactoryEntry menu_item[] = {//定义菜单集合
//文件
{"/ 文件 (_F) ",NULL,NULL,0,"<Branch>"},//Branch:create an item to hold sub items,创建包含子项的项
{"/ 文件 (_F) /新建",NULL,on_menu_activate,0,"<StockItem>",GTK_STOCK_NEW},//"新建"
{"/ 文件 (_F) /打开",NULL,on_menu_activate,1,"<StockItem>",GTK_STOCK_OPEN},//"打开",
{"/ 文件 (_F) /保存",NULL,on_menu_activate,2,"<StockItem>",GTK_STOCK_SAVE},//"保存"
{"/ 文件 (_F) /另存为",NULL,on_menu_activate,3,"<StockItem>",GTK_STOCK_SAVE_AS},//"另存为"
{"/ 文件 (_F) /-",NULL,NULL,0,"<Separator>"},
{"/ 文件 (_F) /退出",NULL,on_menu_activate,4,"<StockItem>",GTK_STOCK_QUIT},//"退出"
//编辑
{"/ 编辑 (_E) ",NULL,NULL,0,"<Branch>"},
{"/ 编辑 (_E) /剪切",NULL,on_menu_activate,0,"<StockItem>",GTK_STOCK_CUT},//"剪切"
{"/ 编辑 (_E) /复制",NULL,on_menu_activate,0,"<StockItem>",GTK_STOCK_COPY},//"复制"
{"/ 编辑 (_E) /粘贴",NULL,on_menu_activate,0,"<StockItem>",GTK_STOCK_PASTE},//"粘贴"
{"/ 编辑 (_E) /查找",NULL,on_menu_activate,0,"<StockItem>",GTK_STOCK_FIND},//"查找",
//帮助
{"/ 帮助 (_H) ",NULL,NULL,0,"<Branch>"},
{"/ 帮助 (_H) /帮助",NULL,on_menu_activate,0,"<StockItem>",GTK_STOCK_HELP},//"帮助"
{"/ 帮助 (_H) /关于...",NULL,on_menu_activate,0,NULL}//"关于"
};
void on_menu_activate(GtkMenuItem* item, gpointer data)
{
g_print("菜单项 %d 被激活\n",(guint*)data);//%s gchar
// g_print("menuitem %s is press!\n ",(gchar*)data);
}
int main (int argc, char* argv[])
{
GtkWidget* window;
GtkWidget* box;
GtkWidget* menubar;//定义菜单条
GtkAccelGroup* accel_group;
GtkItemFactory* item_factory;//创建菜单
gint n = 15;//15
gtk_init(&argc,&argv);
//创建窗口
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window),"菜单测试程序");
gtk_window_set_default_size(GTK_WINDOW(window),200,200);//如果不设置大小的话会出现,窗口很小的问题
g_signal_connect(G_OBJECT(window),"destroy",G_CALLBACK(gtk_main_quit),NULL);
accel_group = gtk_accel_group_new();//创建快捷键集
gtk_window_add_accel_group(GTK_WINDOW(window),accel_group);
box = gtk_vbox_new(FALSE,0);//非均匀排放
gtk_container_add(GTK_CONTAINER(window),box);
//创建Gtktemactory(条目工厂),gtk_item_factory_new
//第一个参数必须是GTK_TYPE_MENU_BAR(菜单条类),
// GTK_TYPE_MENU(菜单类),GTK_TYPE_OPTION_MENU(选项菜单类)中的一个
//gtk_item_factory_create_items,第一个参数是 Gtktemactory(条目工厂),第二个参数为创建条目的个数
//第三个参数为GtkItemFactoryEntry,就是各个实际的条目,第四个为gpointer的回调参数数据
item_factory = gtk_item_factory_new(GTK_TYPE_MENU_BAR,"<main>",accel_group);
gtk_item_factory_create_items(item_factory,n,menu_item,NULL);
// gtk_window_add_accel_group(GTK_WINDOW(window),accel_group);
//gtk_item_factory_get_widget,获取菜单条指针
menubar = gtk_item_factory_get_widget(item_factory,"<main>");
gtk_box_pack_start(GTK_BOX(box),menubar,FALSE,FALSE,0);//到此结束创建菜单条过程
gtk_widget_show(menubar);
gtk_widget_show(window);
gtk_main();
return FALSE;
}//makefile
CC=gcc
all:
$(CC) itemfact.c -o itemfact `pkg-config gtk+-2.0 --cflags --libs`
仔细的人可以看到这个程序与书上的略有不同,那就是在建立条目入口数组时(GtkItemFactoryEntry menu_item[])的第四个参数变化的问题,例如:
书上为:
{"/ 文件 (_F) /新建",NULL,on_menu_activate,"新建","<StockItem>",GTK_STOCK_NEW},
变为了
{"/ 文件 (_F) /新建",NULL,on_menu_activate,0,"<StockItem>",GTK_STOCK_NEW},//"新建"
一开始时使用书上的源码,会报错
遮主要的原因就是版本的问题:那么就来查看为的gtk的
版本:命令为:
pkg-config --modversion gtk+-2.0
pkg-config --modversion gtk+-3.0
结果为:
发现自己的2.0的版本为2.24.10,版本很高了所以定义肯定不同,那么就去查看这个GtkItemFactoryEntry的格式到底是什么,
目录为:/usr/inclide/gtk-2.0/gtk/gtkitemfactory.h 中定义如下:
typedef struct _GtkItemFactoryEntry GtkItemFactoryEntry;
struct _GtkItemFactoryEntry
{
gchar *path;
gchar *accelerator;
GtkItemFactoryCallback callback;
guint callback_action;//这个参数为无符号整形
gchar *item_type;
/* possible values:
* NULL -> "<Item>"
* "" -> "<Item>"
* "<Title>" -> create a title item
* "<Item>" -> create a simple item
* "<ImageItem>" -> create an item holding an image
* "<StockItem>" -> create an item holding a stock image
* "<CheckItem>" -> create a check item
* "<ToggleItem>" -> create a toggle item
* "<RadioItem>" -> create a radio item
* <path> -> path of a radio item to link against
* "<Separator>" -> create a separator
* "<Tearoff>" -> create a tearoff separator
* "<Branch>" -> create an item to hold sub items
* "<LastBranch>" -> create a right justified item to hold sub items
*/
gconstpointer extra_data;
/* Extra data for some item types:
* ImageItem -> pointer to inlined pixbuf stream
* StockItem -> name of stock item
*/
};
可以看到第四个参数为无符号整形的参数,不能使用宋国伟老师书中的字符串来,那么到此问题就解决了吗:
编译运行的结果如下:
从中可以看出没有任何
菜单的东西存在,这就时版本内的问题了,使用3.0的版本编译的话根本编译不通过,报错的现象与上面的一样,但是3.0版本根本就没有 GtkItemFactoryEntry这个东西,也就时:/usr/inclide/gtk-3.0/gtk内也没有相关的库文件存在,连gtkitem相关的库都没了,也就是说这个版本摒弃这种编程方式,那么这么快捷的方式为什么要摒弃掉呢,有没有类时的方式呢,这个值得研究。
因此,将在下小结做一个翻外,Glade的使用和2.0与3.0的初步对比