Pregunta

He creado una aplicación PyGTK que muestra un diálogo cuando el usuario presiona un botón. El diálogo se carga en mi método __init__ con:

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

En el controlador de eventos, el cuadro de diálogo se muestra con el comando self.myDialog.run(), pero esto sólo funciona una vez, porque después de run() el cuadro de diálogo se destruye automáticamente. Si hago clic en el botón por segunda vez, la aplicación se bloquea.

He leído que hay una manera de uso show() en lugar de run() donde el diálogo no se destruye, pero siento que este no es el camino correcto para mí, porque me gustaría que el diálogo que se comporten de forma modal y para devolver el control a la código sólo después de que el usuario ha cerrado.

¿Hay una forma sencilla de mostrar un cuadro de diálogo en varias ocasiones con el método run() usando GtkBuilder? He intentado volver a cargar todo el diálogo usando el GtkBuilder, pero que no parecía realmente a trabajar, el cuadro de diálogo le faltaba todos los elementos secundarios (y yo preferiría tener que utilizar el constructor de una sola vez, al inicio del programa).


[Solución] (editado)
Como se ha señalado por la respuesta a continuación, utilizando hide() hace el truco. Al principio pensé que todavía tenía que coger el "delete-evento", pero esto en realidad no es necesario. Un ejemplo sencillo que funciona es:


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()
¿Fue útil?

Solución

En realidad, lea la documentación en Dialog.run(). El diálogo no se destruye automáticamente. Si hide() cuando las salidas método run(), entonces usted debería ser capaz de run() tantas veces como desee.

Como alternativa, se puede establecer el diálogo para ser modal en el archivo de constructor, y luego simplemente show() ella. Con ello se consigue un efecto que es similar, pero no exactamente lo mismo que run() -. run() porque crea una segunda instancia del bucle principal de GTK

Editar

La razón por la que está recibiendo un fallo de segmentación si no se conecta a la señal delete-event es que se está haciendo clic en el botón cerrar dos veces. Esto es lo que sucede:

  1. Haga clic en "Ejecutar diálogo", esto llama al método run() del diálogo.
  2. Aparecerá el diálogo modales, y comienza su propio bucle principal.
  3. Haga clic en el botón de cierre. principales salidas de bucle del diálogo, pero dado que las anulaciones run() el comportamiento normal del botón de cierre, el diálogo no está cerrada. Asimismo, no se oculta, por lo que se cuelga alrededor.
  4. Uno se pregunta por qué el diálogo es todavía allí y hace clic en el botón de cierre de nuevo. Desde run() ya no está activa, el comportamiento normal del botón de cierre se activa:. El cuadro de diálogo se destruye
  5. haga clic en "Ejecutar diálogo" de nuevo, que trata de llamar al método run() del cuadro de diálogo rotos. Crash!

Así que si se asegura a hide() el cuadro de diálogo después del paso 3, entonces todo debería funcionar. No hay necesidad de conectarse a la señal delete-event.

Otros consejos

Me acaba de pasar algún tiempo calcular esto. Vuelva a buscar el mismo objeto desde un constructor no va a crear una nueva instancia del objeto, pero sólo devuelve una referencia al objeto antiguo (destruido). Si crea una nueva instancia del constructor, sin embargo, y cargar el archivo en el nuevo constructor, se creará una nueva instancia.

Así que mi función de creación de diálogo es como la siguiente:

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()

Tenga en cuenta que yo no estoy bloqueando una respuesta con run () en este caso porque estoy usando retorcida, pero debe ser equivalente.

Su diálogo sólo se tenga que ejecutar una vez. Suponiendo un elemento de menú desencadenantes del cuadro de diálogo, el código debe ser algo como esto:

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() es un bloqueo de bucle principal que vuelve cuando el diálogo de enviar una respuesta. Esto se realiza normalmente a través de la botones Aceptar y Cancelar. Cuando esto sucede, el diálogo está terminado y debe ser destruido.

Para mostrar el cuadro de diálogo en repetidas ocasiones, el usuario debe seguir el mismo flujo de trabajo (en el ejemplo anterior, que sería hacer clic en un elemento de menú). El diálogo es responsable, en __init__, para erigirse. Si hide() el cuadro de diálogo, usted tiene el problema de la comunicación con ese cuadro de diálogo para que se mantenga hasta al día con el resto de la aplicación incluso cuando está oculta .

Una de las razones por las que algunas personas quieren "ejecutar el diálogo en repetidas ocasiones" se debe a que el usuario ha introducido la información no válida, y que desea dar al usuario la oportunidad de corregirlo. Esto debe ser tratado en manejador de señal de respuesta del diálogo. El orden de los acontecimientos en un cuadro de diálogo es:

  1. El usuario empuja físicamente el botón Aceptar
  2. diálogo envía el gtk.RESPONSE_OK respuesta (-5)
  3. Diálogo llama al controlador de la señal de respuesta
  4. Diálogo llama al controlador para el botón Aceptar
  5. método run() de diálogo devuelve la respuesta

Para prevenir los pasos 4 y 5 suceda, el manejador de respuesta debe suprimir la señal de respuesta. Esto se logra como sigue:

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')
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top