注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

Code@Pig Home

喜欢背着一袋Code傻笑的Pig .. 忧美.欢笑.记忆.忘却 .之. 角落

 
 
 

日志

 
 

[gtk+][GLib] GLib入门(2)  

2009-05-17 17:23:41|  分类: gui_X |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
Utility Functions
g_get_current_dir(), 获取当前目录
g_get_home_dir()
g_get_host_name()
g_get_real_name()
g_get_tmp_dir(), 通常 /tmp(*nix), c:\(win32)
g_get_user_name(), 返回 UTF-8 格式(win32), 根据具体设置返回特定encoding(*nix)

gchar* g_getenv(const gchar *variable), 返回 env-var, 不存在,返回 NULL
void g_unsetenv(const gchar *variable)
gboolean g_setenv(const gchar *variable, const gchar *value, gboolean overwrite), 如果 variable 存在,则需要 overwrite = TRUE,新的值才会被写入。
------------------------------------
#include <glib.h>

#define _VAR_NAME    "ImBigFooBar"

int main()
{
    g_print(_VAR_NAME" = %s\n", g_getenv(_VAR_NAME));

    g_setenv(_VAR_NAME, "1", FALSE);
    g_print(_VAR_NAME" = %s\n", g_getenv(_VAR_NAME));

    g_setenv(_VAR_NAME, "2", FALSE);
    g_print(_VAR_NAME" = %s\n", g_getenv(_VAR_NAME));

    g_setenv(_VAR_NAME, "3", TRUE);
    g_print(_VAR_NAME" = %s\n", g_getenv(_VAR_NAME));
    return 0;
}
------------------------------------
$ ./a.out                                                                      
ImBigFooBar = (null)
ImBigFooBar = 1
ImBigFooBar = 1
ImBigFooBar = 3
------------------------------------

Timers
GLib timer 和我预先想的不太一样,我认为的 timer 就是注册一个 callback && interval,然后每隔 interval 系统自动调用一次我的 callback。而 GLib timer 其实就是一个计时器,从 g_timer_new() 开始自动计时,到你调用 g_timer_elapsed() 时,告诉你流逝了多少时间(second),而已。
GTimer* g_timer_new(void);
void g_timer_destroy(GTimer *timer);
void g_timer_start(GTimer *timer);
void g_timer_stop(GTimer *timer);
void g_timer_reset(GTimer *timer);
void g_timer_continue(GTimer *timer);
gdouble g_timer_elapsed(GTimer *timer, gulong *microseconds);
------------------------------------
#include <glib.h>
#include <stdio.h>

int main()
{
    int c;
    GTimer *timer;

    timer = g_timer_new();

    while ( (c = getchar()) != EOF )
    {
        gdouble elapsed = g_timer_elapsed(timer, NULL);
        g_print("elapsed = %f\n", elapsed);
    }

    return 0;
}
------------------------------------
$ ./a.out                                                                     
a\n
elapsed = 0.513058
elapsed = 0.514608
b\n
elapsed = 2.105818
elapsed = 2.105866
------------------------------------

File Manipulation
GTK+ 中有两种操作文件的方法,IO channels / file utility function,这里介绍的是 file util func。
gchar *g_build_filename (const gchar *first_element, ...), 把所有 elem 拼在一起,NULL作为结束。
gboolean g_file_set_contents(const gchar *filename, const gchar *contents, gssize length, GError **error);
gboolean g_file_get_contents(const gchar *filename, const gchar **contents, gsize length, GError **error);
gboolean g_file_test(const gchar *filename, GFileTest test);

g_file_set_contents(), 向文件中的写入内容,将 contents 写入文件 filename 中,length 为 contents 的长度,如果 contents 是 NULL-terminated string,则 length 传 -1 可以让函数内部自动计算长度。

GFileTest
G_FILE_TEST_IS_REGULAR
G_FILE_TEST_IS_SYMLINK
G_FILE_TEST_IS_DIR
G_FILE_TEST_IS_EXECUTABLE
G_FILE_TEST_EXISTS
------------------------------------
#include <glib.h>

static void handle_error(GError *error)
{
    if (error != NULL)
    {
        g_printf(error->message);
        g_clear_error(&error);
    }
}int main()
{
    gchar *filename, *content;
    gsize bytes;
    GError *error = NULL;

    filename = g_build_filename(g_get_home_dir(), "temp", NULL);
    g_print("filename = %s\n", filename);

    g_file_set_contents(filename, "Hello World!", -1, &error);
    handle_error(error);

    if ( !g_file_test(filename, G_FILE_TEST_EXISTS) )
        g_error("Error: File does not exist!");

    g_file_get_contents(filename, &content, &bytes, &error);
    handle_error(error);
    g_print("%s\n", content);

    g_free(content);
    g_free(filename);
    return 0;
}
------------------------------------
$ ./a.out
filename = /home/kasicass/temp
Hello World!
------------------------------------

Directories
GDir *g_dir_open(const gchar *path, guint flags, GError **error);
gchar *g_dir_read_name(GDir *dir);
void g_dir_rewind(GDir *dir);
void g_dir_close(GDir *dir);
g_dir_open() 的 flags 目前没用 reserved for future use,第一次看到 *nix 这类的参数,Win32 下可是无数 reserved。
g_dir_read_name() 并不返回 "." / "..",默认认为此二者存在。
------------------------------------
#include <glib.h>

