1

テキスト入力とボタンを備えた非常にシンプルなアプリケーションがあります。

ユーザーがボタンを押すと、アプリケーションはURLから(他のスレッドの)ファイルをダウンロードし、成功すると、すべて完了したダイアログメッセージを開きます。ダウンロード中にスピナーをアクティブにします(ビジーのように)

ここに画像の説明を入力してください

ファイルをダウンロードするために接続するのにどれくらい時間がかかるかわからないので、私はその目的のために別のスレッドを使用します。しかし、「ダイアログショー」でアプリケーションが失敗し、次のエラーが発生します。

(enter_license.exe:210232): Gdk-WARNING **: gdkdrawable-win32.c:1873: GetDC failed: Invalid window handle.

(enter_license.exe:210232): Gdk-WARNING **: gdkgc-win32.c:968: GetCurrentObject failed: The handle is invalid.

(enter_license.exe:210232): Gdk-WARNING **: gdkgc-win32.c:970: RestoreDC failed: The handle is invalid.

(enter_license.exe:210232): Gdk-CRITICAL **: _gdk_win32_drawable_release_dc: assertion `impl->hdc_count > 0' failed

(enter_license.exe:210232): Gdk-WARNING **: gdkwindow-win32.c:2216: SetWindowLongPtr failed: Invalid window handle.

別のスレッドからGTKオブジェクトを呼び出そうとすると、何か問題があるように聞こえます。どういうわけか、メインスレッドに「show_dialog」を実装するためにコールハンドル(コールバック)が必要ですか?

コンパイル:

 gcc -IC:/MinGW/include -o enter_license enter_license.c  `pkg-config --libs --cflags gtk+-2.0 gthread-2.0``

フロー:メイン->「do_something」を呼び出す->スレッドを作成して「argument_thread」を呼び出す->

コードのスニペットは次のとおりです。

typedef struct _Data
{
 GtkWidget *win; 
 } Data;

主要

int main(int argc, char **argv)
{
 GtkWidget *window;

 gtk_init(&argc, &argv);
 window = do_something(NULL, argv);
 g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
 gtk_main();    

return 0;
}

do_something

GtkWidget * do_something(GtkWidget *do_widget, char **argv){
  ....
 GtkWidget *window;

if (!window){
window = gtk_dialog_new_with_buttons ("GtkSpinner",
                                      GTK_WINDOW (do_widget),
                                      0,
                                      GTK_STOCK_CLOSE,
                                      GTK_RESPONSE_NONE,
                                      NULL);
gtk_window_set_resizable (GTK_WINDOW (window), FALSE);

g_signal_connect (window, "response", G_CALLBACK (gtk_widget_destroy), NULL);
g_signal_connect (window, "destroy",  G_CALLBACK (gtk_widget_destroyed), &window);


 ....

if (!gtk_widget_get_visible (window)){
 gtk_widget_show_all (window);
}
else{
 gtk_widget_destroy (window);
}

    // define thread
    GThread*  thread;
    GError*   err;  
    Data data;

data.win = window;

     thread = g_thread_create((GThreadFunc)argument_thread,&data,FALSE, &err);
 return window;
}

show_dialog

gboolean show_dialog( GtkWidget* mw)
{
 GtkWidget *dialog;

  printf("BOO: \n");

  // here all works fine
  sleep(3000);
  gtk_widget_show(spinner_sensitive);
  gtk_spinner_start (GTK_SPINNER (spinner_sensitive));
  sleep(3000);
  gtk_spinner_stop (GTK_SPINNER (spinner_sensitive));
  sleep(3000);
  gtk_widget_hide(spinner_sensitive);

  printf("BOO\n");
  // here dialog is shown for 1-10 milisec and get error.

     dialog = gtk_message_dialog_new (GTK_WINDOW(mw),
                     GTK_DIALOG_DESTROY_WITH_PARENT,
                     GTK_MESSAGE_INFO,
                     GTK_BUTTONS_CLOSE,
                     "Downloaded successfully");

             g_signal_connect_swapped (G_OBJECT (dialog), "response",
                     G_CALLBACK (gtk_widget_destroy),
                     G_OBJECT (dialog));
             gtk_widget_show(dialog);
printf("BOO\n");

}

arguments_thread

void *argument_thread( gpointer ptr ) {
  Data *data = (Data*)ptr;
gdk_threads_enter();
 show_dialog (data->win);
 gdk_threads_leave();
  return( NULL );
}

私を助けてください、

ありとあらゆる提案をいただければ幸いです

4

2 に答える 2

3

GTK はスレッドセーフではないため、GUI とやり取りするものはすべてメイン スレッドで実行する必要があります。

関数を使用してg_idle_add、ダウンロードが完了したときにメイン スレッドに通知します。

于 2012-12-06T23:32:13.787 に答える
0

答えを探している人のためだけの@VincentPovirkによると、ここに実用的な実装があります:

2番目のスレッド(メインでは別名)の外部で実装される、私たちが呼び出しg_idle_addて呼び出すスレッドに:callback_func

gboolean show_dialog( GtkWidget* mw)
{
sleep(3000);
gtk_widget_show(spinner_sensitive);
gtk_spinner_start (GTK_SPINNER (spinner_sensitive));
sleep(3000);
gtk_spinner_stop (GTK_SPINNER (spinner_sensitive));
gtk_widget_hide(spinner_sensitive);

g_idle_add(callback_func, NULL);  
}

gint callback_func(void *unused)
{
  GtkWidget *dialog;
  dialog = gtk_message_dialog_new (GTK_WINDOW(window),
                     GTK_DIALOG_DESTROY_WITH_PARENT,
                     GTK_MESSAGE_INFO,
                     GTK_BUTTONS_CLOSE,
                     "Succeeded.");

             g_signal_connect_swapped (G_OBJECT (dialog), "response",
                     G_CALLBACK (gtk_widget_destroy),
                     G_OBJECT (dialog));
             gtk_widget_show(dialog);
return FALSE;

}
于 2012-12-06T23:59:12.713 に答える