Why is WxPythons motion detection so slow? - python

I set the on_motion to handle EVT_MOTION. I want the mouse location for interactively generating a coordinate-specific image, but WxPython has a ~400ms delay in registering successive motion events. Which makes the interface sluggish.
Why is EVT_MOTION so slow and how do I fix it? I tried it in Ubuntu 11.10 and WinXP and the delays are comparable?
I need fast response times for selecting a portion from an image like the picture shows. As it stands, the "cross-hairs" follow the mouse too slowly.
Here is the code which I tried EVT_MOTION:
def on_motion(self, event):
"""mouse in motion"""
#pt = event.GetPosition()
self.mouseover_location = event.GetPosition()
self.t2 = time.time()
print "delay",self.t2 - self.t1
self.t1 = self.t2
delay 0.379776954651
delay 0.00115919113159
delay 0.421130895615
delay 0.416938066483
delay 0.376848936081
delay 0.387464046478
delay 0.40311384201
delay 0.392899036407
delay 0.385301113129
delay 0.422554969788
delay 0.355197906494

The question as it stands is incomplete, as there is no sample app to demonstrate the problem. However, I would say that the motion handler has got nothing to do with your problem, because most likely you are doing some expensive operation between subsequent motion handlers (like refreshing your entire drawing canvas).
If this is the case (and you can easily check if your paint routine is called between mouse motion events), I would suggest the following:
If your drawing that stuff yourself, ensure that you are using double buffering (via wx.BufferedPaintDC);
If your paint routine is indeed called between mouse motions, try and refresh only the damaged portion of your plot (via RefreshRect);
Use wx.Overlay to draw your rectangular selection (there are a few demos available on how to do that);
Post a small, runnable sample app that demonstrate the problem.

The EVT_MOTION is fired every time the mouse is moved! If you then call event.GetPosition() on every movement and also process the data, this will slow down performance.
How would it be to use EVT_LEFT_DOWN or something similar, and then get the position and process that data.
This will be much more efficient since you are only looking for a certain area of the image.

We'll really need to see what else is going on in the application to be able to give you any meaningful answers, although many people are able to solve the problems themselves in the process of creating a small sample demonstrating the problem to share with others.
http://wiki.wxpython.org/MakingSampleApps
Optimizing how you are drawing the cross-hairs and/or how you are refreshing the main content of the window is probably your best bet, but until you share more details all we can do is guess.

Related

How can draw a figure on top of another application?

enter image description here
enter image description here
I want to draw a figure on another application as above. How can I do that? I tried using a window handle in c#, so I didn't get the result I wanted.
You could draw a transparent window on top of your target application, effectively creating an overlay. This would most likely involve quite a bit direct usage of the Win32 API. See for example enumerating windows of another application.
But it will likely be an unreliable solution since there is a whole bunch of things you need to take into account:
Ensure that the target application still receives all input events.
Ensure that your transparent window stays on top of the target application
Monitor the target application for any window size change, or minimizing/maximizing
Many more things that you will likely discover later
Note that this will likely not work for full screen applications, and while this should allow for an overlay, any data on what or where to draw things need to come from somewhere else.

Is there any way to speed up the draw rate of a Scrollable Canvas in Tkinter?

So after posting another question about this issue I realised the problem was only happening with my custom resize bind. When I resize the window by the default edges of the window the Issue does not happen and the contents of the canvas is drawn accurately - however when using my custom resize bind the contents of the canvas is laggy and lags behind the true position of the window.
import tkinter as tk
def resize(self, event=None):
y=root.winfo_height()
x1 = root.winfo_pointerx()
x0 = root.winfo_rootx()
root.geometry("%sx%s" % (x1-x0,y))
root=tk.Tk()
canvas = tk.Canvas(root,bg='red')
canvas.pack(padx=20,pady=20)
inside=tk.Frame(root)
inside.pack(fill='both')
for i in range(10):
x=tk.Label(inside,text='Lsdkfjhaskfjhskljdfhaskjfhksfhkjasdhf')
x.pack()
g=tk.Button(root,text='Drag to resize')
g.bind('<B1-Motion>',resize)
g.pack()
canvas.create_window(5,5,window=inside,anchor='nw')
Original content:
Screenshot while resizing window with manual bind via button - as you can see the content is not visible while resizing the window and lags behind where the canvas is.
The issue is fixed if I call root.update() at the start of my resize function however this then causes a recursion depth error to the thousands of calls being made to update in such a small period of time.
Finally to repeat. When resizing with the default window Resize nudges at the edge of the window the canvas resizes perfectly with perfect draw rate and the content stays visible all the time. Why is my binding not acting the same way?
Geometry calculations are quite complex in general (and Tk has some fairly sophisticated solvers behind the scenes for handling them) so they only run when the GUI is considered to be "idle". Idleness occurs when the event queue would otherwise block, waiting for the next message from the external world, i.e., when there's nothing else queued up for immediate attention. Tk also postpones redrawing (another actually really expensive operation) the same way; it makes the UI seem far faster than it really is. This was critical back 20 years ago and more, and yet is still really useful now.
But it breaks if there there is a total flood of events coming in, and drags can do that, especially when there's resizing involved. That's why you can do update idletasks (in Tcl/Tk notation) and update_idletasks() (in Tkinter notation). That that does is immediately process all the pending idle event callbacks without taking further real events, running the pending resize computations and redraws. It is far less likely to trigger reentrant event processing than a full update(), which is the problem you were hitting (and why update is considered harmful under normal circumstances).
Note that it is important to let the event loop itself have some time to process still, as parts of handling widget resizes are inevitably done via real events (as they impact upon the OS/GUI). By far the best way to do that is to just make sure to return normally from your event handlers as soon as practical.
Are you using the right bind event? Try ''
g.bind('<ButtonRelease-1>',resize)

