2012-08-27 23 views
5

He tenido algunos problemas con un programa que he estado escribiendo y agradecería alguna ayuda o aporte. Para algunos antecedentes, estoy usando Python 2.7 y wxPython para hacer un cliente de webcam en tiempo real. El cliente obtiene las imágenes del servidor en su propio hilo y las coloca en una cola. El hilo de la GUI obtiene esas imágenes de la cola y las convierte en un objeto wxBitmap. Esto sucede cada 0,5 segundos y funciona genial. Puedo guardar el objeto wxBitmap como un archivo, así sé que todo funciona correctamente.problemas al mostrar wxBitmaps usando wxPython

El problema que tengo es que el objeto wxBitmap se muestre en mi GUI. Lo único que creo que puedo hacer con la GUI es mostrar un rectángulo gris donde debería estar la imagen de la cámara web.

Aquí es mi onPaint() que se llama cuando quiero actualizar la pantalla:

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) 

En pocas palabras, estoy en una pérdida de por qué no su trabajo. de mi investigación descubrí que debido a que estoy en una máquina con Windows necesitaba las funciones BeginDrawing() y EndDrawing(), así que las agregué. Aún no funciona. No hay errores o excepciones lanzadas.

otras preguntas que pueden ayudar a resolver este problema:

  • estoy actualizando un objeto wxFrame. ¿Tal vez el wxPaintDC necesita operar en otro tipo de contenedor para funcionar?
  • ?

En realidad, tal vez mi función __init__ es la que está teniendo el problema. ¿Estoy configurando esto correctamente?

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() 

De todos modos, gracias de antemano por su ayuda.

EDIT: resolví el problema accidentalmente borrando la línea self.pnl = wx.Panel(self).

Aparentemente se estaba procesando correctamente, pero el mapa de bits estaba debajo del panel. ¿Tal vez? No estoy realmente seguro. Soy nuevo en esto de wxPython.

+1

La imagen que aparece debajo del panel es una posibilidad. A menos que establezca explícitamente la posición de uso de un 'wx.Sizer' los objetos predeterminados a (0,0). Es por eso que uso un medidor incluso si solo tengo 1 artículo. – acattle

Respuesta

1

Eso parece ser lo que la demostración de wxPython también está haciendo: dc.DrawBitmap. ¡Y funciona en Windows! Al menos, eso es lo que hacen en la demostración AlphaDrawing. En la demostración de DrawImage, usan dc.Blit(). Puedes intentar eso.

Sin embargo, me pregunto si no podría hacerlo como lo hice con mi photo viewer. No uso DC para dibujar, sino que solo uso un wx.StaticBitmap que actualizo.

+0

En realidad, había mirado su código para el visor de fotos antes de hacer esta pregunta. Lo había visto y no podía hacer que funcionara. Probablemente haya algún error en mi comprensión de cómo wxPython representa las cosas en la pantalla, y creo que tiene que ver con la forma en que wx.App, wx.Frame y wx.Panel funcionan todos juntos. Observé que tu código para el visor de fotos es un wx.Sizer y wx.Widgets dentro de un wx.Panel, que está dentro de un wx.Frame, que está dentro de una wx.App, mientras que el mío es simplemente un wx. Marco y un objeto de CD. Voy a intentar reestructurar mi código para que sea similar al tuyo y te responda. – user1626536

+0

De acuerdo. Sería bueno ver un pequeño ejemplo ejecutable. Eso ayudaría muchísimo. –

+0

aquí está mi nuevo código que funciona. se basa en el ejemplo de tu blog, el visor de imágenes. Estoy feliz de que funcione, pero no estoy contento con el parpadeo cada vez que se actualiza. Oh bien. Resuelve un error y crea otro, supongo. Aquí está el código: editar: demasiados personajes para dejar como un comentario. http://pastebin.com/WwHhTUAQ – user1626536

1

Este código funciona. Muestra las imágenes todo el tiempo y todo eso. Sin embargo, tiende a 'parpadear'. Entonces, probablemente haya una forma mejor de hacer esto que yo no conozco.

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()