免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2867 | 回复: 0
打印 上一主题 下一主题

gtk+ 编程实例 简易的文件浏览器 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2010-01-26 20:15 |只看该作者 |倒序浏览
经过两天的努力,写了一个简单的文件查看器,当做gtk编程的一个尝试吧,通过这个小程序,对gtk编程也略有一点了解了。用C写界面确实有点费力,连个基本的控件都要控制。不过gtk的扩展性确实没话说,GtkList的Item想做成什么样就能做成什么样的,而且还不是很麻烦,要是用MFC的List恐怕就不是那么容易了。
源码如下:
               
               
                /*
* =====================================================================================
*
*       Filename:  main.c
*
*    Description:  
*
*        Version:  1.0
*        Created:  2010年01月23日 15时14分41秒
*       Revision:  none
*       Compiler:  gcc
*
*         Author:  David Fang (A IT worker), qi_fd@163.com
*        Company:  No
*
* =====================================================================================
*/
#include gtk/gtk.h>
#include dirent.h>
#include string.h>
#include stdio.h>
#include stdlib.h>
#include sys/stat.h>
//窗口退出信号的处理函数
void destroy_main_wnd(GtkWidget* widget, gpointer data);
//根据路径编辑框中的目录路径显示该目录下的文件
int init_file_list(GtkList* file_list, GtkEntry* directory_entry);
//当文件列表中的选择项发生改变时的处理函数
void select_file_changed(GtkList* file_list, gpointer data);
//双击文件列表中的项目时的处理函数
gint file_list_click_handle(GtkWidget* widget, GdkEventButton* event, gpointer data);
//返回按钮点击时的处理函数
void back_btn_clicked(GtkButton* back_btn, gpointer data);
GtkWidget* file_list;    //文件列表
GtkWidget* text;        //文本显示区
GtkWidget* directory_entry; //路径编辑器
//和List中的item关联数据时需要key
//第一个key和item的label关联
//第二个key和item的类型关联(属于目录还是普通文件)
const   gchar   *list_item_data_key_string="list_item_data_label_string";
const    gchar    *list_item_data_key_type="list_item_data_type";
int main(int argc, char* argv[])
{
    GtkWidget* window;                    //主窗口
    GtkWidget* list_scroll_wnd;            //用来放文件列表的滚动窗
    GtkWidget* text_view_scroll_wnd;    //用来放文本显示的滚动窗
    GtkWidget* vbox;                    
    GtkWidget* hbox;
    GtkWidget* valign;
    GtkWidget* halign;
    GtkWidget* directory_label;
    GtkWidget* btn_back;
    gtk_init(&argc, &argv);
    window = (GtkWidget*)gtk_window_new(GTK_WINDOW_TOPLEVEL);
    list_scroll_wnd = (GtkWidget*)gtk_scrolled_window_new(NULL, NULL);
    gtk_scrolled_window_set_policy((GtkScrolledWindow*)(list_scroll_wnd), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
    text_view_scroll_wnd = (GtkWidget*)gtk_scrolled_window_new(NULL, NULL);
    gtk_scrolled_window_set_policy((GtkScrolledWindow*)(text_view_scroll_wnd), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
    vbox = gtk_vbox_new(FALSE, 5);
    hbox = gtk_hbox_new(FALSE, 5);
    valign = gtk_alignment_new(0, 0, 1, 0);
    halign = gtk_alignment_new(1, 0, 0, 0);
    text = gtk_text_view_new();
    gtk_text_view_set_editable((GtkTextView*)text, FALSE);
    file_list = gtk_list_new();
    gtk_list_set_selection_mode((GtkList*)file_list, GTK_SELECTION_BROWSE);
    directory_label = gtk_label_new("路径");
    directory_entry = gtk_entry_new();
    gtk_entry_set_editable((GtkEntry*)(directory_entry), FALSE);
    gtk_entry_set_text((GtkEntry*)(directory_entry), "/");
    btn_back = gtk_button_new_with_label(");
    if(0 != init_file_list((GtkList*)(file_list), (GtkEntry*)(directory_entry)))
    {
        g_print("init file list failed!\n");
        return 1;
    }
    gtk_window_set_position((GtkWindow*)window, GTK_WIN_POS_CENTER);
    gtk_window_set_default_size((GtkWindow*)window, 800, 600);
    gtk_container_set_border_width(GTK_CONTAINER(window), 10);
    gtk_widget_set_size_request(directory_label, 40, 30);
    gtk_widget_set_size_request(btn_back, 40, 30);
    gtk_container_add(GTK_CONTAINER(halign), directory_label);
    gtk_box_pack_start(GTK_BOX(hbox), halign, FALSE, FALSE, 0);
    gtk_box_pack_start(GTK_BOX(hbox), directory_entry, TRUE, TRUE, 0);
    gtk_box_pack_start(GTK_BOX(hbox), btn_back, FALSE, FALSE, 0);
    gtk_container_add(GTK_CONTAINER(valign), hbox);
    gtk_box_pack_start(GTK_BOX(vbox), valign, FALSE, FALSE, 0);
    gtk_scrolled_window_add_with_viewport((GtkScrolledWindow*)list_scroll_wnd, file_list);
    gtk_box_pack_start(GTK_BOX(vbox), list_scroll_wnd, TRUE, TRUE, 0);
    gtk_scrolled_window_add_with_viewport((GtkScrolledWindow*)text_view_scroll_wnd, text);
    gtk_box_pack_start(GTK_BOX(vbox), text_view_scroll_wnd, TRUE, TRUE, 0);
    gtk_container_add(GTK_CONTAINER(window), vbox);
    g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(destroy_main_wnd), NULL);
    g_signal_connect(G_OBJECT(file_list), "selection-changed", G_CALLBACK(select_file_changed), (gpointer)(text));
    g_signal_connect(G_OBJECT(file_list), "button_press_event", G_CALLBACK(file_list_click_handle), (gpointer)(directory_entry));
    g_signal_connect(G_OBJECT(btn_back), "clicked", G_CALLBACK(back_btn_clicked), (gpointer)(directory_entry));
    gtk_widget_show_all(window);
    gtk_main();
    return 0;
}
void destroy_main_wnd(GtkWidget* widget, gpointer data)
{
    gtk_main_quit();
}
GtkWidget* list_item_directory_new(const char* dirname)
{
    GtkWidget* list_item = gtk_list_item_new();
    GtkWidget* hbox = gtk_hbox_new(FALSE, 5);
    GtkWidget* image = gtk_image_new_from_stock(GTK_STOCK_DIRECTORY, GTK_ICON_SIZE_SMALL_TOOLBAR);
    GtkWidget* label = gtk_label_new(dirname);
    gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 0);
    gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
    gtk_container_add(GTK_CONTAINER(list_item), hbox);
    gtk_object_set_data(GTK_OBJECT(list_item),
            list_item_data_key_string,
            (gpointer)dirname);
    gtk_object_set_data(GTK_OBJECT(list_item),
            list_item_data_key_type,
            (gpointer)0);
    return list_item;
}
GtkWidget* list_item_file_new(const char* filename)
{
    GtkWidget* list_item = gtk_list_item_new();
    GtkWidget* hbox = gtk_hbox_new(FALSE, 5);
    GtkWidget* image = gtk_image_new_from_stock(GTK_STOCK_FILE, GTK_ICON_SIZE_SMALL_TOOLBAR);
    GtkWidget* label = gtk_label_new(filename);
    gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 0);
    gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
    gtk_container_add(GTK_CONTAINER(list_item), hbox);
    gtk_object_set_data(GTK_OBJECT(list_item),
            list_item_data_key_string,
            (gpointer)filename);
    gtk_object_set_data(GTK_OBJECT(list_item),
            list_item_data_key_type,
            (gpointer)1);
    return list_item;
}
int init_file_list(GtkList* file_list, GtkEntry* directory_entry)
{
    const char* dirpath = (const char*)gtk_entry_get_text(directory_entry);
    DIR* dir = opendir(dirpath);
    struct dirent* enump = NULL;
    GList* dlist = NULL;
    GList* flist = NULL;
    GtkWidget* list_item = NULL;
    size_t name_len;
    if(NULL == dir)
    {
        g_print("Open directory failed:%s.\n", dirpath);
        return 1;
    }
    while(enump = readdir(dir))
    {
        name_len = strlen(enump->d_name);
        if( (name_len == 1 && enump->d_name[0] == '.')
                || (name_len == 2 && !strncmp(enump->d_name, "..", 2)))
            continue;
        if(DT_DIR == enump->d_type)
        {
            list_item = list_item_directory_new(enump->d_name);
            dlist = g_list_prepend(dlist, list_item);
        }
        if(DT_REG == enump->d_type)
        {
            list_item = list_item_file_new(enump->d_name);
            flist = g_list_prepend(flist, list_item);
        }
    }
    gtk_list_clear_items(file_list, 0, -1);
    gtk_list_append_items(file_list, dlist);
    gtk_list_append_items(file_list, flist);
    gtk_widget_show_all((GtkWidget*)(file_list));
    return 0;
}
void select_file_changed(GtkList* file_list, gpointer data)
{
    GtkTextView*     text = (GtkTextView*)data;
    GList*            dlist = GTK_LIST(file_list)->selection;
    GtkObject*        selected_item = NULL;
    gchar*            item_data_string;
    const gchar*     cur_dir;
    gchar*             path = NULL;
    struct stat     stat_buf;
    if(!dlist)
    {
        return;
    }
    selected_item = GTK_OBJECT(dlist->data);
    item_data_string = (gchar*)gtk_object_get_data(selected_item,
            list_item_data_key_string);
    gint type = (gint)gtk_object_get_data(selected_item, list_item_data_key_type);
    cur_dir = gtk_entry_get_text((GtkEntry*)directory_entry);
    path = (gchar*)malloc(strlen(cur_dir) + strlen(item_data_string) + 1);
    if(NULL == path)
        goto end_proc;
    strcpy(path, cur_dir);
    strcat(path, item_data_string);
    if(stat(path, &stat_buf)  0)
        goto end_proc;
    if(0 == type)
    {
        //directory
    }
    else if(1==type)
    {
        //regular file
    }
end_proc:
    free(path);
}
//0 open failed
//1 open succeeded
int test_open(const char* path)
{
    struct dirent* enump = NULL;
    DIR* dir = opendir(path);
    if(NULL == dir)
    {
        return 0;
    }
    enump = readdir(dir);
    return NULL != enump;
}
void text_view_file_content(GtkWidget* text_view, const gchar* file_path)
{
    struct stat stat_buf;
    FILE* fp;
    size_t buf_size = 1024 * 4;
    GtkTextBuffer* text_buf = NULL;
    char* buf, *utf8_end;
    int i;
    if(stat(file_path, &stat_buf)  0)
        return;
   
    if(NULL == (fp = fopen(file_path, "rb")))
        return;
   
    if(stat_buf.st_size  buf_size)
    {
        buf_size = stat_buf.st_size;
    }
    buf = (char*)malloc(buf_size);
    if(NULL == buf)
        return;
   
    if(fread(buf, 1, buf_size, fp)  buf_size)
        goto end_text_view_file_content;
    text_buf = gtk_text_view_get_buffer((GtkTextView*)text);
    if(NULL == text_buf)
    {
        text_buf = gtk_text_buffer_new(NULL);
        gtk_text_view_set_buffer((GtkTextView*)text, text_buf);
    }
    if(g_utf8_validate((const gchar*)buf, buf_size, (const gchar**)&utf8_end))
    {
        gtk_text_buffer_set_text(text_buf, (const gchar*)buf, buf_size);
    }
    else
    {
        for(i = 0; i  buf_size; ++i)
        {
            if(!isprint(buf))
            {
                buf = '.';
            }
        }
        gtk_text_buffer_set_text(text_buf, (const gchar*)buf, buf_size);
    }
   
end_text_view_file_content:
    free(buf);
}
gint file_list_click_handle(GtkWidget* widget, GdkEventButton* event, gpointer data)
{
    if(GTK_IS_LIST(widget) && event->type == GDK_2BUTTON_PRESS)
    {
        GList* dlist = GTK_LIST(widget)->selection;
        GtkEntry* path_entry = (GtkEntry*)data;
        if(NULL != dlist)
        {
            GtkObject* selected_item = GTK_OBJECT(dlist->data);
            const char* old_path = gtk_entry_get_text(path_entry);
            const char* selected_item_string = (gchar*)gtk_object_get_data(selected_item, list_item_data_key_string);
            gint  type = (gint)gtk_object_get_data(selected_item, list_item_data_key_type);
            if(0 == type)
            {
                //directory
                gchar* new_path = (gchar*)malloc(strlen(old_path) + strlen(selected_item_string) + 2);
                strcpy(new_path, old_path);
                strcat(new_path, selected_item_string);
                strcat(new_path, "/");
                if(test_open(new_path))
                {
                    gtk_entry_set_text(path_entry, new_path);
                    init_file_list((GtkList*)widget, path_entry);
                }
                free(new_path);
            }
            else if(1 == type)
            {
                //regular file
                gchar* file_path = (gchar*)malloc(strlen(old_path) + strlen(selected_item_string) + 1);
                strcpy(file_path, old_path);
                strcat(file_path, selected_item_string);
                text_view_file_content(text, file_path);
            }
        }
    }
}
//calc the position of the second last slash
//      calculated start pos
//      |
// /usr/bin/
gint calc_start_pos(const char* path)
{
    size_t path_len = strlen(path);
    const char* p = path;
    gint count = 0;
    const char* p_second_last_slash = path + path_len - 2;
    while(*p_second_last_slash != '/')
    {
        p_second_last_slash--;
    }
    for(; p != p_second_last_slash; ++p)
    {
        count++;
    }
    //skip the slash
    count+=1;
    return count;
}
void back_btn_clicked(GtkButton* back_btn, gpointer data)
{
    GtkEntry* path_entry = (GtkEntry*)data;
    gint start_pos;
    const char* old_path = gtk_entry_get_text(path_entry);
    if(!strcmp(old_path, "/"))
        return;
    start_pos = calc_start_pos(old_path);
    gtk_editable_delete_text((GtkEditable*)path_entry, start_pos, -1);
    init_file_list((GtkList*)(file_list), (GtkEntry*)(path_entry));
}
下面是运行的界面:



本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u3/95535/showart_2161570.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP