2012-05-11 14 views
5

Napisałem krótki moduł, który może być przekazany obrazowi i po prostu tworzy okno Tkinter i wyświetla je. Problem, który mam, polega na tym, że nawet gdy uruchamiam instancję i wywołuje metodę, która wyświetla obraz w oddzielnym wątku, program główny nie będzie kontynuowany, dopóki okno Tkinter nie zostanie zamknięte.Uruchamianie formularza Tkinter w oddzielnym wątku

Oto mój moduł:

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

Wydaje się działać prawidłowo, z wyjątkiem gdy zgłoszę go z mojego programu testowego jak ten poniżej, to nie wydaje się, aby umożliwić mój program testowy, aby kontynuować, nawet gdy rozpoczęty w innym wątku.

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..." 

myślę, że być może mój problem jest, że powinno być stworzenie nowego wątku w samym module, ale ja chce po prostu spróbować i keep it simple, ponieważ jestem nowy w Pythonie.

W każdym razie, z góry dzięki za pomoc.

edytuj: Dla jasności próbuję utworzyć moduł, który wyświetli obraz w oknie Tkinter, dzięki czemu będę mógł używać tego modułu w dowolnym momencie, gdy chcę wyświetlić obraz. Problem, który mam, polega na tym, że za każdym razem, gdy program używa tego modułu, nie można go wznowić, dopóki okno Tkintera nie zostanie zamknięte.

Odpowiedz

5

Z twoich komentarzy wynika, że ​​wcale nie potrzebujesz GUI. Po prostu zapisz obraz na dysk i zadzwoń do zewnętrznej przeglądarki.

W większości systemów powinno być możliwe, aby uruchomić domyślną przeglądarkę za pomocą czegoś takiego:

import subprocess 

subprocess.Popen("yourimage.png") 
2

Z tego co wiem, Tkinter nie lubi grać w innych wątkach. Zobacz ten post ... I Need a little help with Python, Tkinter and threading

Praca polega na utworzeniu (prawdopodobnie ukrytego) klucza w głównym wątku, odradzeniu oddzielnego wątku w celu otwarcia obrazów itp. - i użyciu kolejki udostępnionej do wysyłania wiadomości z powrotem do Tk wątek.

Czy musisz używać Tkintera do swojego projektu? Lubię Tkintera. Jest "szybki i brudny". - ale są (wiele) przypadków, w których inne zestawy GUI są do zrobienia.

+1

Pierwsza część odpowiedzi jest dobra, ale nie mogę przegłosować ze względu na porady dotyczące wypróbowania innych zestawów narzędzi. Tkinter doskonale nadaje się do tego, o co chodzi w tym pytaniu. –

10

Tkinter nie jest bezpieczny dla wątków, a ogólna zgoda jest taka, że ​​Tkinter nie działa w innym niż główny wątku. Jeśli przepisasz swój kod tak, aby Tkinter działał w głównym wątku, możesz mieć swoich robotników w innych wątkach.

Głównym zastrzeżeniem jest to, że pracownicy nie mogą wchodzić w interakcje z widżetami Tkinter. Będą musieli zapisać dane do kolejki, a główny wątek GUI będzie musiał odpytać tę kolejkę.

Jeśli wszystko, co robisz, pokazuje obrazy, prawdopodobnie nie potrzebujesz w ogóle nic. Nawlekanie jest przydatne tylko wtedy, gdy masz długotrwały proces, który w przeciwnym razie zablokowałby GUI. Tkinter może z łatwością poradzić sobie z setkami zdjęć i okien bez przerywania potu.

+0

Wielkie dzięki za radę. Zauważyłem, że jeśli uruchomię self.mainloop() w module przeglądarki, tak jak w powyższym przykładzie, to nigdy nie będzie kontynuowany z moim rzeczywistym programem, dopóki okno nie zostanie zamknięte. Robi to samo, jeśli umieszczę tę linię w programie (na przykład view.mainloop()). Myślałem, że umieszczenie tej linii w osobnym wątku może rozwiązać problem. Mówisz, że powinienem być w stanie to zrobić bez gwintowania, masz na myśli, że istnieje sposób wyświetlania okna bez mainloopa()? – ballsatballsdotballs

+0

@ballsdotballs: musisz wywołać 'mainloop', jeśli zamierzasz stworzyć interaktywny GUI. Ze względu na swoją naturę, ponieważ uruchamiasz pętlę zdarzeń, prawdopodobnie nie potrzebujesz wątków. To prawda, że ​​po wywołaniu "mainloop" nie będzie on kontynuował [twojego] programu ", ale w ten sposób jest przeznaczony do działania. Ustanawiasz pętlę, a twój program reaguje tylko na zdarzenia. 'mainloop' jest prawie zawsze ostatnią linią kodu w logice uruchamiania aplikacji. –

+0

Myślę, że problemem jest, po prostu chcę napisać moduł, który wyświetla obraz. Potrzebuję sposobu, aby mój program kontynuował działanie po użyciu tego modułu, zamiast czekać na użytkownika, aby zamknąć obraz. Masz na myśli, że nie ma sposobu, aby użyć Tkintera, aby to zrobić? – ballsatballsdotballs

3

Próbowałem uruchomić Tkinter z osobnym wątku, nie jest dobrym pomysłem, zamarza. Istnieje jedno rozwiązanie, które działało. Uruchom GUI w głównym wątku i wysyłaj zdarzenia do głównego Gui. To jest podobny przykład, po prostu pokazuje etykietę.

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") 
Powiązane problemy