Home GTK GTK文本视图

GtkTextView构件用于显示多行文档。它提供了很多方法,用于自定义整个文档或者一部分文档。它甚至可以在文档中插入
GdkPixbuf对象和衍生构件。从这一点来看,GtkTextView是第一个碰到的构件,因此本章的剩余部分都会围绕这个构件。它是个非常灵活的构
件,您需要在很多GTK+程序中使用到它。

        本章的前几个例子,会让您相信GtkTextView只可以被用来显示简单文档,其实不然。它也可以显示许多类型的超文本、文字处理和交互文档,这些被广泛应用于现在的软件中。您将在下面的章节中学到。
        Figure 7-2显示了一个简单的GtkTextView构件,它包含在一个GtkScrolledWindow构件中。
7.2 文本视图 - 郭映辉 - 郭映辉

 
     
文本视图用于GTK+每个类型的文档编辑程序。如果您用过AbiWord、Gedit或者GNOME中大部分其它的文本编辑器,您就已经用了
GtkTextView构件。它还被用于Gaim程序,那是一个即时聊天窗口。(实际上,本书中所有的例子都是用OpenLDev程序创建的,它就是使用
GtkTextView来编辑源代码的!)

文本缓存
       每个文本视图都用于显示GtkTextBuffer类的内容。文本缓存用于存储当前视图中,内容的当前状态。他们包括文本、图像、衍生构件、文本标签,以及其它渲染文档必要的信息。
        一个文本缓存可以用来显示多个文本视窗,但是每个文本视图只能关联一个文本缓存。大部分程序员没有充分利用这个特性,但是在后面的章节中,当您了解如何嵌入衍生构件到文本缓存的时候,这个特性就变得十分重要了。
 
     
正如GTK+中的所有文本构件,文本以UTF-8形式保存。UTF-8是一种类型的字符集,每个字符使用1到4字节。为了区分一个字符到底占用了几个字
节,“0”总是单字节字符的开头,“110”是双字节字符的起始位,“1110”后面跟着的是3字节序列,等等。占用多字节的UTF-8字符用“10”作为标志,这个标志位最重要。
        通过这个方法,基本的128个ASCII字符还可以支持,因为另外的七个比特可以用于单字节字符,而且满足初始比特位“0”。UTF-8还提供了其他语言的字符。这种编码避免了小字节字符序列占用太多字节数。
        当处理文本缓存时,您需要知道两个术语:偏移量和索引。偏移量的单位是字符。UTF-8字符有可能跨越缓存中的一个或多个字节,所以在GtkTextBuffer里面,一个字符的偏移量可能不止一个字节。


警告:索引指的是字节。在后面的例子中,当在文本缓存中跳转时,需要十分小心,因为您不能在两个字符间用索引。


        Listing 7-2展示了一个最简单的文本视窗的例子。它创建了一个新的GtkTextView构件。然后获得缓存,并且插入文本到缓存中。一个滚动窗口用来容纳文本视窗。
        Listing 7-2 一个简单的GtkTextView例子(textview.c)
        #include <gtk/gtk.h>
        int main (int argc,
                      char *argv[])
        {
            GtkWidget *window, *scrolled_win, *textview;
            GtkTextBuffer *buffer;
            gtk_init (&argc, &argv);
            window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
            gtk_window_set_title (GTK_WINDOW (window), “Text Views”);
            gtk_container_set_border_width (GTK_CONTAINER (window), 10);
            gtk_widget_set_size_request (window, 250, 150);
            textview = gtk_text_view_new ();
            buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (textview));
            gtk_text_buffer_set_text (buffer, “Your 1st GtkTextView widget!”, -1);
            scrolled_win = gtk_scrolled_window_new (NULL, NULL);
            gtk_container_add (GTK_CONTAINER (scrolled_win), textview);
            gtk_container_add (GTK_CONTAINER (window), scrolled_win);
            gtk_widget_show_all (window);
            gtk_main();
            return 0;
        }
 
     
