Habe nochmals proxy.py überarbeitet. Jetzt threadsicher nach mainloop und arbeitet auch schon vorher. Enthält auch GUI Funktionsaufruf von anderem Thread aus: execute_lambda
Sorry wegen Tab und nicht vier Leerzeichen. Mein Editor macht es leider nicht anders (für python3):
Code: Alles auswählen
import queue
_mainloop_started = False
Proxy=None
class MessageProxy:
def __init__(self,app):
self.reset(app)
def reset(self,app):
self.app = app
self.Dictionary = {}
self.Queue = queue.Queue()
self.owners = {}
self.counter = 0
self._register("execute_function",lambda msg: msg())
self.app.bind("<<SEND>>",self._send)
def send(self,msgid,msgdata=None):
global _mainloop_started
if _mainloop_started:
self.Queue.put((msgid,msgdata))
self.app.event_generate("<<SEND>>", when="tail")
else:
if self.counter == 0: self._sendImmediate(msgid,msgdata)
else: self.Queue.put((msgid,msgdata))
def execute_lambda(self,cmd): self.send("execute_function",cmd)
# used before mainloop has started - not thread secure - and the first has to wait until all messages are executed
def _sendImmediate(self,msgid,msgdata=None):
while True:
if msgid in self.Dictionary:
receivers = self.Dictionary[msgid].items()
self.counter += 1
for receive,active in receivers:
if active: receive(msgdata)
self.counter -= 1
if self.counter > 0: return
if self.Queue.empty(): return
data = self.Queue.get()
msgid = data[0]
msgdata = data[1]
def _send(self,*args):
try:
data = self.Queue.get()
msgid = data[0]
msgdata = data[1]
if msgid in self.Dictionary:
receivers = self.Dictionary[msgid].items()
for receive,active in receivers:
if active: receive(msgdata)
except: print("sendQeue error")
def _register(self,msgid,receive):
if msgid not in self.Dictionary: self.Dictionary[msgid] = {}
self.Dictionary[msgid][receive] = True
def do_receive(self,owner,msgid,receive):
if not owner in self.owners: self.owners[owner] = {}
self.owners[owner][receive]=msgid
self._sendImmediate('execute_function',lambda: self._register(msgid,receive))
def activate_receive(self,msgid,receive,flag):
if msgid in self.Dictionary:
receivers = self.Dictionary[msgid]
if receive in receivers:
receivers[receive] = flag
def _unregister2(self,msgid,receive):
if msgid in self.Dictionary:
receivers = self.Dictionary[msgid]
if receive in receivers:
receivers.pop(receive,None)
if len(receivers) == 0: self.Dictionary.pop(msgid,None)
def _unregister1(self,msgid,receive):
self.activate_receive(msgid,receive,False)
self._sendImmediate('execute_function',lambda: self._unregister2(msgid,receive))
def undo_receive(self,owner,msgid,receive):
if owner in self.owners:
if receive in self.owners[owner]: self.owners[owner].pop(receive,None)
self._unregister1(msgid,receive)
def undo_receiveAll(self,owner):
if owner in self.owners:
messages = self.owners[owner]
self.owners.pop(owner,None)
for receive,msgid in messages.items():
self._unregister1(msgid,receive)
# define message callback - the callback function must have minimum one parameter for the message - same as event callbacks with message instead of event
def do_receive(owner,msgid,receive): Proxy.do_receive(owner,msgid,receive)
# send a message to registered receivers
def send(msgid,message=None): Proxy.send(msgid,message)
# calling a GUI command - thread secure, after mainloop has started
def execute_lambda(cmd): Proxy.execute_lambda(cmd)
# this you should call, if you destroy the owner - normally a container frame or an instance of a class
def undo_receiveAll(owner): Proxy.undo_receiveAll(owner)
# undefine message callback - normally not used
def undo_receive(owner,msgid,receive): Proxy.undo_receive(owner,msgid,receive)
# ========== Initialising the Message System ============================
# call this when oder after initialising your tk (root = tk.Tk())
def init_proxy(root):
global Proxy
_mainloop_started = False
Proxy = MessageProxy(root)
return root
# call this immediately before you start your mainloop
def mainloop_starts():_mainloop_started = True
# ==========================================================================
Also irgendwie scheinen mir die normalen command und event callbacks nicht sicher zu sein. Wenn ich etwa einen zweiten GUI Designer nachlade, stürzt das Programm ab.
Wenn ich allerdings commands und events nochmals mittels execute_lambda über die Queue schicke, läuft alles wunderbar ohne Probleme.
Das hatte ich bei anderen Gelegenheiten auch schon gemerkt. Ob das ein Ubuntu Problem sein könnte? Aber über die Queue als Message alles problemlos.