我有非常簡單的應用程序與文本輸入和按鈕。當我嘗試在其他線程中調用GtkWidget對象時,GTK應用程序崩潰
當用戶按下按鈕時,應用程序從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;
main
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");
}
argument_thread
void *argument_thread(gpointer ptr) {
Data *data = (Data*)ptr;
gdk_threads_enter();
show_dialog (data->win);
gdk_threads_leave();
return(NULL);
}
請幫助我,
任何和所有的建議將不勝感激
因此我從線程中調用'g_idle_add(callback_func,NULL)',其中'callback_func'是主線程中的方法,對嗎? –
nm,我在錯誤的地方使用過'g_idle_add',謝謝,你節省了我的時間。 –
獎勵:在出色的GTKmm中,它變成了'Glib :: signal_idle()。connect([&] {/ *一些lambda包含你需要延遲的代碼,直到GTK擁有的線程* /});'。因此,您甚至可以將延遲代碼寫入物理函數中,同時防止由於 –