int main()
{
    GDir *dir = g_dir_open(g_get_home_dir(), 0, NULL);
    const gchar *file;

    if ( !g_file_test(g_get_home_dir(), G_FILE_TEST_IS_DIR) )
        g_error("Error: You do not have a home dir!");

    while ((file = g_dir_read_name(dir)))
        g_print("%s\n", file);

    g_dir_close(dir);
    return 0;
}
------------------------------------

File System
从 GLib 2.6 开始,引入了一些针对 *nix 的 util func。因为只针对 *nix 平台,所以需要显式地 #include <glib/gstuio.h> 才能使用这些函数。所有这些函数都是 *nix return-value-style, 0 succeed, -1 fail。

int g_rename(const gchar *old_filename, const gchar *new_filename);
int g_remove(const gchar *filename);
int g_rmdir(const gchar *filename);
int g_mkdir(const gchar *filename, int permissions);
int g_chdir(const gchar *path);
int g_chmod(const gchar *filename, int permissions);

The Main Loop
所谓 main loop, 其实就是类似下面的一种事件模型:
------------------------------------
int main()
{
    do init.
    while (has_event())
    {
        do event.
    }
}
------------------------------------
has_event() 这个地方可以让我们的程序 block 住,当有事件到达时,操作系统会通知我们的程序,然后再开始处理事件。
GLib 提供了对事件模型的 portable wrapper,而 GTK+ 的 main loop 仅仅是 GLib main loop wrapper 而已。

Contexts and Sources
GMainContext 就是一个 Source 的 container。Source 可以来源于操作系统,比如:网络包达到;也可以来源于自己的程序,比如:timeout。
------------------------------------
GMainLoop --> GMainContext --> Source1
                                            \--> Source2
                                                   ...
------------------------------------
typedef gboolean (*GSourceFunc) (gpointer data);

GMainLoop *g_main_loop_new(GMainContext *context, gboolean is_running);
void g_main_loop_run(GMainLoop *loop);
void g_main_loop_quit(GMainLoop *loop);
gboolean g_main_loop_is_running(GMainLoop *loop);
GMainContext *g_main_loop_get_context(GMainLoop *loop);

GMainContext *g_main_context_new(void);
GMainContext *g_main_context_default(void);

GSource *g_source_new(GSourceFuncs *source_funcs, guint struct_size);
guint g_source_attach(GSource *source, GMainContext *context);
void g_source_destroy(GSource *source);

GSource *g_idle_source_new        (void);
GSource *g_timeout_source_new     (guint interval);

guint g_timeout_add(guint interval, GSourceFunc function, gpointer data);

#define g_main_new(is_running)    g_main_loop_new (NULL, is_running);
#define g_main_run(loop)        g_main_loop_run(loop)
#define g_main_quit(loop)       g_main_loop_quit(loop)
#define g_main_destroy(loop)    g_main_loop_unref(loop)
#define g_main_is_running(loop) g_main_loop_is_running(loop)

g_main_loop_new() 的 context 参数,可以传入自己申请的 context,如果传入 NULL,使用 default-context。
对于 g_timeout_add() 这类没有 context 参数的函数,都是默认把此 source 添加到 default-context 上。
GSourceFunc() 返回 FALSE, 则此 source 会被 context 删除。

Timeouts
恩,这个才是我希望看到的定时器功能。:-)
------------------------------------
// 定时器1秒跳1次,共跳5次,然后退出整个循环
#include <glib.h>

GMainLoop *mainloop;

gboolean my_timeout(gpointer data)
{
    static gint i = 0;
    i++;
    g_print("timeout: i = %d\n", i);
    if (i < 5)
    {
        return TRUE;
    }
    else
    {
        g_main_quit(mainloop);
        return FALSE;
    }
}

int main()
{
    mainloop = g_main_new(FALSE);
    g_timeout_add(1000, my_timeout, NULL);
    g_main_run(mainloop);
    g_main_destroy(mainloop);
    return 0;
}
------------------------------------
$ ./a.out                                                                    
timeout: i = 1
timeout: i = 2
timeout: i = 3
timeout: i = 4
timeout: i = 5
------------------------------------

下面是个有趣的 progress bar 程序
------------------------------------
#include <gtk/gtk.h>

static void
destroy(GtkWidget *window, gpointer data)
{
    gtk_main_quit();
}

static gboolean
pulse_progress(GtkProgressBar *progress)
{
    static gint count = 0;

    gtk_progress_bar_pulse(progress);
    count++;

    return (count < 100);
}
int main(int argc, char *argv[])
{
    GtkWidget *window, *progress;

    gtk_init(&argc, &argv);

    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_title(GTK_WINDOW(window), "Timeouts");
    gtk_container_set_border_width(GTK_CONTAINER(window), 10);
    gtk_widget_set_size_request(window, 400, -1);

    g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(destroy), NULL);

    progress = gtk_progress_bar_new();
    gtk_progress_bar_set_pulse_step(GTK_PROGRESS_BAR(progress), 0.1);

    g_timeout_add(100, (GSourceFunc) pulse_progress, (gpointer) progress);

    gtk_container_add(GTK_CONTAINER(window), progress);
    gtk_widget_show_all(window);

    gtk_main();
    return 0;
}
------------------------------------


  评论这张
 
阅读(2416)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017