Domanda

Ho generato un'applicazione PyGTK che mostra una finestra quando l'utente preme un pulsante. La finestra di dialogo viene caricato nel mio metodo __init__ con:

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

Nel gestore di eventi, la finestra di dialogo è mostrata con il comando self.myDialog.run(), ma questo funziona solo una volta, perché dopo run() la finestra viene automaticamente distrutta. Se si fa clic sul pulsante una seconda volta, l'applicazione si blocca.

Ho letto che c'è un modo per utilizzare show() invece di run() in cui il dialogo non è distrutto, ma mi sento come questo non è il modo giusto per me, perché vorrei che la finestra di dialogo di comportarsi modale e per restituire il controllo al codice solo dopo che l'utente ha chiuso esso.

C'è un modo semplice per mostrare ripetutamente una finestra utilizzando il metodo run() utilizzando GtkBuilder? Ho provato a ricaricare l'intera finestra di dialogo con il GtkBuilder, ma che in realtà non sembra funzionare, la finestra di dialogo mancava tutti gli elementi figlio (e io preferirei di dover utilizzare il generatore solo una volta, all'inizio del programma).


[SOLUZIONE] (a cura)
Come ha sottolineato la risposta qui sotto, utilizzando hide() fa il trucco. Ho pensato che ancora bisogno di prendere il "delete-evento", ma questo in realtà non è necessario. Un semplice esempio che funziona è:


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()
È stato utile?

Soluzione

In realtà, leggere il documentazione su Dialog.run(). La finestra di dialogo non viene distrutta automaticamente. Se hide() quando le uscite metodo run(), allora si dovrebbe essere in grado di run() tutte le volte che vuoi.

In alternativa, è possibile impostare la finestra di dialogo per essere modale nel file costruttore, e poi basta show() esso. In questo modo ottenere un effetto che è simile, ma non proprio la stessa di run() -. Perché run() crea una seconda istanza del ciclo GTK principale

Modifica

Il motivo si stanno ottenendo un errore di segmentazione, se non si collega al segnale delete-event è che si fa clic due volte il pulsante di chiusura. Ecco cosa accade:

  1. Si fa clic su "Esegui Dialog", questo chiama il metodo run() della finestra di dialogo.
  2. Gli viene visualizzata la finestra modale, e inizia il proprio ciclo principale.
  3. Si fa clic sul pulsante di chiusura. uscite principali ciclo della finestra di dialogo, ma dal momento che le sostituzioni run() il comportamento normale del pulsante di chiusura, la finestra di dialogo non è chiuso. Inoltre non è nascosta, quindi si blocca intorno.
  4. Ti chiedi perché il dialogo è ancora lì e di nuovo clic sul pulsante di chiusura. Dal momento che run() non è più attivo, viene attivato il comportamento normale del pulsante di chiusura:. Finestra viene distrutto
  5. si fa clic su "Esegui Dialog" ancora una volta, che cerca di chiamare il metodo run() della finestra distrutta. Crash!

Quindi, se hai la certezza di hide() la finestra di dialogo dopo il punto 3, quindi tutto dovrebbe funzionare. Non c'è bisogno di connettersi al segnale delete-event.

Altri suggerimenti

Ho appena passato un po 'di tempo per capire questo fuori. Re-recupero lo stesso oggetto da un costruttore non creerà una nuova istanza dell'oggetto, ma restituire solo un riferimento al vecchio oggetto (distrutto). Se si crea una nuova istanza costruttore, tuttavia, e caricare il file nel nuovo costruttore, si creerà una nuova istanza.

Quindi la mia funzione di creazione finestra simile a questa:

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

Si noti che non sto di blocco per una risposta con run () in questo caso perché sto utilizzando contorto, ma dovrebbe essere equivalente.

Il dialogo dovrebbe solo bisogno di eseguire una sola volta. Assumendo una voce di menu trigger la finestra di dialogo, il codice dovrebbe essere simile a questo:

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() è un blocco principale ciclo che ritorna quando la finestra di inviare una risposta. Questo avviene normalmente tramite il pulsanti OK e Annulla. Quando questo accade, la finestra è finito e deve essere distrutto.

Per visualizzare la finestra di dialogo più volte, l'utente deve seguire lo stesso flusso di lavoro (nell'esempio di cui sopra, che sarebbe cliccando su una voce di menu). La finestra di dialogo è responsabile, in __init__, per ponendosi. Se si hide() la finestra di dialogo, avete il problema di comunicare con quel dialogo in modo che rimanga up-to-date con il resto dell'applicazione anche quando è nascosta .

Una delle ragioni per alcune persone vogliono "eseguire la finestra di dialogo più volte" è perché l'utente ha inserito informazioni non valide, e si vuole dare all'utente la possibilità di correggerlo. Questo deve essere affrontato nel gestore segnale di risposta della finestra di dialogo. L'ordine degli eventi in una finestra è:

  1. User spinge fisicamente il pulsante Ok
  2. Finestra invia la risposta gtk.RESPONSE_OK (-5)
  3. Dialog chiama il gestore per il segnale di risposta
  4. Dialog chiama il gestore per il pulsante Ok
  5. metodo run() Dialog restituisce la risposta

Per evitare che i punti 4 e 5 accada, il gestore risposta deve sopprimere il segnale di risposta. Questo risultato è ottenuto nel seguente modo:

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')
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top