Как мне создать несколько, но независимых модальных диалогов в GTK +? - PullRequest
2 голосов
/ 10 января 2010

У меня есть следующий код, который использует 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();
}

Ответы [ 3 ]

5 голосов
/ 11 ноября 2010

Поместите ваш вызов на gtk_dialog_run внутри функции, которая вызывается g_idle_add().

3 голосов
/ 10 января 2010

В gtk_dialog_run документах есть отдельное упоминание о том, что gtk_dialog_run будет блокировать взаимодействие только с окнами в той же группе окон , что и ваш модальный диалог.

2 голосов
/ 12 ноября 2010

Для меня ваш тестовый код работает нормально, с двумя ошибками, которые я вижу:

  • как вы заметили, gtk_dialog_run () вложены, так что внешний ожидает внутри. это не совсем исправимо, я не думаю, кроме как избежать gtk_dialog_run () в этой ситуации.
  • есть предупреждение о GTK_IS_WINDOW_GROUP, я думаю, что добавление / удаление диалогового окна в / из группы окон вручную приводит к изменению пересчета

Однако я могу точно нажимать на кнопки и перемещаться по файловой системе в диалоговом окне файлов, и я могу использовать кнопки открытия / закрытия.

Я могу предположить, что есть ошибка, специфичная для используемой вами версии GTK, которая не позволяет щелкнуть диалоговое окно. Не зная, в чем заключается ошибка, я полностью верю, что идея Курта запустить диалог в режиме ожидания, а не в обработчике, по которому щелкнули, может обойти это. Возможно, GTK запутается, добавив модальный захват в обработчик, по которому щелкают. Просто предположение. Однако, я не вижу ошибки здесь на GTK 2.20.1.

Пара вещей, которые я заметил в коде:

  • gtk_widget_set_usize должно быть gtk_window_set_default_size, вероятно
  • вам не нужно вручную добавлять / удалять диалог в группу окон. set_transient_for автоматически добавляет диалог в группу окон родителя, а уничтожение окна автоматически удаляет его из его группы окон. удаление этих вызовов исправляет предупреждение, которое я вижу в диалоге отмены.
...