我创建了一个交互式图像序列查看器。只有在没有闪烁的情况下,观看器才能几乎完美地工作。我读了一些关于双缓冲的知识,发现它有点令人困惑。我需要直接解释/代码我应该做些什么来消除我的程序中的闪烁。在大多数示例中都有调整大小的解释。另一方面,我不需要那个,我的窗口是固定大小的。那么我应该采取什么方法来修复闪烁呢?
代码:import wx
class main_frame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, wx.ID_ANY, 'Main window', size=(1300, 750))
self.panel = wx.Panel(self, -1)
self.Centre()
#------------------------------------------------------------------------------
self.Frames = []
l=1
while l < 365:
self.Frames.append(wx.Image('images/{0}.png'.format(l), wx.BITMAP_TYPE_ANY))
print l
l+=1
self.slider = wx.Slider(self.panel, wx.ID_ANY, size = (500,-1))
self.slider.SetMax(356)
l = self.slider.GetValue()
self.image = wx.StaticBitmap(self.panel,-1,wx.BitmapFromImage(self.Frames[l]))
#------------------------------------------------------------------------------
self.sizer = wx.BoxSizer(wx.HORIZONTAL)
self.sizer_v = wx.BoxSizer(wx.VERTICAL)
self.sizer_v.Add(self.image, 0, wx.CENTRE | wx.ALL, 5)
self.sizer_v.Add(self.slider, 0, wx.CENTRE | wx.ALL, 5)
self.sizer.Add(self.sizer_v, 1, wx.EXPAND | wx.ALL | wx.CENTER, 5)
self.panel.SetSizer(self.sizer)
self.Bind(wx.EVT_SLIDER, self.OnSlider, self.slider)
def OnSlider(self,e):
l = self.slider.GetValue()
self.image.SetBitmap(wx.BitmapFromImage(self.Frames[l]))
if __name__ == '__main__':
app = wx.App()
frame = main_frame().Show()
app.MainLoop()
静态位图在static时效果最好,就像不变一样。我觉得不用wx。我将使用绑定EVT_PAINT
事件处理程序的面板。当你想要改变图像时,你只需要做一些类似self.panel.currentBitmap = self.Frames[i]
的事情,然后是self.panel.Refresh()
。(或者更好的做法是将该功能移到panel类中,以便更好地封装。)然后在EVT_PAINT
处理程序中,您只需获得wx.PaintDC
并执行当前位图的DrawBitmap
。此外,我会在列表中保留位图而不是图像,以节省移动滑块时的转换时间。
我将发布一个最小的代码示例来回答wx python中图像序列的非闪烁显示的一般问题,因为我最近正在寻找答案。在更新位图时移除闪烁的关键是使用BufferedPaintDC(或者BufferedDC),并绘制新的位图。当绘制到BufferedPaintDC时,您首先将位图绘制到内存中,当完成时,缓冲位图仅绘制到屏幕一次。
import time
import wx
import threading
def changeBitmapWorker(parent):
img1 = 'img1.png'
img2 = 'img2.png'
i = 0
while True:
if i % 2 == 0:
parent.bitmap = wx.Bitmap(img1)
else:
parent.bitmap = wx.Bitmap(img2)
parent.Refresh()
time.sleep(1)
i += 1
class Window(wx.App):
def __init__(self):
wx.App.__init__(self)
self.init_ui()
self.mainWindow.Show()
def init_ui(self):
self.mainWindow = wx.Frame(None)
self.mainWindow.SetSize((800, 510))
self.vbox1 = wx.BoxSizer(wx.VERTICAL)
panel = MyPanel(self.mainWindow)
panel.SetSizer(self.vbox1)
class MyPanel(wx.Panel):
def __init__(self,parent=None):
wx.Panel.__init__(self,parent,id=-1)
self.parent = parent
self.Bind(wx.EVT_PAINT, self.OnPaint)
self.bitmap = None
t = threading.Thread(target=changeBitmapWorker, args=(self,))
t.setDaemon(True)
t.start()
def OnPaint(self, evt):
if self.bitmap != None:
dc = wx.BufferedPaintDC(self)
dc.Clear()
dc.DrawBitmap(self.bitmap, 0,0)
else:
pass
if __name__ == '__main__':
app = Window()
app.MainLoop()