2008-08-01 7 views
27

J'ai essayé d'implémenter le MessageBox de Win32 en utilisant GTK. L'application utilisant SDL/OpenGL, donc ce n'est pas une application GTK.Implémentation GTK de MessageBox

Je poignée l'initialisation (gtk_init) genre de choses à l'intérieur de la fonction MessageBox comme suit:

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

Maintenant, je suis pas un programmeur expérimenté GTK, et je me rends compte que je fais probablement quelque chose horriblement mal.

Cependant, mon problème est que la dernière boîte de dialogue surgie avec cette fonction reste jusqu'à ce que le processus se termine. Des idées?

Répondre

17

Hmm, ok. Je suggère le code comme ceci, alors:

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 
} 

La structure est parce que vous devez passer autour de quelques morceaux de données. L'appel gtk_idle_add() ajoute une méthode à exécuter lorsque la boucle principale est en cours d'exécution et inactive, et la valeur de retour FALSE de l'appel display_dialog() signifie qu'il n'est exécuté qu'une seule fois. Après avoir obtenu le résultat de la boîte de dialogue, nous quittons la boucle principale. Cela entraînera gtk_main() dans votre méthode principale MessageBox() à retourner, et vous serez en mesure d'accéder au résultat à partir de là.

Espérons que cela aide!

6

Quelques choses:

Vous créez (et ne pas utiliser) une fenêtre toplevel inutile, du nom window. Vous pouvez simplement supprimer ces lignes:

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

De même, le flux ne semble pas tout à fait correct. gtk_main() démarre la boucle principale de GTK, qui bloque jusqu'à ce que quelque chose en sorte. gtk_dialog_run() démarre également une boucle principale, mais il se ferme dès que l'un des boutons est cliqué.

Je pense qu'il vous suffira de supprimer les appels gtk_init_add() et gtk_main(), et de gérer simplement la valeur de retour. L'appel gtk_widget_destroy() est également inutile, car la fenêtre de dialogue est automatiquement détruite lorsque gtk_dialog_run() renvoie.

7

Pour gérer une boîte de dialogue avec GTK +, utilisez GtkDialog et gtk_dialog_run() au lieu de gérer vous-même une fenêtre et une boucle principale.

EDIT/ADDENDA:

Ce que je veux dire est « utilise juste »: Je ne comprends pas pourquoi vous créez une fenêtre que vous utilisez jamais et une boucle principale qui semble inutile (au moins de la pièce de code que vous avez posté). Vous pouvez écrire quelque chose d'aussi court que:

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