2012-05-11 13 views
5

Ho scritto un modulo breve che può essere passato a un'immagine e crea semplicemente una finestra di Tkinter e la visualizza. Il problema che sto avendo è che anche quando istanzio e chiamo il metodo che visualizza l'immagine in un thread separato, il programma principale non continuerà fino a quando la finestra di Tkinter non verrà chiusa.Esecuzione di un modulo Tkinter in una filettatura separata

Ecco il mio modulo:

import Image, ImageTk 
import Tkinter 


class Viewer(Tkinter.Tk): 
    def __init__(self,parent): 
     Tkinter.Tk.__init__(self,parent) 
     self.parent = parent 
     self.initialize() 

    def initialize(self): 
     self.grid() 

    def show(self,img): 
     self.to_display = ImageTk.PhotoImage(img) 
     self.label_image = Tkinter.Label(self,image=self.to_display) 
     self.label_image.grid(column = 0, row = 0, sticky = "NSEW") 
     self.mainloop() 

Sembra funzionare bene, tranne quando chiamo dal mio programma di test come quella qui sotto, non sembrerà a permettere che il mio programma di test per continuare, anche quando iniziato in un thread diverso.

import Image 
from viewer import Viewer 
import threading 

def showimage(im): 
    view = Viewer(None) 
    view.show(im) 

if __name__ == "__main__": 
    im = Image.open("gaben.jpg") 
    t = threading.Thread(showimage(im)) 
    t.start() 
    print "Program keeps going..." 

penso che forse il mio problema è che dovrei essere la creazione di un nuovo thread all'interno del modulo stesso, ma mi è stato che vogliono provare giusto e mantenerlo semplice, come io sono nuovo a Python.

In ogni caso, grazie in anticipo per qualsiasi tipo di assistenza.

modifica: Per maggiore chiarezza, sto solo provando a creare un modulo che visualizzerà un'immagine in una finestra di Tkinter, in modo che possa utilizzare questo modulo ogni volta che voglio visualizzare un'immagine. Il problema che sto avendo è che ogni volta che un programma usa questo modulo, non può riprendere finché la finestra di Tkinter non viene chiusa.

risposta

5

Dai tuoi commenti sembra che tu non abbia bisogno di una GUI. Basta scrivere l'immagine su disco e chiamare un visualizzatore esterno.

Sulla maggior parte dei sistemi dovrebbe essere possibile avviare il visualizzatore predefinito utilizzando qualcosa di simile:

import subprocess 

subprocess.Popen("yourimage.png") 
2

Da quello che posso dire, a Tkinter non piace suonare in altri thread. Vedi questo post ... I Need a little help with Python, Tkinter and threading

Il lavoro attorno è creare un toplevel (possibilmente nascosto) nel thread principale, generare un thread separato per aprire le immagini, ecc. - e usare una coda condivisa per inviare i messaggi al Tk filo.

È necessario utilizzare Tkinter per il progetto? Mi piace Tkinter. È "veloce e sporco". - ma ci sono (molti) casi in cui altri kit GUI sono la strada da percorrere.

+1

La prima parte della risposta è buona, ma non posso andare avanti a causa del consiglio di provare altri toolkit. Tkinter è perfettamente adatto al tipo di cosa di cui tratta questa domanda. –

10

Tkinter non è thread-safe e il consenso generale è che Tkinter non funziona in un thread non principale. Se riscrivi il tuo codice in modo che Tkinter venga eseguito nel thread principale, puoi far funzionare i tuoi worker in altri thread.

L'avvertenza principale è che i lavoratori non possono interagire con i widget di Tkinter. Dovranno scrivere i dati in una coda e il thread principale della GUI dovrà interrogare quella coda.

Se tutto quello che stai facendo è mostrare le immagini, probabilmente non hai bisogno di threading. Il threading è utile solo quando si ha un processo di lunga durata che altrimenti bloccherebbe la GUI. Tkinter può facilmente gestire centinaia di immagini e finestre senza alcuna fatica.

+0

Grazie mille per il consiglio. Ho notato che se eseguo self.mainloop() nel modulo di visualizzazione, come nell'esempio precedente, non continuerà mai con il mio programma effettivo fino a quando la finestra non verrà chiusa. Fa la stessa cosa se inserisco questa linea nel programma (ad esempio view.mainloop()). Avevo pensato che mettere questa linea in un thread separato potesse risolvere il problema. Stai dicendo che dovrei essere in grado di farlo senza fare il threading, vuoi dire che c'è un modo per visualizzare la finestra senza mainloop()? – ballsatballsdotballs

+0

@ballsdotballs: è necessario chiamare 'mainloop' se si intende creare una GUI interattiva. Per sua stessa natura, poiché stai eseguendo un ciclo di eventi probabilmente non hai bisogno di thread. È vero che dopo aver chiamato 'mainloop'" non continuerà mai con [il tuo] programma attuale ", ma è così che è progettato per funzionare. Stabilisci il ciclo, quindi il tuo programma risponde solo agli eventi. 'mainloop' è quasi sempre l'ultima riga di codice nella logica di avvio dell'applicazione. –

+0

Penso che il problema sia, voglio semplicemente scrivere un modulo che mostri un'immagine. Ho bisogno di un modo per il mio programma di continuare a correre dopo che usa questo modulo, invece di aspettare che l'utente chiuda l'immagine. Intendi dire che non c'è modo di usare Tkinter per farlo? – ballsatballsdotballs

3

ho cercato di eseguire tkinter da un thread separato, non è una buona idea, si blocca. C'è una soluzione che ha funzionato. Esegui la GUI nel thread principale e invia eventi alla GUI principale. Questo è un esempio simile, mostra solo un'etichetta.

import Tkinter as t 
global root; 
root = t.Tk() 
root.title("Control center") 
root.mainloop() 

def new_window(*args): 
    global root 
    print "new window" 
    window = t.Toplevel(root) 
    label = t.Label(window, text="my new window") 
    label.pack(side="top", fill="both", padx=10, pady=10) 
    window.mainloop() 

root.bind("<<newwin>>",new_window) 

#this can be run in another thread 
root.event_generate("<<newwin>>",when="tail") 
Problemi correlati