Не могу получить wx.BufferedDC, чтобы нарисовать что-нибудь

1

У меня проблема с 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()
Теги:
wxwidgets

2 ответа

3
Лучший ответ

Я использовал 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
  • ничего не делать при стирании фона, чтобы избежать мерцания.
  • вызывать перерисовку когда и только тогда, когда вам действительно нужно изменить то, что на экране

Если вы храните ссылку на эту пустую ячейку, созданную в on_size, вы даже можете сохранить содержимое окна в файл изображения с помощью wxBitmap.SaveFile()

1

A BufferedDC копируется на экран только тогда, когда объект уничтожается. Поскольку вы никогда не уничтожаете self.bdc, его содержимое никогда не будет скопировано на экран. Итак, вам нужно уйти от self.bdc (возможно, просто замените его новым экземпляром BufferedDc: т.е. Повторите назначение self.bdc = wc.BufferedDc(self.dc) в "стратегические" моменты времени, когда вы хотите визуализировать чертеж.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню