代码之家  ›  专栏  ›  技术社区  ›  Bernard

消息框的GTK实现

  •  30
  • Bernard  · 技术社区  · 16 年前

    我一直在尝试实现win32 MessageBox 使用GTK。应用程序使用SDL/OpenGL,所以这不是GTK应用程序。

    我处理初始化( 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 回复  |  直到 7 年前
        1
  •  16
  •   Joe Shaw OscarRyz    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() 在你的主要 MessageBox() 方法返回,您将能够从中访问结果。

    希望这有帮助!

        2
  •  7
  •   Joe Shaw OscarRyz    16 年前

    几件事:

    您正在创建(而不是使用)一个不必要的顶级窗口,名为 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() GTKKY主() 调用,并简单地处理返回值。也 gtk_widget_destroy() 调用是不必要的,因为当gtk_dialog_run()返回时,对话框窗口会自动销毁。

        3
  •  7
  •   Platypus    14 年前

    要使用gtk+管理对话框,请使用gtk dialog和 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;
        } 
    }