使用双缓冲时的滚动条动画

问题描述

我正在图像所在的单元格中绘制网格 (wx.Bitmap)。

我需要使用双缓冲来消除闪烁(当我绘制光标(所选单元格上的正方形)时出现闪烁)。

我注意到使用双缓冲时,即使我将鼠标悬停在滚动条上,也会调用 wxEVT_PAINT 处理程序。在这种情况下,滚动条的动画(平滑的颜色变化)发生在抽搐中。没有双缓冲,动画流畅。

有没有办法解决这个问题?

代码

import wx
 
 
class PanelDraw(wx.ScrolledCanvas):
 
    def __init__(self,*args,**kwargs):
        super().__init__(*args,**kwargs)
 
        self.SetDoubleBuffered(True)  # !!!
        self.SetScrollRate(42,42)
 
        self.cnt = 25
        self.padding = 32
        self.SetVirtualSize(self.cnt * 64 + 2 * self.padding,self.cnt * 64 + 2 * self.padding)
 
        self.Bind(wx.EVT_PAINT,self.on_paint)
 
    def on_paint(self,event):
        dc = wx.PaintDC(self)
        dc.Clear()
        self.DoPrepareDC(dc)
 
        gc = wx.GraphicsContext.Create(dc)  # type: wx.GraphicsContext
 
        gc.SetBrush(wx.TRANSPARENT_Brush)
        pen = wx.Pen(wx.Colour(80,80,127),1,wx.PENSTYLE_USER_DASH)
        pen.SetDashes([2,2])
        gc.SetPen(pen)
 
        for i in range(self.cnt + 1):
            gc.strokeLine(self.padding + i * 64,self.padding,self.padding + i * 64,self.padding + self.cnt * 64)
            gc.strokeLine(self.padding,self.padding+ self.cnt * 64,self.padding + i * 64)
 
 
class Frame(wx.Frame):
 
    def __init__(self):
        super().__init__(None)
 
        self.canvas = PanelDraw(self)
 
 
if __name__ == '__main__':
    app = wx.App()
    Frame().Show()
    app.MainLoop()

解决方法

我通过删除对 SetDoubleBuffered 的调用并使用 wx.AutoBufferedPaintDC 而不是 wx.PaintDC 设法解决了这个问题。

import wx
 
 
class PanelDraw(wx.ScrolledCanvas):
 
    def __init__(self,*args,**kwargs):
        super().__init__(*args,**kwargs)
 
        # self.SetDoubleBuffered(True)
        self.SetBackgroundStyle(wx.BG_STYLE_PAINT)
        self.SetScrollRate(42,42)
 
        self.cnt = 25
        self.padding = 32
        self.SetVirtualSize(self.cnt * 64 + 2 * self.padding,self.cnt * 64 + 2 * self.padding)
 
        self.Bind(wx.EVT_PAINT,self.on_paint)
 
    def on_paint(self,event):
        dc = wx.AutoBufferedPaintDC(self)
        dc.Clear()
        self.DoPrepareDC(dc)
 
        gc = wx.GraphicsContext.Create(dc)  # type: wx.GraphicsContext
 
        gc.SetBrush(wx.TRANSPARENT_BRUSH)
        pen = wx.Pen(wx.Colour(80,80,127),1,wx.PENSTYLE_USER_DASH)
        pen.SetDashes([2,2])
        gc.SetPen(pen)
 
        for i in range(self.cnt + 1):
            gc.StrokeLine(self.padding + i * 64,self.padding,self.padding + i * 64,self.padding + self.cnt * 64)
            gc.StrokeLine(self.padding,self.padding + self.cnt * 64,self.padding + i * 64)
 
 
class Frame(wx.Frame):
 
    def __init__(self):
        super().__init__(None)
 
        self.canvas = PanelDraw(self)
 
 
if __name__ == '__main__':
    app = wx.App()
    Frame().Show()
    app.MainLoop()