我正在尝试构建一个可以使用鼠标绘制的ScrolledWindow,它也可以正常工作,但是当用户在窗口上绘图而滚动条不在“滚动条”中时,我会得到一个令人讨厌的闪烁家“位置..
要重现,请运行附加的程序,向下滚动(或向右)并按住鼠标左键“涂抹”一下。你现在应该看到闪烁......
import wx
class MainFrame(wx.Frame):
""" Just a frame with a DrawPane """
def __init__(self, *args, **kw):
wx.Frame.__init__(self, *args, **kw)
s = wx.BoxSizer(wx.VERTICAL)
s.Add(DrawPane(self), 1, wx.EXPAND)
self.SetSizer(s)
########################################################################
class DrawPane(wx.PyScrolledWindow):
""" A PyScrolledWindow with a 1000x1000 drawable area """
VSIZE = (1000, 1000)
def __init__(self, *args, **kw):
wx.PyScrolledWindow.__init__(self, *args, **kw)
self.SetScrollbars(10, 10, 100, 100)
self.prepare_buffer()
self.Bind(wx.EVT_PAINT, self.on_paint)
self.Bind(wx.EVT_LEFT_DOWN, self.on_mouse_down)
self.Bind(wx.EVT_MOTION, self.on_motion)
def prepare_buffer(self):
self.buffer = wx.EmptyBitmap(*DrawPane.VSIZE)
dc = wx.BufferedDC(None, self.buffer)
dc.Clear()
dc.DrawLine(0, 0, 999, 999) # Draw something to better show the flicker problem
def on_paint(self, evt):
dc = wx.BufferedPaintDC(self, self.buffer, wx.BUFFER_VIRTUAL_AREA)
def on_mouse_down(self, evt):
self.mouse_pos = self.CalcUnscrolledPosition(evt.GetPosition()).Get()
def on_motion(self, evt):
if evt.Dragging() and evt.LeftIsDown():
dc = wx.BufferedDC(wx.ClientDC(self), self.buffer)
newpos = self.CalcUnscrolledPosition(evt.GetPosition()).Get()
coords = self.mouse_pos + newpos
dc.DrawLine(*coords)
self.mouse_pos = newpos
self.Refresh()
if __name__ == "__main__":
app = wx.PySimpleApp()
wx.InitAllImageHandlers()
MainFrame(None).Show()
app.MainLoop()
我尝试使用SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
,或绑定EVT_ERASE_BACKGROUND
,或使用RefreshRect
代替Refresh
,但闪烁仍在那里..对我可能尝试的内容有任何想法下?
我的环境:Xubuntu 9.04,wxPython 2.8.9.1 (但也在Ubuntu 10.04上测试过)
非常感谢你的时间!
答案 0 :(得分:5)
来自Robin Dunn本人:
首先,默认情况下会
Refresh()
发送前擦除背景 油漆事件(虽然设置了 BG风格或捕捉擦除事件 本来会照顾的。) 第二,也许最明显 在这种情况下的问题是在你的 你不是on_motion
处理程序 通过滚动抵消ClientDC 抵消,只是在的位置 你正在画线的缓冲区 细分市场。所以当缓冲区是 冲到客户端DC就是这样 在物理(0,0)绘制,而不是 虚拟(0,0)。换句话说, 你看到的闪烁来自 在错误的情况下绘制缓冲区 每次鼠标拖动事件后的位置, 然后它立即被绘制 再次在正确的位置on_paint
由...引发Refresh()
。你应该能够解决这个问题 在客户端DC上调用
PrepareDC
在使用之前,像这样:cdc = wx.CLientDC(self) self.PrepareDC(cdc) dc = wx.BufferedDC(cdc, self.buffer)
然而,因为你正在做一个 无论如何
Refresh
或RefreshRect
, 没有必要使用客户端DC 在这里,只是让冲洗 屏幕缓冲区完成 改为on_paint:dc = wx.BufferedDC(None, self.buffer)
答案 1 :(得分:1)
使用Joril建议并删除Refresh(),不再有闪烁(甚至放大帧)。
import wx
class MainFrame(wx.Frame):
""" Just a frame with a DrawPane """
def __init__(self, *args, **kw):
wx.Frame.__init__(self, *args, **kw)
s = wx.BoxSizer(wx.VERTICAL)
s.Add(DrawPane(self), 1, wx.EXPAND)
self.SetSizer(s)
########################################################################
class DrawPane(wx.PyScrolledWindow):
""" A PyScrolledWindow with a 1000x1000 drawable area """
VSIZE = (1000, 1000)
def __init__(self, *args, **kw):
wx.PyScrolledWindow.__init__(self, *args, **kw)
self.SetScrollbars(10, 10, 100, 100)
self.prepare_buffer()
cdc = wx.ClientDC(self)
self.PrepareDC(cdc)
dc = wx.BufferedDC(cdc, self.buffer)
self.Bind(wx.EVT_PAINT, self.on_paint)
self.Bind(wx.EVT_LEFT_DOWN, self.on_mouse_down)
self.Bind(wx.EVT_MOTION, self.on_motion)
def prepare_buffer(self):
self.buffer = wx.EmptyBitmap(*DrawPane.VSIZE)
cdc = wx.ClientDC(self)
self.PrepareDC(cdc)
dc = wx.BufferedDC(cdc, self.buffer)
dc.Clear()
dc.DrawLine(0, 0, 999, 999) # Draw something to better show the flicker problem
def on_paint(self, evt):
dc = wx.BufferedPaintDC(self, self.buffer, wx.BUFFER_VIRTUAL_AREA)
def on_mouse_down(self, evt):
self.mouse_pos = self.CalcUnscrolledPosition(evt.GetPosition()).Get()
def on_motion(self, evt):
if evt.Dragging() and evt.LeftIsDown():
newpos = self.CalcUnscrolledPosition(evt.GetPosition()).Get()
coords = self.mouse_pos + newpos
cdc = wx.ClientDC(self)
self.PrepareDC(cdc)
dc = wx.BufferedDC(cdc, self.buffer)
dc.DrawLine(*coords)
self.mouse_pos = newpos
if __name__ == "__main__":
app = wx.PySimpleApp()
wx.InitAllImageHandlers()
MainFrame(None).Show()
app.MainLoop()