Managing user interface elements in wxPython using threads

I am writing a simple game using Python / wxWidgets.

I wrote a class for the main window and a simple class for another frame that receives user input.

The architecture that I still have is that the application launches and launches a second thread that performs a function called "gameLogic". The main thread then goes into the main loop of the application.

The gameLogic thread runs sequentially and requires user interface control. For example, you need to open a new dialog box with the main frame as the parent. However, I found that this leads to crashes (bad enough to pop up a report failure window in OS X).

I searched and collected what I need to reorganize in order to use events, but I'm not sure how to do this, create my own events. I could have the gameLogic stream raise an event in the main window, which will then open the input dialog and wait for the input (modally), and then return this data back to the gameLogic stream. The gameLogic thread may block while waiting because the user interface thread is separate.

In the function (event handler) in my main frame, I can create a new instance of the input dialog box, show it modally, and then get the input.

I saw all kinds of ideas for implementing this, but I could not find a good example of how to create a custom event in my wxFrame object and call it from another thread, and also have the flow block logic and wait until the input returns, and then how to get this entry back to gameThread.

Advice praised!

+2
source share
1 answer

First, the hard part:

I saw all kinds of ideas for implementing this, but could not find a good example of how to create a custom event in my wxFrame object and call it from another thread

Here is an example of this right in wxPyWiki . You can also see a link to Working with wxPython in a separate thread .

However, I think the wxPython blog post and themes are from The Mouse Vs. Python explains the hard part best. And it also shows you an easier way to do this (using CallAfter and Publisher instead of posting custom events), but let it stick to what you requested.

The only thing he lacks:

... and also have a logical thread block and wait until the input returns, and then how to get this input back to gameThread.

But nothing is said there. The only reason sending information to wx (or any event loop) is complicated because the event loop cannot be blocked. Your logical thread can block, but really should. So any normal thread synchronization mechanism is just fine.

So, you have one thread that wants to block forever until the value is ready, and another thread that wants to send this value without blocking. You can do this quite easily with Condition or Queue . The latter is probably crowded here, but it is more flexible, so let's do it just for fun.

I will take an example from the Mouse blog and make sure that every time the background thread dispatches the EVT_RESULT event, it blocks until this event is processed, returning a line that can ... write or something else, I I think this is not very useful, but I wanted to show that he was missing something.

 from queue import Queue # ... class TestThread(Thread): # ... def run(self): for i in range(6): # ... wx.PostEvent(self.wxObject, ResultEvent(amtOfTime) result_from_gui = self.wxObject.q.get(True, None) # ... class MyForm(wx.Frame): # ... def __init__(self): # ... self.q = Queue() # ... def updateDisplay(self, msg): # ... t = msg.data if isinstance(t, int): text = "Time since thread started: %s seconds" % t else: text = "%s" % t self.btn.Enable() self.displayLbl.SetLabel(text) self.q.put(text) 

In this example, the GUI thread executes self.q.put(text) at the end of updateDisplay . There is no magic reason why it should be there, and then - while this happens (and exactly 1 time), the logical flow will be blocked until this happens. For example, the updateDisplay method can create a new button and send self.q.put (and delete the button) when the user clicks on it.

+1
source

Source: https://habr.com/ru/post/1480010/


All Articles