Hi guys,
In my application, I've just come across a nasty visual highlighting problem which seems to be caused by the fact that wxWindow.Refresh() queues a request to repaint the window rather than repainting it immediately.
I'm implementing a drag-and-drop like capability, but because of the type of visual highlighting I need I'm doing it myself rather than using the standard drag-and-drop built into wxWindows. To achieve this, I'm using:
EVT_LEFT_CLICK(self, self.onMouseDown)
EVT_LEFT_UP(self, self.onMouseUp)
EVT_MOTION(self, self.onMouseMotion)
and then having my onMouseXXX methods do the appropriate visual highlighting to let the user drag an outline of the currently selected object(s) around on the screen. The actual visual highlighting is done by the following routines:
def _showDragOutline(self):
if not self.dragOutlineShown:
self._invertDragOutline()
self.dragOutlineShown = true
def _hideDragOutline(self):
if self.dragOutlineShown:
self._invertDragOutline()
self.dragOutlineShown = false
def _invertDragOutline(self):
dc = wxScreenDC()
dc.SetLogicalFunction(wxINVERT)
dc.StartDrawingOnTop()
...drawing code goes here...
dc.EndDrawingOnTop()
So far so good -- the use of dc.SetLogicalFunction(wxINVERT) causes the drag outline to be drawn on the screen, and a second call to _invertDragOutline() causes the screen image to be restored. This lets me do nice things like:
self._hideDragOutline()
self.curDragPt = newPt
self._showDragOutline()
to implement dragging. However, while dragging I also need to be able to refresh the contents of various sub-windows. At present, I'm calling wxWindow.Refresh() to force the sub-window to redraw itself, a bit like this:
self._hideDragOutline()
dropTarget = self.findTargetAt(mousePt)
dropTarget.highlight(true)
self._showDragOutline()
...
class DropTarget:
def highlight(self):
self.highlighted = true
self.Refresh()
This is where things fall apart. The call to self.Refresh() merely causes the drop target to *queue* a request to redraw itself -- which means that the order of redrawing ends up being:
hide drag outline
show drag outline
redraw drop target
instead of the expected:
hide drag outline
redraw drop target
show drag outline
As a result, an image of the drag outline remains on the screen where the affected window was redrawn. What I really need is some kind of wxWindow.RefreshNow() method, to force the window to be redrawn immediately. Is there any way of achieving this, perhaps by simulating an OnPaint() call?
Unfortunately, there are several things which can trigger the underlying windows to redraw themselves during a drag operation, so I really need to be able to redraw an entire *frame's* contents, including all subwindows, immediately rather than using Refresh() which queues the redraw request...
Has anyone else had similar problems -- and found a way around it? In many windowing toolkits, there's a distinction between:
window.RequestRedraw()
and
window.RedrawImmediately()
but I can't find an equivalent under wxPython. Any suggestions would be most welcome!
Thanks,
- Erik.