常见问题 - 在GTK +手册中找到常见问题的答案
问题与解答
这是由常见的“我如何…”问题组织的参考手册的“索引”。如果您不确定为您的问题阅读哪些文档,该列表是开始的好地方。
GTK + 网站提供了一些 教程和其他文档(大部分关于GTK + 2.x,但大多数仍然适用)。GNOME开发人员网站上可以找到从白皮书到在线图书的更多文档。研究这些材料后,您应该准备好回到本参考手册了解详情。
请参阅有关此主题的文档。
请参阅从GTK + 2.x迁移到GTK + 3。您还可以在文档中找到特定小部件和功能的有用信息。
如果您的手册中没有涵盖的问题,请随时在邮件列表中提出问题,并根据文档提交错误报告。
请参阅GObject和GInitiallyUnowned的文档。对于GObject说明具体g_object_ref()和g_object_unref()。GInitiallyUnowned是GObject的一个子类,所以应用相同的点,除了它有一个“浮动”状态(在其文档中解释)。
对于从函数返回的字符串,如果不能被释放,它们将被声明为“const”。非const字符串应该被释放g_free()。数组遵循相同的规则。如果您在规则中发现了一个未记录的异常,请向https://bugzilla.gnome.org报告错误。
如果GtkFoo不是顶楼窗口,那么
foo = gtk_foo_new();
gtk_widget_destroy(foo);
是一个内存泄漏,因为没有人假定初始浮动引用。如果您使用的是小部件,而不是立即将其打包到容器中,那么可能需要标准引用计数,而不是浮动引用计数。
要获得这个,您必须获取对小部件的引用,并在创建之后删除浮动引用(“ ref and sink ” in GTK + parlance ):
foo = gtk_foo_new ();
g_object_ref_sink (foo);
当你想摆脱这个小部件时,你必须调用gtk_widget_destroy() 断开任何外部连接到小部件,然后再删除你的引用:
gtk_widget_destroy (foo);
g_object_unref (foo);
当你立即添加一个小部件到一个容器,它负责假设初始浮动引用,你不必担心引用计数在所有…只是调用gtk_widget_destroy() 去摆脱小部件。
这覆盖了 GDK线程文档。另请参阅GThread文档中的便携式线程原语。
大多数人使用GNU gettext,为了安装GLib而已经是必需的。在安装了gettext的UNIX或Linux系统上,键入info gettext 以阅读文档。
关于如何使用gettext的简短清单是:call bindtextdomain()so gettext可以找到包含您的翻译的文件,调用textdomain() 设置默认的翻译域,调用bind_textdomain_codeset()请求所有翻译的字符串以UTF-8的形式返回,然后调用 gettext()查找每个字符串要在默认域中翻译。
gi18n.h为方便起见,提供以下简写宏。通常,为方便起见,人们定义宏如下:
#define _(x) gettext (x)
#define N_(x) x
#define C_(ctx,x) pgettext (ctx, x)
您使用N_()(N表示无操作)在gettext()不允许调用函数的位置标记字符串以进行翻译,例如在数组初始化程序中。你最终必须调用gettext()字符串来实际获取翻译。()两者都标记翻译字符串并实际翻译。该C()宏(C代表上下文)增加了额外的上下文被标记为翻译字符串,它可以帮助消除歧义,可能需要在你的程序的不同部分不同的翻译短字符串。
使用这些宏的代码最终看起来像这样:
#include
static const char *global_variable = N_("Translate this string");
static void
make_widgets (void)
{
GtkWidget *label1;
GtkWidget *label2;
label1 = gtk_label_new (_("Another string to translate"));
label2 = gtk_label_new (_(global_variable));
...
应该使用使用gettext的库,dgettext()而不是使用gettext()它们,它们可以在每次请求翻译时指定翻译域。库也应该避免调用textdomain(),因为它们将指定域而不是使用默认值。
根据约定,宏GETTEXT_PACKAGE被定义为保存您的图书馆翻译域, gi18n-lib.h可以包括以提供以下便利:
#define _(x) dgettext (GETTEXT_PACKAGE, x)
GTK + 对所有文本使用Unicode(更准确地说是UTF-8)。UTF-8将每个Unicode代码点编码为一到六个字节的序列,并具有许多不错的属性,这使得它在C程序中使用Unicode文本成为不错的选择:
ASCII字符由他们熟悉的ASCII码点编码。
ASCII字符不会显示为任何其他字符的一部分。
零字节不会作为字符的一部分出现,因此UTF-8字符串可以用通常的C库函数来处理零终止的字符串。
有关Unicode和UTF-8的更多信息,可以在Unix / Linux的 UTF-8和Unicode FAQ中找到。GLib的为UTF-8和其它编码,见之间转换字符串提供了函数g_locale_to_utf8()和g_convert()。
来自外部来源的文本(例如文件或用户输入)必须在转换为GTK +之前转换为UTF-8。以下示例将IS0-8859-1编码文本文件的内容写入 stdout:
gchar *text, *utf8_text;
gsize length;
GError *error = NULL;
if (g_file_get_contents (filename, &text, &length, NULL))
{
utf8_text = g_convert (text, length, "UTF-8", "ISO-8859-1",
NULL, NULL, &error);
if (error != NULL)
{
fprintf ("Couldn't convert file %s to UTF-8\n", filename);
g_error_free (error);
}
else
g_print (utf8_text);
}
else
fprintf (stderr, "Unable to read file %s\n", filename);
对于源代码中的字符串文字,处理非ASCII内容有几种替代方法:
直接UTF-8
如果您的编辑器和编译器能够处理UTF-8编码的源码,那么简单地使用UTF-8作为字符串文字就非常方便,因为它允许您编辑“wysiwyg”中的字符串。请注意,选择此选项可能会降低代码的可移植性。
逃脱UTF-8
即使你的工具链不能直接处理UTF-8,你仍然可以使用八进制或十六进制编码的UTF-8字符串文字像逃逸 \212或\xa8以每个字节编码。这是可移植的,但修改转义的字符串不是很方便。将十六进制转义与普通文本混合时要小心; “\xa8abcd”是长度为1的字符串!
运行时转换
如果字符串文字可以用您的工具链可以处理的编码(例如IS0-8859-1)表示,则可以使用该编码编写源文件,并g_convert()在运行时将字符串转换为UTF-8。请注意,这具有一些运行时开销,因此您可能希望将转换从内部循环中移出。
下面是一个示例,显示了使用版权符号的三种方法,它们具有Unicode和ISO-8859-1编码点169,并以UTF-8表示为两个字节194,169或”\302\251”字符串字面值:
g_print ("direct UTF-8: ©");
g_print ("escaped UTF-8: \302\251");
text = g_convert ("runtime conversion: ©", -1, "ISO-8859-1", "UTF-8", NULL, NULL, NULL);
g_print(text);
g_free (text);
如果您正在使用gettext()本地化应用程序,则需要调用bind_textdomain_codeset()以确保以UTF-8编码方式返回已翻译的字符串。
有两种方法可以解决这个问题。GTK +头文件使用C的子集也是有效的C ++,所以你可以简单地在C ++程序中使用普通的GTK + API。或者,您可以使用“C ++绑定”,如 提供本机C ++ API的gtkmm。
直接使用GTK +时,请记住只有功能可以连接到信号,而不是方法。因此,您将需要使用全局函数或“静态”类函数进行信号连接。
直接使用GTK +的另一个常见问题是C ++不会将整数转换为枚举。使用bitfields时出现; 在C中你可以写下面的代码:
gdk_window_set_events (gdk_window,
GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
而在C ++中你必须写:
gdk_window_set_events (gdk_window,
(GdkEventMask) GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
然而,很少有需要这种演员的功能。
请参阅https://www.gtk.org上的语言绑定列表。
要将图像文件直接加载到显示窗口小部件中,请使用 [1]。要将图像加载到另一个目的,请使用。要加载动画,请使用。 也可以加载非动画图像,因此可以结合使用它来加载未知类型的文件。 gtk_image_new_from_file() gdk_pixbuf_new_from_file()gdk_pixbuf_animation_new_from_file()gdk_pixbuf_animation_new_from_file()gdk_pixbuf_animation_is_static_image()
要异步加载图像或动画文件(不阻止),请使用 GdkPixbufLoader。
fontdesc = pango_font_description_from_string ("Luxi Mono 12");
pango_layout_set_font_description (layout, fontdesc);
pango_cairo_show_layout (cr, layout);
pango_font_description_free (fontdesc);
g_object_unref (layout);
另见Pango手册的 开罗渲染 部分。
要获取一段文本的大小,请使用Pango布局,并 pango_layout_get_pixel_size()使用以下代码:
layout = gtk_widget_create_pango_layout (widget, text);
fontdesc = pango_font_description_from_string ("Luxi Mono 12");
pango_layout_set_font_description (layout, fontdesc);
pango_layout_get_pixel_size (layout, &width, &height);
pango_font_description_free (fontdesc);
g_object_unref (layout);
另见Pango手册的 布局对象 部分。
这些GTK_TYPE_BLAH宏被定义为gtk_blah_get_type()对该_get_type() 函数的调用 ,并且这些函数被声明为G_GNUC_CONST允许编译器如果看起来没有使用该值,则优化该调用。
此问题的常见解决方法是将结果存储在易失性变量中,从而使编译器不会优化调用。
易失性
GType dummy = GTK_TYPE_BLAH ;
为了使窗口透明,需要使用支持该窗口的视觉效果。这是通过获取屏幕的RGBA视觉 gdk_screen_get_rgba_visual()并将其设置在窗口来完成的。请注意,如果屏幕上不支持透明窗口, gdk_screen_get_rgba_visual()则会返回NULL,gdk_screen_get_system_visual()在这种情况下您应该回退 。此外,请注意,这将从屏幕更改为屏幕,因此每当窗口移动到不同的屏幕时,都需要重复。
GdkVisual *视觉;
GdkVisual *visual;
visual = gdk_screen_get_rgba_visual (screen);
if (visual == NULL)
visual = gdk_screen_get_system_visual (screen);
gtk_widget_set_visual (GTK_WIDGET (window), visual);
要填充窗口上的Alpha通道,只需使用cairos RGBA绘图功能即可。
请注意,RGBA视觉的存在不能保证窗口实际上会在屏幕上显示为透明。在X11上,这需要一个合成管理器才能运行。查看 gtk_widget_is_composited()一个方法来确定alpha通道是否被尊重。
请参阅tree widget概述 - 你应该使用GtkTreeView小部件。(列表只是一个没有分支的树,所以树窗口小部件也用于列表)。
请参阅文本小部件概述 - 您应该使用GtkTextView小部件。
如果你只有少量的文字,GtkLabel也可能是适当的。可以选择gtk_label_set_selectable()。对于单行文本条目,请参阅GtkEntry。
GtkImage可以使用GTK +了解的任何格式显示图像。您还可以使用 GtkDrawingArea,如果您需要执行更复杂的操作,例如在图像顶部绘制文本或图形。
使用GTK +,GtkComboBox是用于此用例的推荐小部件。这个小部件看起来像组合框或当前选项菜单,具体取决于当前的主题。如果您需要可编辑的文本输入,请使用 “has-entry”属性。
3#. GtkWidget
看到gtk_widget_override_color()和gtk_widget_override_background_color()。您还可以通过安装自定义样式提供程序来更改窗口小部件的外观,请参阅gtk_style_context_add_provider()。
要更改没有背景的GtkLabel等小部件的背景颜色,请将它们放在GtkEventBox中并设置事件框的背景。
这有几个可能的答案,这取决于你想要实现什么。一个选择是gtk_widget_override_font()。
PangoFontDesc *font_desc = pango_font_description_new ();
pango_font_description_set_size (font_desc, 40);
gtk_widget_override_font (widget, font);
pango_font_description_free (font_desc);
如果要使标签的文字更大,可以使用 gtk_label_set_markup():
gtk_label_set_markup ( label, “<big> big text big>” );
这是许多应用程序的首选,因为它是用户选择的字体大小的相对大小。看看g_markup_escape_text()你是否正在构建这样的字符串。
您也可以通过放置来更改小部件的字体
.my-widget-class {
font: Sans 30;
}
在一个CSS文件中,加载它gtk_css_provider_load_from_file(),并添加提供者gtk_style_context_add_provider_for_screen()。要将此样式信息与您的小部件相关联,请使用它的GtkStyleContext设置样式类gtk_style_context_add_class()。这种方法的优点是用户可以覆盖您选择的字体。有关更多讨论,请参阅GtkStyleContext文档。
在GTK +中,禁用的小部件被称为“不敏感”。见gtk_widget_set_sensitive()。
见gtk_text_buffer_get_bounds()和gtk_text_buffer_get_text() 或gtk_text_iter_get_text()。
GtkTextIter start, end;
GtkTextBuffer *buffer;
char *text;
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text_view));
gtk_text_buffer_get_bounds (buffer, &start, &end);
text = gtk_text_iter_get_text (&start, &end);
/* use text */
g_free (text);;
如果您使用gtk_text_buffer_insert_with_tags()适当的标签选择字体,插入的文本将具有所需的外观,但用户在标记的块之前或之后键入的文本将以默认样式显示。
为了确保所有文本都具有所需的外观,可以使用 gtk_widget_override_font()更改窗口小部件的默认字体。
保持文本缓冲区滚动到最后的一个好方法是在缓冲区的末尾放置一个 标记,并给出正确的重力。重力的作用是将插入标记的文字插入之前,将标记保持在最后。
为了确保缓冲区的结尾保持可见,用户 gtk_text_view_scroll_to_mark()可以在插入新文本后滚动到标记。
gtk-demo应用程序包含一个这个技术的例子。
请记住,GtkTreeModel列不一定必须显示。因此,您可以像模型中的非用户可见数据一样将数据放入模型中,并将其与其一起检索gtk_tree_model_get()。请参阅树小部件概述。
您可以 使用或或将多个GtkCellRenderer 包装到单个GtkTreeViewColumn中。所以将一个GtkCellRendererPixbuf和一个GtkCellRendererText包装到列中。 gtk_tree_view_column_pack_start()gtk_tree_view_column_pack_end()
gtk_list_store_set()gtk_tree_store_set()
无论是GtkTreeStore和GtkListStore实现GtkTreeModel 接口。因此,您可以使用此接口实现的任何功能。读取一组数据的最简单的方法是使用 gtk_tree_model_get()。
使用gtk_tree_view_insert_column_with_data_func() 或gtk_tree_view_column_set_cell_data_func()执行从数字到字符串的转换(用,说,g_strdup_printf())。
以下示例演示如下:
enum
{
DOUBLE_COLUMN,
N_COLUMNS
};
GtkListStore *mycolumns;
GtkTreeView *treeview;
void
my_cell_double_to_text (GtkTreeViewColumn *tree_column,
GtkCellRenderer *cell,
GtkTreeModel *tree_model,
GtkTreeIter *iter,
gpointer data)
{
GtkCellRendererText *cell_text = (GtkCellRendererText *)cell;
gdouble d;
gchar *text;
/* Get the double value from the model. */
gtk_tree_model_get (tree_model, iter, (gint)data, &d, -1);
/* Now we can format the value ourselves. */
text = g_strdup_printf ("%.2f", d);
g_object_set (cell, "text", text, NULL);
g_free (text);
}
void
set_up_new_columns (GtkTreeView *myview)
{
GtkCellRendererText *renderer;
GtkTreeViewColumn *column;
GtkListStore *mycolumns;
/* Create the data model and associate it with the given TreeView */
mycolumns = gtk_list_store_new (N_COLUMNS, G_TYPE_DOUBLE);
gtk_tree_view_set_model (myview, GTK_TREE_MODEL (mycolumns));
/* Create a GtkCellRendererText */
renderer = gtk_cell_renderer_text_new ();
/* Create a new column that has a title ("Example column"),
* uses the above created renderer that will render the double
* value into text from the associated model's rows.
*/
column = gtk_tree_view_column_new ();
gtk_tree_view_column_set_title (column, "Example column");
renderer = gtk_cell_renderer_text_new ();
gtk_tree_view_column_pack_start (column, renderer, TRUE);
/* Append the new column after the GtkTreeView's previous columns. */
gtk_tree_view_append_column (GTK_TREE_VIEW (myview), column);
/* Since we created the column by hand, we can set it up for our
* needs, e.g. set its minimum and maximum width, etc.
*/
/* Set up a custom function that will be called when the column content
* is rendered. We use the func_data pointer as an index into our
* model. This is convenient when using multi column lists.
*/
gtk_tree_view_column_set_cell_data_func (column, renderer,
my_cell_double_to_text,
(gpointer)DOUBLE_COLUMN, NULL);
}
将树视图的expander-column属性设置为隐藏列。看到gtk_tree_view_set_expander_column()和gtk_tree_view_column_set_visible()。
在“画”信号得到一个准备使用的开罗上下文,你应该使用参数。
GTK +中的所有绘图通常在绘图处理程序中完成,GTK +创建一个用于双缓冲绘图的临时像素图。可以关闭双缓冲, gtk_widget_set_double_buffered()但是这不是理想的,因为它可能会导致一些闪烁。
不,GDK X11后端使用开罗X后端(而其他GDK后端使用其各自的本机开罗后端)。GTK +开发人员认为,改进GDK绘图性能的最佳方法是优化开源X后端以及所使用的X服务器(主要是Render扩展)中的相关代码路径。
不,至少还没有。开罗图像表面不支持GdkPixbuf使用的像素格式。