Getting screenshot via printwindow not redrawing if laptop screen off

My goal is to take screenshots off an application while the laptop screen is off, but instead the screenshot will always be the same as just before turning off the screen. It does not redraw itself once the screen is off, and remains frozen.
I'm obtaining a screenshot using printwindow from Python (using method described here: Python Screenshot of inactive window PrintWindow + win32gui
This method works nicely as long as I have my laptop screen on, but if I turn it off, it simply returns the last image before the screen turned off. I've tried using win32gui.RedrawWindow, hoping that this would force a redraw, but I haven't gotten it to work, even trying all the different flags. I've also tried getting screenshots via pyautogui, but this also has the same problem. Is there any way to redraw the application while the laptop screen is off?
It would be nice if there were a straightforward way to do what you want to do, but unfortunately it's just not possible without some convoluted low-level work.
In the underlying WinAPI, native windows redraw themselves only when they receive WM_PAINT messages, and they only receive WM_PAINT messages if they are visible. They don't get the messages if they're behind another window, or if they're dragged off screen, or minimized, or their visibility is set to False. They also aren't visible when the screen is off. Since they aren't visible, they simply never get told to redraw themselves. That's why the screen capture image doesn't change after the screen is turned off.
There is no command you can issue that will override this -- it is implemented as a fundamental part of the windowing paradigm.
One solution is to have the application paint itself in something that's not a window (e.g., a dialog box) and capture that rather than capturing the screen. You could also modify the application by overriding OnPaint and using a timer to invalidate and call your OnPaint function periodically (since WM_PAINT messages won't be received).
If it were me I'd override OnPaint, make my application draw itself to a background context bitmap rather than the normal window, then use a timer to invalidate and redraw periodically and just take the bitmap of the background context whenever I wanted to capture the output.
If you don't own the code for the applications that are running, you may still be able to get applications to redraw themselves by running everything in a virtual machine. I've done that successfully for headless computing in the past, but it was many OS versions ago and things may be different now, so YMMV...
Information on manual screenshots under VMWare is here.
Information on programmatic screenshots under Hyper-V is here.

Using SwapBuffers() with multiple OpenGL canvases and vertical sync?

I have a GUI written using wxPython that contains two GLCanvases, a 'display' canvas and a 'preview' canvas onto which I am drawing some very simple geometry using PyOpenGL. The 'preview' and 'display' canvases display the contents of the same framebuffer:
I need both of these canvases to be updated synchronously at a consistent framerate with no tearing.
So far I have just been calling
self.SetCurrent()
# draw stuff...
self.SwapBuffers()
for both the preview and display canvases within my rendering loop. This works reasonably well provided that I disable vsync in my driver settings.
However, if I enable vsync my framerate drops to ~30Hz, half the vertical refresh rate of my display. Presumably this is because the execution of the rendering loop stalls at each SwapBuffers() call waiting for the next vertical refresh - if I comment out one of the two SwapBuffers() calls, my framerate goes back up to 60Hz, but then of course only one of my canvases gets updated.
What I'd really like is for both of my canvases to be updated synchronously, once per vsync interval. Is there any way that I can achieve this using the wx.glcanvas.GLCanvas class?
What Andon implied in his comment is, that you use {wgl|glX}SwapInterval to set the swap interval for the first, synching SwapBuffers to 1, and then right after the synching SwapBuffers returns set the swap interval to 0 and do the other SwapBuffers.

More Pyglet - Supress mouse motion events?

In the same game as last time, I've ran into a new problem. When I move the mouse, FPS increases from around 60 to over 500. I know what you're thinking; it's not because of on_draw() getting fired each event (I think), since I already did override of pyglet.app.EventLoop.idle:
class EventLoop:
def idle(self):
pyglet.clock.tick(poll=True)
return pyglet.clock.get_sleep_time(sleep_idle=True)
pyglet.app.EventLoop = EventLoop()
Also I call flip() on the window in my drawing function. All the useless mouse motion events take up a lot of CPU, which is annoying. What can I do about it?
Edit
I added window.invalid = False to my drawing function and window.invalid = True to my update function, this seems to reduce CPU usage with other mouse actions.
Edit 2
The drawing function is a typical on_draw() function.
Edit 3
After some more investigating, it seems that all those events don't take that much CPU as I thought they would. Still it would be good to know if this is the way Pyglet is supposed to act, or if it's something that should be avoided.
All you should be doing on mouse events is updating your apps' model of the input control state and using that in the next regular scheduled update and redisplay of the world model (which is presumably much more complex with physics and rendering and stuff).
ie just because mouse events come in at ~300fps doesn't mean you actually have to do all the stuff you want to do at 300fps.
It's been a while since I did any Pyglet, but the pattern I seemed to use was to subclass Pyglet's window.Window as MyGameWindow, then that registered event handlers like
#self.event
def on_mouse_motion(x,y,dx,dy):
self.mouse_position=(x,y)
self.mouse_buttons=0
self.invalid = False
(also on_mouse_drag, on_mouse_press, on_mouse_release). Hmmm... actually, I think that assignment to self.invalid might have been crucial for overriding Pyglet's default behaviour and defering any further updating/drawing until the next "clock tick".

Categories

Resources