2010-06-30 61 views
3

我正在尝试构建一个可以使用鼠标进行绘制的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测试过)

非常感谢您的时间!

回答

5

罗宾·邓恩本人:

首先,Refresh()默认会 发送 油漆事件(尽管设置 BG风格或捕捉擦除事件 会照顾前擦除背景)。 第二个也许最明显的 问题在这种情况下是在您的 on_motion处理程序你不是 偏移ClientDC的滚动 偏移量,只是在您正在绘制线段 的 缓冲区。所以当缓冲区是 刷新到客户端DC时,它是 绘制在物理(0,0),而不是 虚拟(0,0)。换句话说,在 闪烁,你看到的是从 来在每一个鼠标拖动事件, 后错 位置绘制缓冲区,然后立即被在 on_paint正确的位置由 Refresh()再次触发绘制 。

您应该能够通过 在客户端上调用PrepareDC DC 使用它之前解决这个问题,就像这样:

cdc = wx.CLientDC(self) 
    self.PrepareDC(cdc) 
    dc = wx.BufferedDC(cdc, self.buffer) 

但是因为你正在做一个 RefreshRefreshRect反正 没有需要在所有使用客户端DC 这里,只是让的 冲洗缓冲区到屏幕上 on_paint替代来实现:

dc = wx.BufferedDC(None, self.buffer) 
1

使用Joril recomendations和删除刷新(),没有闪烁了(甚至放大框架)。

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()