Search code examples
pythonmultithreadingwxpython

HOW to multithread an EVT_MOTION handler and other Functions in wxPython


I have 2 functions.

The first function responds to a key event that moves everything that is already drawn on my screen to the left (pan right).

The second function is my onMove handler that redraws a line to my current cursor position when my mouse moves. (Think of drawing a line in a cad program)

My problem is that while my screen is slowly panning right, my mouse motion is not captured. What is the most efficient to allow for motion of my drawn objects while also capturing my mouse movement?

I suspect that multithreading is the answer. However, I attempted this as per "wxPython in Action" and wx.CallAfter() with no success. I could make the program successfully run in that configuration but the mouse movement problem persisted.

This handles a "pan right" command initiated by pressing the "f" key:

elif key == 70:
    timeincrement = .01
    t = .5  # number of seconds we want to move
    a = -500  # pixels per second squared
    v = 1000  # initial pixel velocity pixels per second
    x = 0  # starting time
    start = copy(parent.xloc)

    while x <= t:
        x = x + timeincrement

        # Below is the current location of the center of the screen 
        # based on the acceleration values listed above
        dist = ((v * x) + (.5 * a * x ** 2)) / (72 * parent.zoom)  

        sleep(timeincrement)
        parent.xloc = start + dist
        parent.drawingpanel.updateDrawing()

This handles the EVT_MOTION

def onMove(self, evt):
    position = evt.GetPosition()
    self.parent.mousepos = (position.x, position.y)
    self.updateDrawing()

Any help would be appreciated.


Solution

  • You indeed need another thread if you sleep in the main one :-) Anyway, as you know, you cannot really have the wx functions run in more than one thread, therefore I would suggest having a thread that waits on a Queue. When it finds something in the queue, it will perform the scrolling and call wx.Window.Refresh() to "schedule" the repaint. I am not sure if you can call Refresh from the thread, maybe you will have to do something like a PostMessage to tell the main thread to do the refresh.

    The actual painting will be done in your OnPaint based on the data prepared by this thread.

    In the main thread, you will handle the key press and add something into the queue on the right key.

    The mouse motion events should not get lost anymore.