GTK实现的MessageBox

42

我一直在尝试使用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程序员,我意识到我可能做错了一些事情。

但是,我的问题是最后一个对话框弹出后,这个函数一直停留到进程退出。有什么想法吗?

3个回答

18

好的,我建议使用以下代码:

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() 调用会在主循环运行且空闲时添加一个方法,而来自 display_dialog() 调用的 FALSE 返回值表示它只运行一次。 在从对话框获取结果后,我们退出主循环。 这将导致您主要的 MessageBox() 方法中的 gtk_main() 返回,然后您就可以从那里访问结果。


9
使用GtkDialog和gtk_dialog_run()来管理GTK+对话框,而不是自己管理窗口和主循环。
编辑/补充说明:
我的意思是“只需使用”:我不明白为什么你要创建一个从未使用的窗口和一个似乎无用的主循环(至少从你发布的代码片段来看)。你可以写出如下简短的代码:
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;
    } 
}

5
一些事项:
您正在创建(而不是使用)一个名为window的不必要的顶级窗口。您可以删除以下行:
```javascript var window = new BrowserWindow({show: false}); ```
请按照上述步骤进行修改,以避免不必要的资源消耗。
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() 返回时,对话框窗口会自动销毁。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接