Discussion:
[fc] FloatCanvas
Chris Barker
2014-02-05 20:01:47 UTC
Permalink
Wouter,

I am cc-ing this to the floatcanvas mailing list -- others may have
suggestions, and its good to have an archive of questions, issues, etc.

http://mail.paulmcnett.com/cgi-bin/mailman/listinfo/floatcanvas
First of all, thank you for the great wxPython addition. It's wonderful :)
I'm using it for an application to graphically create android games, it's
far from complete, but thanks to the floatcanvas already usable.
Are actually running wx on Android? Or using it to help the development
process?

Yesterday I updated my wxPython to version 3.0.0.0, and unfortunate a lot
of code broke at that point. It took some time but all errors, except for
one, are fixed.
Ahh -- sorry I haven't had a chance to do the upgrade and test yet...
- Debain Wheezy 7.3
- Python 2.7
- wxPython 3.0.0.0 (compiled from source) / wxPython 2.8.12.1 (this is the
version from the debian repository)
Has anyone tested on Windows or Mac with 3.0 yet?
- If a wxPython app uses the floatcanvas with hitable objects and you
"../src/gtk/dcclient.cpp(250): assert "Assert failure" failed in
wxFreePoolGC(): Wrong GC"
This is the same with my own application as well as some of the demo's in
the demo dir. For instance: MovingTriangle.py, BB_HitTest.py and
ClickableBoxes.py.
sounds pretty clear that it's a general hit-able canvas issue.
I expected that this was a problem due to storage of a DC object. So I
explicitly deleted all DC objects which are created in the methods of the
FloatCanvas object, due to the local scope this didn't do anything ;)
right -- as a rule, you dont want to keep DCs around -- so for most part,
FloatCanvas doesn't
Because of the fact that the problem only rises when there's a hitable
object I looked at the hierarchy of these objects. In the baseobject
(DrawObject) there's a Bind method, this method uses the colorgenerator
generator. Which calls the _cycleidxs function and the colormatch function.
In these functions you use a global _testDC to store a wx.MemoryDC object.
This is a subclass of the WindowDC object and, according to the docs,
shouldn't be stored.
yup -- you found the exception. In theory, it should be able to keep the
wx.Bitmap around, and not need the DC. But in practice, at least at some
point, and on some platform (I do not remember the details), I think I
needed the DC to access the color or a pixel (which is used to ID the
clicked-on object). And as this happens a lot when the mouse is moving, I
didn't want to re-construct a DC every time. It may be that with modern
wx, this isn't required.

If I close my application, or one of the example files, and just before the
app is destroyed set the FC._testDC to None, the problem is gone.
This is still a bit odd, as Python should garbage collect it as everyting
is deleted as teh app shuts down, but maybe it's not happening in the
correct order. I wonder if we could put something in a __del__ method in
the canvas to force it then.
(somewhere around line 112 in FloatCanvas.py)
---------original------------
* dc = _testDC*
B = _testBitmap = wx.EmptyBitmap(1, 1)
* dc = _testDC = wx.MemoryDC()*
---------end-----------------
to
----------changed----------
* dc = wx.MemoryDC()*
B = _testBitmap = wx.EmptyBitmap(1, 1)
* dc = wx.MemoryDC()*
-----------end--------------
The problem is also gone.
Ahh! -- just looked closely -- this is probably the right thing to do. I
was thinking that it was keeping a DC around for the hit test -- but it's
not -- this is used only to make sure that you've got a unique color -- if
the system color bitdepth is not 32 bit, then you can get some rounding and
not get the same color back when set a pixel and then retrieve it -- it's
critical when using a color for hit testing, that it round trips exactly.
Granted, there may not be many systems these days with lower bit-depths,
but I did have at least one user with the problem at some point.

And the core problem herre is that it's getting stred in a global, so
won't get deleted 'till the module gets deleted, which won't happen until
the entire python process shuts down -- too late.

As this gets called only when creating a new hit color for an object, not
on every mouse move, teh overhead of creating a DC is probably not a biggie.

I did some quick testing in both wxPython 2.8 as well as 3.0 and I think
this works. (you don't have to explicitly set it to None, because it's not
used anymore)
I don't see it used anywhere else, so I think it's safe to remove it
completely.
Indeed. In fact, it looks like the dc was getting re-created every time
anyway on the Mac (the mac doesn't like accessing the bitmap when it's
selected into a DC. So if it works there, why not do it everywhere?

I've committed a patch to SVN.

Thanks for tracking this down -- nice work.

-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.Barker-***@public.gmane.org
Loading...