Вопросы | c

GTK реализация MessageBox

Вопрос

Bernard | 8001 просмотров | рейтинг: 16

Я пытался реализовать Win32 MessageBox, используя GTK. Приложение использует SDL / OpenGL, так что это не приложение GTK. Я выполняю инициализацию (gtk_init) в функции MessageBox следующим образом:

 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;
}
 
Теперь я ни в коем случае не опытный программист GTK, и я понимаю, что, возможно, я делаю что-то ужасно неправильно. Однако моя проблема в том, что последнее диалоговое окно с этой функцией остается до завершения процесса. Есть идеи?



Ответы

Joe Shaw

+ 7 -
Несколько вещей: Вы создаете (и не используете) ненужное окно верхнего уровня с именем window. Вы можете просто удалить эти строки:
 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);
 

Кроме того, поток кажется не совсем правильным. gtk_main() запускает основной цикл GTK, который блокируется, пока что-то не выйдет из него. gtk_dialog_run() также запускает основной цикл, но он завершается, как только нажимается одна из кнопок. Я думаю, вам может быть достаточно удалить вызовы gtk_init_add() и gtk_main() и просто обработать возвращаемое значение. Также нет необходимости в вызове gtk_widget_destroy(), поскольку диалоговое окно автоматически уничтожается при возврате gtk_dialog_run ().  


Anonymous

+ 16 -
Хм, ок. Я бы предложил такой код, тогда:
 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
}
 

Структура заключается в том, что вам нужно передать пару фрагментов данных. Вызов gtk_idle_add() добавляет метод, который будет запускаться, когда основной цикл работает и простаивает, и возвращаемое значение FALSE из display_dialog() в вашем основном методе gtk_main(), и вы сможете получить доступ к результату оттуда. Надеюсь это поможет!


Теги

c | linux | gtk | x11