2012-08-27 19 views
5

Ho avuto qualche problema con un programma che stavo scrivendo e apprezzerei qualche aiuto o input. Per qualche background, sto usando Python 2.7 e wxPython per fare un client di streaming webcam. Il client ottiene le immagini dal server nel proprio thread e le inserisce in una coda. Il thread della GUI ottiene quindi quelle immagini dalla coda e le converte in un oggetto wxBitmap. Succede ogni 0,5 secondi e funziona alla grande. Sono in grado di salvare l'oggetto wxBitmap come un file, quindi so che tutto funziona correttamente.problemi di visualizzazione di wxBitmaps usando wxPython

Il problema che sto riscontrando è che l'oggetto wxBitmap viene visualizzato nella GUI. L'unica cosa che sembra essere in grado di fare la GUI è mostrare un rettangolo grigio dove dovrebbe essere l'immagine della web cam.

Ecco il mio onPaint() che viene chiamato quando voglio aggiornare la schermata:

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) 

In poche parole, io sono in perdita per spiegare perché non il suo lavoro. dalla mia ricerca ho scoperto che poiché sono su una macchina Windows avevo bisogno delle funzioni BeginDrawing() e EndDrawing(), quindi le ho aggiunte. Ancora non funziona. Non ci sono errori o eccezioni lanciati.

altre domande che potrebbero aiutare a risolvere questo problema:

  • sto aggiornando un oggetto wxFrame. Forse il wxPaintDC deve funzionare in un altro tipo di contenitore per funzionare?
  • ?

In realtà, forse la mia funzione __init__ è il problema. Sto configurando questo correttamente?

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

In ogni caso, grazie in anticipo per il vostro aiuto.

MODIFICA: Ho risolto il problema accidentalmente cancellando la linea self.pnl = wx.Panel(self).

Quindi apparentemente era il rendering in modo corretto, ma la bitmap era sotto il pannello. Può essere? Non sono veramente sicuro. Sono nuovo di questa intera cosa di wxPython.

+1

L'immagine che appare sotto il pannello è una possibilità. A meno che non si imposti esplicitamente la posizione di uso di un 'wx.Sizer', gli oggetti vengono impostati su (0,0). Ecco perché uso un misuratore anche se ho solo 1 oggetto. – acattle

risposta

1

Questo sembra essere ciò che sta facendo anche la demo wxPython: dc.DrawBitmap. E funziona su Windows! Almeno, questo è quello che fanno nella demo di AlphaDrawing. Nella demo DrawImage, usano dc.Blit(). Potresti provarlo.

Tuttavia, mi chiedo se non è possibile farlo come ho fatto con il mio photo viewer. Non uso DCs per disegnare, ma invece uso solo un wx.StaticBitmap che aggiorno.

+0

Avevo effettivamente guardato il tuo codice per il visualizzatore di foto prima di porre questa domanda. L'avevo guardato e non riuscivo a farlo funzionare. C'è probabilmente qualche difetto nella mia comprensione di come wxPython rende le cose sullo schermo, e penso che abbia a che fare con il modo in cui wx.App, wx.Frame e wx.Panel lavorano tutti insieme. Ho notato che il tuo codice per il visualizzatore di foto è un wx.Sizer e wx.Widgets all'interno di un wx.Panel, che si trova all'interno di un wx.Frame, che è all'interno di un wx.App, mentre il mio è semplicemente un wx. Frame e un oggetto dc. Cercherò di ristrutturare il mio codice per essere simile al tuo e tornare da te. – user1626536

+0

OK. Sarebbe bello vedere un piccolo esempio eseguibile. Ciò aiuterebbe enormemente. –

+0

ecco il mio nuovo codice che funziona. si basa sull'esempio del tuo blog, il visualizzatore di immagini. Sono contento che funzioni, ma non sono felice del flicker ogni volta che si aggiorna. Oh bene. Risolvi un bug e creane un altro credo. ecco il codice: modifica: troppi caratteri da lasciare come commento. http://pastebin.com/WwHhTUAQ – user1626536

1

Questo codice funziona. Visualizza le immagini ogni volta e tutto il resto. Tende a 'sfarfallio', però. Quindi probabilmente c'è un modo migliore per farlo di cui non sono a conoscenza.

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