2016-12-27 2 views
1

Ich schreibe eine GUI, um ein paar Bilder (Buchumschläge von Amazon) aus einer definierten Liste von URLs anzuzeigen, ich konnte sie in einem Panel erfolgreich, aber trotzdem laden Mit Hilfe von Threads scheint die GUI zu warten, bis die Schleife vorbei ist und dann alle Bilder auf einmal angezeigt werden. Wie kann ich die GUI erreichen, um jedes Bild anzuzeigen, wie es abgerufen wird? Die GUI ist im Wesentlichen eingefroren bis die Bilder werden geholt ... Danke!wxpython Threading Bilder anzeigen, wie sie geladen werden

die Frage wieder, die mir jedes Bild erhalten, um sicherzustellen, auf der GUI angezeigt werden, da sie nicht alle auf einmal gezogen werden ...

import wx 
import os 
import sys 
import urllib2 
import cStringIO 
import threading 
import time 

urls = ['https://images-na.ssl-images-amazon.com/images/I/51-u3J3mtTL._AC_US100_.jpg', 
     'https://images-na.ssl-images-amazon.com/images/I/51cRqX8DTgL._AC_US100_.jpg', 
     'https://images-na.ssl-images-amazon.com/images/I/515iBchIIzL._AC_US100_.jpg', 
     'https://images-na.ssl-images-amazon.com/images/I/511MaP7GeJL._AC_US100_.jpg', 
     'https://images-na.ssl-images-amazon.com/images/I/51jizRmRYYL._AC_US160_.jpg', 
    'https://images-na.ssl-images-amazon.com/images/I/51jizRmRYYL._AC_US160_.jpg', 
    'https://images-na.ssl-images-amazon.com/images/I/31Pw7voGDFL._AC_US160_.jpg', 
    'https://images-na.ssl-images-amazon.com/images/I/51g30m1xpPL._AC_US160_.jpg', 
    'https://images-na.ssl-images-amazon.com/images/I/51qx+6aQUnL._AC_US160_.jpg'] 

class Example(wx.Frame): 

    def __init__(self, *args, **kwargs): 
     super(Example, self).__init__(*args, **kwargs) 
     self.InitUI() 
     self.Ctrls() 
     self.makeButtons() 

    def makeButtons(self): 

     def _update_data(data): 
      time.sleep(2) 
      stream = cStringIO.StringIO(data) 
      bmp = wx.BitmapFromImage(wx.ImageFromStream(stream)) 
      button = wx.Button(self.panel, -1, "Book cover", style=wx.ALIGN_CENTER, size=wx.Size(100,100)) 
      button.SetToolTipString("wx.Button can how have an icon on the left, right,\n" 
          "above or below the label.") 
      button.SetBitmap(bmp, 
        wx.LEFT # Left is the default, the image can be on the other sides too 
        #wx.RIGHT 
        #wx.TOP 
        #wx.BOTTOM 
        ) 
      button.SetBitmapMargins((4,4)) 
      button.SetFont(wx.Font(8, wx.SWISS, wx.NORMAL, wx.BOLD, False)) 
      self.wrapSizer.Add(button, 1, wx.EXPAND) 
      self.Show(True) 
      self.panel.Layout() 

     def f(): 
      f = urllib2.urlopen(url) 
      data = f.read() 
      wx.CallAfter(_update_data, data) 

     for url in urls: 
      threading.Thread(target=f).start() 

    def InitUI(self): 
     self.SetSize((800, 400)) 
     self.SetTitle('Dynamically Flow Buttons to Next Row on Window-Resize') 
     self.Centre() 


    def Sizers(self): 
     self.wrapSizer = wx.WrapSizer() 
     self.panel.SetSizer(self.wrapSizer) 

    def Ctrls(self): 
     self.panel = wx.Panel(parent=self,pos=wx.Point(0,0), size=wx.Size(750,550), style=wx.TAB_TRAVERSAL) 
     self.Sizers() 

def main(): 

    ex = wx.App() 
    Example(None) 
    ex.MainLoop() 

if __name__ == '__main__': 
    main() 

Antwort

2

