使用wxPython显示wxBitmaps的问题

时间:2012-08-27 01:02:22

标签: python wxpython

我一直在编写一些我一直在写的程序的问题,并希望得到一些帮助或输入。对于某些背景,我使用Python 2.7和wxPython来做一个流媒体网络摄像头客户端。客户端从自己的线程中获取服务器中的图像,并将它们放入队列中。然后,GUI线程从队列中获取这些图像并将它们转换为wxBitmap对象。这种情况每0.5秒发生一次,效果很好。我能够将wxBitmap对象保存为文件,因此我知道一切正常。

我遇到的问题实际上是让wxBitmap对象显示在我的GUI上。我似乎唯一可以做GUI的工作是显示一个灰色矩形,其中应该是网络摄像头图像。

以下是我要刷新屏幕时调用的onPaint()

    def onPaint(self,e):
            ## this is the function that actually draws and redraws the window
            ## to be displayed. I think it is something similar to blit()
            ## in other graphical display frameworks
            print "in onPaint"

            ## create the device context object (graphics painter)
            dc = wx.PaintDC(self)
            dc.BeginDrawing()

            ## draw the bitmap to the screen
            dc.DrawBitmap(self.imageBit,0,0,True)
            dc.EndDrawing()            

            ## test code.
            ## the following works and updates, which means that
            ## everything is being converted properly and updated.
            ## not sure why the dc won't paint it to the window. 
            self.imageBit.SaveFile("bit.bmp", wx.BITMAP_TYPE_BMP)

简单地说,我不知道为什么它不起作用。从我的研究中我发现,因为我在Windows机器上,我需要BeginDrawing()EndDrawing()函数,所以我添加了它们。仍然无法正常工作。没有错误或异常被抛出。

可能有助于解决此问题的其他问题:

  • 我正在更新wxFrame个对象。也许wxPaintDC需要在另一种类型的容器中运行才能工作?

实际上,也许我的__init__函数存在问题。我正确地设置了吗?

class viewWindow(wx.Frame):
    imgSizer = (480,360)
    def __init__(self, *args, **kw):
            ## this is called when an instance of this class is created
            super(viewWindow,self).__init__(*args,**kw)

            ## here is where the actual stuff inside the frame is set up.

            self.pnl = wx.Panel(self)

            ## create a button that opens up a Connection Window
            #test = wx.Button(self.pnl, label='Connection Settings')
            ## test.Bind(wx.EVT_BUTTON, self.openConnectionWindow)

            ## create the wxImage for the web cam pic
            self.image = wx.EmptyImage(self.imgSizer[0],self.imgSizer[1])

            ## create the wxBitmap so that the wxImage can be displayed
            self.imageBit = wx.BitmapFromImage(self.image)

            ## create a timer that will update the window based of frame rate
            self.timex = wx.Timer(self, wx.ID_OK)
            self.timex.Start(500)
            self.Bind(wx.EVT_TIMER, self.redraw, self.timex)

            ## need to do the following in order to display images in wxPython:
            self.Bind(wx.EVT_PAINT, self.onPaint)

            self.SetSize(self.imgSizer)
            self.SetTitle('View Window')
            self.Show()

无论如何,提前感谢您的帮助。

编辑:我通过删除行self.pnl = wx.Panel(self)意外地解决了问题。

显然它渲染得很好,但位图位于面板下方。也许?我不太确定。我是整个wxPython的新手。

3 个答案:

答案 0 :(得分:1)

这似乎也是wxPython演示所做的:dc.DrawBitmap。它适用于Windows!至少,这就是他们在AlphaDrawing演示中所做的事情。在DrawImage演示中,他们使用dc.Blit()。你可以尝试一下。

然而,我想知道你是不是像我对photo viewer那样做了。我不使用DC来绘制,而只是使用我更新的wx.StaticBitmap。

答案 1 :(得分:1)

此代码有效。它每次都显示图像。但它确实倾向于“闪烁”。所以我可能还有一种更好的方法,我不知道。

class viewWindow(wx.Frame):
    imgSizer = (480,360)
    def __init__(self, parent, title="View Window"):
            super(viewWindow,self).__init__(parent)
            ## create the menu and its sub trees
            menubar = wx.MenuBar()
            filemenu = wx.Menu()
            menubar.Append(filemenu, 'File')
            self.fitem = filemenu.Append(wx.ID_ANY, 'Open Connection Window')
            self.Bind(wx.EVT_MENU, self.openConnectionWindow, self.fitem)
            self.SetMenuBar(menubar)

            ## here is where the actual stuff inside the frame is set up.
            self.pnl = wx.Panel(self)
            self.vbox = wx.BoxSizer(wx.VERTICAL)

            ## create the wxImage for the web cam pic
            self.image = wx.EmptyImage(self.imgSizer[0],self.imgSizer[1])

            ## create the wxBitmap so that the wxImage can be displayed
            self.imageBit = wx.BitmapFromImage(self.image)
            self.staticBit = wx.StaticBitmap(self.pnl,wx.ID_ANY, self.imageBit)

            ## add the staticBit to the sizer so it is rendered properly on resizes and such
            ## note: not actually needed to get the image to display, but reccommended for ease
            ## of layout
            self.vbox.Add(self.staticBit)

            ## register the sizer with the panel so the panel knows to use it.
            self.pnl.SetSizer(self.vbox)

            ## create a timer that will update the window based on frame rate
            self.timex = wx.Timer(self, wx.ID_OK)
            self.timex.Start(1000/framerate)
            self.Bind(wx.EVT_TIMER, self.redraw, self.timex)

            ## set the size of the frame itself when it is first opened
            self.SetSize(self.imgSizer)
            self.Show()

    def openConnectionWindow(self, e):
            ## this will open a new connection window
            connect = connectionWindow(None)

    def redraw(self,e):
            ## this function updates the frame with the latest web cam image that has been
            ## retrieved by the client thread from the server.

            ## get the newest image in the queue 
            if not imgQ.empty():                        
                    picz = imgQ.get()
                    ## convert the image from a string to something usable (wxImage)
                    self.image.SetData(picz)
                    ## from wxImage to wxBitmap
                    self.imageBit = wx.BitmapFromImage(self.image)
                    self.staticBit = wx.StaticBitmap(self.pnl,wx.ID_ANY, self.imageBit)
                    ## refresh the frame
                    self.Refresh()

答案 2 :(得分:0)

几个小时后,我研究了一个不同的问题,我发现了这个问题:

How to detect motion between two PIL images? (wxPython webcam integration example included)

其中的示例代码效果很好。