More Pyglet - Supress mouse motion events? - python

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".

Related

how to handle pygame VideoExpose event

I was experimenting with pygame and noticed it raised a VideoExpose event when I press alt+tab and the window is fullscreen. when I switch press alt+tab again, everything on the screen is moved to the bottom left.
I know that this is supposed to mean that 'portions of the window must be redrawn', but how am I supposed to redraw them and what why does pygame even have this event in the first place?
If you are writing a program to use the windowing Event Model, the windowing environment sends the program events to notify it of environmental changes - window resize, mouse move, need to re-paint, etc.
Not handling these events will cause your application to be considered "non responsive" by the environment. Here on SO, there's about one question a week with PyGame and exactly this issue.
When working with PyGame re-drawing event handling may seem superfluous as the majority of PyGame games redraw the entire screen every frame, e.g.: 60 FPS. But if unnecessary, this method is a complete waste of resources (CPU-time, electricity, etc.) It is quite simple though, so good for beginners.
Say you were writing a card game like Solitaire... the screen updates only when interacting with the user. In terms of CPU, it's doing nothing 99.9% of the time while the user contemplates their next move. In this case, the program could be written to only re-draw the screen when necessary. When is it necessary? When the player gives input, or the program receives a pygame.VIDEOEXPOSE event from the widowing environment.
If your program is redrawing the window constantly, you can simply ignore the message. If not, when receiving the message call whatever block of code is normally used to render the window. The expose message may come with the region of the screen that needs to be re-drawn, in this case a really good application would only update that section of the display.

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)

Event processing for layered images in a canvas

I have a canvas that is covered by many...many images. Most overlap each other sometimes 10 deep. A simple example is
a1 = self.Canvas.create_rectangle(0,0,100,100,fill="red")
self.Canvas.tag_bind(a1,"<Button-1>",self.eventa1)
b1 = self.Canvas.create_rectangle(0,0,100,100,fill="green")
self.Canvas.tag_bind(b1,"<Button-1>",self.eventb1)
c1 = self.Canvas.create_rectangle(0,0,100,100,fill="blue")
self.Canvas.tag_bind(c1,"<Button-1>",self.eventc1)
The top layer shows blue. I click on it and eventc1 is called as expected.
I was wondering if there is any way when I click on position X, Y to get each event covering that point (red, green and blue layer in this case) to fire the corresponding event for that layer in order top to bottom.
Or can the blue event processing have a way to cause the next lower layer' event to automatically fire. There is no way the blue event knows what it is sitting on top of. 20 years ago, I used GTK+ in C and it allowed an event to return an indication to fire a lower level event or not.
Your code does not look at all like C I must say. Looks more like some slippery slithery language...
In GTK you can customise a widget to your hearts content. GtkDrawingArea is typically used when you want to tinker around UI side too. You can override the event handlers for mouse interaction e.g.: widget_klass->button_press_event, widget_klass->motion_notify_event widget_klass->button_release_event and widget_klass->expose_event. You can make your own signal handlers with g_signal_new and fire off which ever one (or multiple ones thereof) you want according to where the click is in each of your custom event handlers. Make sure to add gtk_widget_add_events(widget, GDK_BUTTON_PRESS_MASK|etc...) to enable these events in your classes init function.
Enforcing a strict signal handling order might be a bit more complicated. The signals have the option for G_SIGNAL_RUN_FIRST etc, and you could get 3 running a strict order this way though there's always the chance that the event loop may receive signals at two different stages. Best would be to fire off the one signal with data provided that would list the functions to call and order in which they need to be invoked.
So yes you can do that in C, though it might be tricky. I'm pretty sure all the bindings don't loose functionality so you should be able to do it in almost any language, but as for all non-c coding, when you want to delve deep, the deobfuscation places you on a slippery slope. If you know how to do it in C, skip the snakes and ladders game and write it in C. If you've got boss/team constraints, port it when done, to make people happy - I believe there is enough consistency across the GTK API bindings that it shouldn't be too much of an issue. But being forced to think in a ladedah mindset of simpleness and being expected to achieve fine detailed complex solutions is just untenable.

wx.SpinButton acceleration when holding down one of the buttons (up/down)

Some GUI's libraries have spin button widget with optional feature - acceleration.
When holding down one of the buttons (up or down) - as a result an acceleration of change in the value according to how long it is depressed.
Is this feature in wx.SpinButton and what's the best way to implement it?
No, that's not a built in feature of the SpinButton. Note that the SpinButton isn't implemented cross-platform, so you might want to look at wx.SpinCtrl or FloatSpin. Anyway, to implement what you want, you could probably catch the wx.EVT_SPIN and start a wx.Timer. When the timer hits some pre-determined value, you could start updating the control yourself. I'm not sure if this would work as you would be trying to update a widget that is already being updated, but it might...
Of course, you'd also have to bind to the mouse up event to stop the timer and stop the updates. I suspect you my have to roll your own widget though...
I would ask on the wxPython mailing list. Someone there might have more ideas.

Why is WxPythons motion detection so slow?

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.

Categories

Resources