一个五脏俱全的Gtk小程序

tt posted @ 2007年11月07日 05:51 in gtk , 10618 阅读

本人自从学习Gtk以来,一直没能做一个像模像样的例子,前段时间抽空写了一个小程序,大概800多行,是调用Gtk和GLib库共同编译的,贴到这里和大家分享:

 

#include<gtk/gtk.h>
#include<glib.h>
#include<stdio.h>
#include<malloc.h>
#include<math.h>

enum            /*定义图形的类型*/
{
    PIX_DRAW=1,    /*类型-点*/
    LINE_DRAW,
    CIRCLE_DRAW,
    RECT_DRAW,
    POLY_DRAW
};
typedef struct        /*定义含树视图和绘图区的结构体,以便回调函数传递参数*/
{
    GtkWidget *tree_view;
    GtkWidget *draw_area;
}tree_drawing;
typedef struct        /*定义含树视图、绘图区和文本输入框的结构体,以便回调函数传递参数*/
{
    GtkWidget *window;
    GtkWidget *view;
    GtkWidget *entry;
}wview;
typedef struct        /*为方便参数传递而创建的结构体*/
{
    GtkWidget *window;
    GtkWidget *view;
    GtkWidget *entry;
    GtkWidget *draw_area;
}wdview;
typedef struct _2D_POINT    /*定义二维数据点结构体*/
{
    float x,y;
}_2d_point;
/*------------定义全局变量--------------*/
double width=100.0,height=100.0;    /*定义系统长宽,这里与窗口窗宽无关*/
int draw_type=0;            /*定义图像类型*/
GSList *prt=NULL;            /*定义存放数据的链表*/
GtkTreeModel *model;            /*定义树视图模型*/
GtkTreeStore *tree_store;        /*定义树形存储*/
GtkTreeIter top_pix,top_line,top_circle,top_rect,top_poly,other;    /*定义树视图的项,以便添加元素*/
/*-----------函数声明部分------------------*/
GtkTreeView* create_tree(void);        /*创建树视图*/
GtkTreeModel* create_model(void);    /*创建树视图模型*/

void get_new_file(GtkWidget *button,wview *wv);/*获得文件名,并修改树视图显示*/
void create_file(GtkWidget *create_file_button,GtkWidget *view);/*创建文件菜单的回调函数*/
void get_import_file(GtkWidget* button,wdview *wdv);        /*获得导入文件名,并修改树视图和绘图区显示*/
void messagebox(const char *str);                /*消息提示框,用于提示相关信息*/
void import_file(GtkWidget *import_file_button,tree_drawing *td);/*导入文件菜单的回调函数*/
void export_file(GtkWidget *export_file_button,GtkWidget *view);/*导出文件菜单的回调函数*/

void enlarge_obj(GtkWidget *enlarge,GtkWidget *data);/*工具栏中放大按钮的回调函数,修改绘图区显示*/
void deflate_obj(GtkWidget *deflate,GtkWidget *data);/*工具栏中缩小按钮的回调函数,修改绘图区显示*/
void draw_pix(void);                    /*draw菜单下,points菜单的回调函数*/
void draw_line(void);                    /*Line菜单的回调函数*/
void draw_circle(void);                    /*Circle菜单的回调函数*/
void draw_rect(void);                    /*Rectagle菜单的回调函数*/
void draw_poly(void);                    /*Plygon菜单的回调函数*/
void draw_prt(GtkWidget *data);                /*在绘图区中按照图像类型,将链表内容绘制出来,修改绘图区显示*/
/*下面这几个函数都没实现,这里不做具体介绍*/
/*
void show_part(GtkWidget *view,GtkWidget *draw_area);
void hide_part(GtkWidget *view,GtkWidget *draw_are);
void del_part(GtkWidget *view,GtkWidget *draw_area);
void modify_part(GtkWidget *view,GtkWidget *draw_area);
GtkWidget* pop_menu(GtkWidget *draw_area);
static gboolean view_press(GtkWidget *widget,GdkEventButton *event,GtkWidget *menu);
*/
/*-----------函数定义部分------------*/
/*
GtkWidget* pop_menu(GtkWidget *draw_area)
{
    GtkWidget *file_menu;
    GtkWidget *show_item,*hide_item,*del_item,*modify_item;

    show_item=gtk_menu_item_new_with_label("show");
    hide_item=gtk_menu_item_new_with_label("hide");
    del_item=gtk_menu_item_new_with_label("delete");
    modify_item=gtk_menu_item_new_with_label("modify");

    gtk_menu_append(GTK_MENU(file_menu),show_item);
    gtk_menu_append(GTK_MENU(file_menu),hide_item);
    gtk_menu_append(GTK_MENU(file_menu),del_item);
    gtk_menu_append(GTK_MENU(file_menu),modify_item);

    g_signal_connect_swapped(G_OBJECT(show_item),"activate",G_CALLBACK(show_part),draw_area);
    g_signal_connect_swapped(G_OBJECT(hide_item),"activate",G_CALLBACK(hide_part),draw_area);
    g_signal_connect_swapped(G_OBJECT(del_item),"activate",G_CALLBACK(del_part),draw_area);
    g_signal_connect_swapped(G_OBJECT(modify_item),"activate",G_CALLBACK(modify_part),draw_area);

    return file_menu;
}
void show_part(GtkWidget *view,GtkWidget *draw_area)
{
}
void hide_part(GtkWidget *view,GtkWidget *draw_are)
{
}
void del_part(GtkWidget *view,GtkWidget *draw_area)
{
}
void modify_part(GtkWidget *view,GtkWidget *draw_area)
{
}
*/
/*上面几个函数都还没实现,由于事件问题,在这里就不具体实现了*/
/*-----------函数定义部分-------------*/
/*创建树视图,向里面添加列,并调用树视图模型创建函数完成树视图的创建,
 * 输入参数:无
 * 输出参数:树视图构件tree_view
 * 日期:2007-4-7修改*/
GtkTreeView* create_tree(void)
{
    GtkWidget *tree_view;
    GtkTreeViewColumn *col;
    GtkCellRenderer *cell;
   
    tree_view=gtk_tree_view_new();
    col=gtk_tree_view_column_new();
    gtk_tree_view_column_set_title(col,"part");
    gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view),col);
    cell=gtk_cell_renderer_text_new();
        //g_object_set(cell,"editable",TRUE,NULL);
    //g_signal_connect(cell,"edited",G_CALLBACK(cell_edited),NULL);
    gtk_tree_view_column_pack_start(col,cell,TRUE);
    gtk_tree_view_column_add_attribute(col,cell,"text",0);
    model=create_model();
    gtk_tree_view_set_model(GTK_TREE_VIEW(tree_view),model);

    return GTK_TREE_VIEW(tree_view);
}
/*创建树视图模型,向tree_store里面添加条目
 * 输入参数:无
 * 输出参数:树视图模型tree_store
 * 日期:2007-4-7修改*/
GtkTreeModel* create_model()
{
    tree_store=gtk_tree_store_new(1,G_TYPE_STRING);
    //添加树的项
    gtk_tree_store_append(tree_store,&top_pix,NULL);
    gtk_tree_store_set(tree_store,&top_pix,
        0,"Points",-1);
    gtk_tree_store_append(tree_store,&top_line,NULL);
    gtk_tree_store_set(tree_store,&top_line,
        0,"Lines",-1);
    gtk_tree_store_append(tree_store,&top_circle,NULL);
    gtk_tree_store_set(tree_store,&top_circle,
        0,"Circles",-1);
    gtk_tree_store_append(tree_store,&top_rect,NULL);
    gtk_tree_store_set(tree_store,&top_rect,
        0,"Rectangles",-1);
    gtk_tree_store_append(tree_store,&top_poly,NULL);
    gtk_tree_store_set(tree_store,&top_poly,
        0,"Polygons",-1);
    gtk_tree_store_append(tree_store,&other,NULL);
    gtk_tree_store_set(tree_store,&other,
        0,"Others",-1);
    return GTK_TREE_MODEL(tree_store);

}
/*获得文本输入框内容,并将其加入到树视图中显示,并隐藏新建文件窗口
 * 输入参数:按钮构件本身button,包含文本输入框、树视图和绘图区的结构体wv
 * 输出参数:无
 * 日期:2007-4-7修改*/
void get_new_file(GtkWidget *button,wview *wv)
{
    char *str=malloc(20*sizeof(char));
    str=(char*)gtk_entry_get_text(GTK_ENTRY(wv->entry));
    GtkTreeIter child;
    gtk_tree_store_append(tree_store,&child,&other);/*向树存储类型的构件中添加条目*/
    gtk_tree_store_set(tree_store,&child,        /*设置新添加条目的文本显示*/
        0,str,-1);
    /*FILE *fp=NULL;
    if((fp=fopen(str,"w"))==NULL)
        printf("error in open file %s\n",str);
    fclose(fp);*/
    gtk_widget_hide(wv->window);
}
/*隐藏窗口,
 * 输入参数:按钮button,窗口构件window
 * 输出参数:无
 * 日期:2007-4-7修改*/
void cancel_create(GtkWidget *button,GtkWidget *window)
{
    gtk_widget_hide(window);
}
/*创建文件菜单的回调函数。用于打开一个对话框,让用户输入文件名,然后将文件名放到树视图的other条目下,创建文件,
 * 输入参数:菜单项本身create_file_item, 树视图view
 * 输出参数:无
 * 日期:2007-4-7修改*/
void create_file(GtkWidget *create_file_button,GtkWidget *view)
{
    GtkWidget *window,*entry;
    GtkWidget *label,*vbox,*hbox,*b_ok,*b_cancel;
   
    window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_widget_set_size_request(window,300,110);
    gtk_window_set_title(GTK_WINDOW(window),"create part file");
    g_signal_connect(G_OBJECT(window),"destroy",G_CALLBACK(gtk_widget_destroy),NULL);
    gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER);
   
    vbox=gtk_vbox_new(FALSE,15);
    gtk_container_add(GTK_CONTAINER(window),vbox);
   
    label=gtk_label_new("Please input the file name:");
    gtk_box_pack_start(GTK_BOX(vbox),label,FALSE,FALSE,0);
    entry=gtk_entry_new();
    gtk_box_pack_start(GTK_BOX(vbox),entry,FALSE,FALSE,0);
    hbox=gtk_hbox_new(FALSE,0);
    gtk_box_pack_start(GTK_BOX(vbox),hbox,FALSE,FALSE,0);

    wview *wv=malloc(sizeof(wview));
    wv->window=window;
    wv->view=view;
    wv->entry=entry;

    b_ok=gtk_button_new_with_label("  ok   ");
    g_signal_connect(G_OBJECT(b_ok),"clicked",G_CALLBACK(get_new_file),wv);
    gtk_box_pack_start(GTK_BOX(hbox),b_ok,FALSE,FALSE,50);
    b_cancel=gtk_button_new_with_label("cancel");
    g_signal_connect(G_OBJECT(b_cancel),"clicked",G_CALLBACK(cancel_create),window);
   
    gtk_box_pack_start(GTK_BOX(hbox),b_cancel,FALSE,FALSE,50);

    gtk_widget_show_all(window);
}
/*用于隐藏构件,这里是将messagebox窗口隐藏,
 * 输入参数:按钮本身button,窗口构件data
 * 输出参数:无
 * 日期:2007-4-7修改*/
void f_button(GtkWidget * button,GtkWidget * data)
{
    gtk_widget_hide(data);
}
/*一个消息提示框,弹出一个窗口,用于提示当前的错误或者其它信息
 * 输入参数:字符串str
 * 输出参数:无
 * 日期:2007-4-7修改*/
void messagebox(const char* str)
{
    GtkWidget * window,*table,*label,*button;
    /////
    window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_title(GTK_WINDOW(window),"messagebox");
    gtk_widget_set_size_request(GTK_WIDGET(window),300,100);
    gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER);
    g_signal_connect(G_OBJECT(window),"destroy",G_CALLBACK(gtk_widget_destroy),NULL);
    /////
    table=gtk_table_new(2,3,FALSE);
    gtk_container_add(GTK_CONTAINER(window),table);
    ///
    label=gtk_label_new(str);
    gtk_table_attach_defaults(GTK_TABLE(table),label,1,2,0,1);
    gtk_widget_show(label);
   
   
    button=gtk_button_new_with_label("     确定     ");
    gtk_table_attach(GTK_TABLE(table),button,1,2,1,2,GTK_SHRINK,GTK_FILL,0,0);
    g_signal_connect(G_OBJECT(button),"clicked",G_CALLBACK(f_button),window);
    gtk_widget_show(button);
    gtk_widget_show_all(window);
}
/*导入文件对话框ok按钮的回调函数,实现读取文件名,并在将文件内容读取到链表结束后,
 * 根据图形类型修改树视图和绘图区,将文件名添加到树视图的相应条目下。
 * 输出参数:按钮本身:button,包含标签、树视图和绘图区的一个结构体
 * 输出参数:无
 * 日期:2007-4-7修改*/
void get_import_file(GtkWidget* button,wdview *wdv)
{
    char *str=malloc(20*sizeof(char));
    str=(char*)gtk_entry_get_text(GTK_ENTRY(wdv->entry));
    char *filename=malloc(20*sizeof(char));
    sprintf(filename,"%s.124",str);
    FILE *fp=NULL;
    if((fp=fopen(filename,"r"))==NULL)
    {
    messagebox("the file you import is not exist !");
    return ;
    }
    char ch;
    _2d_point *p=malloc(sizeof(_2d_point));
    fscanf(fp,"%c",&ch);
    GtkTreeIter child;
    if(ch=='P')            //判断是哪种类型的部件,以便放到对应目录下
    {
    gtk_tree_store_append(tree_store,&child,&top_pix);
    gtk_tree_store_set(tree_store,&child,
        0,str,-1);
    draw_type=PIX_DRAW;
    }
    else if(ch=='L')
    {
    gtk_tree_store_append(tree_store,&child,&top_line);
    gtk_tree_store_set(tree_store,&child,
        0,str,-1);
    draw_type=LINE_DRAW;
    }
    else if(ch=='C')
    {
    gtk_tree_store_append(tree_store,&child,&top_circle);
    gtk_tree_store_set(tree_store,&child,
        0,str,-1);
    draw_type=CIRCLE_DRAW;
    }
    else if(ch=='R')
    {
    gtk_tree_store_append(tree_store,&child,&top_rect);
    gtk_tree_store_set(tree_store,&child,
        0,str,-1);
    draw_type=RECT_DRAW;
    }
    else if(ch=='D')
    {
    gtk_tree_store_append(tree_store,&child,&top_poly);
    gtk_tree_store_set(tree_store,&child,
        0,str,-1);
    draw_type=POLY_DRAW;
    }
    else
    {
        gtk_tree_store_append(tree_store,&child,&other);
        gtk_tree_store_set(tree_store,&child,
        0,str,-1);
    }
    GSList *iter1=prt;
    while(iter1)//删除数组中原来内容
    {
    prt=g_slist_remove_link(prt,iter1);
    g_slist_free(iter1);
    iter1=prt;
    }
    while(!feof(fp))
    {
    p=malloc(sizeof(_2d_point));
    int ret=fscanf(fp,"%f",&(p->x));
    ret=fscanf(fp,"%f",&(p->y));
    if(ret!=1)
    {
        break;
    }
    prt=g_slist_append(prt,p);
    }
    draw_prt(wdv->draw_area);
   
    gtk_widget_destroy(wdv->window);
    fclose(fp);
}
/*导入菜单的回调函数,创建一个窗口用于输入要导入的文件名,ok按钮的回调函数实现读取文件名,
 * 将文件读取到链表,并修改树视图和绘图区的显示,
 * 输入参数:菜单项本生import_file_button, 包含树视图和绘图区的结构体td
 * 输出参数:无,
 * 日期:2007-4-7修改*/
