posting mouse event to update cursor

70 views
Skip to first unread message

C M

unread,
Jul 22, 2013, 3:29:27 AM7/22/13
to wxPytho...@googlegroups.com
I have a hourglass cursor that is present during a long running task
in a thread, and when the task is done, the cursor is set back to the
standard one, but it doesn't update to that one until the user moves
the mouse. Since a return to the standard cursor is one of the cues
to the user that the processing is done, I want the cursor to return
to normal immediately.

To do this, I was trying:

self.SetCursor(self.stockCursor1)
event = wx.MouseEvent(wx.EVT_MOTION)
wx.PostEvent(self, event)

But this gives me the error:

TypeError: in method 'new_MouseEvent', expected argument 1 of type 'wxEventType'

I thought that's what I had provided, but clearly I'm misunderstanding
something. Or perhaps I'm going about updating the cursor entirely
the wrong way?

Robin Dunn

unread,
Jul 22, 2013, 1:08:42 PM7/22/13
to wxpytho...@googlegroups.com
wx.EVT_MOTION is an instance of a Python class called wx.PyEventBinder.
It has an attribute that is the C++ wxEventType value (an integer):

>>> wx.EVT_MOTION
<wx._core.PyEventBinder object at 0x595cd0>
>>> wx.EVT_MOTION.typeId
10033
>>>

> Or perhaps I'm going about updating the cursor entirely
> the wrong way?

However I don't think posing the event like the above will actually do
the job. It doesn't actually send the system level messages that will
move the cursor and in turn generate the corresponding events. It just
sends the wx event through the wx layers.

To really move the cursor you can use wx.Window.WarpPointer. On the
other hand, perhaps just a wx.WakeUpIdle() will work, or a wx.Yield().

--
Robin Dunn
Software Craftsman
http://wxPython.org

C M

unread,
Jul 22, 2013, 2:25:27 PM7/22/13
to wxpytho...@googlegroups.com
I tried these last two now, and neither worked. Maybe I'm using them
wrongly? I tried them either before or after the SetCursor() call,
but neither did it.

I'm probably missing some key point here... For more info, here is the
structure of the relevant code:

I start a new thread (using the thread module, not the threading
module) that calls the function self.StartProcess():

status = thread.start_new_thread( self.StartProcess, ("Thread-1",))

Within the StartProcess() function, I set the cursor to the hourglass,
while it is working.

Then after that line, I have the call to set the standard (arrow) cursor:

self.SetCursor(self.stockCursor1)

Is there something different I should be doing? This is the first
time I have used threads with long running tasks. It is working
beautifully other than the cursor update.

Thanks.

Robin Dunn

unread,
Jul 24, 2013, 1:31:34 AM7/24/13
to wxpytho...@googlegroups.com
The whole point of using threads is to allow the main thread to continue
moving forward while the thread is working in the background. But since
you are trying to reset the cursor immediately it seems that you are
expecting the calling thread to not move forward until the background
job is done. Regardless, you should not do anything in the background
thread that directly interacts with the UI.

C M

unread,
Jul 24, 2013, 11:37:18 AM7/24/13
to wxpytho...@googlegroups.com
> The whole point of using threads is to allow the main thread to continue
> moving forward while the thread is working in the background. But since you
> are trying to reset the cursor immediately it seems that you are expecting
> the calling thread to not move forward until the background job is done.
> Regardless, you should not do anything in the background thread that
> directly interacts with the UI.

Well, maybe I'm going about this the wrong way. Putting this in terms
of the user experience, I thought it would be good to have the
following conditions:

1) While the numbers are crunching (up to a minute or more), the
cursor is an hourglass, to mean "please wait and don't bother to do
anything, we're not done".

2) But, so that the user doesn't wonder whether the program has simply
crashed and is never going to finish (which had happened in earlier
versions with my client), I thought it would be great to keep the GUI
updating the user on the status by writing text about which file is
processed. (Thus using a worker thread so as to not block the GUI
thread).

3) Then, when it's all done, the hourglass returns to the arrow cursor
to mean, "Now you can click on the 'See the results' button if you
want.". In fact, this is complementary to the other UX point of the
text saying, "Files processed!".

I would think this is the default approach in the GUI world, and
updating the cursor once a number crunching thread is finished should
be trivial.

Does that make sense? Sorry to draw this out, but it's more about the
learning point for me more than even this program (in that the cursor
is not that crucial at all). Thanks again!

Tim Roberts

unread,
Jul 24, 2013, 12:54:53 PM7/24/13
to wxpytho...@googlegroups.com
C M wrote:
>
> Well, maybe I'm going about this the wrong way. Putting this in terms
> of the user experience, I thought it would be good to have the
> following conditions:
>
> 1) While the numbers are crunching (up to a minute or more), the
> cursor is an hourglass, to mean "please wait and don't bother to do
> anything, we're not done".
>
> 2) But, so that the user doesn't wonder whether the program has simply
> crashed and is never going to finish (which had happened in earlier
> versions with my client), I thought it would be great to keep the GUI
> updating the user on the status by writing text about which file is
> processed. (Thus using a worker thread so as to not block the GUI
> thread).
>
> 3) Then, when it's all done, the hourglass returns to the arrow cursor
> to mean, "Now you can click on the 'See the results' button if you
> want.". In fact, this is complementary to the other UX point of the
> text saying, "Files processed!".
>
> I would think this is the default approach in the GUI world, and
> updating the cursor once a number crunching thread is finished should
> be trivial.

Right. Here's how you do that in an event driven world. In the routine
that fires off the number crunching, you set the cursor to hourglass,
fire off the thread, and return.

In the thread, you do your number crunching, then when the crunching is
done, you use wx.CallAfter or fire off an event to the main window
saying "we're done".

Then, in the "we're done" handler, you set the cursor back to the default.

--
Tim Roberts, ti...@probo.com
Providenza & Boekelheide, Inc.

C M

unread,
Jul 24, 2013, 1:41:13 PM7/24/13
to wxpytho...@googlegroups.com
> Right. Here's how you do that in an event driven world. In the routine
> that fires off the number crunching, you set the cursor to hourglass,
> fire off the thread, and return.
>
> In the thread, you do your number crunching, then when the crunching is
> done, you use wx.CallAfter or fire off an event to the main window
> saying "we're done".

Thanks, Tim. wx.CallAfter did the trick; I couldn't easily figure out
how to post an event, but this seems like a simple way to do it.
Sorry to all if what I was trying to do before wasn't clear. I've
never used threads until now; nice addition to my (glacially rapid)
growing wx knowledge. :D

Mike Driscoll

unread,
Jul 24, 2013, 2:13:44 PM7/24/13
to wxpytho...@googlegroups.com
Hi Che,

I should have jumped in and said something. You might find my old article helpful the next time you want to deal with threads: http://www.blog.pythonlibrary.org/2010/05/22/wxpython-and-threads/

- Mike
Reply all
Reply to author
Forward
0 new messages