Hallo,
dank der Hilfe hier im Forum habe ich ein Tkinter Programm, dass den print Befehl in einer Endlosschleife ausführt mit einem Button zum Stoppen der Schleife (http://www.python-forum.de/viewtopic.php?f=18&t=36170). Jetzt möchte ich in der Schleife ein externes Gerät steuern, was einige Minuten dauert und auch währenddessen die Schleife abbrechen können. Sollte ich das mit 2 Threads machen oder gibt es da einen bessere Lösung? Hier https://gist.github.com/zed/4067619wurde ein ähnliches Problem z.B. mit subprocess gelöst
Threads um Endlosschleife abzubrechen?
Threads zu nutzen wäre durchaus sinnvoll. Bei der Verwendung von Threads würdest du einen Thread haben indem du mit dem Gerät kommunizierst, diesem Thread würdest du über eine Queue Nachrichten schicken wie z.B. abbrechen und du würdest after bzw. after_idle nutzen um eine Methode im GUI Thread mit einer Nachricht aufzurufen die auf die dann mit Veränderungen an der GUI reagiert werden kann.
Danke für deinen Beitrag. Zum testen habe ich mal diesen Thread genommen:
Das Fenster lässt sich bedienen während die Schleife läuft. Aber leider kriege ich das Abbrechen der Schleife nicht hin. Wenn der Stop Button gedrückt wird sollte sich der Thread beenden, auch wenn er grade time.sleep ausführt. Könnt Ihr mir einen Tipp geben was ich machen muss?
Code: Alles auswählen
class sleepThread(threading.Thread):
def run(self):
i = 1
while True:
print (i)
time.sleep(15)
i = i+1
Oh, deinen letzten Beitrag hatte ich nicht mehr gelesen. Ist zwar schon eine Weile her und der Programmteil funktioniert auch ganz gut, aber fals noch jemand einen Tipp hat was man es besser programmieren kann würde ich mich freuen. Hier der Code:
Das beim Drücken von Start noch jedesmal ein neuer Thread erstellt wird wollte ich noch ändern.
Code: Alles auswählen
from functools import partial
import ScrolledText
import serial
import threading
import time
import tkFileDialog
import Tkinter as tk
class ProgrammThread(threading.Thread):
def __init__(self, masetr=None):
threading.Thread.__init__(self)
self.stop_signal = False
def run(self):
k = 0
while True:
if self.stop_signal == False:
#hier wird in jedem Durchlauf ein anderer Befehl ausgeführt
if k == 10: break
k = k+1
main_frame.stop()
class MainFrame(tk.Frame):
def __init__(self, master=None):
tk.Frame.__init__(self, master)
self.start_button = tk.Button(self, text='Skript Starten', relief='flat', command=self.start)
self.start_button.grid(row=0, column=4, sticky='W')
self.stop_button = tk.Button(self, text='Stop', state=tk.DISABLED, relief='flat', command=self.stop)
self.stop_button.grid(row=0, column=5, sticky='W')
def start(self):
self.start_button['state'] = tk.DISABLED
self.stop_button['state'] = tk.NORMAL
self.programm = ProgrammThread()
self.programm.setDaemon(True)
self.programm.start()
def stop(self):
self.start_button['state'] = tk.NORMAL
self.stop_button['state'] = tk.DISABLED
self.programm.stop_signal = True
if __name__ == '__main__':
root = tk.Tk()
main_frame = MainFrame(root)
main_frame.pack()
root.mainloop()
@semper27: Zeile 19 wäre ja das Interessante. stop_signal sollte nie etwas anderes sein als False, weil Du sonst eine Endlosschleife hast. So wie es jetzt geschrieben ist, ist es nur eine komplizierte for-Schleife:
Aus Threads heraus darf die GUI nicht verändert werden, Du mußt also innerhalb der GUI per after regelmäßig abfragen, ob der Thread noch läuft; außerdem ist main_frame eine globale Variable, die nicht existieren sollte; die Zeilen in 'if ... __main__' gehören in eine Funktion, die üblicherweise main heißt. Eingerückt wird mit 4 Leerzeichen.
Code: Alles auswählen
def run(self):
for k in range(11):
if self.stop_signal:
break
do_something()
@semper27: `ProgrammThread.__init__` hat ein `masetr`-Argument, das überhaupt nicht verwendet wird.
Ungetestet:
Ungetestet:
Code: Alles auswählen
#!/usr/bin/env python
# coding: utf8
from __future__ import absolute_import, division, print_function
import Tkinter as tk
from threading import Thread
from time import sleep
class ProgramThread(Thread):
def __init__(self):
Thread.__init__(self)
self.stop_signal = False
def run(self):
for i in xrange(11):
if self.stop_signal:
break
print(i)
sleep(1)
class MainFrame(tk.Frame):
def __init__(self, master=None):
tk.Frame.__init__(self, master)
self.thread = None
self.start_button = tk.Button(
self, text='Skript Starten', command=self.start
)
self.start_button.pack(side=tk.LEFT)
self.stop_button = tk.Button(
self, text='Stop', state=tk.DISABLED, command=self.stop
)
self.stop_button.pack(side=tk.LEFT)
def _check_thread(self):
if self.thread.is_alive():
self.after(500, self._check_thread)
else:
self.start_button['state'] = tk.NORMAL
self.stop_button['state'] = tk.DISABLED
self.thread = None
def start(self):
assert self.thread is None
self.start_button['state'] = tk.DISABLED
self.stop_button['state'] = tk.NORMAL
self.thread = ProgramThread()
self.thread.daemon = True
self.thread.start()
self._check_thread()
def stop(self):
assert self.thread is not None
self.thread.stop_signal = True
def main():
root = tk.Tk()
main_frame = MainFrame(root)
main_frame.pack()
root.mainloop()
if __name__ == '__main__':
main()