Es wäre auch möglich, alle Threads auf einmal abzutrennen, wie es im Codebeispiel in der Frage versucht wurde. Das Problem im ursprünglichen Code war, dass die GUI wegen der Zeitverzögerung bei der Verarbeitung der Anforderung für die Bitmaps blockiert wurde.

Bedenken Sie, dass in der folgenden Tabelle die Reihenfolge der Bitmaps von der Reihenfolge abhängt, in der die Threads enden (was in diesem Fall zufällig ist).

import wx 
import urllib2 
import cStringIO 
import threading 
import time 
from random import random 

urls = ['https://images-na.ssl-images-amazon.com/images/I/51-u3J3mtTL._AC_US100_.jpg', 
     'https://images-na.ssl-images-amazon.com/images/I/51cRqX8DTgL._AC_US100_.jpg', 
     'https://images-na.ssl-images-amazon.com/images/I/515iBchIIzL._AC_US100_.jpg', 
     'https://images-na.ssl-images-amazon.com/images/I/511MaP7GeJL._AC_US100_.jpg', 
     'https://images-na.ssl-images-amazon.com/images/I/51jizRmRYYL._AC_US160_.jpg', 
    'https://images-na.ssl-images-amazon.com/images/I/51jizRmRYYL._AC_US160_.jpg', 
    'https://images-na.ssl-images-amazon.com/images/I/31Pw7voGDFL._AC_US160_.jpg', 
    'https://images-na.ssl-images-amazon.com/images/I/51g30m1xpPL._AC_US160_.jpg', 
    'https://images-na.ssl-images-amazon.com/images/I/51qx+6aQUnL._AC_US160_.jpg'] 

def url2bmp(url, callback): 
    f = urllib2.urlopen(url) 
    data = f.read() 

    # to simulate random read delay 
    time.sleep(2 * random()) 

    stream = cStringIO.StringIO(data) 
    bmp = wx.BitmapFromImage(wx.ImageFromStream(stream)) 
    wx.CallAfter(callback, bmp) 

class Example(wx.Frame): 

    def __init__(self, *args, **kwargs): 
     super(Example, self).__init__(*args, **kwargs) 
     self.InitUI() 
     self.Ctrls() 
     self.Show(True) 
     self.makeButtons() 

    def makeButtons(self): 
     for url in urls: 
      threading.Thread(target=url2bmp, args=(url, self.update_ui)).start() 

    def update_ui(self, bmp): 
     button = wx.Button(self.panel, -1, "Book cover", style=wx.ALIGN_CENTER, size=wx.Size(100,100)) 
     button.SetToolTipString("wx.Button can how have an icon on the left, right,\n" 
         "above or below the label.") 
     button.SetBitmap(bmp, 
       wx.LEFT # Left is the default, the image can be on the other sides too 
       #wx.RIGHT 
       #wx.TOP 
       #wx.BOTTOM 
       ) 
     self.wrapSizer.Add(button, 1, wx.EXPAND) 
     self.panel.Layout() 

    def InitUI(self): 
     self.SetSize((800, 400)) 
     self.SetTitle('Dynamically Flow Buttons to Next Row on Window-Resize') 
     self.Centre() 

    def Sizers(self): 
     self.wrapSizer = wx.WrapSizer() 
     self.panel.SetSizer(self.wrapSizer) 

    def Ctrls(self): 
     self.panel = wx.Panel(parent=self,pos=wx.Point(0,0), size=wx.Size(750,550), style=wx.TAB_TRAVERSAL) 
     self.Sizers() 

def main(): 

    ex = wx.App() 
    Example(None) 
    ex.MainLoop() 

if __name__ == '__main__': 
    main() 

EDIT: umschrieb das Beispiel der leeren Tasten zuerst zu erzeugen, dann die Bitmap anwenden, sobald sie ankommen. Dies ist jetzt hässlicher und es wäre an der Zeit zu refaktorieren, um eine sicherere Zuordnung Schaltfläche zu url als (falsch) mit dem Etikett zu haben.

import wx 
import urllib2 
import cStringIO 
import threading 
import time 
from random import random 

