【问题标题】:How do I create multiple but independent modal dialogs in GTK+?如何在 GTK+ 中创建多个但独立的模式对话框?
【发布时间】:2010-01-10 11:17:17
【问题描述】:

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

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

在 win32 中,我可以通过在单独的线程中运行每个顶级窗口来完成此操作。但是,gtk_main 似乎只能从一个线程运行。那么如何在 GTK+ 中管理多个窗口堆栈(尽可能不牺牲gtk_dialog_run 的简单性)?

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

#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();
}

【问题讨论】:

    标签: c++ c modal-dialog gtk


    【解决方案1】:

    将您对gtk_dialog_run 的调用放入由g_idle_add() 调用的函数中。

    【讨论】:

      【解决方案2】:

      gtk_dialog_run docs 中单独提到 gtk_dialog_run 只会阻止与您的模态对话框相同window group 中的窗口的交互。

      【讨论】:

      • 感谢您的回答。我尝试将每个窗口放入自己的组中,但是在单击其中一个窗口中的按钮后,另一个窗口仍然不接受点击(尽管它令人惊讶地确实响应了鼠标移动)。即使它工作正常,我仍然无法想象如果不使用多个线程它会如何工作。如果我单击按钮 1,然后单击按钮 2,然后隐藏对话框 1,如果循环在同一个线程中运行,则第一个对话框的 gtk_dialog_run 不可能返回,直到对话框 2 也关闭。我认为我缺少一些基本点。
      • 您确定将对话框也添加到窗口组吗?
      • 好收获。不幸的是,在我修复它之后没有任何改变。如果您可以查看,我已经用我当前的代码更新了这个问题。无论哪种情况,你都有我的 +1。
      【解决方案3】:

      对我来说,您的测试代码运行良好,但我看到了两个错误:

      • 正如您所注意到的,gtk_dialog_run() 是嵌套的,因此外层正在等待内层。除了在这种情况下避免使用 gtk_dialog_run() 之外,我认为这并不能真正解决。
      • 有一个关于 GTK_IS_WINDOW_GROUP 的警告,我认为手动在窗口组中添加/删除对话框正在破坏引用计数

      但是,我可以很好地单击按钮并在文件对话框中浏览文件系统,并且可以使用打开/关闭按钮。

      我可能猜到存在特定于您正在使用的 GTK 版本的错误,该错误会阻止单击该对话框。在不知道错误是什么的情况下,我完全相信 Kurt 在空闲而不是在单击的处理程序中运行对话框的想法可以解决它。 GTK 可能会因为在 clicked 处理程序中添加模态抓取而感到困惑。只是猜测。但是,我没有在 GTK 2.20.1 上看到这个错误。

      我在代码中注意到的几件事:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-10-22
        • 2011-04-12
        • 1970-01-01
        • 2015-11-30
        • 2012-05-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多