2011-07-23 27 views
1
// gcc -o 0 $(pkg-config --cflags --libs gtk+-2.0) 1.c 
#include <gtk/gtk.h> 
#include <gdk/gdkkeysyms.h> 
struct tst 
{ 
    GtkWidget *win, *w2, *hb, *vb, *ent, *btn, *b2, *pbar; 
    GtkAccelGroup *acc; 
}; 
GCancellable *can1; 
GError *err1; 
GThread *t1; 
static void t1_stop (struct tst *prg) 
{ 
    g_cancellable_cancel (can1); 
    can1 = NULL; 
} 
gpointer t1_do (gpointer ptr1) 
{ 
    struct tst *prg = (gpointer)ptr1; 
    g_file_copy (g_file_new_for_path ("/1.avi"), g_file_new_for_path ("/2.avi"), G_FILE_COPY_NOFOLLOW_SYMLINKS, can1, NULL, NULL, &err1); 
    if (err1 != NULL) g_error_free (err1); 
    gtk_widget_destroy (prg->w2); 
} 
static void window_pbar (struct tst *prg) 
{ 
    prg->w2 = gtk_window_new (GTK_WINDOW_TOPLEVEL); 
    prg->hb = gtk_hbox_new (FALSE, 0); 
    prg->pbar = gtk_progress_bar_new(); 
    prg->b2 = gtk_button_new_with_label ("Cancel"); 
    gtk_container_add (GTK_CONTAINER (prg->w2), GTK_WIDGET (prg->hb)); 
    gtk_window_set_position (GTK_WINDOW (prg->w2), GTK_WIN_POS_CENTER); 
    gtk_box_pack_start (GTK_BOX (prg->hb), GTK_WIDGET (prg->pbar), FALSE, FALSE, 0); 
    gtk_box_pack_start (GTK_BOX (prg->hb), GTK_WIDGET (prg->b2), FALSE, FALSE, 0); 
    g_signal_connect_swapped (prg->w2, "delete_event", G_CALLBACK (t1_stop), prg); 
    g_signal_connect_swapped (prg->b2, "clicked", G_CALLBACK (t1_stop), prg); 
    gtk_widget_show_all (GTK_WIDGET (prg->w2)); 
    can1 = g_cancellable_new(); 
    err1 = NULL; 
    t1 = g_thread_create (t1_do, (gpointer)prg, TRUE, NULL); 
} 
static void window_new() 
{ 
    struct tst *prg = g_new0 (struct tst, 1); 
    prg->win = gtk_window_new (GTK_WINDOW_TOPLEVEL); 
    prg->vb = gtk_vbox_new (FALSE, 0); 
    prg->btn = gtk_button_new_with_label ("start"); 
    gtk_container_add (GTK_CONTAINER (prg->win), GTK_WIDGET (prg->vb)); 
    gtk_box_pack_start (GTK_BOX (prg->vb), GTK_WIDGET (prg->btn), FALSE, FALSE, 0); 
    g_signal_connect (prg->win, "delete_event", G_CALLBACK (gtk_main_quit), NULL); 
    g_signal_connect_swapped (prg->btn, "clicked", G_CALLBACK (window_pbar), prg); 
    gtk_window_set_title (GTK_WINDOW (prg->win), "Test program"); 
    gtk_window_set_position (GTK_WINDOW (prg->win), GTK_WIN_POS_CENTER); 
    gtk_widget_show_all (GTK_WIDGET (prg->win)); 
    gtk_main(); 
} 
int main (int argc, char *argv[]) 
{ 
    gtk_init (&argc, &argv); 
    window_new(); 
    return 0; 
} 

このプログラムは一例です。 'スタート'ボタンをクリックするとプログレスバーとキャンセルボタンがあるウィンドウが作成され、/1.aviを/2.aviにコピーするスレッドが作られますが、/1.aviはプログラムが存在しないためです「エラー!」と表示されます。プログレスバーのウィンドウを閉じます。 しかし、このプログラムには1つの問題があります。私は、プログラムが何か別のエラーメッセージを端末に書き込むと、何度も '開始'ボタンを何度かクリックしています。時にはメッセージはGDK、時にはGObjectについてのもの、時にはGTK +に関するものもあります。そして時にはプログラム自体がフリーズまたはクラッシュします。GThreadとファイルコピーに関する問題

