[asking for help] Confliction with periodic multi-thread tasks? Asking for a solution...... #2083
-
The situation: def Support:
def __init__(self,app):
self.app=app
...
self.executor=concurrent.futures.ThreadPoolExecutor(max_workers=5) # multi-threading
self._intervals={'keep':1,'msg':2} # time intervals, in seconds
......
def login(self):
...
# after successful login
self.executor.submit(self.update_connection,self._intervals['keep']) # no bugs currently
self.executor.submit(self.refresh_messages,self._intervals['msg']) where class MyApp(toga.App):
......
def startup(self):
self.supports=Supports(self)
... The crucial problem now, is that i can find no way of presenting the chat message (successfully obtained from server). I have tried using Widgets, such as my current (not-working) code: # in class Support
def refresh_messages(self,interval:int|float):
while self.alive:
if self.user:
... # gets response from server
if response['message'].startswith('Successful'):
public_messages=response['data']['messages']
if public_messages:
self.app.received_messages_multiline.value=public_messages ######
......
self.sleep(interval) related objects: # in Support
self.alive: bool=True
self.user: str='' # will be non-empty if successfully logged-in
response: {'message':str, 'data':dict}
# in MyApp
self.received_messages_multiline=toga.MultilineTextInput(
style=Pack(padding=(10,5)), readonly=True, value=''
) Now, for the marked line above (######), it just wouldn’t work...... however the functionality is just as expected, as soon as i replace that line with is it because of the problem with re-assigning string values for Labels/Multi-line? What might be a possible solution for my wished effects? Thanks for anyone who have read this whole lot~~ |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 6 replies
-
There's no problem changing the value of a MultilineTextInput. The problem is that you can't do this from a thread (at least, not reliably, on all platforms). Generally speaking, GUI toolkits are sensitive to having GUI operations only performed on the GUI thread. This isn't 100% true on all GUI toolkits, but it's a sufficiently widespread property of GUI toolkits that it's safe to assume it's the default behavior unless you know otherwise. Being a cross-platform toolkit, Toga is effectively constrained by the lowest-common denominator, which means you shouldn't depend on being able to modify your GUI from a non-GUI thread. There's 2 possible fixes in your case:
In option 1, your worker code remains the same; however, instead of directly changing the value of the MultilineTextWidget, you put a message on a queue with the change you want to make. Then, on the main GUI thread, you install a background worker that periodically wakes up and applies those changes In option 2, you set up a worker to run as a background task that enters a The magic sauce behind both 1 and 2 is
or a co-routine:
This generator or co-routine will run on the main GUI thread, but won't block the GUI thread during the "sleep" portion. So - as long as the rest of the logic in the handler is fast, it will happily live as a background worker, ticking every second until the app exits. However, you can't use What does "fast" mean? Well, 0.1s max total runtime between sleeps is a reasonable rule of thumb - but the faster the better. This generally means that synchronous API calls to do external network access won't be viable in a handler - but you can use asynchronous network APIs in an async handler. If you use an async |
Beta Was this translation helpful? Give feedback.
There's no problem changing the value of a MultilineTextInput. The problem is that you can't do this from a thread (at least, not reliably, on all platforms).
Generally speaking, GUI toolkits are sensitive to having GUI operations only performed on the GUI thread. This isn't 100% true on all GUI toolkits, but it's a sufficiently widespread property of GUI toolkits that it's safe to assume it's the default behavior unless you know otherwise. Being a cross-platform toolkit, Toga is effectively constrained by the lowest-common denominator, which means you shouldn't depend on being able to modify your GUI from a non-GUI thread.
There's 2 possible fixes in your case: