dc.DrawText performance issues

75 views
Skip to first unread message

Jonathan

unread,
May 23, 2012, 12:42:02 PM5/23/12
to wxPython-users
I'm drawing a network graph with wx.PaintDC. For each link in my graph
I draw the source and destination port numbers on a box over the link
30pixels away from the endpoints. This works fine when I'm only
drawing the ports for a single link, but when I draw the ports for all
of the links (I'm testing on tree with 12 links) I get a major
performance hit. What strategies can I use to get my graph back to a
usable state?

# If extra info is desired draw ports
if link.hover or link.info:
dc.SetPen(wx.Pen(wx.Colour(58,58,58), 1))
dc.SetBrush(wx.Brush(wx.Colour(255,255,255)))

# Draw srcport
sx, sy = gmath.PointOnLine(dstpos, srcpos, -30)
ss = str(link.srcport)
sw, sh = dc.GetTextExtent(ss)
dc.DrawRectangle(sx-3, sy-3, sw+6, sh+6)
# Draw dstport
dx, dy = gmath.PointOnLine(srcpos, dstpos, -30)
ds = str(link.dstport)
dw, dh = dc.GetTextExtent(ds)
dc.DrawRectangle(dx-3, dy-3, dw+6, dh+6)

dc.DrawText(ss, sx, sy)
dc.DrawText(ds, dx, dy)

Jonathan

unread,
May 24, 2012, 9:37:43 AM5/24/12
to wxPython-users
I should note the problem lies in dc.DrawText. Remove these calls and
everything runs smoothly. Is there a limit to how many times
dc.DrawText should be called per OnPaint?

Tim Roberts

unread,
May 24, 2012, 12:42:51 PM5/24/12
to wxpytho...@googlegroups.com
Jonathan wrote:
> I should note the problem lies in dc.DrawText. Remove these calls and
> everything runs smoothly. Is there a limit to how many times
> dc.DrawText should be called per OnPaint?

No, there is no "limit". How often is this being called? The mention
of "link.hover" and "link.info" makes me wonder if you are calling this
during mouse move operations, hundreds or thousands of times a second.
Is that the case?

You could save a little time by creating the wx.Pen and wx.Brush ahead
of time and caching them.

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

Jonathan

unread,
May 24, 2012, 1:09:13 PM5/24/12
to wxPython-users
You're correct, this is being called under mouse operations. I've seen
the clipping region functions while browsing the documentation, but
I've read some comments talking about drawing performance that said
adding this wouldn't help much. Perhaps it would be better to isolate
this code into a separate drawing function that is only called when
the graph is phyically modified (ie a node is moved), although then I
need to deal with the text not being drawn over when refreshing the
graph.
> Tim Roberts, t...@probo.com
> Providenza & Boekelheide, Inc.
>
>

Chris Barker

unread,
May 24, 2012, 1:29:31 PM5/24/12
to wxpytho...@googlegroups.com
I've found that calling DrawText hundreds of times is usually pretty
fast -- thousands not so much.

On Thu, May 24, 2012 at 10:09 AM, Jonathan <jonaunc...@gmail.com> wrote:
> You're correct, this is being called under mouse operations.

re-drawing eveyting on mouse_move is pretty sketcy -- you really need
blzingly fast drawing for that to feel smooth (liek OPneGL..).

Is something changing with every mouse move? what?

Is the common case, there is a little bit that might change on a
mouse_move, like a highlight of the object the mouse is over. In this
case, I'd look at using an overlay to draw just that.

or double-buffer and then draw the changing bit yourself (really jsut
a hand-done overlay)

see:

http://wiki.wxpython.org/DoubleBufferedDrawing

for more about that.

(note: that page was written before wxOverlay existed)


HTH,
-Chris


> Perhaps it would be better to isolate
> this code into a separate drawing function that is only called when
> the graph is phyically modified (ie a node is moved),

probably , yes.

you might want to take a look at wx.lib.floatcanvas -- it does a lot
of this for you.

see the demo in:

http://svn.wxwidgets.org/viewvc/wx/wxPython/3rdParty/FloatCanvas/Demos/ProcessDiagram.py?view=markup

for an example that might be close to what you need to do.

in any case, FloatCanvas itself may give you ideas about how to handle
double buffering, etc.

HTH,
-Chris


--

Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R            (206) 526-6959   voice
7600 Sand Point Way NE   (206) 526-6329   fax
Seattle, WA  98115       (206) 526-6317   main reception

Chris....@noaa.gov

Robin Dunn

unread,
May 24, 2012, 2:14:27 PM5/24/12
to wxpytho...@googlegroups.com
On 5/24/12 10:09 AM, Jonathan wrote:
> You're correct, this is being called under mouse operations. I've seen
> the clipping region functions while browsing the documentation, but
> I've read some comments talking about drawing performance that said
> adding this wouldn't help much. Perhaps it would be better to isolate
> this code into a separate drawing function that is only called when
> the graph is phyically modified (ie a node is moved), although then I
> need to deal with the text not being drawn over when refreshing the
> graph.

Also consider a design where only that which is changing is actually
drawn, and cache as much of the rest of it as you can in one or more
bitmaps.

For example if your window's content fits this model you could have a
bitmap for the "background" (grid lines, labels, etc) for things that
don't change very often if at all. Then another bitmap that is the
background plus the current content. When the current content needs to
change you don't have to redraw the entire background, just draw the
background bitmap into the content bitmap via a wx.MemoryDC and then
redraw the content on top of that. Then for immediate changes, such as
in mouse events you can either manipulate just the section of the
content bitmap that is changing or simply draw on top of it and then
adjust the actual content bitmap in idle time or something. When paint
events happen you just draw the content bitmap and you are done, so they
are very efficient.


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

Kevin Ollivier

unread,
May 24, 2012, 2:49:00 PM5/24/12
to wxpytho...@googlegroups.com
Hi Robin, Jonathan,
Another thing that would help is to call RefreshRect() instead of Refresh, passing in the rect of whatever part of the canvas that needs redrawn, and clipping your drawing to it. (You can get the rect via window.GetUpdateRegion().GetBox()) Clipping does indeed affect performance quite considerably, because the calls to DrawText and such will do no drawing if they're outside the clipping rect.

Also, you can make sure to call RefreshRect only if something in the canvas needs redrawn, e.g. when the .hover or .info state of one of the links changes. This would probably significantly reduce the number of paint events you're sending.

Regards,

Kevin



>
> --
> Robin Dunn
> Software Craftsman
> http://wxPython.org
>
> --
> To unsubscribe, send email to wxPython-user...@googlegroups.com
> or visit http://groups.google.com/group/wxPython-users?hl=en

Reply all
Reply to author
Forward
0 new messages