Как несколько раз показать диалог с PyGTK / Gtkbuilder? - PullRequest
9 голосов
/ 11 января 2011

Я создал приложение PyGTK, которое показывает диалог, когда пользователь нажимает кнопку.Диалог загружается в моем методе __init__ с помощью:

builder = gtk.Builder()
builder.add_from_file("filename")
builder.connect_signals(self) 
self.myDialog = builder.get_object("dialog_name")

В обработчике событий диалог отображается с командой self.myDialog.run(), но это работает только один раз, потому что после run() диалоговое окноавтоматически уничтожается.Если я нажимаю кнопку еще раз, приложение вылетает.

Я прочитал, что есть способ использовать show() вместо run(), когда диалог не разрушен, но я чувствую, что это не такправильный путь для меня, потому что я хотел бы, чтобы диалог вел себя модально и возвращал управление коду только после того, как пользователь закрыл его.

Есть ли простой способ многократно показывать диалог, используя run()метод с помощью gtkbuilder?Я попытался перезагрузить весь диалог с помощью gtkbuilder, но, похоже, это не сработало, в диалоговом окне отсутствовали все дочерние элементы (и я бы предпочел использовать построитель только один раз, в начале программы).


[РЕШЕНИЕ] (отредактировано)
Как указано в ответе ниже, использование hide() помогает.Сначала я подумал, что вам нужно поймать «delete-event», но на самом деле это не обязательно.Простой пример, который работает:


import pygtk
import gtk

class DialogTest:

    def rundialog(self, widget, data=None):
        self.dia.show_all()
        result = self.dia.run() 
        self.dia.hide()


    def destroy(self, widget, data=None):
        gtk.main_quit()

    def __init__(self):
        self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
        self.window.connect("destroy", self.destroy)

        self.dia = gtk.Dialog('TEST DIALOG', self.window, 
           gtk.DIALOG_MODAL  | gtk.DIALOG_DESTROY_WITH_PARENT)
        self.dia.vbox.pack_start(gtk.Label('This is just a Test'))


        self.button = gtk.Button("Run Dialog")    
        self.button.connect("clicked", self.rundialog, None)
        self.window.add(self.button)
        self.button.show()
        self.window.show()



if __name__ == "__main__":
    testApp = DialogTest()
    gtk.main()

Ответы [ 3 ]

5 голосов
/ 12 января 2011

На самом деле, прочитайте документацию на Dialog.run().Диалог не уничтожается автоматически.Если вы hide() используете его при выходе из метода run(), тогда вы сможете run() использовать его столько раз, сколько захотите.

В качестве альтернативы вы можете установить диалоговое окно в модале вашего модератора.файл, а затем просто show() это.Это приведет к эффекту, аналогичному, но не совсем такому, как run() - поскольку run() создает второй экземпляр основного цикла GTK.

EDIT

Причина, по которой вы получаете ошибку сегментации, если вы не подключаетесь к сигналу delete-event, заключается в том, что вы дважды нажимаете кнопку закрытия.Вот что происходит:

  1. При нажатии кнопки «Выполнить диалог» вызывается метод run() диалогового окна.
  2. Появляется модальное диалоговое окно и запускается собственный основной цикл.
  3. Вы нажимаете кнопку закрытия.Основной цикл диалога завершается, но поскольку run() переопределяет нормальное поведение кнопки закрытия, диалог не закрывается.Это также не скрыто, поэтому оно висит вокруг.
  4. Вы задаетесь вопросом, почему диалог все еще там, и снова нажимаете кнопку закрытия.Так как run() больше не активен, нормальное поведение кнопки закрытия срабатывает: диалоговое окно уничтожается.
  5. Вы снова нажимаете «Run Dialog», который пытается вызвать метод run() уничтоженногодиалог.Crash!

Итак, если вы убедитесь, что hide() диалоговое окно после шага 3, то все должно работать.Нет необходимости подключаться к сигналу delete-event.

2 голосов
/ 16 февраля 2011

Я просто потратил некоторое время на выяснение этого.Повторная выборка того же объекта из компоновщика не создаст новый экземпляр объекта, а только вернет ссылку на старый (уничтоженный) объект.Однако если вы создадите новый экземпляр компоновщика и загрузите свой файл в новый компоновщик, он создаст новый экземпляр.

Таким образом, моя функция создания диалога выглядит примерно так:

def create():
    builder = gtk.Builder()
    builder.add_from_file('gui/main.ui')

    dlg = builder.get_object('new_dialog')

    def response_function(dialog, response_id):
        ... do stuff ...
        dialog.destroy()

    dlg.connect('response', response_function)
    dlg.show_all()

Обратите внимание, что в этом случае я не блокирую ответ с помощью run (), потому что я использую витую, но она должна быть эквивалентной.

1 голос
/ 22 января 2011

Ваш диалог должен быть запущен только один раз.Предполагая, что пункт меню запускает диалог, код должен выглядеть примерно так:

def on_menu_item_clicked(self, widget, data=None):
    dialog = FunkyDialog()
    response = dialog.run()

    if response = gtk.RESPONSE_OK:
        // do something with the dialog data

    dialog.destroy()

dialog.run() - это блокирующий основной цикл, который возвращается, когда диалог отправляет ответ.Обычно это делается с помощью кнопок Ok и Cancel.Когда это происходит, диалоговое окно завершается и его необходимо уничтожить.

Чтобы повторно отобразить диалоговое окно, пользователь должен следовать тому же рабочему процессу (в приведенном выше примере это будет нажатие на элемент меню).В __init__ диалог отвечает за настройку.Если вы hide() диалоговое окно, у вас есть проблема связи с этим диалоговым окном, поэтому он остается актуальным с остальной частью приложения , даже если он скрыт .

Один изПричины, по которым некоторые люди хотят «многократно запускать диалоговое окно», заключаются в том, что пользователь ввел неверную информацию, и вы хотите дать пользователю возможность ее исправить.Это должно быть решено в обработчике ответного сигнала диалога.Порядок событий в диалоге:

  1. Пользователь физически нажимает кнопку ОК
  2. Диалог отправляет ответ gtk.RESPONSE_OK (-5)
  3. Диалог вызываетобработчик для ответного сигнала
  4. Dialog вызывает обработчик для кнопки Ok
  5. Dialog run() метод возвращает ответ

, чтобы предотвратить выполнение шагов 4 и 5обработчик ответа должен подавить ответный сигнал.Это достигается следующим образом:

def on_dialog_response(self, dialog, response, data=None:
    if response == gtk.RESPONSE_OK:
        if data_is_not_valid:
            # Display an error message to the user

            # Suppress the response
            dialog.emit_stop_by_name('response')
...