2012-08-27 13 views
5

Mam problemy z programem, który pisałem i docenię pomoc lub dane wejściowe. Na pewnym tle używam Pythona 2.7 i wxPythona, aby zrobić klienta kamery strumieniowej. Klient pobiera obrazy z serwera we własnym wątku i umieszcza je w kolejce. Wątek GUI pobiera te obrazy z kolejki i konwertuje je do obiektu wxBitmap. Dzieje się to co 0,5 sekundy i działa świetnie. Jestem w stanie zapisać obiekt wxBitmap jako plik, więc wiem, że wszystko działa poprawnie.Problemy z wyświetlaniem wxBitmaps za pomocą wxPython

Problem, który mam, polega na tym, że obiekt wxBitmap pojawia się na moim GUI. Jedyne, co wydaje mi się być w stanie zrobić GUI to wyświetlanie szarego prostokąta, w którym powinien być obraz kamery internetowej.

Oto mój onPaint() która jest wywoływana, gdy chcę, aby odświeżyć ekran:

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) 

Mówiąc najprościej, jestem w rozterce, dlaczego jej nie działa. z moich badań wynika, że ​​ponieważ jestem na komputerze z systemem Windows potrzebowałem funkcji BeginDrawing() i EndDrawing(), więc dodałem je. Nadal nie działa. Nie są zgłaszane żadne błędy ani wyjątki.

innych pytań, które mogą pomóc rozwiązać ten problem:

  • mam aktualizowania wxFrame obiektu. Może wxPaintDC musi działać w innym typie pojemnika do pracy?
  • ?

Właściwie może moja funkcja __init__ jest tym, co trzyma problem. Czy to ustawienie jest poprawne?

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

W każdym razie, z góry dzięki za pomoc.

EDYCJA: Rozwiązałem problem przez przypadek, kasując linię self.pnl = wx.Panel(self).

Najwyraźniej renderowanie było prawidłowe, ale bitmapa znajdowała się pod panelem. Może? Nie jestem do końca pewny. Jestem nowy w tej całej sprawie wxPython.

+1

Obraz znajdujący się pod panelem jest możliwy. Dopóki nie ustawisz wyraźnie pozycji użycia 'wx.Sizer', obiekt domyślnie (0,0). Dlatego używam sizera, nawet jeśli mam tylko 1 przedmiot. – acattle

Odpowiedz

1

Wydaje się, że to samo robi demo wxPython: dc.DrawBitmap. I działa w systemie Windows! Przynajmniej tak robią w demo AlphaDrawing. W demo DrawImage używają dc.Blit(). Możesz spróbować tego.

Zastanawiam się jednak, czy nie można tego zrobić tak, jak zrobiłem to z moim photo viewer. Nie używam DC do rysowania, ale zamiast tego używam aktualizowanej przeze mnie wx.StaticBitmap.

+0

Właściwie sprawdziłem twój kod dla przeglądarki zdjęć, zanim zadałem to pytanie. Spojrzałem na niego i nie mogłem go uruchomić. Prawdopodobnie jest jakaś wada w moim zrozumieniu tego, w jaki sposób wxPython renderuje rzeczy na ekranie i myślę, że ma to związek z tym, jak wx.App, wx.Frame i wx.Panel działają razem. Zauważyłem, że twój kod do przeglądarki zdjęć to wx.Sizer i wx.Widgets wewnątrz wx.Panel, który jest wewnątrz wx.Frame, który jest wewnątrz wx.App, podczas gdy mój jest tylko wx. Ramka i obiekt DC. Zamierzam zrestrukturyzować mój kod tak, aby był podobny do twojego i do Ciebie. – user1626536

+0

W porządku. Byłoby dobrze zobaczyć mały, działający przykład. To bardzo pomogłoby. –

+0

Oto mój nowy kod, który działa. jest oparty na przykładzie z twojego bloga, przeglądarki obrazów. Cieszę się, że to działa, ale nie jestem szczęśliwy z powodu migotania za każdym razem, gdy się odświeża. No cóż. Rozwiąż jeden błąd i stwórz kolejny, jak sądzę. heres the code: edit: zbyt wiele znaków, aby opuścić jako komentarz. http://pastebin.com/WwHhTUAQ – user1626536

1

Ten kod działa. Wyświetla obrazy za każdym razem i tak dalej. Jednak ma tendencję do "migotania". Prawdopodobnie jest lepszy sposób na zrobienie tego, czego nie jestem świadomy.

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