【问题标题】:Can't get wx.BufferedDC to draw anything无法让 wx.BufferedDC 绘制任何内容
【发布时间】:2010-01-31 23:17:47
【问题描述】:

我的 DC 有问题。我正在尝试制作一个将在屏幕上绘制许多线条并且需要非常快速地更新的应用程序,并且由于我不想闪烁,所以我决定试一试缓冲 dcs。但是当我运行这段代码时,它什么也没画。我做错了什么?

import wx

class MainFrame(wx.Frame):
    def __init__(self):
        screensize = wx.GetDisplaySize()
        self.framesize = (screensize[0]/4*3, screensize[1]/4*3)
        wx.Frame.__init__(self, None, -1, "CursorTracker", size=self.framesize,
                          style=wx.SYSTEM_MENU|
                          wx.CAPTION|
                          wx.CLOSE_BOX|
                          wx.MINIMIZE_BOX)
        self.dc = wx.ClientDC(self)
        self.bdc = wx.BufferedDC(self.dc)
        self.SetBackgroundColour(wx.WHITE)
        self.Timer = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.OnTimer)
        self.Timer.Start(100)

    def OnTimer(self, event):

        self.bdc.DrawLine(1,1,100,100)


class App(wx.App):
    def OnInit(self):
        frame = MainFrame()
        frame.Show()
        return True

app = App(redirect=False)
app.MainLoop()

【问题讨论】:

    标签: python wxwidgets


    【解决方案1】:

    我使用过 AutoBufferedPaintDC,但我发现自己使用 MemoryDC 进行双缓冲会更灵活。这是给你的模板。

    import wx
    
    class Frame(wx.Frame):
        def __init__(self):
            super(Frame, self).__init__(None, -1, 'CursorTracker')
            self.mdc = None # memory dc to draw off-screen
            self.Bind(wx.EVT_SIZE, self.on_size)
            self.Bind(wx.EVT_ERASE_BACKGROUND, self.on_erase)
            self.Bind(wx.EVT_PAINT, self.on_paint)
            w, h = wx.GetDisplaySize()
            w, h = w * 3 / 4, h * 3 / 4
            self.SetSize((w, h))
            self.Center()
            self.on_timer()
        def on_size(self, event):
            # re-create memory dc to fill window
            w, h = self.GetClientSize()
            self.mdc = wx.MemoryDC(wx.EmptyBitmap(w, h))
            self.redraw()
        def on_erase(self, event):
            pass # don't do any erasing to avoid flicker
        def on_paint(self, event):
            # just blit the memory dc
            dc = wx.PaintDC(self)
            if not self.mdc:
                return
            w, h = self.mdc.GetSize()
            dc.Blit(0, 0, w, h, self.mdc, 0, 0)
        def on_timer(self):
            # refresh every N milliseconds
            self.redraw()
            wx.CallLater(100, self.on_timer)
        def redraw(self):
            # do the actual drawing on the memory dc here
            dc = self.mdc
            w, h = dc.GetSize()
            dc.Clear()
            dc.DrawLine(0, 0, w, h)
            self.Refresh()
    
    if __name__ == '__main__':
        app = wx.PySimpleApp()
        frame = Frame()
        frame.Show()
        app.MainLoop()
    

    基本做法是:

    • 为屏幕外绘图创建内存 dc
    • 如果调整了窗口大小,则调整内存 dc 的大小并重绘
    • 当绘制事件发生时,只需将内存 dc blit 到绘制 dc 上
    • 对擦除背景事件不执行任何操作以避免闪烁
    • 仅当您真正需要更改屏幕上的内容时才调用重绘

    如果您存储对在 on_size 中创建的 EmptyBitmap 的引用,您甚至可以使用 wxBitmap.SaveFile() 将窗口内容保存到图像文件

    【讨论】:

      【解决方案2】:

      只有当对象被销毁时,BufferedDC 才会被复制到屏幕上。既然你永远不会破坏self.bdc,那么它的内容当然永远不会被复制到屏幕上。因此,您需要安排放弃 self.bdc(也许只需将其替换为新的 BufferedDc 实例:即,在您确实希望绘图可视化的“战略”时刻重做分配 self.bdc = wc.BufferedDc(self.dc)

      【讨论】:

        猜你喜欢
        • 2014-06-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-01-29
        • 2010-12-15
        • 1970-01-01
        相关资源
        最近更新 更多