Реализация MessageBox в GTK

Я пытался реализовать Win32 с MessageBox помощью GTK. Приложение использует SDL / OpenGL, поэтому это не приложение GTK.

Я обрабатываю gtk_init вещи типа initialization ( ) внутри 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 и понимаю, что, вероятно, делаю что-то ужасно неправильно.

Однако моя проблема в том, что в последнем диалоговом окне появилась эта функция, которая остается до завершения процесса. Любые идеи?

Ответов (3)

Решение

Хмм хорошо. Тогда я бы предложил такой код:

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() в вашем основном MessageBox() методе, и вы сможете получить доступ к результату оттуда.

Чтобы управлять диалоговым окном с помощью GTK +, используйте GtkDialog и gtk_dialog_run () вместо того, чтобы самостоятельно управлять окном и основным циклом.

ИЗМЕНИТЬ / ДОБАВИТЬ:

Я имею в виду «просто используйте»: я не понимаю, почему вы создаете окна, которые никогда не используете, и основной цикл, который кажется бесполезным (по крайней мере, из того фрагмента кода, который вы опубликовали). Вы можете написать что-нибудь очень короткое:

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

Несколько вещей:

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