【问题标题】:wxPython: Dynamically drawn picture becomes brokenwxPython:动态绘制的图片变坏了
【发布时间】:2012-03-01 08:42:30
【问题描述】:

我正在学习 wxPython,但在教程示例中遇到了以下故障。

应用程序启动后,它会根据应用程序窗口的大小显示具有大小的图形。一开始它看起来应该是这样。但是当我调整窗口大小时,绘图会损坏。这是视频http://screencast.com/t/0XOetqJ2W5x

这里是代码:

# Chapter 8: Drawing to the Screen, Using Device Contexts
# Recipe 1: Screen Drawing
#
import os
import wx

#---- Recipe Code ----#

class Smiley(wx.PyControl):
    def __init__(self, parent, size=(50,50)):
        super(Smiley, self).__init__(parent,
                                     size=size,
                                     style=wx.NO_BORDER)

        # Event Handlers
        self.Bind(wx.EVT_PAINT, self.OnPaint)

    def OnPaint(self, event):
        """Draw the image on to the panel"""
        dc = wx.PaintDC(self) # Must create a PaintDC

        # Get the working rectangle we can draw in
        rect = self.GetClientRect()

        # Setup the DC
        dc.SetPen(wx.BLACK_PEN) # for drawing lines / borders
        yellowbrush = wx.Brush(wx.Colour(255, 255, 0))
        dc.SetBrush(yellowbrush) # Yellow fill

        # Find the center and draw the circle
        cx = (rect.width / 2) + rect.x
        cy = (rect.width / 2) + rect.y
        radius = min(rect.width, rect.height) / 2
        dc.DrawCircle(cx, cy, radius)

        # Give it some square blue eyes
        # Calc the size of the eyes 1/8th total
        eyesz = (rect.width / 8, rect.height / 8)
        eyepos = (cx / 2, cy / 2)
        dc.SetBrush(wx.BLUE_BRUSH)
        dc.DrawRectangle(eyepos[0], eyepos[1],
                         eyesz[0], eyesz[1])
        eyepos = (eyepos[0] + (cx - eyesz[0]), eyepos[1])
        dc.DrawRectangle(eyepos[0], eyepos[1],
                         eyesz[0], eyesz[1])

        # Draw the smile
        dc.SetBrush(yellowbrush)
        startpos = (cx / 2, (cy / 2) + cy)
        endpos = (cx + startpos[0], startpos[1])
        dc.DrawArc(startpos[0], startpos[1],
                   endpos[0], endpos[1], cx, cy)

        # Draw a yellow rectangle to cover up the
        # unwanted black lines from the wedge part of
        # our arc
        dc.SetPen(wx.TRANSPARENT_PEN)
        dc.DrawRectangle(startpos[0], cy,
                         endpos[0] - startpos[0],
                         startpos[1] - cy)

#---- End Recipe Code ----#

class SmileyApp(wx.App):
    def OnInit(self):
        self.frame = SmileyFrame(None,
                                 title="Drawing Shapes",
                                 size=(300,400))
        self.frame.Show()
        return True

class SmileyFrame(wx.Frame):
    def __init__(self, parent, *args, **kwargs):
        wx.Frame.__init__(self, parent, *args, **kwargs)

        # Attributes
        self.panel = SmileyPanel(self)

        # Layout
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.panel, 1, wx.EXPAND)
        self.SetSizer(sizer)

class SmileyPanel(wx.Panel):
    def __init__(self, parent):
        wx.Panel.__init__(self, parent)

        # Layout
        self.__DoLayout()

    def __DoLayout(self):
        # Layout a grid of 4 smileys
        msizer = wx.GridSizer(2, 2, 0, 0)

        for x in range(4):
            smile = Smiley(self)
            msizer.Add(smile, 0, wx.EXPAND)

        self.SetSizer(msizer)

if __name__ == '__main__':
    app = SmileyApp(False)
    app.MainLoop()

如您所见,绘图功能被放置在绑定到 wx.EVT_PAINT 事件的 OnPaint 方法中。所以我认为每次系统重新绘制窗口时它应该在面板上绘制一个新图像。

我正在使用 Win7、Python2.7 和 wxPython 2.8.12.1

这对我来说很重要,因为我将在其窗口上编写一个带有可伸缩图表的应用程序。