urls = ['https://images-na.ssl-images-amazon.com/images/I/51-u3J3mtTL._AC_US100_.jpg', 
     'https://images-na.ssl-images-amazon.com/images/I/51cRqX8DTgL._AC_US100_.jpg', 
     'https://images-na.ssl-images-amazon.com/images/I/515iBchIIzL._AC_US100_.jpg', 
     'https://images-na.ssl-images-amazon.com/images/I/511MaP7GeJL._AC_US100_.jpg', 
     'https://images-na.ssl-images-amazon.com/images/I/51jizRmRYYL._AC_US160_.jpg', 
    'https://images-na.ssl-images-amazon.com/images/I/51jizRmRYYL._AC_US160_.jpg', 
    'https://images-na.ssl-images-amazon.com/images/I/31Pw7voGDFL._AC_US160_.jpg', 
    'https://images-na.ssl-images-amazon.com/images/I/51g30m1xpPL._AC_US160_.jpg', 
    'https://images-na.ssl-images-amazon.com/images/I/51qx+6aQUnL._AC_US160_.jpg'] 

def url2bmp(url, callback): 
    f = urllib2.urlopen(url) 
    data = f.read() 

    # to simulate random read delay 
    time.sleep(2 * random()) 

    stream = cStringIO.StringIO(data) 
    bmp = wx.BitmapFromImage(wx.ImageFromStream(stream)) 
    wx.CallAfter(callback, url, bmp) 

class Example(wx.Frame): 

    def __init__(self, *args, **kwargs): 
     super(Example, self).__init__(*args, **kwargs) 
     self.InitUI() 
     self.Ctrls() 
     self.Show(True) 
     self.makeButtons() 

    def makeButtons(self): 
     for url in urls: 
      self.update_ui(url) 
      threading.Thread(target=url2bmp, args=(url, self.update_ui)).start() 

    def update_ui(self, url, bmp=None): 
     if bmp is None: 
      # create button, but not bitmap 
      button = wx.Button(self.panel, -1, url, style=wx.ALIGN_CENTER, size=wx.Size(100,100)) 
      button.SetToolTipString("wx.Button can how have an icon on the left, right,\n" 
          "above or below the label.") 
      self.wrapSizer.Add(button, 1, wx.EXPAND) 
     else: 
      children = self.wrapSizer.GetChildren() 
      # http://www.blog.pythonlibrary.org/2012/08/24/wxpython-how-to-get-children-widgets-from-a-sizer/ 
      for widget in children: 
       button = widget.GetWindow() 
       if isinstance(button, wx.Button): 
        if button.GetLabel() == url: 
         button.SetBitmap(bmp, 
           wx.LEFT # Left is the default, the image can be on the other sides too 
           #wx.RIGHT 
           #wx.TOP 
           #wx.BOTTOM 
           ) 
         button.SetLabel('') 
     self.panel.Layout() 

    def InitUI(self): 
     self.SetSize((800, 400)) 
     self.SetTitle('Dynamically Flow Buttons to Next Row on Window-Resize') 
     self.Centre() 

    def Sizers(self): 
     self.wrapSizer = wx.WrapSizer() 
     self.panel.SetSizer(self.wrapSizer) 

    def Ctrls(self): 
     self.panel = wx.Panel(parent=self,pos=wx.Point(0,0), size=wx.Size(750,550), style=wx.TAB_TRAVERSAL) 
     self.Sizers() 

def main(): 

    ex = wx.App() 
    Example(None) 
    ex.MainLoop() 

if __name__ == '__main__': 
    main() 
+0

Oh danke dafür, ich lerne viel. Dies ist das Ergebnis, nach dem ich gesucht habe, da ich die Sortierung nach dem Holen erledigen lassen werde. –

+0

Ich dachte an Queue zusammen mit Threading, in der Hoffnung, dass es mehrere Threads spawnen wird und dann Queue wird sich um die Reihenfolge kümmern? Nicht sicher, ob dies herauskommt, entspricht der ersten Antwort, die von Ihnen gepostet wird. –

+1

Der Code wurde geändert, um zu zeigen, wie die Schaltflächen zuerst generiert werden und die Bitmap später angewendet wird. '' Queue'' wird Ihnen nicht helfen, denn wie im ersten Beispiel werden die Threads nacheinander und nicht gleichzeitig verarbeitet. – nepix32

1

erlaubt habe zu schreiben. Wichtig ist, so schnell wie möglich aus der __init__ Methode (Aufruf Show vor dem Starten des Threads) und lassen Sie den Thread asynchron arbeiten. Sie haben auch alle Ihre Threads gleichzeitig gestartet, während dieses Beispiel einen Thread verwendet, um eine Bitmap nach der anderen zu erhalten.

import wx 
import os 
import sys 
import urllib2 
import cStringIO 
import threading 
import time 

urls = ['https://images-na.ssl-images-amazon.com/images/I/51-u3J3mtTL._AC_US100_.jpg', 
     'https://images-na.ssl-images-amazon.com/images/I/51cRqX8DTgL._AC_US100_.jpg', 
     'https://images-na.ssl-images-amazon.com/images/I/515iBchIIzL._AC_US100_.jpg', 
     'https://images-na.ssl-images-amazon.com/images/I/511MaP7GeJL._AC_US100_.jpg', 
     'https://images-na.ssl-images-amazon.com/images/I/51jizRmRYYL._AC_US160_.jpg', 
    'https://images-na.ssl-images-amazon.com/images/I/51jizRmRYYL._AC_US160_.jpg', 
    'https://images-na.ssl-images-amazon.com/images/I/31Pw7voGDFL._AC_US160_.jpg', 
    'https://images-na.ssl-images-amazon.com/images/I/51g30m1xpPL._AC_US160_.jpg', 
    'https://images-na.ssl-images-amazon.com/images/I/51qx+6aQUnL._AC_US160_.jpg'] 

def gen_urls(): 
    """Gives back one bitmap after another.""" 
    for url in urls: 
     f = urllib2.urlopen(url) 
     data = f.read() 
     time.sleep(2) 
     stream = cStringIO.StringIO(data) 
     bmp = wx.BitmapFromImage(wx.ImageFromStream(stream)) 
     yield bmp 

class Example(wx.Frame): 

    def __init__(self, *args, **kwargs): 
     super(Example, self).__init__(*args, **kwargs) 
     self.InitUI() 
     self.Ctrls() 
     self.Show(True) 
     threading.Thread(target=self.makeButtons).start() 

    def makeButtons(self): 
     for bmp in gen_urls(): 
      wx.CallAfter(self.update_ui, bmp) 

    def update_ui(self, bmp): 
     button = wx.Button(self.panel, -1, "Book cover", style=wx.ALIGN_CENTER, size=wx.Size(100,100)) 
     button.SetToolTipString("wx.Button can how have an icon on the left, right,\n" 
         "above or below the label.") 
     button.SetBitmap(bmp, 
       wx.LEFT # Left is the default, the image can be on the other sides too 
       #wx.RIGHT 
       #wx.TOP 
       #wx.BOTTOM 
       ) 
     button.SetBitmapMargins((4,4)) 
     button.SetFont(wx.Font(8, wx.SWISS, wx.NORMAL, wx.BOLD, False)) 
     self.wrapSizer.Add(button, 1, wx.EXPAND) 
     self.panel.Layout() 

    def InitUI(self): 
     self.SetSize((800, 400)) 
     self.SetTitle('Dynamically Flow Buttons to Next Row on Window-Resize') 
     self.Centre() 

    def Sizers(self): 
     self.wrapSizer = wx.WrapSizer() 
     self.panel.SetSizer(self.wrapSizer) 

    def Ctrls(self): 
     self.panel = wx.Panel(parent=self,pos=wx.Point(0,0), size=wx.Size(750,550), style=wx.TAB_TRAVERSAL) 
     self.Sizers() 

def main(): 

    ex = wx.App() 
    Example(None) 
    ex.MainLoop() 

if __name__ == '__main__': 
    main() 
+0

Super! Das funktionierte genau so, wie ich es wollte, Vielen Dank, wie Sie sehen können, lerne ich immer noch wxpython und ging ein bisschen außerhalb meiner Liga mit Threading etc .. –

+0

Kann es möglich sein, das Threading mehrere Abrufe und anzeigen zu lassen Gegenstände, wie sie abgeholt wurden, im Gegensatz zu einem nach dem anderen? –

+0

Auch dies kann getan werden, siehe separate Antwort. – nepix32

Verwandte Themen