大部分GtkTextView构件由gtk_text_view_new()创建。通过使用这个函数,会创建一个空的缓存。默认的缓存之后可以通过
gkt_text_view_set_buffer()替换,或者通过gtk_text_view_get_buffer()获取。
        如果您想用一个您穿件好的缓存设置为初始缓存,您可以通过gtk_text_view_new_with_buffer()来创建文本视窗。在多数情况下,使用默认的文本缓存时简单的方式。
        当您可以访问一个GtkTextBuffer对象时,有很多方式来添加内容,但是最简单的方式是调用gtk_text_buffer_set_text()。这个函数接受一个文本缓存、一个用来设置为缓存新文本的UTF-8字符串和文本的长度。
        void gtk_text_buffer_set_text (GtkTextBuffer *buffer,
                                                        const gchar *text,
                                                        gint length);
        如果文本字符串以NULL结尾,您可以使用-1作为字符串的长度。如果在指定的文本长度之前发现了一个空字符,这个函数会悄悄失败。
        缓存中的当前内容会完全被指定的新字符串替换。在“文本迭代器和标记”一节中,您将了解到,这个函数也可以插入一段文本,不用完全覆盖当权内容,这对插入大量文字尤为重要。
        回忆上一节,一共有5种构件具有天生的滚动能力,包括了GtkTextView构件。因为文本视图已经具备了管理调整对象的能力,应该一直使用gtk_container_add()添加它们到滚动窗口。
文本视窗属性
        GtkTextView是一种非常灵活的对话框。因为这个构件提供了很多属性。在本节中,您将了解这个构件的一些属性。
        让文本视图构件特别有用的一个特性,就是您可以修改构件中的全部或者部分内容。可以用文字标签修改文本的属性。本章的下一节,将会谈到自定义文档的部分内容。
        Listing 7-3显示了许多属性,它们可以用于修改GtkTextBuffer的全部内容。您应该注意,许多属性会被文档中局部生效的文字标签里的内容覆盖。
        Listing 7-3 使用GtkTextView属性(textview2.c)
        #include <gtk/gtk.h>
        int main (int argc,
                      char *argv[])
        {
            GtkWidget *window, *scrolled_win, *textview;
            GtkTextBuffer *buffer;
            PangoFontDescription *font;
            gtk_init (&argc, &argv);
            window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
            gtk_window_set_title (GTK_WINDOW (window), “Text Views Properties”);
            gtk_container_set_border_width (GTK_CONTAINER (window), 10);
            gtk_widget_set_size_request (window, 250, 150);
            font = pango_font_description_from_string (“Monospace Bold 10”);
            textview = gtk_text_view_new ();
            gtk_widget_modify_font (textview, font);
            gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (textview), GTK_WRAP_WORD);
            gtk_text_view_set_justification (GTK_TEXT_VIEW (textview), GTK_JUSTIFY_RIGHT);
            gtk_text_view_set_editable (GTK_TEXT_VIEW (textview), TRUE);
            gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (textview), TRUE);
            gtk_text_view_set_pixels_above_lines (GTK_TEXT_VIEW (textview), 5);
            gtk_text_view_set_pixels_below_lines (GTK_TEXT_VIEW (textview), 5);
            gtk_text_view_set_pixels_inside_wrap (GTK_TEXT_VIEW (textview), 5);
            gtk_text_view_set_left_margin (GTK_TEXT_VIEW (textview), 10);
            gtk_text_view_set_right_margin (GTK_TEXT_VIEW (textview), 10);
            buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (textview));
            gtk_text_buffer_set_text (buffer, “This is some text!\nChange me!\nPlease!”, -1);
            scrolled_win = gtk_scrolled_window_new (NULL, NULL);
            gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
            GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
            gtk_container_add (GTK_CONTAINER (scrolled_win), textview);
            gtk_container_add (GTK_CONTAINER (window), scrolled_win);
            gtk_widget_show_all (window);
            gtk_main();
            return 0;
        }
        解释每个GtkTextView的属性的最好方式,就是显示结果的屏幕截图,这个您可以在Figure 7-3中看到。您应该在您的计算机上编译这个程序,试着改变Listing 7-3的值,体会一下它们的效果。
