- 论坛徽章:
- 0
|
经过两天的努力,写了一个简单的文件查看器,当做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 |
|