void import_file(GtkWidget *import_file_button,tree_drawing *td)
{
    GtkWidget *window,*entry;
    GtkWidget *label,*vbox,*hbox,*b_ok,*b_cancel;
   
    window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_widget_set_size_request(window,300,110);
    gtk_window_set_title(GTK_WINDOW(window),"create part file");
    g_signal_connect(G_OBJECT(window),"destroy",G_CALLBACK(gtk_widget_destroy),NULL);
    gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER);
   
    vbox=gtk_vbox_new(FALSE,15);
    gtk_container_add(GTK_CONTAINER(window),vbox);
   
    label=gtk_label_new("Please input the file you want to import:");
    gtk_box_pack_start(GTK_BOX(vbox),label,FALSE,FALSE,0);
    entry=gtk_entry_new();
    gtk_box_pack_start(GTK_BOX(vbox),entry,FALSE,FALSE,0);
    hbox=gtk_hbox_new(FALSE,50);
    gtk_box_pack_start(GTK_BOX(vbox),hbox,FALSE,FALSE,0);

    wdview *wdv=malloc(sizeof(wdview));
    wdv->window=window;
    wdv->view=td->tree_view;
    wdv->entry=entry;
    wdv->draw_area=td->draw_area;

    b_ok=gtk_button_new_with_label("  ok   ");
    g_signal_connect(G_OBJECT(b_ok),"clicked",G_CALLBACK(get_import_file),wdv);
    gtk_box_pack_start(GTK_BOX(hbox),b_ok,FALSE,FALSE,50);
    b_cancel=gtk_button_new_with_label("cancel");
    g_signal_connect(G_OBJECT(b_cancel),"clicked",G_CALLBACK(cancel_create),window);
   
    gtk_box_pack_start(GTK_BOX(hbox),b_cancel,FALSE,FALSE,0);

    gtk_widget_show_all(window);

}
/*导出文件的回调函数,根据当前选中的树视图中的项,将链表中的数据写到文本文件中,
 * 在文本文件中,第一行是图形的类型,后面的是数据,
 * 存储的文件名就是当前选中的那一行的文本。
 * 输入参数:菜单项本身export_file, 树视图view
 * 输出参数:无
 * 日期:2007-4-7修改*/
void export_file(GtkWidget *export_file,GtkWidget *view)
{
    GtkTreeIter iter;
    GtkTreeView *treeview=(GtkTreeView*)view;
    GtkTreeSelection *selection=gtk_tree_view_get_selection(treeview);/*获得树视图的选定行*/

    if(gtk_tree_selection_get_selected(selection,NULL,&iter))/*从选定行获得选定项*/
    {
    gint i;
    GtkTreePath *path;
    path=gtk_tree_model_get_path(model,&iter);        /*由选定项获得路径。这条在这里无用*/
    //i=gtk_tree_path_get_indeces(path)[0];
    // gtk_tree_store_set (tree_store, &iter, column,
        //                  filename, -1);
    //获得文本
    char *text=malloc(sizeof(char));
    gtk_tree_model_get(GTK_TREE_MODEL(tree_store),&iter,0,&text,-1);/*由项获得项的文本*/
    char *file_name=malloc(19*sizeof(char));
    sprintf(file_name,"%s.124",text);
    FILE *fp=NULL;
    if((fp=fopen(file_name,"w"))==NULL)
    {
        messagebox("conn't open file you saved!");
        return ;
    }
    GSList *iterator=prt;
    char type;
    if(draw_type==PIX_DRAW)
    {
        type='P';
    }
    else if(draw_type==LINE_DRAW)
    {
        type='L';
    }
    else if(draw_type==CIRCLE_DRAW)
    {
        type='C';
    }
    else if(draw_type==RECT_DRAW)
    {
        type='R';
    }
    else if(draw_type==POLY_DRAW)
    {
        type='D';
    }
    else
    {
        messagebox("you have not create file!");
        return ;
    }
    fprintf(fp,"%c\n",type);
    while(iterator)
    {
        fprintf(fp,"%f\t%f\n",((_2d_point*)(iterator->data))->x,((_2d_point*)(iterator->data))->y);
        iterator=iterator->next;
    }
    fclose(fp);
    }
    return;
}
/*绘图函数,根据width和height的值将链表中的数据进行变换到当前坐标系下,由draw_type决定绘制什么图形,
 * 输入参数:绘图区data,
 * 输出参数:无
 * 日期:2007-4-7*/
void draw_prt(GtkWidget *data)
{
    int area_w=100,area_h=100;
    area_w=data->allocation.width;            //获得窗口尺寸
    area_h=data->allocation.height;
    gdk_window_clear(data->window);
    GSList *iter1=NULL,*iter2=NULL;
    iter1=prt;
    if(iter1==NULL){
        return ;
    }
    iter2=prt->next;
    if(draw_type==PIX_DRAW)
    {
        int x,y;
        while(iter1)
        {
            x=(((_2d_point*)(iter1->data))->x)*area_w/width+area_w/2;
            y=(((_2d_point*)(iter1->data))->y)*area_h/height+area_h/2;
            gdk_draw_point(GTK_WIDGET(data)->window,GTK_WIDGET(data)->style->
                fg_gc[GTK_WIDGET_STATE (data)],x,y);
            iter1=iter1->next;
        }
    }
    if(draw_type==LINE_DRAW)
    {
        int x0,x1,y0,y1;
        while(iter2)
        {
            x0=(((_2d_point*)(iter1->data))->x)*area_w/width+area_w/2;
            y0=(((_2d_point*)(iter1->data))->y)*area_h/height+area_h/2;
            x1=(((_2d_point*)(iter2->data))->x)*area_w/width+area_w/2;
            y1=(((_2d_point*)(iter2->data))->y)*area_h/height+area_h/2;           
            gdk_draw_line(GTK_WIDGET(data)->window,GTK_WIDGET(data)->
                style->fg_gc[GTK_WIDGET_STATE (data)],x0,y0,x1,y1);
            iter1=iter2;
            iter2=iter1->next;
        }
    }
    if(draw_type==CIRCLE_DRAW)
    {
        int x0,x1,y0,y1;
        int r=0.0;
        while(iter1&&iter2)
        {
            x0=(((_2d_point*)(iter1->data))->x)*area_w/width+area_w/2;
            y0=(((_2d_point*)(iter1->data))->y)*area_h/height+area_h/2;
            x1=(((_2d_point*)(iter2->data))->x)*area_w/width+area_w/2;
            y1=(((_2d_point*)(iter2->data))->y)*area_h/height+area_h/2;           
            r=sqrt((x1-x0)*(x1-x0)+(y1-y0)*(y1-y0));
            gdk_draw_arc(GTK_WIDGET(data)->window,GTK_WIDGET(data)->style->
                    fg_gc[GTK_WIDGET_STATE (data)],FALSE,x0-r,y0-r,2*r,2*r,0,64*360);
            iter1=iter2->next;
            if(iter1)
            {
                iter2=iter1->next;
            }
        }
    }
    if(draw_type==RECT_DRAW)
    {
        int x0,x1,y0,y1;
        while(iter1&&iter2)
        {
            x0=(((_2d_point*)(iter1->data))->x)*area_w/width+area_w/2;
            y0=(((_2d_point*)(iter1->data))->y)*area_h/height+area_h/2;
            x1=(((_2d_point*)(iter2->data))->x)*area_w/width+area_w/2;
            y1=(((_2d_point*)(iter2->data))->y)*area_h/height+area_h/2;   
            int h=abs(y1-y0);
            int w=abs(x1-x0);
            x0=x0<x1?x0:x1;
            y0=y0<y1?y0:y1;   
            gdk_draw_rectangle(GTK_WIDGET(data)->window,GTK_WIDGET(data)->style->
                    fg_gc[GTK_WIDGET_STATE (data)],FALSE,x0,y0,w,h);
            iter1=iter2->next;
            if(iter1)
            {
                iter2=iter1->next;
            }
        }
    }
    if(draw_type==POLY_DRAW)
    {
        int x0,x1,y0,y1;
        while(iter2)
        {
            x0=(((_2d_point*)(iter1->data))->x)*area_w/width+area_w/2;
            y0=(((_2d_point*)(iter1->data))->y)*area_h/height+area_h/2;
            x1=(((_2d_point*)(iter2->data))->x)*area_w/width+area_w/2;
            y1=(((_2d_point*)(iter2->data))->y)*area_h/height+area_h/2;               
            gdk_draw_line(GTK_WIDGET(data)->window,GTK_WIDGET(data)->style->
                    fg_gc[GTK_WIDGET_STATE (data)],x0,y0,x1,y1);
            iter1=iter2;
            iter2=iter1->next;
        }
        x0=(((_2d_point*)(iter1->data))->x)*area_w/width+area_w/2;
        y0=(((_2d_point*)(iter1->data))->y)*area_h/height+area_h/2;
        x1=(((_2d_point*)(prt->data))->x)*area_w/width+area_w/2;
        y1=(((_2d_point*)(prt->data))->y)*area_h/height+area_h/2;
        gdk_draw_line(GTK_WIDGET(data)->window,GTK_WIDGET(data)->style->
                fg_gc[GTK_WIDGET_STATE (data)],x0,y0,x1,y1);
    }
}
/*工具栏上放大按钮的回调函数,实现将对象放大显示(通过将全局变量width和height的值改变,并修改绘图区显示),
 * 输入参数:工具栏按钮本身enlarge和绘图区构件data,
 * 输出参数:无,
 * 日期:2007-4-7修改*/
void enlarge_obj(GtkWidget *enlarge,GtkWidget *data)
{
    width=width/1.2;
    height=height/1.2;
    draw_prt(data);
}
/*工具栏上缩小按钮的回调函数,实现将对象缩小显示(通过将全局变量width和height的值改变,并修改绘图区显示),
 * 输入参数:工具栏按钮本身deflate和绘图区构件data,
 * 输出参数:无,
 * 日期:2007-4-7修改*/
void deflate_obj(GtkWidget *deflate,GtkWidget *data)
{
    width=width*1.2;
    height=height*1.2;
    draw_prt(data);
}
/*菜单Draw下的Plygon菜单项的回调函数,实现将全局变量draw_type属性为点,并将存放数据信息的链表清空。
 * 输入参数:无
 * 输出参数:无
 * 时间:2007-4-7修改*/
void draw_pix(void)
{
    //清空绘图区
    //设置图象类型
    GSList *iter1=prt;
    while(iter1)
    {
        prt=g_slist_remove_link(prt,iter1);
        g_slist_free(iter1);
        iter1=prt;
    }
    draw_type=PIX_DRAW;

}
/*菜单Draw下的Plygon菜单项的回调函数,实现将全局变量draw_type属性为线,并将存放数据信息的链表清空。
 * 输入参数:无
 * 输出参数:无
 * 时间:2007-4-7修改*/
void draw_line(void)
{
    // 清空绘图区
    GSList *iter1=prt;
        while(iter1)
    {
        prt=g_slist_remove_link(prt,iter1);
        g_slist_free(iter1);
        iter1=prt;
    }
    draw_type=LINE_DRAW;
}
/*菜单Draw下的Plygon菜单项的回调函数,实现将全局变量draw_type属性为圆,并将存放数据信息的链表清空。
 * 输入参数:无
 * 输出参数:无
 * 时间:2007-4-7修改*/
