GTK实现的MessageBox

weos 发布于 2018-02-03 c 最后更新 2018-02-03 01:05 859 浏览

我一直在试图使用GTK来实现Win32的MessageBox。该应用程序使用SDL/OpenGL,所以这不是一个GTK应用程序。 我处理MessageBox函数中的初始化(gtk_init)类型的东西,如下所示:

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程序员,我意识到我可能做了一些可怕的错误。 但是,我的问题是,用这个函数弹出的最后一个对话框会一直存在,直到进程退出。有任何想法吗?
已邀请:

tet

赞同来自:

一些东西: 您正在创建(而不是使用)不必要的顶层窗口,名为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()返回时,对话窗口会自动销毁。

tet

赞同来自:

嗯。。好。我建议这样的代码,然后:

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调用的PLACEHOLDER_FOR_CODE_2返回值意味着它只运行一次。从对话框中得到结果后,我们退出主循环。这将导致gtk_main()方法中的PLACEHOLDER_FOR_CODE_4返回,您将可以从那里访问结果。 希望这可以帮助!

jsed

赞同来自:

要使用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;
    } 
}