《GTK+/GNOME程序设计》 笔记(一) GTK+

胡安怡
2023-12-01

2016.05.13 笔记

##GTK+简介
GTK 最初为GIMP(一个图像处理软件,类似Photoshop)的工具包
后来GTK重写为面向对象的GTK+

GTK+ 并非是用C++写的,而是用C语言,所谓的面向对象是用C语言模拟的。强大

GTK+ 2.0 新特性:
使用Pango(a theme engine)增强了文本渲染
improved accessibility using the Accessibility Toolkit, transition to Unicode using UTF-8 strings, and a more flexible API.

GTK+ 2.8, GTK+ 2 depends on the Cairo graphics library for rendering vector graphics.

GTK+ 3.0
included revised input device handling, support for themes written with CSS-like syntax, and the ability to receive information about other opened GTK+ applications.

版本的新特性参考 wiki GTK+

##编译
GTK+ 3.0的编译选项,用法见下文:
pkg-config --cflags gtk+-3.0
pkg-config --libs gtk+-3.0
https://developer.gnome.org/gtk3/stable/gtk-getting-started.html

fedora Linux中安装gtk+/gnome开发包:
dnf install gnome-devel
dnf install gtk3-devel
dnf install gtk2-devel
dnf install gtk+-devel
dnf install gcc
dnf install gcc-c++

#include <gtk/gtk.h>
void CloseRequest(GtkWidget* theWindow, gpointer data);

gint main(gint argc, gchar* argv[])
{
  GtkWidget* window;
  
  gtk_init(&argc, &argv);
  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  gtk_signal_connect(GTK_OBJECT(window), "destroy",
      GTK_SIGNAL_FUNC(CloseRequest), NULL);

  gtk_widget_show(window);
  gtk_main();
  return 0;
}

void CloseRequest(GtkWidget* theWindow, gpointer data)
{
  gtk_main_quit();
}

编译:
gcc -Wall -o test01 test01.cpp `gtk-config --cflags --libs`

-Wall 输出所有警告和错误

`gtk-config` 飘号中的命令会首先执行,命令执行返回的字符串将替换到该位置,gtk-config将返回编译选项:所需的头文件或库文件等信息。详情参考Linux命令行中飘号的用法。

##GLib
<glib.h>
GLib提供了一些标准的数据类型

gboolean
gpointer
gchar guchar
gint guint gshort
glong gulong
gint8 guint8 gint16
guint16 gint32 guint32
gint64 guint64
gfloat gdouble
gsize
gssize


G_DIR_SEPARATOR 目录分隔符 单个字符
G_DIR_SEPARATOR_S 0终结的串

G_SEARCHPATH_SEPARATOR PATH 分隔符
G_SEARCHPATH_SEPARATOR_S

MIN(x, y)
MAX(x, y)
ABS() 绝对值
CLAMP(a, x, y)

g_assert()
g_print() 非调试模式可以使用g_set_print_handler()函数忽略
g_assert_not_reached()  用来定义代码中不应该到达某个点
g_return_if_fail()
g_return_val_if_fail()
g_error() g_set_error_handler()
g_warning() g_set_warning_handler()

glib支持管理有序二叉树、n叉树、单向和双向链表的函数
如果glib分配内存的尝试由于某种原因未成功,则应用程序将终止

g_malloc()
g_free()
g_new(类型, 个数) g_new(char, 50)
g_realloc()
g_memdup() 自动分配一个新内存块,然后拷贝源块中的数据到新块,返回新块的指针

##链表
单向链表函数名 g_slist开头
双向链表函数名 g_list 开头

struct GSList
{
    gpointer data;
    GSList* next;
}

struct GList
{
    gpointer data;
    GList* next;
    GList* prev;
}

建立表是初始化一个表为NULL

GList* list = NULL;
g_list_free(list)
g_slist_free()

g_list_append()
g_list_prepend()
g_list_insert(list, "data", 1); 索引从0开始,插入的位置
g_list_insert_sorted(list, "data", 比较函数)