void draw_circle(void)
{
    //
    GSList *iter1=prt;
    while(iter1)
    {
        prt=g_slist_remove_link(prt,iter1);
        g_slist_free(iter1);
        iter1=prt;
    }
    draw_type=CIRCLE_DRAW;
}
/*菜单Draw下的Plygon菜单项的回调函数,实现将全局变量draw_type属性为矩形,并将存放数据信息的链表清空。
 * 输入参数:无
 * 输出参数:无
 * 时间:2007-4-7修改*/
void draw_rect(void)
{
    //
    GSList *iter1=prt;
    while(iter1)
    {
        prt=g_slist_remove_link(prt,iter1);
        g_slist_free(iter1);
        iter1=prt;
    }
    draw_type=RECT_DRAW;
}
/*菜单Draw下的Plygon菜单项的回调函数,实现将全局变量draw_type属性为多边形,并将存放数据信息的链表清空。
 * 输入参数:无
 * 输出参数:无
 * 时间:2007-4-7修改*/
void draw_poly(void)
{
    //
    GSList *iter1=prt;
    while(iter1)
    {
        prt=g_slist_remove_link(prt,iter1);
        g_slist_free(iter1);
        iter1=prt;
    }
    draw_type=POLY_DRAW;
}
/*创建File菜单
 * 输入参数:包含树视图和绘图区的结构体td,
 * 输出参数:菜单项file_item,
 * 日期:2007-4-7修改*/
GtkWidget* create_file_item(tree_drawing *td)
{
    GtkWidget *file_menu;    //定义菜单
    GtkWidget *file_item;
    GtkWidget *new_file,*import_item,*export_item,*quit_item;    //file 菜单下的菜单项
    char *path=malloc(100*sizeof(char));
    //-------------------创建file菜单----------------------------------
    file_menu=gtk_menu_new();                //创建菜单
        /* 创建菜单项 */
    new_file=gtk_menu_item_new_with_label("New");
        import_item = gtk_menu_item_new_with_label ("Import");
        export_item = gtk_menu_item_new_with_label ("Export");
        quit_item = gtk_menu_item_new_with_label ("Quit");
   
        /* 将它们加到菜单中 */
    gtk_menu_append(GTK_MENU(file_menu),new_file);
        gtk_menu_append (GTK_MENU (file_menu),import_item);
        gtk_menu_append (GTK_MENU (file_menu),export_item);
        gtk_menu_append (GTK_MENU (file_menu),quit_item);   
   
        /* 将回调函数绑定到activate信号 */
    g_signal_connect_swapped(G_OBJECT(new_file),"activate",G_CALLBACK(create_file),td->tree_view);
         g_signal_connect_swapped (G_OBJECT (import_item), "activate",G_CALLBACK (import_file),td);
         g_signal_connect_swapped (G_OBJECT (export_item), "activate", G_CALLBACK (export_file),td->tree_view);   
        g_signal_connect_swapped (G_OBJECT (quit_item), "activate",G_CALLBACK (gtk_main_quit),NULL);

    file_item = gtk_menu_item_new_with_label ("File");
    //gtk_widget_set_size_request(GTK_WIDGET(file_item),50,20);
    gtk_menu_item_set_submenu (GTK_MENU_ITEM (file_item), file_menu);

    return file_item;
}
/*创建菜单Draw
 * 输入参数:无
 * 输出参数:菜单项:draw_menu
 * 日期:2007-4-7修改*/
GtkWidget* create_draw_item(void)
{
    GtkWidget *draw_menu;    //定义菜单
    GtkWidget *draw_item;
    GtkWidget *circle_draw,*rect_draw,*polygon_draw,*line_draw,*pixel_draw;

    draw_menu=gtk_menu_new();
    pixel_draw=gtk_menu_item_new_with_label("Pixel");
    line_draw=gtk_menu_item_new_with_label("Line");
    circle_draw=gtk_menu_item_new_with_label("Circle");
    rect_draw=gtk_menu_item_new_with_label("Rectangle");
    polygon_draw=gtk_menu_item_new_with_label("Polygon");

    gtk_menu_append(GTK_MENU(draw_menu),pixel_draw);
    gtk_menu_append(GTK_MENU(draw_menu),line_draw);
    gtk_menu_append(GTK_MENU(draw_menu),circle_draw);
    gtk_menu_append(GTK_MENU(draw_menu),rect_draw);
    gtk_menu_append(GTK_MENU(draw_menu),polygon_draw);

    g_signal_connect_swapped(G_OBJECT(pixel_draw),"activate",G_CALLBACK(draw_pix),NULL);
    g_signal_connect_swapped(G_OBJECT(line_draw),"activate",G_CALLBACK(draw_line),NULL);
    g_signal_connect_swapped(G_OBJECT(circle_draw),"activate",G_CALLBACK(draw_circle),NULL);
    g_signal_connect_swapped(G_OBJECT(rect_draw),"activate",G_CALLBACK(draw_rect),NULL);
    g_signal_connect_swapped(G_OBJECT(polygon_draw),"activate",G_CALLBACK(draw_poly),NULL);

    draw_item=gtk_menu_item_new_with_label("Draw");
    //gtk_widget_set_size_request(GTK_WIDGET(draw_item),50,20);
    gtk_menu_item_set_submenu(GTK_MENU_ITEM(draw_item),draw_menu);

    return draw_item;
}
/*创建工具栏,由于在工具栏中的按钮的回调函数需要修改树视图和绘图区,
 * 所以将树视图和绘图区作为参数传递进来,以便回调函数参数传递
 * 输入参数:包含绘图区和树视图的结构体td
 * 输出参数:工具栏构件handlebox
 * 时间:2007-4-7修改*/
