I'm writing an application for the Maemo platform using pygtk and the rendering speed of the tree view seems to be a problem. Since the application is a media controller I'm using transition animations in the UI. These animations slide the controls into view when moving around the UI. The issue with the tree control is that it is slow.
Just moving the widget around in the middle of the screen is not that slow but if the cells are being exposed the framerate really drops. What makes this more annoying is that if the only area that is being exposed is the title row with the row labels, the framerate remains under control.
Judging by this I'm suspecting the GTK tree view is drawing the full cells again each time a single row of pixels is being exposed. Is there a way to somehow force GTK to draw the whole widget into some buffer even if parts of it are off screen and then use the buffer to draw the widget when animating?
Also is there a difference between using Viewport and scrolling that up and using Layout panel and moving the widgets down? I'd have imagined Viewport is faster but I saw no real difference when I tried both versions.
I understand this isn't necessarily what GTK has been created for. Other alternative I've tried is pygame but I'd prefer some higher level implementaion that has widget based event handling built in. Also pygtk has the benefit of running in Windows and a window so development is easier.
I never did this myself but you could try to implement the caching yourself. Instead of using the predefined cell renderers, implement your own cell renderer (possibly as a wrapper for the actual one), but cache the pixmaps.
In PyGTK, you can use gtk.GenericCellRenderer. In your decorator cell renderer, do the following when asked to render:
keep a cache of off-screen pixmaps (or better, just one large one) and a cache of sizes
if asked to predict the size or render, create a key from the relevant properties
if the key exists in the cache, use the cached pixmap, blit the cached pixmap on the drawable you are given
otherwise, first have the actual cell renderer do the work and then copy it
The last step also implies that caching does incur an overhead during the first time the cell is renderered. This problem can be mitigated a bit by using a caching strategy. You might want to try out different things, based on the distribution of rendered values:
if all cells are unique, not much to do than caching everything up to a certain limit, or some MRU strategy
if you have some kind of Zipf distribution, i.e. some cells are very common, while others are very rare, you should only cache the cells with high frequency and get rid off the caching overhead for rare cell values.
That being said, I can't say if it's going to make any difference. My experience from a somewhat similar problem is that anything involving text is usually slow enough that caching makes sense---sorry that I can't give simpler advice.
Before you try that, you could also simple write a decorating cell renderer which just counts how often your cells are actually rendered and get some timing information, so that you get an idea where the hot spots are and if caching the values would make any sense at all.
Related
I have a python program where I have several matplotlib canvases embedded into a wxpython application. One of the canvases has many crosses in it. When the user right-click in this canvas the closest cross should be removed together with everything belonging to this cross (they are linked through an unique id-tag, and there might be things in every canvas that should be removed). I want the removing (or actually the replotting) to be as fast as possible. The program is quite large so I use several threads etc.
The easiest thing to implement this is to use wx.CallAfter(canvas.draw) for each canvas. However, there is a delay between the rightclick and the refresh of every canvas so I believe that canvas.draw() is too slow.
I saw two other functions for fast redrawing: the matplotlib functions blit() and draw_artist(). As far as I understand, blit() refreshes changed pixels inside some area (I used the axes bbox). I managed to get it to work with blit() in the sense that the program ran without crashing...but not updating what you see on the screen.
Did not manage to get draw_artist() to work when removing a pixel (tried using first line.remove(), then draw_artist(line) but the line was ofcourse already dead so draw_artist did not work).
Note: I called blit() and draw_artist() with wx.CallAfter()!
The feeling I have is that blit() is the best solution, but I did not manage to get it to update to the "screen-level". So my question is: what is the fastest and most resource-saving way of removing artists from matplotlib.canvases (embedded into wxPython) without redrawing more than you need to, but still let the change propagate to the screen?
This is my first question ever so bear with me!
Currently in my program, I have a parent widget which acts as a canvas. The user can add or remove widgets to the parent at run-time. Those widgets are then given an absolute position, that is, they are not positioned by a layout. Once added, a widget can be moved around arbitrarily by the user.
I want the user to be able to select a group of widgets by dragging a box around them. I have already coded the part that displays the rectangle while the user is dragging. Now, I want to be able to retrieve all the widgets within that rectangle (region).
I am aware of the findChild() and findChildren() functions, and they indeed do return the children as they are supposed to. But what I'd really need is a way to limit the search to the boundaries of the region since there will most-likely be quite a lot of widgets within the 'canvas'. (There could be thousands of widgets spread over a very large area due to the nature of what I'm doing!)
Here is my question: What would be my best option? Should I just go ahead and use findChildren() and loop through the list to find the children within the region manually. Or should I loop through all the pixels within the region using findChild(x, y)? Or perhaps there is an even simpler solution that would speed up the process? Something along the lines of findChildren(x, y, width, height)?
Hopefully my question made sense. I tried to explain things as best as I could. Thanks!
If you had used QGraphicsScene instead of rolling your own, you could have used the items(..) methods to very efficiently find your children in a particular area.
It's only possible in QGraphicsScene because it uses a BSP spatial acceleration structure, so if you cannot migrate to QGraphicsScene in a reasonable amount of time - you are going to have write your own. It's not as hard as it sounds, I've written numerous bounding volume hierarchy structures and they're quite straightforward.
I have a gtk.IconView with several icons in it. Sometimes I will resize the window to see more icons. When I do this, the extra space generated isn't distributed evenly between all the columns. Instead, it all gets put on the right until there's enough space for a new column.
I'm not seeing anything in the documentation that would let me do this automatically. Do I need to check for resize signals and then manually set the column and row spacings? If so, which resize signal do I use.
Here's a picture of what I mean. I've marked the extra space in red.
This is what I'd like to see (of course, with the gaps actually evenly spaced, unlike my poor MS Paint job).
We have encountered that problem in Ubuntu Accomplishments Viewer, and as we managed to solve it, I'll present our solution.
The trick is to place the GtkIconView in a GtkScrolledWindow, and set it's hscrollbar_policy to "always". Then, a check-resize signal has to be used, to react when the user resizes the window (note that it must be checked if the size has changed, for the signal is emitted also when e.g. the window is dragged around). When the size changes, the model used by GtkIconView has to be cleared and recreated, as this triggers GtkIconView properly reallocating the newly gained space (or shrinking). Also, as the result the horizontal scrollbar will never be seen, as the GtkIconView uses exactly that much space as the GtkScrolledWindow uses.
Yeap, it seems after a very fat look that you will need to do that on your own. And regardeing the signal, I'd check for GtkContainer::check-resize.
Use the event size_allocate.
I defined my class :
class toto(Gtk.IconView):
def __init__(self):
super(toto,self).__init__()
self.connect("size_allocate",self.resize)
self.set_columns(4)
Then I modify the number of working columns
def resize(self,_iv,_rect):
print("X",rect.x)
print("Y",rect.y)
print("W",rect.width)
print("H",rect.height)
# calculate number of columns, let's say 3
_cols=3
self.set_columns(_cols)
Seems working for me
I'm having problems getting my wxPython window to refresh. It's currently plotting a graph using wxmpl which can be zoomed, panned, etc. On occasion the user may plot a large amount of data and zoom in on a small portion, which can cause it to 'freeze up'. By that I mean the plot itself is not updated, and the axis labels are drawn on top of each other. It is modifying the plot, just not displaying the updated info correctly. If you resize the window the plot is redrawn correctly.
I've spend an inordinate amount of time digging through source code and documentation for wx, wxmpl, and matplotlib... The best solution I've come up with is resizing the window to force a repaint (thus displaying the updated plot correctly).
# All of these fail - displays the same, incorrect plot
# (view is a wxmpl.PlotPanel object, which inherits from wx.Window among other things)
view.Refresh()
view.Update()
view.draw()
# This works, but is clearly less than ideal
view.SetSize((view.GetSize().width, view.GetSize().height+1))
view.SetSize((view.GetSize().width, view.GetSize().height-1))
There's got to be a better way - what I really want to know is what wx.Window.SetSize does to redraw the window, and just call that instead. Or, is there another method that I missed somewhere?
The panel.Layout() command is a great option because it is exactly the same method that is called when you resize your window. I also had trouble with the refresh and update methods. Layout seems to work when those two fail.
If you can't place it anywhere else, you could try
wx.Yield()
instead of Refresh or Update.
I would also try Show(False) and then Show(True) on the PlotPanel.
In a computational expensive application, where you are expecting something to be calculated for over 0.1 sec and probably have some user input it is not recommended usually to make those intense drawing in the GUI thread.
Not aware of your specific situation, but general approach if that you move all time consuming tasks (be it computation, image adjustment (e.g. scaling)) to the non GUI thread. Just a normal Python thread is fine, and once you have an long part complete, you refresh your GUI. During computation of course it would be a user friendly to display some sort of "waiting" sign. Also disable other controls, so bored user will not be able to change anything midway to your computation.
I was stuck with that issue since my early days with Java and later with Python, mostly in connection to network operations (which NEVER should be in GUI thread).
In case it is image adjusment (or graphics generation), which takes much time, background thread can prepare image in wxMemoryDC and then wxDC::Blit it to the window of your choice. I am not aware if this can be done with your component wxmpl.PlotPanel, so you will have to research this.
I'm working on a Minecraft-style game, and I need a way to reduce the amount of the world rendered. Currently, I'm using a naive, render-everything approach, which is having obvious scaling problems. I need a way to take an array of blocks, and in some way find out which ones are touching air, water, or any other translucent block.
I'm open to using external modules like NumPy or SciPy, though some of their documentation is a bit over my head. Alternatively, it would also be acceptable to iterate through each block and get a list of neighbors, though the performance cost of doing these calculations in Python instead of C would be pretty hefty.
For the record, I've already tried looking at NetworkX, but it seems to be more for scientific analysis or pathfinding than visibility checking.
If you only need to do this once, performance should not be an issue. If you also incrementally update the .isBoundary property of blocks whenever the world is changed, you will never have to do it again.
However you still run into issues if your world is too large or full of holes and caverns and transparent-interleaved-with-nontransparent. If you need to dynamically determine what is visible, you can keep an octree ( http://en.wikipedia.org/wiki/Octree ) where you can have giant expanses of air/water/etc. as a single node (giant block), labeled as "transparent". Then use the "paintbucket" algorithm (modified to perform Dijkstra's algorithm, so it is easy to detect when you've "gone around a corner" by checking to see if blocks exist between the current block and the origin) to quickly figure out which blocks are in sight. Updates for things far in the distance can be delayed significantly if the player is moving slowly.
You could use the Z-Buffer solution. Concerning speed, I'd write as much as possible in python and use pypy. EVE Online (a successful 3D MMO) was written in stackless python I believe.