Frage

in meinem C-Programm, laden Sie einige Dateien aus dem Internet, im mit einem GTK Fortschrittsbalken mit dem Download-Fortschritt zu zeigen.

ich will, wenn ich eine Datei herunterladen, meine app einen Fortschrittsbalken zeigen

, wenn ich drei Dateien herunterladen, können meine app drei Fortschrittsbalken zeigen. der Rest kann auf die gleiche Weise durchgeführt werden.

  

i erstellen UI mit glade3. GtkTreeView   haben 3 Spalten

     
      
  1. Name
  2.   
  3. Fortschritt
  4.   
  5. Status
  6.   

, und ich schrieb einige Code, kann seine Arbeit aber ein Problem haben

, wenn ich eine Datei herunterladen, app Lonking nicht schlecht.

aber wenn ich herunterladen zwei Dateien. App konnte nicht twoprogress bar anzeigen.

app zeigt nur zwei Thread in einem Fortschritt

Wie soll ich es lösen?

progress.glade

und der Quellcode:

/*
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;
}

=============================================== ==========

Update: 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;
}
War es hilfreich?

Lösung

Hier sind meine Tipps für Ihren Code immer zu arbeiten:

  1. Wenn es eine pkg-config-Datei für eine Bibliothek ist, wie gthread oder Libcurl, verwenden Sie dann, dass statt pkg-config Anrufe und -l Schalter der Vermischung. Dies war nicht das Problem, aber es könnte Probleme geben später. So kompilieren Sie Ihre Datei wie folgt:

    gcc -Wall -g `pkg-config --cflags --libs gtk+-2.0 gmodule-export-2.0 gthread-2.0 libcurl` liststore.c -o liststore
    
  2. Wenn Threads, immer, immer, immer , wickeln Sie Ihren Anruf gtk_main() und gdk_threads_enter() gdk_threads_leave() dazwischen. Dies war nicht das Problem auch nicht, aber es wird auf jeden Fall geben Sie Probleme später.

  3. Der nächste Schritt, beseitigen alle Warnungen auf der ganzen Konsole spuckt. Es ist einfacher, einen Fehler zu erkennen, wenn die Warnung erzeugt sie nicht in 50 anderen Warnungen verloren. Und diese Warnungen tun meinen Sie etwas falsch machen, so sie nicht ignorieren.

    a. Die ersten Warnungen Ich habe beschwerten sich über NaNs. NaN steht für „keine Zahl“, und es ist das, was Sie bekommen, wenn Sie durch Null teilen. Die einzige Abteilung in Ihrem Code ist in my_progress_func() wahrscheinlich so CURL geht manchmal in Null als dltotal Parameter. Wenn Sie, dass der Check, beseitigt diese Warnungen:

    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;
    }
    

    b. Die nächste Ursache der Warnungen ist die unref Aussage am Ende des thread_create(). Was Sie tun, ist gtk_tree_view_get_model() mit dem Modell aus der Baumansicht zu bekommen, aber das macht man nicht einen Verweis auf das Modell geben. Also, wenn Sie es UNREF, Sie zerstören tatsächlich das Modell während der Baumansicht noch es verwendet, ist. Löschen diese Aussage, und alle Warnungen auf magische Weise verschwinden. Sie brauchen nicht das Modell überhaupt UNREF. Die Baumansicht besitzt den einzigen Hinweis darauf, und wenn die Baumansicht zerstört wird es das Modell automatisch UNREF. Das ist noch nicht das Problem aber.

  4. Alles, was jetzt aus dem Weg ist, können Sie sicher sein, das Problem wird durch ein ungültiges Zeiger oder Thread Problem nicht verursacht wird. Und es stellt sich heraus, etwas ganz einfach nach allem sein:

    gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (store) ,
                                         &iter,
                                         g_strdup_printf ("%d",0));
    

    Hier werden Sie immer bekommen eine iter Zeigenummer Zeile 0, das heißt die erste Zeile. Und das ist, warum alle der Download-Fortschritt in der ersten Zeile erscheint. Ich würde mit GPrivate empfehlen eine pro Thread Datenstruktur mit einem eigenen Fortschritt Fraktion zu haben, und eine GtkTreeRowReference auf die Zeile, die Sie erstellen, wenn Sie den Thread zu starten. Erhalten Sie ROTATION, dass die Datenstruktur an die Callback zu senden. nicht verwenden, um ein GtkTreeIter oder GtkTreePath die Zeile zu speichern. Stattdessen erhalten Ihre GtkTreeIter wie folgt aus:

    gtk_tree_model_get_iter(gtk_tree_row_reference_get_model(row_reference), &iter, gtk_tree_row_reference_get_path(row_reference));
    

Viel Glück.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top