昨晚将phoneyc检测网页的结果写入数据库时,想起可以顺手加个md5值作为每个url的签名,于是在终端里敲下echo "www.godorz.cn" | md5sum ,在这之前,一切都是美好的,可当我要拿出计算出的md5值时,才知道原来在终端里复制文本是这么繁琐,首先要选定文本,然后右键+c,后一步是很容易的,但是前一步选定文本对于鼠标不灵视力不好脾气火爆的我来说,就真的是个杯具了..正好最近在学gtk,干脆就写个计算md5的gui,然后将结果默认选定,酱紫就可以直接ctrl+c复制啦,呵呵..
md5算法是在这里找的,说来惭愧的是,,作为计算机系的学生,生平第一次真正见到request for comment文档,还是21页的文档,很长很恐怖,我马上把它关了..
有了md5源码,其余的就很简单了,打开glade,设计好界面如下:
然后新建一个c文件,用GtkBuilder *builder将glade设计好的界面引用下来,然后逐个传给GtkWidget组件,剩下需要作的就是捣鼓捣鼓每个组件回调函数了. 代码如下,注释已经很明了了:
#include<gtk/gtk.h> GtkWidget *resultentry; GtkWidget *filew; GtkWidget *entry; gchar filepath[512]; ..... void cb_okbutton(GtkWidget *widget, GtkWidget *entry) { //得到输入控件entry值,传入filename const gchar *tmp; tmp = gtk_entry_get_text(GTK_ENTRY(entry)); char filename[512]; sprintf(filename, "%s", tmp); if (filename[0]==34) filename[strlen(filename)-1]=0,strcpy(filename,filename+1); //支持文件拖曳,但会多出双引号,这里是处理多余的双引号 if (!(fp=fopen(filename,"rb"))) {printf("Can not open this file!\n"); return;} //以二进制打开文件 fseek(fp, 0, SEEK_END); //文件指针转到文件末尾 if((len=ftell(fp))==-1) {printf("Sorry! Can not calculate files which larger than 2 GB!\n");fclose(fp); return ;} //ftell函数返回long,最大为2GB,超出返回-1 rewind(fp); //文件指针复位到文件头 A=0x67452301,B=0xefcdab89,C=0x98badcfe,D=0x10325476; //初始化链接变量 flen[1]=len/0x20000000; //flen单位是bit flen[0]=(len%0x20000000)*8; memset(x,0,64); //初始化x数组为0 fread(&x,4,16,fp); //以4字节为一组,读取16组数据 for(i=0;i<len/64;i++) { //循环运算直至文件结束 md5(); memset(x,0,64); fread(&x,4,16,fp); } ((char*)x)[len%64]=128; //文件结束补1,补0操作,128二进制即10000000 if(len%64>55) md5(),memset(x,0,64); memcpy(x+14,flen,8); //文件末尾加入原文件的bit长度 md5(); fclose(fp); // 将结果高低位逆反输出到buf char buf[512]; sprintf(buf, "%08x%08x%08x%08x",PP(A),PP(B),PP(C),PP(D)); //高低位逆反输出 //printf("%08x%08x%08x%08x\n",PP(A),PP(B),PP(C),PP(D)); //高低位逆反输出 // printf("%s\n", buf); // 将buf内容显示在输入控件resultentry上 gtk_entry_set_text(GTK_ENTRY(resultentry),buf); // 输入控件resultentry内容默认选定,方便用户复制 gtk_editable_select_region(GTK_EDITABLE(resultentry), 0, GTK_ENTRY(resultentry)->text_length); } // 获得文件名,并将它打印到控制台(console)上 void file_ok_sel( GtkWidget *w, GtkFileSelection *fs ) { // 将文件选择控件所选择的文件路径传给filepath sprintf(filepath, "%s", gtk_file_selection_get_filename (GTK_FILE_SELECTION (fs))); //printf("%s\n", filepath); // 将文件选择控件所选择的文件路径显示在输入空间entry上 gtk_entry_set_text (GTK_ENTRY (entry), filepath); //const gchar *tmp; //tmp = gtk_entry_get_text(GTK_ENTRY(entry)); //printf("<<<<<<<<<< %s\n", tmp); // 文件已选择完毕,隐藏文件选择控件,貌似不能直接destroy掉.. //gtk_widget_destroy(GTK_WIDGET(fs)); gtk_widget_hide(GTK_WIDGET(fs)); } void cb_button(GtkWidget *widget, GtkWidget *entry) { // 创建一个新的文件选择构件 filew = gtk_file_selection_new ("File selection"); g_signal_connect (G_OBJECT (filew), "destroy", G_CALLBACK (gtk_widget_destroy), NULL); // 为 ok_button 按钮设置回调函数,连接到 file_ok_sel function 函数 g_signal_connect (G_OBJECT (GTK_FILE_SELECTION (filew)->ok_button), "clicked", G_CALLBACK (file_ok_sel), filew); // 为 cancel_button 设置回调函数,销毁构件 g_signal_connect_swapped (G_OBJECT (GTK_FILE_SELECTION (filew)->cancel_button), "clicked", G_CALLBACK (gtk_widget_destroy), filew); // 设置文件名,比如这个一个文件保存对话框,我们给了一个缺省文件名 gtk_file_selection_set_filename (GTK_FILE_SELECTION(filew), "hello.cmp"); gtk_widget_show (filew); } ....
编译命令为: gcc -o gtkmd5 gtkmd5.c `pkg-config --cflags --libs gtk+-2.0` -export-dynamic
比较恶心的是文件选择控件filew,当点击button时它被new出来,但是选择好文件之后,filew应该是消失的,我理所当然的调用 gtk_widget_destroy(GTK_WIDGET(fs)); 将之destroy掉了,伴随而来的副作用是主窗口也将退出,于是搞了个很猥琐的方法,直接用gtk_widget_hide(GTK_WIDGET(fs)); 将它隐藏起来了..不过,现在想想这种做法是不错的,因为用户可能重新需要选择文件,其实也就没有必要将之destroy掉了,隐藏起来正好是歪打正着..
最后是测试,居然很傻的总是先用md5sum算出gtkmd5.c的md5值,然后在gtkmd5.c中这修改那调整一点,然后compile+link,用生成的程序再次计算gtkme5.c的值,然后目光呆滞的看着两个不同的结果,抱着脑袋纠结了半天不明所以..真成杯具批发商了..最后,怨妇般的在这里对着个helloworld般的小程序吐槽.莫非更年期到了?
完整代码和glade文件在这..
最最后: 程序写得仔细点的话,应该把计算文件夹里所有文件md5值的功能加上的,这样,就可以把图中蹩脚的result entry换成GTK_TEXT_VIEW了..HoHo~~其实还应该加上个选择按钮,计算文件或者字符串的..
人人都是代码控.真是写200行文章无视一切的补丁啊.居家必备.杀人无形.
谢谢,用来做GTK学习的入门程序,呵呵。