42 Stimmen

GTK-Implementierung von MessageBox

Ich habe versucht, die Win32-Funktionalität zu implementieren. MessageBox unter Verwendung von GTK. Die Anwendung verwendet SDL/OpenGL, es handelt sich also nicht um eine GTK-Anwendung.

Ich kümmere mich um die Initialisierung ( gtk_init ) im Inneren des MessageBox wie folgt funktionieren:

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

Nun, ich bin keineswegs ein erfahrener GTK-Programmierer, und ich weiß, dass ich wahrscheinlich etwas schrecklich falsch mache.

Mein Problem ist jedoch, dass das letzte Dialogfeld mit dieser Funktion auftauchte, die bis zum Beenden des Prozesses bestehen bleibt. Irgendwelche Ideen?

18voto

Joe Shaw Punkte 21088

Hmm, okay. Ich würde dann einen Code wie diesen vorschlagen:

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
}

Die Struktur ist erforderlich, weil Sie einige Daten weitergeben müssen. Die gtk_idle_add() Aufruf fügt eine Methode hinzu, die ausgeführt wird, wenn die Hauptschleife läuft und im Leerlauf ist, und die FALSE Rückgabewert aus der display_dialog() Aufruf bedeutet, dass er nur einmal ausgeführt wird. Nachdem wir das Ergebnis des Dialogs erhalten haben, beenden wir die Hauptschleife. Das führt dazu, dass die gtk_main() in Ihrem Haupt MessageBox() zurückgeben, und Sie können von dort aus auf das Ergebnis zugreifen.

9voto

Platypus Punkte 184

Um ein Dialogfeld mit GTK+ zu verwalten, verwenden Sie ein GtkDialog und gtk_dialog_run() anstatt ein Fenster und eine Hauptschleife selbst zu verwalten.

EDIT / ADDENDUM :

Was ich meine, ist "just use": Ich verstehe nicht, warum Sie ein Windows erstellen, das Sie nie benutzen, und eine Hauptschleife, die nutzlos zu sein scheint (zumindest nach dem von Ihnen geposteten Stück Code). Sie können etwas so kurzes schreiben wie :

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

5voto

Joe Shaw Punkte 21088

Ein paar Dinge:

Sie erstellen (und verwenden nicht) ein unnötiges Toplevel-Fenster, das window . Sie können diese Zeilen einfach löschen:

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

Außerdem scheint der Fluss nicht ganz richtig zu sein. gtk_main() startet die GTK-Hauptschleife, die so lange blockiert, bis sie durch etwas beendet wird. gtk_dialog_run() startet ebenfalls eine Hauptschleife, die jedoch beendet wird, sobald eine der Schaltflächen angeklickt wird.

Ich denke, es könnte ausreichen, wenn Sie die gtk_init_add() y gtk_main() aufruft und einfach mit dem Rückgabewert umgeht. Auch die gtk_widget_destroy() Aufruf ist unnötig, da das Dialogfenster automatisch zerstört wird, wenn gtk_dialog_run() zurückkehrt.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X