2008-08-01 18 views
27

Próbowałem zaimplementować Win32's MessageBox używając GTK. Aplikacja używająca SDL/OpenGL, więc nie jest to aplikacja GTK.Implementacja GTK MessageBox

I obsłużyć inicjalizacji (gtk_init) porządek rzeczy wewnątrz funkcji MessageBox następująco:

int MessageBox(HWND hwnd, const char* text, const char* caption, UINT type) 
{ 
    GtkWidget *window = NULL; 
    GtkWidget *dialog = NULL; 

    gtk_init(&gtkArgc, &gtkArgv); 
    window = gtk_window_new(GTK_WINDOW_TOPLEVEL); 
    g_signal_connect(G_OBJECT(window), "delete_event", G_CALLBACK(delete_event), NULL); 
    g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(destroy), NULL); 
    // gcallback calls gtk_main_quit() 
    gtk_init_add((GtkFunction)gcallback, NULL); 

    if (type & MB_YESNO) { 
     dialog = gtk_message_dialog_new(GTK_WINDOW(window), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO, text); 
    } else { 
     dialog = gtk_message_dialog_new(GTK_WINDOW(window), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_INFO, GTK_BUTTONS_OK, text); 
    } 

    gtk_window_set_title(GTK_WINDOW(dialog), caption); 
    gint result = gtk_dialog_run(GTK_DIALOG(dialog)); 

    gtk_main(); 

    gtk_widget_destroy(dialog); 

    if (type & MB_YESNO) { 
     switch (result) { 
     default: 
     case GTK_RESPONSE_DELETE_EVENT: 
     case GTK_RESPONSE_NO: 
      return IDNO; 
      break; 
     case GTK_RESPONSE_YES: 
      return IDYES; 
      break; 
     } 
    } 

    return IDOK; 
} 

Teraz jestem bynajmniej doświadczonego programistę GTK, i zdaję sobie sprawę, że jestem prawdopodobnie robić coś okropnie nie tak.

Jednak moim problemem jest to, że ostatnie okno pojawiło się z tą funkcją, dopóki proces się nie zakończy. Jakieś pomysły?

Odpowiedz

17

Hmm, ok. Sugeruję kod taki jak ten, a następnie:

typedef struct { 
    int type; 
    int result; 
} DialogData; 

static gboolean 
display_dialog(gpointer user_data) 
{ 
    DialogData *dialog_data = user_data; 
    GtkWidget *dialog; 

    if (dialog_data->type & MB_YESNO) 
     dialog = gtk_message_dialog_new(...); 
    else 
     dialog = gtk_message_dialog_new(...); 

    // Set title, etc. 

    dialog_data->result = gtk_dialog_run(...); 

    gtk_main_quit(); // Quits the main loop run in MessageBox() 

    return FALSE; 
} 

int MessageBox(...) 
{ 
    DialogData dialog_data; 

    dialog_data.type = type; 

    gtk_idle_add(display_dialog, &dialog_data); 

    gtk_main(); 

    // Do stuff based on dialog_data.result 
} 

Struktura jest dlatego, że trzeba przekazać kilka kawałków danych. Wywołanie gtk_idle_add() dodaje metodę, która ma zostać uruchomiona, gdy główna pętla działa i jest w stanie bezczynności, a wartość zwracana FALSE z wywołaniaoznacza, że ​​jest uruchamiana tylko raz. Po uzyskaniu wyniku z okna dialogowego opuściliśmy główną pętlę. To spowoduje, że metoda gtk_main() w powrocie do głównej metody będzie w stanie uzyskać dostęp do wyniku.

Mam nadzieję, że to pomoże!

6

kilka rzeczy:

tworzysz (i nie jest używana) niepotrzebne Toplevel okno o nazwie window. Możesz po prostu usunąć następujące linie:

window = gtk_window_new(GTK_WINDOW_TOPLEVEL); 
g_signal_connect(G_OBJECT(window), "delete_event", G_CALLBACK(delete_event), NULL); 
g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(destroy), NULL); 

Przepływ nie wydaje się być całkiem poprawny. gtk_main() uruchamia główną pętlę GTK, która blokuje, dopóki coś nie wyjdzie. gtk_dialog_run() również uruchamia pętlę główną, ale kończy działanie, gdy tylko jeden z przycisków zostanie kliknięty.

Myślę, że może wystarczyć, aby usunąć wywołania gtk_init_add() i gtk_main() i po prostu zająć się zwracaną wartością. Również wywołanie gtk_widget_destroy() jest niepotrzebne, ponieważ okno dialogowe jest automatycznie niszczone, gdy funkcja gtk_dialog_run() zwraca.

7

Aby zarządzać oknem dialogowym za pomocą GTK +, użyj GtkDialog i gtk_dialog_run() zamiast samodzielnie zarządzać oknem i główną pętlą.

EDIT/Uzupełnienie:

Co mam na myśli to „po prostu użyć”: Nie rozumiem, dlaczego utworzyć okna nigdy użyciu i główną pętlę, która wydaje się bezużyteczne (przynajmniej z kawałka kod, który wysłałeś). Możesz napisać coś tak krótkiego jak:

int MessageBox(HWND hwnd, const char* text, const char* caption, UINT type) 
{ 
    GtkWidget *dialog ; 

    /* Instead of 0, use GTK_DIALOG_MODAL to get a modal dialog box */ 

    if (type & MB_YESNO) 
     dialog = gtk_message_dialog_new(NULL, 0, GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO, text); 
    else 
     dialog = gtk_message_dialog_new(NULL, 0, GTK_MESSAGE_INFO, GTK_BUTTONS_OK, text); 


    gtk_window_set_title(GTK_WINDOW(dialog), caption); 
    gint result = gtk_dialog_run(GTK_DIALOG(dialog)); 
    gtk_widget_destroy(GTK_WIDGET(dialog)); 

    if (type & MB_YESNO) 
    { 
     switch (result) 
     { 
     default: 
     case GTK_RESPONSE_DELETE_EVENT: 
     case GTK_RESPONSE_NO: 
      return IDNO; 
     case GTK_RESPONSE_YES: 
      return IDYES; 
     } 
     return IDOK; 
    } 
}