BlackJack hat geschrieben:@Alfons Mittelmeyer: Das mit dem Kontextwechsel bei Threads hatte ich gerade im dedizierten Thema dazu beantwortet, darum hier nur kurz: Es werden native Threads verwendet soweit auf dem System vorhanden, man muss also allgemein davon ausgehen das der Wechsel auf Prozessorebene stattfindet wenn man threadsicher programmieren will. `Queue.Queue` aus der Standardbibliothek ist aber beispielsweise von der Dokumentation her garantiert threadsicher und `collections.deque` auch. So etwas muss man sich also nicht aus einer Liste und Sperrobjekten selber basteln.
Also hab es mal mit queue (Python3) gemacht. Hier das Modul execute_gui.py:
Code: Alles auswählen
from spazieren import *
import queue
_queue = queue.Queue()
_root = None
def _execute(*args):
try: _queue.get()()
except: print("execute error")
def init(root):
global _root
_root = root
root.bind("<<EXEC>>",_execute)
def execute(command):
_queue.put(command)
_root.event_generate("<<EXEC>>", when="tail")
Und dazu das angepasste buttons.py:
Code: Alles auswählen
from spazieren import *
import execute_gui
import threading
class App:
def __init__(self, master):
frame = Frame(master)
frame.pack()
self.button = Button(frame,
text="QUIT", fg="red",
command=frame.quit)
self.button.pack(side=LEFT)
self.slogan = Button(frame,
text="Hello",
command=self.write_slogan)
self.slogan.pack(side=LEFT)
def write_slogan(self):
print("Tkinter is easy to use!")
root = Tk()
app = App(root)
ls()
execute_gui.init(root)
class MyThread(threading.Thread):
def run(self):
while True:
a = input("> ")
try:
command = lambda cmd=compile(a+"\nls()",'<string>', 'exec'): eval(cmd)
execute_gui.execute(command)
except: print("Error:",a)
mythread = MyThread()
mythread.daemon = True
mythread.start()
root.mainloop()
Hoffe, dass das jetzt auch unter Windows geht.
Außerdem hattest Du geschrieben:
BlackJack hat geschrieben:@Alfons Mittelmeyer: Events sind auch thread-safe, allerdings benutzt das kaum jemand weil die Implementierung in der `Tkinter`-Anbindung nicht vollständig ist. Man kann nur Ereignisse ohne zusätzlich Daten auslösen, also wirklich nur ein Event mit einem eigenen Namen ohne das man da weitere Informationen mitgeben kann. Wenn einem das reicht, kann man das natürlich so verwenden. In der Praxis habe ich das aber nur *sehr* selten gesehen, in der Regel wird einem immer eine `Queue.Queue` und `after()`/`after_idle()` nahegelegt.
Stimmt natürlich nicht ganz, denn den command kann man auch mit Parametern machen. Sozusagen Funktionsaufruf von außen in Gui Callback verwandelt.