Events, während meine schleife läuft?

Fragen zu Tkinter.
Antworten
jörg

Hallo,
ich hätte da mal folgendes noob-problem...
Wie schaffe ich es denn dass mein Programm auf Events in der GUI reagiert,
während es in einer Schleife steckt, also zB in folgendem Fall:

Code: Alles auswählen

from Tkinter import *
from math import *

class App:

    def __init__(self, master):

        frame = Frame(master)
        frame.pack()

        self.button_quit  = Button(frame, text="quit",  command=frame.quit)
        self.button_quit.pack()

        self.button_sinus = Button(frame, text="Sinus", command=self.sinus)
        self.button_sinus.pack()

    def sinus(self):
        for i in range(1000):
           print i,":",sin(i)

root = Tk()

app = App(root)

root.mainloop()

Da wär's natürlich gut wenn der Quit-Button auch während der sinus-schleife
funktioniert, noch besser wär's wenn's neben 'quit' auch einfach ein 'cancel' gäbe,
und schliesslich brauch ich das ganze aber eigentlich für ein programm dass Webseiten
liest - also das (fern-)ziel wäre ein 'cancel'-button während urllib.urlretrieve() läuft...

Ich rauf mir über dieser Frage schon seit gestern abend die Haare, das blöde ist,
dass sowohl mein Programm ganz gut funkt als auch die GUI schick aussieht, bloss
die Zusammenführung hängt eben schon an dieser simplen Geschichte...
Danke schon jetzt für eure Antworten,
jörg

EDIT mawe: code in python-tags geändert
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Eigentlich hab ich keine Ahnung von TKinter... Aber ist command=frame.quit richtig??? Kann man direkt vom Button aus, das "Frame beenden" oder muß nicht vielmehr eine Funktion ala self.QuitFrame aufgerufen werden???
mawe
Python-Forum Veteran
Beiträge: 1209
Registriert: Montag 29. September 2003, 17:18
Wohnort: Purkersdorf (bei Wien [Austria])

Hi!

Du könntest thread verwenden:

Code: Alles auswählen

from Tkinter import *
import thread
from math import sin

class App:
	def __init__(self,master):
		frame = Frame(master)
		frame.pack()

		self.button_quit = Button(frame, text="Quit", command=frame.quit)
		self.button_quit.pack()

		self.button_sinus = Button(frame, text="Sinus", command=self.sinus)
		self.button_sinus.pack()
	
	def sinus(self):
		thread.start_new_thread(self.calc_sin,())
	
	def calc_sin(self):
		for i in range(100000):
			print i,":",sin(i)

root = Tk()
app = App(root)
root.mainloop()
Gruß, mawe
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

jens hat geschrieben:Eigentlich hab ich keine Ahnung von TKinter... Aber ist command=frame.quit richtig??? Kann man direkt vom Button aus, das "Frame beenden" oder muß nicht vielmehr eine Funktion ala self.QuitFrame aufgerufen werden???
Ich zwar auch nicht, aber es schein zu funktionieren, denn bei mir beendet sich Python dadurch (ja, ok, er wird vom OS gekillt, aber das ist bei mir mit Tk oft so).

jörg, was du brauchst ist threading bzw. das lowlevel modul thread.

Edit: Typos ;) - oje meine Beiträge sind zum Teil so schlimm geschrieben
Zuletzt geändert von Leonidas am Dienstag 7. Dezember 2004, 19:13, insgesamt 1-mal geändert.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Dookie
Python-Forum Veteran
Beiträge: 2010
Registriert: Freitag 11. Oktober 2002, 18:00
Wohnort: Salzburg
Kontaktdaten:

Hi,

du musst in der Schleife update_idletasks() aufrufen.


Gruß

Dookie
[code]#!/usr/bin/env python
import this[/code]
jörg

...ich probier schon grad mit "thread" und "threading" rum ("threading" ist mir irgendwie sympathischer,
allerdings frage ich mich bei beiden im Moment noch wie man denn von aussen (also zB aus
der function eines 'cancel'-Buttons) einen bestimmten Thread beenden kann).

Ich glaube dieses problem hätte ich doch womöglich auch mit update_idletasks(),
oder? Dann könnte ich zwar mit frame.quit einfach das ganze Programm beenden, aber wie
beende ich denn nur einen meiner (sub-)threads? Fantastisch wäre dafür ja sowas wie

Code: Alles auswählen

def startbutton(self):
   mythread.start()

def cancelbutton(self):
   mythread.stop()

OK, mythread.start() gibt's ja, aber ...stop()?
jörg

Noch zur Ergänzung, grad sieht also mein Programm so aus:

Code: Alles auswählen


from Tkinter import *
import threading
import math

class printsin(threading.Thread):
    def __init__(self, endrange):
        threading.Thread.__init__(self)        
        self.endrange = endrange
        
    def run(self):
        for i in range(self.endrange):
            print i," : ",math.sin(i)

class App:
    def __init__(self,master):
        frame = Frame(master)
        frame.pack()

        self.button_quit = Button(frame, text="Quit", command=frame.quit)
        self.button_quit.pack()

        self.button_sinus = Button(frame, text="Sinus", command=self.sinus)
        self.button_sinus.pack()

        self.button_cancel = Button(frame, text="Cancel Sinus", command=self.cancel)
        self.button_cancel.pack()
   
    def sinus(self):
        sinusthread = printsin(1000)
        sinusthread.start()
   
    def cancel(self):
        print "cancel pressed!"
        
root = Tk()
app = App(root)
root.mainloop() 
Das klappt auch ganz gut so - erst ist es immer abgestürzt wenn ich nachdem der
Thread gestartet wurde einen Button gedrückt habe, aber grad hab ich bemerkt
dass das nur dran lag dass ich das prog unter IDLE gestartet hatte - ohne IDLE klappt
es schon fast so wie es soll (der quit-button funktioniert nicht, frame.quit beendet das
Programm erst dann, wenn der sinus-thread durch ist...)

Bleibt also die Frage, wie komme ich im Nachhinein noch an den Thread ran?

EDIT mawe: code in python-tags geändert
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hallo Jörg

Hier ist eine Möglichkeit Deinem Sinusrechner
den Wind aus den Segeln zu nehmen.

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: iso-8859-15 -*-

from   Tkinter import *
import threading
import math

class printsin(threading.Thread):
    def __init__(self, endrange):
        threading.Thread.__init__(self)
        self.endrange = endrange
        self.stopflag = FALSE

    def run(self):
        for i in range(self.endrange):
            if self.stopflag == TRUE:
               break
            print i," : ",math.sin(i)


class App:
    def __init__(self,master):
        frame = Frame(master)
        frame.pack()

        #self.button_quit = Button(frame, text="Quit", command=frame.quit)
        self.button_quit = Button(frame, text="Quit")
        self.button_quit.pack()
        self.button_quit.bind("<Button-1>", self.FrameQuit)

        self.button_sinus = Button(frame, text="Sinus", command=self.sinus)
        self.button_sinus.pack()

        self.button_cancel = Button(frame, text="Cancel Sinus", command=self.cancel)
        self.button_cancel.pack()

    def FrameQuit(self,event):
        self.sinusthread.stopflag = TRUE
        root.destroy()

    def sinus(self):
        self.sinusthread = printsin(10000)
        self.sinusthread.start()

    def cancel(self):
        print "cancel pressed!"

root = Tk()
app = App(root)
root.mainloop()
Gruss wuf :wink:
Take it easy Mates!
jörg

Puh, sehr schön... in die Richtung hatte ich schon gar nicht mehr gedacht, dabei war's so simpel... Danke, danke... :)
Antworten