7.2 文本视图 - 郭映辉 - 郭映辉

 

        只改变文本视图内容中一部分内容的字体和颜色,也是可以的,但是在Listing 7-3中,使用过去章节提到的函数来改变整个构件的全部内容。这对于编辑一个固定风格的文档还是有用的,比如一个纯文本文件。
 
      当处理一个显示多行文本的构件时,您需要决定文字是如何换行的。在Listing
7-3中,换行模式通过gtk_text_view_set_wrap_mode(),被设置为GTK_WRAP_WORD。这个设置会换行,但是不会在
两行中折断一个单词。在GtkWrapMode枚举中一共有四种类型的换行模式:
        .    GTK_WRAP_NONE:没有换行。如果一个能够滚动的窗口包含这个视窗,滚动条就会延伸。否则,文本视窗会在屏幕上延伸。如果一个滚动窗口不包含GtkTextView构件,它会自动水平延伸构件。
        .    GTK_WRAP_CHAR:按字符为单位换行,即使换行的位置在一个单词之中。这对于一个文本编辑器通常不是一个好的选择,这样会把一个单词劈开在两行显示。
        .    GTK_WRAP_WORD:使用尽量多的单词充满一行,但是不会在单词中换行。作为替代,整个单词都出现在下一行中。
        .    GTK_WRAP_WORD_CHAR:和GTK_WRAP_WORD同样的换行方式,但是如果整个单词的长度超过了文本视图可见区域的长度,按照字符换行。
        有时,您也许需要阻止用户编辑文档。通过使用gtk_text_view_set_editable(),可以设置整个文本视图的编辑属性。这对于文本标签就没有意义了,你可以为文档的某些章节推翻这个属性,因此这不是一个终极解决方案。
 
     
和上面的方法不同,通过gtk_widget_set_sensitive(),它用于彻底阻止用户和构件交互。如果文本视图被设置为不可编辑,用户还可
以对文本执行某些操作,只要它们不涉及编辑文本缓存就可以了,比如选取文字。设置一个文本视图为未激活状态,可以阻止用户执行任何操作。
        当您设置文档为不可编辑,还有一个有用的函数,它阻止光标可见,gtk_text_view_set_cursor_visible()。默认状态下,这两个属性都被设置为TRUE,因此您需要同时改变它们。
        在默认状态下,行之间没有多余的间距,但是Listing 7-3向您展示了如何在一行之上添加间距,在一行之下添加间距,在换行之间添加间距。这些函数为行间添加了额外的空间,您可以假设行之间已经有足够的位置。在多数情况下,您不需要使用这个特性,因为用户也许会认为行间距显示不正确。
 
     
对齐是文本视图的另外一个重要的属性,特别是处理有格式的文本的时候。一共有4中默认的对齐方式:GTK_JUSTIFY_LEFT、
GTK_JUSTIFY_RIGHT、GTK_JUSTIFY_CENTER和GTK_JUSTIFY_FILL。在多数情况下,您想使用默认的
GTK_JUSTIFY_LEFT对齐方式,除非用户需要改变它。文本默认是左对齐的。
        void gtk_text_view_set_justification (GtkTextView *textview,
                                                                 GtkJustification justification);
 
      在Listing
7-3中,最后设置的属性是左边和右边的页面边距。默认状态下,左边和右边都没有添加任何多余的边距,但是您可以添加一些像素的边距,通过
gtk_text_view_set_left_margin()设置左边距,通过gtk_text_view_set_right_margin()设
置右边距。
Pango Tab队列
        加到文本视图中的Tab都设置了默认宽度,但是也有时候您需要改变这个。举例来说,对于代码编辑器,一个用户想要缩进两个空格,另外一个用户想要缩进五个空格。GTK+提供了PangoTabArray对象,它定义了新的tab大小。
        当改变了默认的tab大小,根据当前的字体,首先
需要计算占用的水平像素数量。下面的函数make_tab_array(),可以用来计算一个新的tab大小。这个函数先根据所需的空格数量,创建一个字
符串。那个字符串被翻译成pangoLayout对象,它用于获取显示字串所需的像素宽度。最后,PangoLayout对象被翻译成
PangoTabArray,它可以直接应用于文本视图。
        static void
        make_tab_array (PangoFontDescription *fd,
                                    gsize tab_size,
                                    GtkWidget *textview)
        {
            PangoTabArray *tab_array;
            PangoLayout *layout;
            gchar *tab_string;
            gint width, height;
            g_return_if_fail (tab_size < 100);
            tab_string = g_strnfill (tab_size, ‘ ‘);
            layout = gtk_widget_create_pango_layout (textview, tab_string);
            pango_layout_set_font_description (layout, fd);
            pango_layout_get_pixel_size (layout, &width, &height);
            tab_array = pango_tab_array_new (1, TRUE);
            pango_tab_array_set_tab (tab_array, 0, PANGO_TAB_LEFT, width);
            gtk_text_view_set_tabs (GTK_TEXT_VIEW (textview), tab_array);
            g_free (tab_string);
        }
        PangoLayout对象用于展示一整段文本。一般来说,在内部使用Pango给构件中的文本进行布局。然而,在这个例子中,它可以被用来计算tab字符串的宽度。
 
     
通过GtkTextView,我们开始创建一个新的PangoLayout对象,并且通过
gtk_widget_create_pango_layout()创建一个tab字符串。这使用了文本视图默认的文字描述符。如果整篇文档都使用同一种
字体,这就很好。PangoLayout用于描述如何渲染文字段落。
        PangoLayout* gtk_widget_create_pango_layout (GtkWidget *textview,
                                                                                      const gchar *text);
 
     
如果字体在文档中是变化的,或者文档视图还没有应用某种字体,为了计算您就需要指定文字。您可以通过
pango_layout_set_font_description()来设置Pango排版用的字体。它用PangoFontDescription
来描述排版的字体。
        void pango_layout_set_font_description (PangoLayout *layout,
                                                                         const PangoFontDescription *fd);
        当您正确配置了您的PangoLayout,字符串的宽度可以通过pango_layout_get_pixel_size()获得。这是缓存中字符串占用的距离,计算出来的结果,当用户按下Tab键时,它会被添加到构件中。

        void pango_layout_get_pixel_size (PangoLayout *layout,

                                                               int *width,

                                                               int *height);
        现在您已经获得了tab键的宽度,您需要通过pango_tab_array_new()创建一个新的PangoTabArray。这个函数接受元素的数量参数,它要加到队列中的元素数量,还包括一个参数,表示每个元素的大小是否以像素为单位

        void pango_tab_array_new (gint initial_size,
                                                     gboolean positions_in_pixels);

        您应该总是创建只有一个元素的tab队列,因为一次只支持一个tab类型。如果第二个参数没有设置为TRUE,tab会保存为Pango单位;1像素等于1024个Pango单位。

        在应用tab队列之前,您需要添加宽度。这由pango_tab_array_set_tab()来实现。整数“0”指的是PangoTabArray的第一个元素,它只有这一个元素。第三个参数必须是PANGO_TAB_LEFT,因为只是当前只支持的值。最后一个参数是tab键的宽度,用像素来表示。
        void pango_tab_array_set_tab (PangoTabArray *tabarray,
                                                          gint tab_index,
                                                          PangoTabAlign alignment,
                                                          gint location);
 
     
当您从这个函数中收到了返回的tab队列以后,您需要把它应用到整个文本视图中,函数是gtk_text_view_set_tabs()。这会确保文本
视图中所有的tab被设置为同样宽度。然而,和文本视图的其它属性一样,这个属性可以被每段落或每章节的标记语言推翻。
        void gtk_text_view_set_tabs (GtkTextView *textview,
                                                      PangoTabArray *tabs);
        当您完成了对tab队列的操作,它可以通过pango_tab_array_free()来释放,如果您在后面也不打算再使用它的话。

0 comment

You may also like

Leave a Comment