##创建窗口
X Windows System API

继承关系

GtkObject
  GtkWidget
    GtkContainer
      GtkBin
        GtkWindow

gtk_window_new()
GTK_WINDOW_TOPLEVEL
GTK_WINDOW_DIALOG
GTK_WINDOW_POPUP

gtk_window开头 使用GtkWindow
gtk_widget开头 使用GtkWidget

gtk_main() 启动GTK+循环

##事件和信号
X本身能够抓住所产生的某些事情,如窗口删除、点击按钮等,这些都为信号。
GTK+还添加了自己的特定类型,为事件
在代码中使用信号和事件没有区别。

##信号连接

gtk_signal_connect(GTK_OBJECT(theWindow), "destroy",
    GTK_SIGNAL_FUNC(StopTheApp), NULL);

GTK_OBJECTtheWindow转换为基类对象GtkObject
因为信号处理程序的声明不一样,所以GTK_SIGNAL_FUNC转换
编写信号处理程序时,需要查询信号文档以便知道处理函数应有的格式。
参考 GTK+/GNOME程序设计附录A

信号处理程序是事后调用的。这样,一个窗口取消并且在其取消后调用信号处理程序。

事件是事前产生的。因此,每个窗口有一个称为delete_event的事件,该事件在窗口取消前产生。

事件处理程序中:
return TRUE 告诉GTK+我处理了此事件
return FALSE 告诉GTK+我不处理这个事件,你来处理
比如在delete_event处理程序中返回TRUE以禁止GTK+取消窗口
连接事件只需将"destroy"改为"delete_event"

GdkEvent 参考第三章
GdkEventType

事件类型 “event” 捕获所有事件

gint gtk_signal_connect()返回处理程序ID

断开信号处理程序的连接
gtk_signal_disconnect(GTK_OBJECT(myWindow), id);

不使用ID断开连接:
gtk_signal_disconnect_by_func()

##设置窗口标题
gtk_window_set_title(GTK_WINDOW(myWindow), "This is the caption");

gtk_window_set_default_size(GTK_WINDOW(myWindow), 640, 480);

gtk_window_set_position()
GTK_WIN_POS_NONE     GTK+将窗口放在它想放置的位置,默认
GTK_WIN_POS_CENTER   屏幕居中
GTK_WIN_POS_MOUSE    窗口中心和鼠标点相同

gtk_widget_set_uposition()

GTK+的按钮实际上是一个容器,包含一个文本标签

将小部件添加到容器的步骤:

  1. 建立需要添加的窗口小部件
  2. 将其添加到容器中
  3. 设置其信号和事件的回调机制
  4. 显示这个窗口小部件
GtkWidget* AddButton(GtkWidget* theWindow, const gchar* buttonText)
{
	GtkWidget* button;
	button = gtk_button_new_with_label(buttonText);
	gtk_container_add(GTK_CONTAINER(theWindow), button);
	gtk_widget_show(button);
	return button;
}
gtk_signal_connect(GTK_OBJECT(button), "clicked", 
	GTK_SIGNAL_FUNC(ButtonClicked), NULL);

gtk_container_border_width(GTK_CONTAINER(window), 5);

##布局
GtkBox GtkHBox GtkVBox
gtk_hbox_new()
gtk_box_pack_start()
gtk_box_pack_end()

包装框添加小部件的步骤:

  1. 建立窗口小部件
  2. 将它添加到包装框中
  3. 显示它
/* 示例 */
GtkWidget* box;
box = gtk_hbox_new(TRUE, 5); // homogenous 均匀的 第二个参数,小部件间的间距
button = gtk_button_new_with_label(...);
gtk_box_pack_start(GTK_BOX(box), button, 
	FALSE, TRUE, 0);  // expand fill padding
gtk_widget_show(button);
gtk_widget_show(box);

最好建立了窗口的所有内容并准备显示时再显示此窗口。否则在速度慢的机器上用户会看到窗口和用户界面一点一点建立的过程。

