Glade+GTK+ 实现通讯录信息管理系统图形界面软件开发

开发环境

OS:Ubuntu20.04.3 LTS
CPU:Intel® Core™ i5-10210U CPU @ 1.60GHz × 8
编译器:gcc 7.5.0 GTK+ 3.24.20
开发语言:C语言
IDE:VS

前期准备

开发环境配置

由于采用了C语言开发,故选择了传统GTK用来界面设计,首先安装好Glade(apt-get install glade),GTK+一般linux系统都会自带,选择好不同版本即可(重要!!!GTK+不同版本差异很大,很多函数在新版本都废弃了……),其他相关配置参见 Ubuntu下安装GTK+及Glade开发C应用界面

软件功能要求

本通讯录信息管理系统要求满足以下功能:

  1. 系统功能:添加联系人信息,通常包括编号、姓名、性别、电话以及地址等数据项;此外可实现通讯者信息的插入、查询、删除、更新等功能。也支持从系统批量上传联系人信息,或将联系人信息导出。
  2. 程序可对输入数据的容错性进行检查,保证数据的合法性,如性别取值只能为男或女,电话号码利用正则表达式判断合法性等
  3. 用户界面的友好性:程序可提供与用户之间合理的交互以及相应的菜单供用户选择。

软件开发过程

数据结构设计

由于该软件是小编的一次数据结构课程实践作业,故数据存储结构采用了数组链表,链表数组一般用于在不借用数据库的情况下,对于大量数据的临时存储,来实现快速查找的功能。

typedef struct Node
{
   
    struct Node *next;
    char num[MAXSIZE];//身份证号  
    char name[MAXSIZE];//姓名,只能为英文,如果是中文在排序时会出错,该问题尚未解决
    char gender[MAXSIZE];//性别
    char phone_number[MAXSIZE];//手机号
    char address[MAXSIZE];//地址
}Linklist;

typedef struct 
{
   
    Linklist *root;//头结点
    Linklist *rear;//尾指针,始终指向链表的最后一个元素
}Index_linklist;//A-Z 26个字母为索引,分别对应一个链表

Index_linklist system_data[26];
链表函数编写
int linklist_length(Linklist* list)//计算链表元素个数
{
   
    Linklist *p=list;
    int length=0;
    for (;list->next!=NULL;)
    {
   
        length+=1;
    }
    return length;
}

void insert_linklist(Linklist *list,int index,Linklist *new_node)//在链表第index(从0计数)个元素后插入新节点
{
   
    Linklist *p=list;
    for (int i=0;i<index;i++)
    {
   
        p=p->next;
    }
    new_node->next=p->next;
    p->next=new_node;
}
void delete_linklist(Linklist *list,int index)//删除链表中第index个元素(1-length)
{
   
    Linklist *p=list;//指向链表头结点
    for (int i=1;i<index;i++)
    {
   
        p=p->next;//指向第index-1个元素
    }
    Linklist *q=p->next;
    p->next=p->next->next;
    free(q);
}
数据处理函数
#include "system_functions.h"
/*
**从文件读取数据初始化链表
*/
int data_insert_from_file(Index_linklist *system,FILE *ip)//从文件读取数据
{
   
	const char whitespace[] = " ";//分隔符
    const char linebreak[]="\n";//换行符
    char buffer[200];//缓冲区
    int count=0;//记录读取了多少条数据
    while (fgets(buffer,N,ip))//按行读取
    {
      
        Linklist *new_node=(Linklist *)malloc(sizeof(Linklist));
        int length=strlen(buffer);
        /*进行字符串分割*/
        strcpy(new_node->num,strtok(buffer,whitespace));
        strcpy(new_node->name,strtok(NULL,whitespace));
        strcpy(new_node->gender,strtok(NULL,whitespace));
        strcpy(new_node->phone_number,strtok(NULL,whitespace));
        strcpy(new_node->address,strtok(NULL,linebreak));
        if (insert_data(system,new_node)==1)
        {
   
            count+=1;
        }
    }
    return count;
}

int data_export_to_file(Index_linklist *system,char *filename)//数据导出文件
{
   
    FILE *op;
    if ((op=fopen(filename,"w"))!=NULL)
    {
   
        print_data(system,op);
        fclose(op);
        return 1;
    }
    else return 0;
}