GtkWidget* create_toolbar(tree_drawing *td)
{
    GtkWidget *handlebox;
    GtkWidget *toolbar;
    GtkWidget *new_button,*import_button,*export_button,*quit_button;//工具按钮
    GtkWidget *zoom_out,*zoom_in;
    GtkWidget * iconw;


    handlebox=gtk_handle_box_new();
    toolbar=gtk_toolbar_new();    //设置工具栏格式
    gtk_toolbar_set_orientation (GTK_TOOLBAR (toolbar), GTK_ORIENTATION_HORIZONTAL);
    gtk_toolbar_set_style (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_BOTH);
    gtk_container_set_border_width (GTK_CONTAINER (toolbar), 5);

    new_button=gtk_toolbar_append_item(GTK_TOOLBAR(toolbar),"New","Create a file","Private",NULL,GTK_SIGNAL_FUNC(create_file),td->tree_view);
    import_button=gtk_toolbar_append_item(GTK_TOOLBAR(toolbar),"Import",
            "Import file","Private",NULL,GTK_SIGNAL_FUNC(import_file),td);   
    export_button=gtk_toolbar_append_item(GTK_TOOLBAR(toolbar),"Export",
            "Export file","Private",NULL,GTK_SIGNAL_FUNC(export_file),td->tree_view);   
    iconw=gtk_image_new_from_file("enlarge.png");
    zoom_out=gtk_toolbar_append_item(GTK_TOOLBAR(toolbar),NULL,"zoom out","Private",iconw,GTK_SIGNAL_FUNC(enlarge_obj),td->draw_area);
    gtk_toolbar_append_space(GTK_TOOLBAR(toolbar));

    iconw=gtk_image_new_from_file("deflate.png");
    zoom_in=gtk_toolbar_append_item(GTK_TOOLBAR(toolbar),NULL,"zoom in","Private",iconw,GTK_SIGNAL_FUNC(deflate_obj),td->draw_area);
    quit_button=gtk_toolbar_append_item(GTK_TOOLBAR(toolbar),"Quit",
            "Quit the file","Private",NULL,GTK_SIGNAL_FUNC(gtk_main_quit),NULL);   
    gtk_container_add(GTK_CONTAINER(handlebox),toolbar);

    return handlebox;
}
/*在绘图区中点击鼠标事件的回调函数,
 * 如果点击左键则按照绘图类型将鼠标处的坐标值处理后添加到链表prt中,并调用显示函数,显示图形;
 * 如果是鼠标右键,则将绘图类型设置为FALSE
 * 输入参数:事件盒构件本身event_box,事件:event,绘图区构件:data
 * 输出参数:TURE活FALSE,这个暂时没实际意义
 * 时间:2007-4-7修改*/
static gboolean button_press_callback(GtkWidget *event_box,GdkEventButton *event,GtkWidget *data)
{
   
    if(!draw_type)
    {
        return FALSE;
    }
    /*
if(event->button==2)
{
    gtk_menu_popup()
}   
*/
    if(event->button==3)
    {
        draw_type=FALSE;
    }
    int area_w=100,area_h=100;
    area_w=data->allocation.width;            //获得窗口尺寸
    area_h=data->allocation.height;
    if(event->button==1)
    {
        _2d_point *p=malloc(sizeof(_2d_point));
        p->x=((event->x-area_w/2)*width/area_w);
        p->y=((event->y-area_h/2)*height/area_h);
        prt=g_slist_append(prt,p);
        //printf("%f %f\t,%d,%d\n",p->x,p->y,area_w,area_h);
        GSList *iter1=NULL,*iter2=NULL;
        iter1=prt;
        iter2=prt->next;
        gdk_draw_point(GTK_WIDGET(data)->window,GTK_WIDGET(data)->style->
                fg_gc[GTK_WIDGET_STATE (event_box)],event->x,event->y);
        draw_prt(data);   
    }
    //gdk_drawable_unref(GTK_WIDGET(data)->window);
    return TRUE;
}
/*
static gboolean view_press(GtkWidget *widget,GdkEventButton *event,GtkWidget *menu)
{
      if(event->button==3)
    {
        gtk_menu_popup(GTK_MENU(widget),NULL,NULL,NULL,NULL,event->button,event->time);
    }
}*/
static gboolean
expose_event(GtkWidget *widget, GdkEventExpose *event,gpointer data)
{
    draw_prt(widget);
    return TRUE;
}
gint main(gint argc,char *argv[])
{
    GtkWidget *window;
    GtkWidget *file_item,*draw_item;    /*菜单项*/
    GtkWidget *menu_bar;            /*菜单*/
    GtkWidget *tool_bar;            /*工具栏*/
    GtkWidget *vbox,*hpaned;        /*竖直盒,水平分栏窗口*/
    GtkWidget *view,*event_box,*draw_area;
    GtkWidget *handle_box;            /*手柄构建,用于存放工具按钮*/

    gtk_init(&argc,&argv);
   
    window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_title(GTK_WINDOW(window),"drawing window");
    g_signal_connect(G_OBJECT(window),"destroy",G_CALLBACK(gtk_main_quit),NULL);
    gtk_widget_set_size_request(GTK_WIDGET(window),500,400);
    gtk_container_set_border_width (GTK_CONTAINER (window), 10);
    vbox = gtk_vbox_new (FALSE, 0);            /*创建主竖直盒*/
    gtk_container_add (GTK_CONTAINER (window), vbox);
    gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER);/*将窗口的显示位置设定为屏幕中央*/

    draw_area=gtk_drawing_area_new();/*由于这两个构件需要作为其它构件回调函数的参数,所以先在这里创建*/
    view=(GtkWidget*)create_tree();
    tree_drawing *td=malloc(sizeof(tree_drawing));/*定义结构体,以便回调函数调用*/
    td->tree_view=view;
    td->draw_area=draw_area;
    /*======================== 添加菜单 =====================================    */
    menu_bar = gtk_menu_bar_new ();
    gtk_box_pack_start(GTK_BOX(vbox),menu_bar,FALSE,FALSE,3);
    file_item=create_file_item(td);                //调用自定义创建菜单file的函数
    gtk_menu_bar_append (GTK_MENU_BAR (menu_bar), file_item);
    draw_item=create_draw_item();
    gtk_menu_bar_append(GTK_MENU_BAR(menu_bar),draw_item);
    /*
    GtkWidget *pop_up;
    pop_up=pop_menu(draw_area);
    */
    /*========================= 添加工具栏 =================================*/
    handle_box=create_toolbar(td);            /*调用自定义函数创建工具栏,由于工具栏中的按钮需要改变绘图区和树视图,所以需要将绘图区和树视图作为参数进行传递*/
    gtk_box_pack_start(GTK_BOX(vbox),handle_box,FALSE,FALSE,3);

    /*========================= 添加树视图 ==========================================*/
    hpaned=gtk_hpaned_new();            /*创建水平分栏窗口*/
    gtk_box_pack_start(GTK_BOX(vbox),hpaned,TRUE,TRUE,3);
    //g_signal_connect_swapped(G_OBJECT(view),"event",G_CALLBACK(view_press),pop_up);//添加右键菜单

    gtk_paned_add1(GTK_PANED(hpaned),view);

    /*========================== 添加绘图区 =========================================*/
    event_box=gtk_event_box_new();            //添加eventbox以便鼠标响应
    gtk_paned_add2(GTK_PANED(hpaned),event_box);
    gtk_container_add(GTK_CONTAINER(event_box),draw_area);
   
    /*-----------test - color------*/
    GdkColor color;
    color.red=55000;
    color.blue=55000;
    color.green=55000;
    gtk_widget_modify_bg(draw_area,GTK_STATE_NORMAL,&color);    /*设置背景颜色*/
    GdkColor colorf;
    colorf.red=0;
    colorf.blue=65535;
    colorf.green=0;
    gtk_widget_modify_fg(draw_area,GTK_STATE_NORMAL,&colorf);    /*设置前景颜色*/
    g_signal_connect(G_OBJECT(event_box),"button_press_event",G_CALLBACK(button_press_callback),draw_area);
    g_signal_connect(G_OBJECT(draw_area),"expose_event",G_CALLBACK(expose_event),NULL);
    //-----------------------------

    gtk_widget_show_all(window);
    width=draw_area->allocation.width;            /*获得绘图区尺寸,并赋值给全局变量width和height*/
    height=draw_area->allocation.height;   
    gtk_main();

    return 0;
}




下面是编译命令:

$> gcc -o main `pkg-config --cflags --libs gtk+-2.0 glib-2.0` soft.c

编译完成之后将图标enlarge.png和deflate.png拷贝到同一目录下即可执行了。界面如下:

关于使用方面的这里介绍一点,打开后,点击菜单Draw,然后选中对应类型就可以在绘图区绘制了,也可以导入对象,导入文件的格式全部为.124格式( :),自己随便定义的格式),若想保存,应该首先新建,然后绘制,绘制完毕之后,选中树视图中的对象名,点击export工具图标即可导出,导入时只需输入文件名,不需要扩展名(切记),在绘图时不要点击右键,右键将清空绘图。当然了,放大/缩小图标就是用来放大缩小用的。

 

Avatar_small
spmno 说:
2007年11月21日 17:36 写的不错,值得一看.谢谢.
Avatar_small
嘉谟 说:
2011年3月09日 16:39

我想写一个gtk 显示并发的进程

这个进程 每次从共享缓冲区获得一个值
窗口就是要 当它获得之后 就答应出来

gtk 可以实现不?

Avatar_small
NCERT 8th Class Solu 说:
2022年9月09日 04:04

Those Secondary Education Class VIII Standard students can download subject wise solutions in chapter wide for all subjects of the course introduced by the school education department for Hindi medium, English medium, NCERT 8th Class Solutions Urdu medium students designed and suggested by the National Council of Educational Research and Training (NCERT).The NCERT has introduced those Secondary education STD-8 subject wide answer solutions for Term-1, Term-2, Term-3, Term-4 in session wide for Session-1 & Session-2 (Part-A and Part-B) exams and published at their official web portals of NCERT & ePathshala, and various private websites also shared to the class 8th standard students studying at all regions of the country.

Avatar_small
pavzi.com 说:
2024年1月24日 23:42

Pavzi website is a multiple Niche or category website which will ensure to provide information and resources on each and every topic. Some of the evergreen topics you will see on our website are Career, Job Recruitment, Educational, Technology, Reviews and others. pavzi.com We are targeting mostly so it is true that Tech, Finance, and Product Reviews. The only reason we have started this website is to make this site the need for your daily search use.


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter