代码之家  ›  专栏  ›  技术社区  ›  Joril

无闪烁可绘制滚动窗口

  •  3
  • Joril  · 技术社区  · 14 年前

    我试图建立一个滚动窗口,你可以用鼠标绘制,它也工作,但我得到一个恶劣的闪烁,当用户在窗口上绘制,而滚动条不在“主页”的位置。。

    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

    2 回复  |  直到 7 年前
        1
  •  5
  •   Joril    14 年前

    首先,一个 Refresh() 绘制事件(尽管设置 BG样式或捕捉擦除事件 会处理好的。)The 这个案子的问题是 on_motion 你不是吗 通过滚动偏移ClientDC 偏移量,只是 你在画一条线 段位于。所以当缓冲区 虚拟(0,0)。换言之 你看到的闪烁来自 在错误的位置绘制缓冲区 然后它马上就被画出来了 再次在正确的位置 on_paint 刷新() .

    你应该可以通过 打电话 PrepareDC 在使用之前,像这样:

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

    但是既然你在做 Refresh RefreshRect 不管怎样, 不需要使用客户机DC 在这里,就让水冲出来吧 屏幕的缓冲区将在

        dc = wx.BufferedDC(None, self.buffer)
    
        2
  •  2
  •   laurent    14 年前

    使用Joril recomendations和removing 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()