int insert_data(Index_linklist *system,Linklist *node)//从终端读取数据进行插入
{
   
    if (strcmp(node->gender,"woman")==0)
    {
   
        strcpy(node->gender,"女");
    }
    if (strcmp(node->gender,"man")==0)
    {
   
        strcpy(node->gender,"男");
    }
    if (strcmp(node->gender,"男")==0 || strcmp(node->gender,"女")==0)
    {
           
        //判断性别输入是否合理
        int index=to_upper(node->name[0])-'A';
        Linklist *p=system[index].root;
        //按照姓名顺序进行插入
        if (p->next==NULL)//若链表为空则直接插入
        {
   
            system[index].rear->next=node;
            node->next=NULL;
            system[index].rear=node;
        }
        else
        {
   
            for (;strcmp(p->next->name,node->name) <= 0;)
            {
   
                p=p->next;
                if (p->next==NULL)
                {
   
                    node->next=NULL;
                    p->next=node;
                    system[index].rear=node;
                    return 1;
                }
            }
            //找到第一个name比新节点大的节点的前一个节点,新节点插在其之前
            node->next=p->next;
            p->next=node;
        }
        return 1;
    }
    else
    {
   
        //printf("%s \'s gender input ERROR!\n",node->name);
        return 0;
    }
}

void print_data(Index_linklist system[],FILE *op)
{
   
    for (int i=0;i<26;i++)
    {
   
        Linklist *p=system[i].root->next;
        while (p!=NULL)
        {
   
            fprintf(op,"%s %s %s %s %s\n",p->num,p->name,p->gender,p->phone_number,p->address);
            p=p->next;
        }
    }
}

int search_data(Index_linklist const system[],char *num,char *name)//根据ID进行完全匹配搜索
{
   
    int index=to_upper(name[0])-'A';
    Linklist *p=system[index].root->next;
    int flag=0; //标志是否存在
    int location=0;
    for (;p!=NULL;location+=1)
    {
   
        if (strcmp(p->num,num)==0)
        {
   
            //printf("%s %s %s %s %s\n",p->num,p->name,p->gender,p->phone_number,p->address);
            flag=1;
            location+=1;
            break;
        }
        p=p->next;
    }
    if (flag==0) return -1;//printf("%s is not in the address book!",name);
    return location;//当前链表中第location个位置(从头结点下一个节点开始从1计数)
}

void delete_data(Index_linklist *system,char *num,char *name)//删除数据
{
   
    if (name==NULL)
    {
   
        return;
    }
    int index=to_upper(name[0])-'A';
    Linklist *p=system[index].root;
    int location=search_data(system,num,name);
    delete_linklist(p,location);
}

void system_empty(Index_linklist *system)//将系统数据清空
{
   
    for (int i=0;i<26;i++)
    {
   
        Linklist *p=system[i].root->next;
        system[i].rear=system[i].root;
        for (;p!=NULL;)
        {
   
            Linklist *q=p;
            p=p->next;
            free(q);
        }
        system[i].root->next=NULL;
    }
}

int count_linklist_elem_num(Index_linklist *system,char *name)
{
   
    if (name==NULL)
    {
   
        return -1;
    }
    int index=to_upper(name[0])-'A';
    Linklist *p=system[index].root;
    if (p->next==NULL) 
    {
   
        return 0;//无元素
    }
    else if (p->next->next==NULL) 
    {
   
        return 1;//一个元素
    }
    else
    {
   
        return 2;
    }
}

在将数据从文件读取时,采用了标准库中的strtok()函数进行字符串分割;插入数据时首先进行输入格式判断,再根据首字母进行排序插入。

软件开发设计

系统初始化界面窗口

该窗口为软件的初始化进入窗口,首先借助Glade进行窗口设计,在主窗口GtkWindow下选用GtkFixed固定容器进行布局,添加一些标签和按钮如下图,背景图使用GtkImage进行添加即可。

创建主窗口函数如下:

GtkWidget *create_main_window()//创建主窗口
{
   
    //void on_Enter_button_clicked(GtkWidget *widget,gpointer window);
    //void set_widget_font_size(GtkWidget *widget, int size, gboolean is_button);//改变控件字体大小

    GtkBuilder *builder;//新建一个GtkBuilder对象用于读取GtkBuilder界面文件
    GtkWidget *main_window;
    GtkWidget *Enter_button;
    GtkWidget *Exit_button;
    GtkWidget *about_button;
    
    builder=gtk_builder_new();
    gtk_builder_add_from_file(builder,"main_window.glade",NULL);//从glade获取控件

    main_window=GTK_WIDGET(gtk_builder_get_object(builder,"main_window"));//获取主窗体
    gtk_window_set_icon(GTK_WINDOW(main_window), create_pixbuf("addressbook.png"));//设置软件图标
    gtk_window_set_title(GTK_WINDOW(main_window),"通讯录信息管理系统");//设置主窗口标题
    Enter_button=GTK_WIDGET(gtk_builder_get_object(builder,"Enter_button"));//获取主窗口中的进入按钮
    Exit_button=GTK_WIDGET(gtk_builder_get_object(builder,"Exit_button"));//获取主窗口中的退出按钮
    about_button=GTK_WIDGET(gtk_builder_get_object(builder,"About_button"));//获取主窗口中的退出按钮
    gtk_widget_set_opacity(main_window,0.2);
    //set_widget_font_size(Enter_button,50,TRUE);//改变控件字体大小
    // PangoFontDescri
  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值