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

如何在gtk+中创建多个独立的模态对话框?

  •  2
  • avakar  · 技术社区  · 15 年前

    下面的代码使用gtk+小部件工具包来显示带有按钮的窗口。单击此按钮将显示一个模式对话框。请注意 gtk_dialog_run 将递归地启动主循环的另一个实例,即 on_click 在关闭对话框之前,函数不会返回。

    我希望有两个这样的顶级窗口,每个窗口都有一个按钮,并且能够生成自己的模式对话框。显示对话框只会禁用生成它的窗口,同时最多可以有两个活动的模式对话框,每个顶级窗口一个。

    在win32中,我可以通过在单独的线程中运行每个顶级窗口来实现这一点。然而,似乎 gtk_main 只能从一个线程运行。因此,如何在gtk+中管理多个窗口堆栈(而不牺牲 gtk_对话运行 如果可能的话?

    更新: 代码现在显示两个窗口并将它们添加到各自的窗口组中。

    #include <gtk/gtk.h>
    
    struct modal_stack
    {
        GtkWindowGroup * group;
        GtkWidget * window;
    };
    
    static void on_click(GtkWidget *widget, gpointer sptr)
    {
        modal_stack * s = (modal_stack *)sptr;
        GtkWidget * dialog = gtk_file_chooser_dialog_new(
            "Open File", 0, GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL,
            GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL);
        gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(s->window));
        gtk_window_group_add_window(s->group, GTK_WINDOW(dialog));
        gtk_dialog_run (GTK_DIALOG (dialog));
        gtk_window_group_remove_window(s->group, GTK_WINDOW(dialog));
        gtk_widget_destroy(dialog);
    }
    
    void create_window(modal_stack & s)
    {
        s.group = gtk_window_group_new();
        s.window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    
        gtk_widget_set_usize(s.window, 200, 200);
        g_signal_connect(G_OBJECT (s.window), "destroy",
            G_CALLBACK(gtk_main_quit), NULL);
        g_signal_connect(G_OBJECT (s.window), "delete_event",
            G_CALLBACK(gtk_main_quit), NULL);
    
        GtkWidget * button = gtk_button_new ();
        gtk_button_set_label(GTK_BUTTON(button), "show dialog");
        g_signal_connect(G_OBJECT (button), "clicked",
            G_CALLBACK(on_click), (gpointer) &s);
        gtk_widget_show(button);
    
        gtk_container_add(GTK_CONTAINER (s.window), button);
        gtk_widget_show(s.window);
    
        gtk_window_group_add_window(s.group, GTK_WINDOW(s.window));
    }
    
    int main(int argc, char *argv[])
    {
        gtk_init (&argc, &argv);
        modal_stack wnd1, wnd2;
        create_window(wnd1);
        create_window(wnd2);
        gtk_main();
    }
    
    3 回复  |  直到 11 年前
        1
  •  5
  •   Peter O. Manuel Pinto    12 年前

    打电话给 gtk_dialog_run 在由调用的函数中 g_idle_add() .

        2
  •  3
  •   Tobu    15 年前

    gtk_dialog_run docs 那个 gtk_dialog_run 只会阻止与同一窗口的交互 window group 作为你的模态对话。

        3
  •  2
  •   Havoc P    14 年前

    对我来说,你的测试代码运行良好,有两个bug:

    • 正如您所注意到的,gtk_dialog_run()是嵌套的,因此外部的正在等待内部的。我不认为这真的是不可修复的,除了在这种情况下避免gtk_dialog_run()之外。
    • 有一个关于gtk_i s_window_group的警告,我认为手动添加/删除对话框到窗口组/从窗口组删除对话框会损坏refcounting

    但是,我可以在文件对话框中单击按钮并在文件系统中导航,还可以使用打开/关闭按钮。

    我可能猜你使用的gtk版本有一个特定的bug阻止了点击对话框。在不知道bug是什么的情况下,我完全相信kurt在idle中而不是在clicked处理程序中运行对话框的想法可以解决这个问题。可能是gtk通过在单击的处理程序中添加模式抓取而混淆了。只是猜测而已。但是,fwiw我在gtk 2.20.1上没有看到这个bug。

    我注意到代码中有几点:

    • gtk_widget_set_usize应该是gtk_window_set_default_size大概
    • 不需要手动将对话框添加/删除到窗口组。set_transient_for自动将对话框添加到父窗口组,而销毁窗口则自动将其从窗口组中删除。删除这些调用修复了我在对话框取消时看到的警告。