2010-06-30 59 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()