Christopher Barker wrote:
Christopher Barker wrote:
Chris Mellon wrote:
It's not well documented in wx, but this sort of drawing isn't well
supported in OS X, and there's special mechanisms for doing it.
Well, more poking around. I was thinking that there were issues with wxClientDC, but it's not that. The problem is with SetLogicalMode. It turns out that if I turn that off, the drawing works fine.
However, how can I draw something, then get the original back without it? I though the while XOR trick was really, really nifty!
I did do another implementation where I put the drawing of the line in method called in OnPaint, then called Refresh() when I wanted it drawn. This re-blits the window with every mouse move, but it does seem to be blazingly fast. However, I still have a problem:
I want to be able to draw a dotted line that I know the user will be able to see regardless of the colors that are on the screen. Drawing on top with dc.SetLogicalFunction(wx.XOR) did this beautifully. How else can I do it?
Try wx.INVERT instead of wx.XOR.
BTW, what version of OS X do you have? Your first sample worked fine for me on both 10.5 and 10.4.
My understanding of the changes related to wx.ClientDC are that it is intended to still work (although I know there are some situations that don't) but that it will be much more efficient to use a different drawing model. This is because when using the Quartz (aka CoreGraphics) APIs there is a rendering pipeline that is used by the system to help the system optimize and streamline what gets put on the screen. When you use a wx.ClientDC it has to interrupt the rendering pipeline, do the drawing you want, and then restart the rendering pipeline again. Although the real time needed for this overhead is pretty small, it can add up quickly when there are many refreshes per second. And it's my understanding that the rendering pipeline is for the whole system, not just your window (although I'm not 100% sure on that one) so suspending/restarting it a large amount can have consequences.
Anyway, the new recommended model to use is to do all drawing, if possible, from the EVT_PAINT handler. I know in the past it's been convenient for doing drawing directly from mouse event handlers with a wx.ClientDC to deal with things like doodles, or rubber-banding selection boxes, etc. In the past I broke it down into two different kinds of drawing, things that were temporary or needed done "right now" and things that were permanent, and I would use client DCs for the first category and a paint DC from the EVT_PAINT handler for the second. But if you shift your perspective a little you can see that there really isn't any such thing as temporary drawing since you'll want to be able to reproduce that same view from the EVT_PAINT handler in case the window gets damaged and refreshed while you want that temporary drawing to stay visible. And for the "right now" stuff I found that "real soon" was good enough and still quicker than my eye can detect any delay. The "real soon" essentially just translates to a self.Refresh() call, so instead of this in the old model:
some event -> draw with wx.ClientDC
you would have this in the new style:
some event -> set some data members -> call self.Refresh
paint event -> draw with wx.PaintDC
On Mac using the Refresh adds an update to the rendering pipeline, and if there are other refreshes in the meantime, or portions of the window damaged by others, then they are coalesced into a single event so when it is time for your window to be updated your paint handler won't have to work as much. You can also use RefreshRect to clip the update to just the portion of the window you are changing, and if there are more updates before the paint event is sent then the rects get Unioned into a single update region that can be used in the paint handler to optimize your drawing further.
I'll try to come up with a sample showing the use of wx.Overlay...
···
--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!