// gcc -o 0 $(pkg-config --cflags --libs gtk+-2.0) 1.c 
#include <gtk/gtk.h> 
#include <gdk/gdkkeysyms.h> 
struct tst 
{ 
    GtkWidget *win, *w2, *hb, *vb, *ent, *btn, *b2, *pbar; 
    GtkAccelGroup *acc; 
}; 
GCancellable *can1; 
GError *err1; 
GThread *t1; 
static void t1_stop (struct tst *prg) 
{ 
    g_cancellable_cancel (can1); 
    can1 = NULL; 
} 
gpointer t1_do (gpointer ptr1) 
{ 
    struct tst *prg = (gpointer)ptr1; 
    g_file_copy (g_file_new_for_path ("/1.avi"), g_file_new_for_path ("/2.avi"), G_FILE_COPY_NOFOLLOW_SYMLINKS, can1, NULL, NULL, &err1); 
    if (err1 != NULL) g_error_free (err1); 
    gtk_widget_destroy (prg->w2); 
} 
static void window_pbar (struct tst *prg) 
{ 
    prg->w2 = gtk_window_new (GTK_WINDOW_TOPLEVEL); 
    prg->hb = gtk_hbox_new (FALSE, 0); 
    prg->pbar = gtk_progress_bar_new(); 
    prg->b2 = gtk_button_new_with_label ("Cancel"); 
    gtk_container_add (GTK_CONTAINER (prg->w2), GTK_WIDGET (prg->hb)); 
    gtk_window_set_position (GTK_WINDOW (prg->w2), GTK_WIN_POS_CENTER); 
    gtk_box_pack_start (GTK_BOX (prg->hb), GTK_WIDGET (prg->pbar), FALSE, FALSE, 0); 
    gtk_box_pack_start (GTK_BOX (prg->hb), GTK_WIDGET (prg->b2), FALSE, FALSE, 0); 
    g_signal_connect_swapped (prg->w2, "delete_event", G_CALLBACK (t1_stop), prg); 
    g_signal_connect_swapped (prg->b2, "clicked", G_CALLBACK (t1_stop), prg); 
    gtk_widget_show_all (GTK_WIDGET (prg->w2)); 
    can1 = g_cancellable_new(); 
    err1 = NULL; 
    t1 = g_thread_create (t1_do, (gpointer)prg, TRUE, NULL); 
    g_thread_join (t1); 
} 
static void window_new() 
{ 
    struct tst *prg = g_new0 (struct tst, 1); 
    prg->win = gtk_window_new (GTK_WINDOW_TOPLEVEL); 
    prg->vb = gtk_vbox_new (FALSE, 0); 
    prg->btn = gtk_button_new_with_label ("start"); 
    gtk_container_add (GTK_CONTAINER (prg->win), GTK_WIDGET (prg->vb)); 
    gtk_box_pack_start (GTK_BOX (prg->vb), GTK_WIDGET (prg->btn), FALSE, FALSE, 0); 
    g_signal_connect (prg->win, "delete_event", G_CALLBACK (gtk_main_quit), NULL); 
    g_signal_connect_swapped (prg->btn, "clicked", G_CALLBACK (window_pbar), prg); 
    gtk_window_set_title (GTK_WINDOW (prg->win), "Test program"); 
    gtk_window_set_position (GTK_WINDOW (prg->win), GTK_WIN_POS_CENTER); 
    gtk_widget_show_all (GTK_WIDGET (prg->win)); 
    gtk_main(); 
} 
int main (int argc, char *argv[]) 
{ 
    gtk_init (&argc, &argv); 
    window_new(); 
    return 0; 
} 

私はプログラムの一部を変更しました。私は何度も 'スタート'ボタンをクリックしても問題は発生しませんが、別の問題が発生しました。 /1.aviを/2.aviにコピーできるときは、「スタート」ボタンをクリックして/1.aviを/2.aviにコピーしますが、このプロセス中はプログラムウィンドウがフリーズし、プログレスバーウィンドウは表示されません(最初の例では、この問題は発生しません)。

2つの問題のどちらにも当てはまらないようにこのプログラムを作成するにはどうすればよいですか?

答えて

2

あなたのコードで直面する問題は、gtk_thread_enter()でそれを囲まずにセカンダリスレッドから実行されるt1_doのGtk関数を呼び出していることです。 gtk_thread_leave();

メインUIスレッドではないスレッドからUI関数を呼び出さないでください。あなたがその問題を解決するまで、完全にランダムなエラーと動作を得ることができます。

+0

ありがとう。私はgtk_widget_destroyをgdk_threads_setで囲むことで問題を解決しました。gdk_threads_enter() - > gtk_widget_destroy(...) - > gdk_threads_leave()です。 – 5frame