C 使用gtk控制多线程进度条

C 使用gtk控制多线程进度条,c,curl,gtk,glade,C,Curl,Gtk,Glade,在我的C程序中,从internet下载一些文件,我使用GTK进度条显示下载进度 我想如果我下载一个文件,我的应用程序会显示一个进度条 如果我下载三个文件,我的应用程序可以显示三个进度条。其余的都可以用同样的方式完成 我用glade3创建UI。GtkTreeView 有3列 名字 进展 地位 我写了一些代码,它可以工作,但有一些问题 如果我下载一个文件,应用程序lonking还不错 但如果我下载两个文件。 应用程序无法显示两个进度条 应用程序只显示一个进程中的两个线程 我该如何解决它 和源代码:

在我的C程序中,从internet下载一些文件,我使用GTK进度条显示下载进度

我想如果我下载一个文件,我的应用程序会显示一个进度条

如果我下载三个文件,我的应用程序可以显示三个进度条。其余的都可以用同样的方式完成

我用glade3创建UI。GtkTreeView 有3列

  • 名字
  • 进展
  • 地位
  • 我写了一些代码,它可以工作,但有一些问题

    如果我下载一个文件,应用程序lonking还不错

    但如果我下载两个文件。 应用程序无法显示两个进度条

    应用程序只显示一个进程中的两个线程

    我该如何解决它

    和源代码:

    /*
    gcc -Wall -g `pkg-config --cflags --libs gtk+-2.0 gmodule-export-2.0` -lcurl -lgthread-2.0  liststore.c -o liststore
     */
    #include <stdio.h>
    #include <gtk/gtk.h>
    #include <glib.h>
    #include <unistd.h>
    #include <pthread.h>
    
    #include <curl/curl.h>
    #include <curl/types.h> /* new for v7 */
    #include <curl/easy.h> /* new for v7 */
    
    gchar *URL = "http://soundclash-records.co.uk/mp3s/upfull_rockers_never_gonna_let_you_down.mp3";
    
    size_t my_write_func(void *ptr, size_t size, size_t nmemb, FILE *stream)
    {
        return fwrite(ptr, size, nmemb, stream);
    }
    
    size_t my_read_func(void *ptr, size_t size, size_t nmemb, FILE *stream)
    {
        return fread(ptr, size, nmemb, stream);
    }
    
    typedef struct _Data Data;
    struct _Data
    {
        GtkWidget *down; /* Down button */
        GtkWidget *tree; /* Tree view */
        gdouble progress;
    };
    
    enum
    {
        STRING_COLUMN,
        INT_COLUMN,
        N_COLUMNS
    };
    
    gboolean set_download_progress(gpointer data)
    {
        Data *treeview = (Data *)data;
        GtkListStore* store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(treeview->tree)));
        GtkTreeIter iter;
    
        gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (store) ,
                                           &iter,
                                           g_strdup_printf ("%d",0));   
        gtk_list_store_set(store, &iter,
                           INT_COLUMN,treeview->progress, -1);
        
        return FALSE;
    }
    
    int my_progress_func(Data *data,
                         double t, /* dltotal */
                         double d, /* dlnow */
                         double ultotal,
                         double ulnow)
    {
    //  printf("%d / %d (%g %%)\n", d, t, d*100.0/t);
        gdk_threads_enter();
        gdouble progress;
        progress = d*100.0/t;
        data->progress = progress;
        g_idle_add(set_download_progress, data);
    
        gdk_threads_leave();
        return 0;
    }
    
    void *create_thread(void *data)
    {
        Data *viewtree = (Data *)data;
        GtkTreeIter iter;
      
        GtkListStore* store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(viewtree->tree)));
        gtk_list_store_append( store, &iter );
     
        
        g_print("url\n");
        CURL *curl;
        CURLcode res;
        FILE *outfile;
        gchar *url = URL;
    
        curl = curl_easy_init();
        if(curl)
        {
            outfile = fopen("test.curl", "w");
            if(outfile)
                g_print("curl\n");
    
            curl_easy_setopt(curl, CURLOPT_URL, url);
            curl_easy_setopt(curl, CURLOPT_WRITEDATA, outfile);
            curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, my_write_func);
            curl_easy_setopt(curl, CURLOPT_READFUNCTION, my_read_func);
            
            curl_easy_setopt(curl, CURLOPT_NOPROGRESS, FALSE);
            curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, my_progress_func);
            curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, data);
    
            res = curl_easy_perform(curl);
    
            fclose(outfile);
            /* always cleanup */
            curl_easy_cleanup(curl);
        }
        g_object_unref( G_OBJECT( store ) );
        return NULL;
    }
    
    
    G_MODULE_EXPORT void
    cb_add( GtkWidget *button,
             Data      *data )
    {
        if (!g_thread_create(&create_thread, data, FALSE, NULL) != 0)
            g_warning("can't create the thread");
    } 
    int main(int argc, char **argv)
    {
        GtkBuilder *builder;
        GtkWidget  *window;
        Data       *data;
    
    
        curl_global_init(CURL_GLOBAL_ALL);
        if( ! g_thread_supported() )
            g_thread_init( NULL );
    
        gdk_threads_init();
        gtk_init(&argc, &argv);
    
        data = g_slice_new( Data );
    
        /* Create builder */
        builder = gtk_builder_new();
        gtk_builder_add_from_file( builder, "progress.glade", NULL );
    
        window    = GTK_WIDGET( gtk_builder_get_object( builder, "window1" ) );
        data->down   = GTK_WIDGET( gtk_builder_get_object( builder, "down" ) );
        data->tree = GTK_WIDGET( gtk_builder_get_object( builder, "treeview" ) );
    
        gtk_builder_connect_signals( builder, data );
        g_object_unref( G_OBJECT( builder ) );
    
        gtk_widget_show( window );
    
        gtk_main();
        g_slice_free( Data, data );
    
        return 0;
    }
    
    /*
    gcc-Wall-g`pkg config--cflags--libs gtk+-2.0 gmodule-export-2.0`-lcurl-lgthread-2.0 liststore.c-o liststore
    */
    #包括
    #包括
    #包括
    #包括
    #包括
    #包括
    #包括/*v7的新功能*/
    #包括/*v7的新功能*/
    gchar*URL=”http://soundclash-records.co.uk/mp3s/upfull_rockers_never_gonna_let_you_down.mp3";
    大小\我的写入\函数(void*ptr、大小\ t size、大小\ t nmemb、文件*流)
    {
    返回fwrite(ptr、大小、nmemb、流);
    }
    大小为my\u read\u func(无效*ptr,大小为,大小为nmemb,文件为*流)
    {
    返回fread(ptr、大小、nmemb、流);
    }
    typedef结构数据;
    结构数据
    {
    GtkWidget*向下;/*向下按钮*/
    GtkWidget*树;/*树视图*/
    双倍进步;
    };
    枚举
    {
    字符串_列,
    INT_栏,
    N_列
    };
    gboolean设置\下载\进度(gpointer数据)
    {
    数据*树视图=(数据*)数据;
    GtkListStore*store=GTK_列表_存储(GTK_树视图_获取模型(GTK_树视图(treeview->tree)));
    GtkTreeIter iter;
    gtk_树模型从字符串获取iter_(gtk_树模型(存储),
    &国际热核聚变实验堆,
    g_strdup_printf(“%d”,0));
    gtk_列表_存储_集(存储和iter,
    INT_列,树状视图->进度,-1);
    返回FALSE;
    }
    int my_progress_func(数据*数据,
    双t,/*dltotal*/
    双d,/*dlnow*/
    双ultotal,
    双ulnow)
    {
    //printf(“%d/%d(%g%%)\n”,d,t,d*100.0/t);
    gdk_threads_enter();
    双倍进步;
    进度=d*100.0/t;
    数据->进度=进度;
    g\u空闲\u添加(设置\u下载\u进度、数据);
    gdk_线程_离开();
    返回0;
    }
    void*创建线程(void*数据)
    {
    数据*视图树=(数据*)数据;
    GtkTreeIter iter;
    GtkListStore*store=GTK_列表_存储(GTK_树视图_获取模型(GTK_树视图(viewtree->tree)));
    gtk列表、存储、附加(存储和iter);
    g_print(“url\n”);
    卷曲*卷曲;
    卷曲编码;
    文件*输出文件;
    gchar*url=url;
    curl=curl_easy_init();
    if(curl)
    {
    outfile=fopen(“测试卷曲度”,“w”);
    如果(输出文件)
    g_print(“curl\n”);
    curl_easy_setopt(curl,CURLOPT_URL,URL);
    curl_easy_setopt(curl,CURLOPT_WRITEDATA,outfile);
    curl\u easy\u setopt(curl,CURLOPT\u WRITEFUNCTION,my\u write\u func);
    curl\u easy\u setopt(curl,CURLOPT\u READFUNCTION,my\u read\u func);
    curl\u easy\u setopt(curl,CURLOPT\u NOPROGRESS,FALSE);
    curl\u easy\u setopt(curl,CURLOPT\u PROGRESSFUNCTION,my\u progress\u func);
    curl_easy_setopt(curl,CURLOPT_PROGRESSDATA,data);
    res=旋度(curl)\u容易执行(curl);
    fclose(输出文件);
    /*总是清理*/
    旋度\轻松\清洁(旋度);
    }
    g_object_unref(g_object(store));
    返回NULL;
    }
    G_模块_导出无效
    cb_添加(GtkWidget*按钮,
    数据*数据)
    {
    如果(!g_thread_create(&create_thread,data,FALSE,NULL)!=0)
    g_警告(“无法创建线程”);
    } 
    int main(int argc,字符**argv)
    {
    GtkBuilder*builder;
    GtkWidget*窗口;
    数据*数据;
    curl\u global\u init(curl\u global\u ALL);
    如果(!g_thread_supported())
    g_thread_init(NULL);
    gdk_线程_init();
    gtk_init(&argc,&argv);
    数据=g_切片_新(数据);
    /*创建生成器*/
    builder=gtk_builder_new();
    gtk_builder_从_文件添加_(builder,“progress.glade”,NULL);
    窗口=GTK_小部件(GTK_生成器_获取对象(生成器,“窗口1”);
    data->down=GTK_小部件(GTK_builder_get_对象(builder,“down”));
    数据->树=GTK_小部件(GTK_生成器_获取_对象(生成器,“树视图”));
    gtk建筑商连接信号(建筑商,数据);
    g_object_unref(g_object(builder));
    gtk_widget_show(窗口);
    gtk_main();
    g_片_自由(数据,数据);
    返回0;
    }
    
    =========================================================

    更新:12-11-09

    /*
    gcc -Wall -g `pkg-config --cflags --libs gtk+-2.0 gmodule-export-2.0 gthread-2.0 libcurl` liststore2.c -o liststore2
     */
    #include <stdio.h>
    #include <gtk/gtk.h>
    #include <glib.h>
    #include <unistd.h>
    #include <pthread.h>
    
    #include <curl/curl.h>
    #include <curl/types.h> /* new for v7 */
    #include <curl/easy.h> /* new for v7 */
    
    gchar *URL = "http://soundclash-records.co.uk/mp3s/upfull_rockers_never_gonna_let_you_down.mp3";
    static GHashTable* TreeRowReferences;
    static GPrivate* current_data_key = NULL;
    
    size_t my_write_func(void *ptr, size_t size, size_t nmemb, FILE *stream)
    {
        return fwrite(ptr, size, nmemb, stream);
    }
    
    size_t my_read_func(void *ptr, size_t size, size_t nmemb, FILE *stream)
    {
        return fread(ptr, size, nmemb, stream);
    }
    
    typedef struct _Data Data;
    struct _Data
    {
        GtkWidget *down; /* Down button */
        GtkWidget *tree; /* Tree view */
        gdouble progress;
    };
    
    enum
    {
        STRING_COLUMN,
        INT_COLUMN,
        N_COLUMNS
    };
    
    gboolean set_download_progress(gpointer data)
    {
        Data *treeview = (Data *)data;
    
        GtkListStore* store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(treeview->tree)));
        GtkTreeIter iter;
    
        GtkTreeRowReference* reference = g_hash_table_lookup(TreeRowReferences,data);
    
        GtkTreePath* path = gtk_tree_row_reference_get_path(reference);
    
        gtk_tree_model_get_iter(GTK_TREE_MODEL(store), 
                        &iter, path);
                               
        gtk_list_store_set(store, &iter,
                           INT_COLUMN,treeview->progress, -1);
    
        gtk_tree_path_free (path);
        return FALSE;
    }
    
    int my_progress_func(Data *data,
                 double t, /* dltotal */
                 double d, /* dlnow */
                 double ultotal,
                 double ulnow)
    {
        if(t == 0)
            return 0;
        data->progress = d*100.0/t;
    
        gdk_threads_enter();
        g_idle_add(set_download_progress, data);
        gdk_threads_leave();
        return 0;
    }
    
    void *create_thread(void *data)
    {
        
        Data *current_treeview = g_private_get (current_data_key);
    
        if (!current_treeview)
        {
          current_treeview = g_new (Data, 1);
          current_treeview = (Data *)data;
          g_private_set (current_data_key, current_treeview);
          g_print("p %g\n",current_treeview->progress);
        }
        else{
            current_treeview = (Data *)data;
            g_print("c %g\n",current_treeview->progress);
        }
    
        g_print("url\n");
        CURL *curl;
        CURLcode res;
        FILE *outfile;
        gchar *url = URL;
        gdk_threads_enter();
        curl = curl_easy_init();
        if(curl)
        {
            outfile = fopen("test.curl", "w");
            if(outfile)
                g_print("curl\n");
    
            curl_easy_setopt(curl, CURLOPT_URL, url);
            curl_easy_setopt(curl, CURLOPT_WRITEDATA, outfile);
            curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, my_write_func);
            curl_easy_setopt(curl, CURLOPT_READFUNCTION, my_read_func);
            
            curl_easy_setopt(curl, CURLOPT_NOPROGRESS, FALSE);
            curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, my_progress_func);
            curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, current_treeview);
            gdk_threads_leave();
            res = curl_easy_perform(curl);
    
            fclose(outfile);
            /* always cleanup */
            curl_easy_cleanup(curl);
        }
        return NULL;
    }
    
    
    G_MODULE_EXPORT void
    cb_add( GtkWidget *button,
             Data      *data )
    {    
        Data *current_download = (Data *)data;
        GtkTreeIter iter;
        GtkListStore* store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(current_download->tree)));
        gtk_list_store_append( store, &iter );
    
        GtkTreeRowReference* reference = NULL;
        GtkTreePath* path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iter);
        reference = gtk_tree_row_reference_new(GTK_TREE_MODEL(store), path);
        g_hash_table_insert(TreeRowReferences, current_download, reference);
        gtk_tree_path_free(path);
    
        if (!g_thread_create(&create_thread, current_download, FALSE, NULL) != 0)
            g_warning("can't create the thread");
    } 
    
    int main(int argc, char **argv)
    {
        GtkBuilder *builder;
        GtkWidget  *window;
        Data       *data;
    
    
        curl_global_init(CURL_GLOBAL_ALL);
        if( ! g_thread_supported() )
            g_thread_init( NULL );
    
        gdk_threads_init();
        gtk_init(&argc, &argv);
    
        data = g_slice_new( Data );
    
        /* Create builder */
        builder = gtk_builder_new();
        gtk_builder_add_from_file( builder, "progress.glade", NULL );
    
        window    = GTK_WIDGET( gtk_builder_get_object( builder, "window1" ) );
        data->down   = GTK_WIDGET( gtk_builder_get_object( builder, "down" ) );
        data->tree = GTK_WIDGET( gtk_builder_get_object( builder, "treeview" ) );
        TreeRowReferences = g_hash_table_new(NULL, NULL);
    
        gtk_builder_connect_signals( builder, data );
        g_object_unref( G_OBJECT( builder ) );
    
        gdk_threads_enter();
        gtk_widget_show( window );
        gdk_threads_leave();
    
        gtk_main();
        g_slice_free( Data, data );
    
        return 0;
    }
    
    /*
    gcc-Wall-g`pkg config--cflags--libs gtk+-2.0 gmodule-export-2.0 gthread-2.0 libcurl`liststore2.c-o liststore2
    */
    #包括
    #包括
    #包括
    #包括
    #包括
    #包括
    #包括/*v7的新功能*/
    #包括/*v7的新功能*/
    gchar*URL=”http://soundclash-records.co.uk/mp3s/upfull_rockers_never_gonna_let_you_down.mp3";
    静态GHashTable*树引用;
    静态GPrivate*当前数据密钥=NULL;
    大小\我的写入\函数(void*ptr、大小\ t size、大小\ t nmemb、文件*流)
    {
    返回fwrite(ptr、大小、nmemb、流);
    }
    大小为my\u read\u func(无效*ptr,大小为,大小为nmemb,文件为*流)
    {
    返回fread(ptr、大小、nmemb、流);
    }
    typedef结构数据;
    结构数据
    {
    GtkWidget*向下;/*向下按钮*/
    GtkWidget*树;/*树视图*/
    双倍进步;
    };
    枚举
    {
    字符串_列,
    INT_栏,
    N_列
    };
    gboolean设置\下载\进度(gpointer数据)
    {
    数据*树视图=(数据*)数据;
    GtkListStore*store=GTK_列表_存储(GTK_树视图_获取模型(GTK_树视图(treeview->tree)));
    GtkTreeIter iter;
    GtkTreeRowReference*reference=g_哈希_表_查找(树引用,数据);
    GtkTreePath*path=gtk_树_行_参考_获取_路径(参考);
    gtk_tree_mo
    
    gcc -Wall -g `pkg-config --cflags --libs gtk+-2.0 gmodule-export-2.0 gthread-2.0 libcurl` liststore.c -o liststore
    
    int my_progress_func(Data *data,
                 double t, /* dltotal */
                 double d, /* dlnow */
                 double ultotal,
                 double ulnow)
    {
        if(t == 0)
            return 0;
        data->progress = d*100.0/t;
        gdk_threads_enter();
        g_idle_add(set_download_progress, data);
        gdk_threads_leave();
        return 0;
    }
    
    gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (store) ,
                                         &iter,
                                         g_strdup_printf ("%d",0));
    
    gtk_tree_model_get_iter(gtk_tree_row_reference_get_model(row_reference), &iter, gtk_tree_row_reference_get_path(row_reference));