在gtkdrawingarea中输入文字

在游戏设计中,通常会用到drawing area构件,并在该构件上画图。而且为了让游戏更酷一点,通常不想用到比如entry,button之类的构件。而是希望能在drawing area上全部处理掉,但是如何在drawing area上直接输入文字?这2天,老农查了不少资料,做了不少实验,终于搞定,在此分享一下。
Gtk的输入主要用了GtkIMContext,GtkIMContext在gtk参考文档上是这样介绍的:
GtkIMContext defines the interface for GTK+ input methods. An input method is used by GTK+ text input widgets like GtkEntry to map from key events to Unicode character strings.
即:GtkIMContext是为GTK提供了一个输入的方法,而且GTK中的一些文字输入相关的构件(如:GtkEntry)都采用了这种方法。GtkIMContext能把key event转换成统一编码的字符串。
GtkIMContext的具体用法在网上很难找到。老农在goolge上找了大半天,未果,于是只能找些关于GTK的一些官方参考资料,但还是不太清楚。然而我们有一个线索,就是GtkEntry等构件就是用GtkIMContext进行输入的,所以,看看GtkEntry的源码,也许可以找到点线索。我想这就是开源的好处吧,当缺乏资料的时候,至少我们有源代码,那儿什么宝物都有,只要有耐心去找。
最后老农终于在GtkEntry的代码中,找到了GtkIMContext的用法。

首先定义一个GtkIMContext:
        GtkIMContext *im_context;

再创建一个GtkIMContext,用gtk_im_multicontext_new()函数:
        im_context= gtk_im_multicontext_new();

再给GtkIMContext加上一个回调函数:
        g_signal_connect (im_context, "commit", G_CALLBACK (gtk_entry_commit_cb), NULL);
        "commit"信号的说明:当用户输入一个完整的序列时,该信号被触发。输入可以是一个字符,也可以是一个字符串。(老农理解:当输入为英文字符或数字时,即为一个字符,当输入为中文字时,一次输入为一个字符串)

另外,还需要2个函数:
        gtk_im_context_set_client_window(im_context, window->window);
        gtk_im_context_focus_in (im_context);
        第一个函数是把GtkIMContext和主窗口关联起来,第二个函数是把im_context设置成focus_in的,即输入焦点。

还没有结束,因为当按键时,GtkIMContext的"commit"是不会自动触发的,它需要另外一个函数来触发,gtk_im_context_filter_keypress()函数,如下:
        gtk_im_context_filter_keypress (im_context, event);
        第一个参数是im_context,第二个参数是key_press_event产生的GdkEventKey。
所以我们要给"key-press-event"加一个回调函数,把下面的语句放到main()函数gtk_main()之前:
        g_signal_connect(window, "key-press-event", G_CALLBACK(main_key_press_event), NULL);
定义回调函数main_key_press_event()如下:
        static gboolean main_key_press_event (GtkWidget *widget, GdkEventKey *event, gpointer user_data)
        {
                gtk_im_context_filter_keypress (im_context, event);
                return FALSE;
        }
        该回调函数只是调用了gtk_im_context_filter_keypress(),用于触发GtkIMContext的"commit"信号。最后定义"commit"信号的回调函数如下:

static void gtk_entry_commit_cb (GtkIMContext *context, const guchar  *str, gpointer data)
{
        int i;
        int len, len_c;
        
        len= strlen(str);
        len_c= strlen(c_input)-1;                //最后一个是'_'
        for(i= 0; i< len; i++)
                c_input[len_c+i]= *(str+i);
        c_input[len_c+ len]= '_';
        gtk_widget_queue_draw(draw_main);
}

c_input为输入的字符串。没有输入时,c_input有一个字符’_’,表示输入位置。每次输入的字符放在’_’的前面显示。字符的显示,用了Pango,代码如下,先不做解释:
gchar font[]= "Monospace Bold 15";
static void show_pictures(cairo_t *cr)
{
        PangoLayout *layout;
        PangoFontDescription *desc;

        cairo_save(cr);
        layout = pango_cairo_create_layout (cr);
        pango_layout_set_text (layout, c_input, -1);
        desc = pango_font_description_from_string (font);
        pango_layout_set_font_description (layout, desc);
        pango_font_description_free (desc);
        cairo_set_source_rgba (cr, 0, 0, 1, 1);
        pango_cairo_update_layout (cr, layout);
        cairo_move_to (cr, 100, 100);
        pango_cairo_show_layout (cr, layout);
        cairo_restore(cr);
        g_object_unref (layout);
}
看看效果(连中文也能显示噢):
 
下载 (14.86 KB)
2010-7-5 08:30

来看看代码(现在代码只有输入,没有删除功能等):
 readkey1.rar (1.09 KB)

作者: liudan0201   发布时间: 2010-10-17