【问题讨论】:

    标签: wxpython


    【解决方案1】:

    所以我找到了解决方案——我必须使用 wx.BufferedDC 和 wx.EmptyBitmap。我在“wxPython in Action”一书中找到了它(关于 Sketch 应用程序的示例)。

    这是一个新代码:

    import wx
    
    
    class Smiley(wx.PyControl):
        def __init__(self, parent, size=(50,50)):
            super(Smiley, self).__init__(parent,
                                         size=size,
                                         style=wx.NO_BORDER)
    
            self.InitBuffer()                   # new
            self.Bind(wx.EVT_SIZE, self.OnSize) # new
            self.Bind(wx.EVT_IDLE, self.OnIdle) # new
    
            self.Bind(wx.EVT_PAINT, self.OnPaint)
    
    # new block
        def InitBuffer(self):
            self.client_size = self.GetClientSize()
            self.buffer = wx.EmptyBitmap(self.client_size.width, self.client_size.height)
            dc = wx.BufferedDC(None, self.buffer)
            dc.SetBackground(wx.Brush(self.GetBackgroundColour()))
            dc.Clear()
            self.DrawImage(dc)
            self.reInitBuffer = False
    
        def OnSize(self, event):
            self.reInitBuffer = True
    
        def OnIdle(self, event):
            if self.reInitBuffer:
                self.InitBuffer()
                self.Refresh(False)
    
        def DrawImage(self, dc):
    
            # Get the working rectangle we can draw in
            rect = self.client_size 
    
            # Find a square inside a rectangle (size of the client)
            min_side = min(rect.x, rect.y)
            rect.SetHeight(min_side)
            rect.SetWidth(min_side)
    
            # Setup the DC
            dc.SetPen(wx.BLACK_PEN) # for drawing lines / borders
            yellowbrush = wx.Brush(wx.Colour(255, 255, 0))
            dc.SetBrush(yellowbrush) # Yellow fill
    
            # Find the center and draw the circle
            cx = rect.width / 2
            cy = rect.width / 2
            radius = min(rect.width, rect.height) / 2
            dc.DrawCircle(cx, cy, radius)
    
            # Give it some square blue eyes
            # Calc the size of the eyes 1/8th total
            eyesz = (rect.width / 8, rect.height / 8)
            eyepos = (cx / 2, cy / 2)
            dc.SetBrush(wx.BLUE_BRUSH)
            dc.DrawRectangle(eyepos[0], eyepos[1],
                             eyesz[0], eyesz[1])
            eyepos = (eyepos[0] + (cx - eyesz[0]), eyepos[1])
            dc.DrawRectangle(eyepos[0], eyepos[1],
                             eyesz[0], eyesz[1])
    
            # Draw the smile
            dc.SetBrush(yellowbrush)
            startpos = (cx / 2, (cy / 2) + cy)
            endpos = (cx + startpos[0], startpos[1])
            dc.DrawArc(startpos[0], startpos[1],
                       endpos[0], endpos[1], cx, cy)
    
            # Draw a yellow rectangle to cover up the
            # unwanted black lines from the wedge part of
            # our arc
            dc.SetPen(wx.TRANSPARENT_PEN)
            dc.DrawRectangle(startpos[0], cy,
                             endpos[0] - startpos[0],
                             startpos[1] - cy)
    # end of a new block
    
        def OnPaint(self, event):
            wx.BufferedPaintDC(self, self.buffer)
    
    
    class SmileyApp(wx.App):
        def OnInit(self):
            self.frame = SmileyFrame(None,
                                     title="Drawing Shapes",
                                     size=(300,400))
            self.frame.Show()
            return True
    
    class SmileyFrame(wx.Frame):
        def __init__(self, parent, *args, **kwargs):
            wx.Frame.__init__(self, parent, *args, **kwargs)
    
            # Attributes
            self.panel = SmileyPanel(self)
    
            # Layout
            sizer = wx.BoxSizer(wx.VERTICAL)
            sizer.Add(self.panel, 1, wx.EXPAND)
            self.SetSizer(sizer)
    
    class SmileyPanel(wx.Panel):
        def __init__(self, parent):
            wx.Panel.__init__(self, parent)
    
            # Layout
            self.__DoLayout()
    
        def __DoLayout(self):
            # Layout a grid of 4 smileys
            msizer = wx.GridSizer(2, 2, 0, 0)
    
            for x in range(4):
                smile = Smiley(self)
                msizer.Add(smile, 0, wx.EXPAND)
    
            self.SetSizer(msizer)
    
    if __name__ == '__main__':
        app = SmileyApp(False)
        app.MainLoop()
    

    现在它是如何工作的:http://screencast.com/t/HXohd4tVJi

    并不完美,但要好得多。 我希望我能找到方法让它更接近完美

    【讨论】:

      【解决方案2】:

      我一直在寻找完全不同的东西,但我整天都在用 wx.Python 绘图,所以我很快就在这里看到了答案——每次调整窗口大小时只需调用self.InitBuffer()

      只需将self.InitBuffer() 添加到您大部分固定代码的第 28 行,它就可以完美地为我工作。

      def OnSize(self, event):
          self.reInitBuffer = True
          self.InitBuffer()
      

      【讨论】:

        猜你喜欢
        • 2010-11-13
        • 1970-01-01
        • 1970-01-01
        • 2017-10-10
        • 2010-12-30
        • 1970-01-01
        • 2011-09-21
        • 2012-04-11
        相关资源
        最近更新 更多