gpt4 book ai didi

c - 使用 gtk 的多线程进度条控制

转载 作者:太空宇宙 更新时间:2023-11-03 23:36:31 26 4
gpt4 key购买 nike

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

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

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

i create UI with glade3. GtkTreeViewhave 3 columns

  1. Name
  2. Progress
  3. Status

我写了一些代码,它可以工作但有一些问题

如果我下载一个文件,应用程序会很不错。

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

app 一次只显示两个线程

我该如何解决?

progress.glade

和源代码:

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

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

更新: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;
}

最佳答案

以下是让您的代码正常工作的提示:

  1. 如果库有 pkg​​-config 文件,例如 gthread 或 libcurl,则使用它而不是混合调用 pkg-config 和 -l 开关。这不是问题所在,但以后可能会给您带来麻烦。所以像这样编译你的文件:

    gcc -Wall -g `pkg-config --cflags --libs gtk+-2.0 gmodule-export-2.0 gthread-2.0 libcurl` liststore.c -o liststore
  2. 如果使用线程,总是,总是,总是,将对 gtk_main() 的调用包装在 gdk_threads_enter()gdk_threads_leave()。这也不是问题所在,但以后肯定会给您带来麻烦。

  3. 下一步,消除控制台中喷涌而出的所有警告。如果错误生成的警告未在其他 50 条警告中丢失,则更容易发现错误。这些警告 确实 意味着您做错了什么,所以不要忽略它们。

    一个。我收到的第一个警告是提示 NaN。 NaN 代表“不是数字”,它是除以零时得到的结果。您的代码中唯一的划分是在 my_progress_func() 中,因此 CURL 有时可能会传入零作为 dltotal 参数。如果您检查它,它会消除这些警告:

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

    下一个警告原因是 thread_create() 末尾的 unref 语句。您正在做的是使用 gtk_tree_view_get_model() 从 TreeView 中获取模型,但这并没有为您提供模型的引用。因此,当您取消引用它时,您实际上是在破坏模型,而 TreeView 仍在使用它。删除该语句,所有警告都会神奇地消失。您根本不需要取消引用模型。 TreeView 拥有对它的唯一引用,当 TreeView 被销毁时,它会自动取消对模型的引用。不过,这仍然不是问题。

  4. 现在一切都已解决,您可以确定问题不是由某些无效指针或线程问题引起的。事实证明这毕竟是一件非常简单的事情:

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

    在这里,您总是得到一个指向行号 0 的 iter,即第一行。这就是为什么所有下载进度都显示在第一行的原因。我建议使用 GPrivate 来让每线程数据结构具有自己的进度分数,并为您在启动线程时创建的行使用 GtkTreeRowReference。获取 CURL 以将该数据结构发送到回调。 不要使用GtkTreeIterGtkTreePath 来存储行。相反,像这样获取你的 GtkTreeIter:

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

祝你好运。

关于c - 使用 gtk 的多线程进度条控制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1878783/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com