2016-12-27 28 views
1

我寫一個GUI來從定義的URL列表中顯示一些圖片(書從亞馬遜蓋),我已經能夠加載它們在面板成功,但是儘管如此,使用線程,GUI似乎等到所有的循環結束,然後所有的圖像立刻出現,我怎麼才能實現GUI來顯示每個圖像,因爲它們是在運行時獲取的。GUI基本上是凍結的,直到圖像被提取...謝謝!wxPython的線程顯示圖像,因爲它們加載

問題又是保證我得到的GUI顯示每個圖像,因爲他們被拉到,而不是一下子...

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

回答

2

也可以一次剝離所有線程,就像問題代碼示例中已經嘗試的那樣。原始代碼中的問題是由於處理位圖請求的時間延遲導致GUI被阻塞。

記住,位圖的順序將取決於螺紋精加工的順序(它是隨機的在這種情況下)在下面的樣本。

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

編輯:重寫了先產生空按鈕,然後儘快爲他們到達應用的位圖的例子。現在這是醜陋的,現在是時候重構一個更安全的映射按鈕到url比使用標籤的(錯誤)。

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

謝謝你,我正在學習很多東西。這就是我一直在尋找,因爲我請人給自己的排序進行一次牽強的結果.. –

+0

我與線程一起思考排隊,希望它會產生多個線程,然後隊列將採取訂單的照顧?不知道這是否會等同於您發佈的第一個答案。 –

+1

修改了代碼,以顯示如何首先生成按鈕並稍後應用位圖。 ''Queue''不會對你有所幫助,因爲在第一個例子中,線程將按順序處理,而不是同時處理。 – nepix32

1

已經允許自己改寫。重要的是獲得了__init__方法儘快(在啓動線程之前調用Show),並讓該線程asynchronuosly工作。您還一次啓動了所有線程,而此示例使用一個線程來獲取一個位圖。

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

真棒!這工作就像我想它,太感謝你了,因爲你可以告訴,我仍然在學習wxPython的,去了一下我的聯賽與線程等。 –

+0

可不可以這樣可能讓線程做多取和顯示物品在完成時被提取,而不是一次一個? –

+0

也可以這樣做,請參閱單獨的答案。 – nepix32

相關問題