GtkRequisition
  gint16 width
  gint16 height

GtkAllocation
  gint16 x
  gint16 y
  guint16 width
  guint16 height

gtk_widget_show_all() 可以一次显示所有的窗口小部件

##包装表 GtkTable
gtk_table_new(guint rows, guint columns, gboolean homogenous)

homogenous
TRUE 所有列使用表中最大窗口小部件的宽度,行同理

将窗口小部件添加到表中:
gtk_table_attach_defaults(..., guint left_attach, guint right_attach, ...)

left_attach 0 right_attach 1
表示小部件放在第一列,0 2 表示 横跨1 2两列
defaults表示 expand fill padding 为默认 TRUE TRUE 0
gtk_table_attach()
GtkAttachOptions
GTK_EXPAND GTK_FILL

##窗口小部件 GtkLabel

  gtk_label_new(const gchar* str)
  gtk_label_set_text(..., const gchar* str) 空指针表示清除文本
  gtk_label_set_line_wrap() 使文本超过宽度自动换行
  gtk_label_set_justify() 总是垂直居中,无法控制,不能在运行中改变对齐方式,必须在显示前设置
    GtkJustification
    GTK_JUSTIFY_LEFT GTK_JUSTIFY_FIGHT GTK_JUSTIFY_CENTER GTK_JUSTIFY_FULL

##GtkEntry 文本输入框

  gtk_entry_new(void)
  gtk_entry_new_width_max_length(guint16 max) // 限制字符数
  gtk_entry_set_max_length()
  gtk_entry_get_text()
  gtk_entry_set_text()
  gtk_entry_set_visibility(..., gboolean visible)  // false 用星号显示,无法定制使用其他符号
  gtk_entry_prepend_text()  // 将文本插入到已有文本前面
  gtk_entry_append_text()

##GtkEditable
GtkEditableGtkEntry的基类

  gtk_editable_set_editable()
  gtk_editable_select_region() 高亮选中文本 [start, end)  MAXINT
  剪贴板函数,对选中的文本进行操作
  gtk_editable_cut_clipboard()
  gtk_editable_copy_clipboard()
  gtk_editable_paste_clipboard()

##GtkToggleButton
GtkToggleButton 派生于 GtkButton
“toggled” “clicked”

  gtk_toggle_button_new_with_label("Toggle Me")
  gtk_toggle_button_new()
  gtk_toggle_button_get_active()
  gtk_toggle_button_set_active()
  gtk_toggle_button_toggled()

##GtkCheckButton
窗口小部件的外观取决于所使用的窗口管理器,它负责窗口小部件的绘制。

  gtk_check_button_new_with_label()
  gtk_check_button_new()

##GtkRadioButton
GtkRadioButton 派生于 GtkCheckButton

步骤:

  1. 建立一个空的GList指针(单向链表)
  2. 将列表传递给建立单选钮的函数
  3. 将单选钮添加到容器中
  4. 显示单选钮
  5. 得到从单选钮中返回的更改过的链表
GSList* group = NULL;
GtkWidget* radio;
radio = gtk_radio_button_new_with_label(group, "Some Text");
group = gtk_radio_button_group(radio);

##GtkFrame
GtkFrame 一个可视容器,如同窗口一样只能拥有一个窗口小部件,所以,先将一个Box添加到Frame上

  gtk_frame_set_label_align(..., gfloat xalign, yalign) 0 - 1,标题的显示位置
  gtk_frame_set_shadow_type()
    GtkShadowType
    GTK_SHADOW
    GTK_SHADOW_IN
    GTK_SHADOW_OUT
    GTK_SHADOW_ETCHED_IN
    GTK_SHADOW_ETCHED_OUT

##GtkList 基本的列表框
GtkCList GtkList
GtkList 是一个容器,可将各种窗口小部件添加到此列表中,GtkListItem
GtkListItem也是容器,没有标签的可以将任意窗口小部件按钮或像素映射图加到其中

  gtk_list_new()
  gtk_list_item_new_with_label()
  gtk_container_add(GTK_CONTAINER(listbox), listitem)
  gtk_widget_show(listitem)
  使用列表
  memeroylist = g_list_append(memorylist, listitem)
  gtk_list_append_items(GTK_LIST(listbox), memorylist)
  gtk_list_set_selection_mode(GTK_LIST(list), GTK_SELECTION_EXTENDED);
连接信号
  gtk_signal_connect(GTK_OBJECT(list), "select_child", ...)
  gtk_signal_connect(GTK_OBJECT(list), "unselect_child", ...)
void ItemPrinter(gpointer data, gpointer userdata)
{
  // data - list item
}
g_list_foreach(list, ItemPrinter, NULL);

##GtkCombo

struct GtkCombo
{
  Gtk_HBox hbox;
  GtkWidget* entry;
  GtkWidget* button;
  GtkWidget* popup;
  GtkWidget* popwin;
  GtkWidget* list;
}
gtk_combo_new()
GList* options = NULL;
options = g_list_append(options, "Male");
options = g_list_append(options, "Female");
options = g_list_append(options, "Other");
gtk_combo_set_popdown_strings(GTK_COMBO(mycombo), options);
获取当前项文本:
gchar* selectedValue;
selectedValue = gtk_enty_get_text(
  GTK_ENTRY(GTK_COMBO(combo)->entry));

#GtkCList 多列列表

  gtk_clist_new()
  gtk_clist_new_with_titles()
  gtk_clist_column_titles_show()
  gtk_clist_column_tities_hide()
  gtk_clist_column_title_active()  // 使指定列标题按钮可点击
  gtk_clist_column_title_passive()
  gtk_clist_column_titles_active()
  gtk_clist_column_titles_passive()
  gtk_clist_set_column_width()
  gtk_clist_set_row_height()
  
  gtk_clist_prepend(..., gchar* text[]);
  gtk_clist_append()
  gtk_clist_insert()
  gtk_clist_remove(..., gint row)
  gtk_clist_clear()

  gtk_clist_freeze()  // 更改列表时不刷新,避免闪烁
  gtk_clist_thaw()

  gtk_clist_set_text()
  gtk_clist_get_text()
  gtk_clist_set_pixmap()
  gtk_clist_set_pixtext()

  gtk_clist_select_row()
  gtk_clist_unselect_row()
  gtk_clist_get_selection_info()  // 利用坐标所对应的行和列更新row column参数

事件
select_row
unselect_row

#对话框

  gtk_window_new(GTK_WINDOW_DIALOG);  // 没有最大化图标
  gtk_window_set_modal(..., gboolean modal)  // 模态对话框
  gtk_widget_destroy()  // destroy信号
  gtk_widget_hide()     // hide信号
  gtk_hseparator_new()  // GtkHSeparator 分隔控件

  gtk_main() gtk_main_quit()可以嵌套调用

###GtkDialog 内建包装框
vbox
action_area

###GtkFileSelection
文件列表、目录列表、目录选择按钮、录入框(显示文件过滤器和所选文件名)

  gtk_file_selection_new()
  gtk_widget_show()
  gtk_file_selection_set_filename() // 提供缺省文件名
  
  gtk_file_selection_show_fileop_buttons()
  gtk_file_selection_hide_fileop_buttons()
  gtk_file_selection_complete()   // 希望设置的过滤器的串的指针
  ok_button       成员
  cancel_button   成员
  gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(filedialog)->ok_button), ...)
  gtk_file_selection_get_filename()  // 绝对路径文件名

###GtkColorSelectionDialog
核心小部件 GtkColorSelection
重要成员:
colorsel
ok_button
reset_button
cancel_button
help_button

  gdouble selectedcolor;
  gtk_color_selection_get_color(GTK_COLOR_SELECTION(
	  GTK_COLOR_SELECTION_DIALOG(theDialog)->colorsel), & selectedcolor);
 类似资料: