Skip to main content
 首页 » 编程设计

python之更新 wx.Gauge 并使当前帧保持事件状态

2025年05月04日10dudu

我正在编写一个小工具,使用 python 和 wxpython 从网站下载文件。

一切正常,唯一困扰我的是我想使用进度条来显示完成,在 urlretrieve 之后,唯一移动的是进度条,GUI 变得没有响应。我知道这与线程有关,但我真的很陌生。有人可以给我提示吗?

这个想法是在主框架上,我从一个站点获取搜索结果,并将结果提供给此 DownloadListingFrame,然后它会动态生成按钮和 staticText。问题是单击下载按钮后,进度条会随着文件的下载而更新,但除此之外整个应用程序都会挂起。在从其他示例中阅读了其他人的代码后,我认为我将 doDownload 函数放在一个线程中并执行它,它的行为与未使用线程相同...

class DownloadListingFrame ( wx.Frame ): 
 
    data = '' 
 
    def __init__( self, parent, result ): 
        wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = u'result', pos = wx.DefaultPosition, size = wx.Size( 500,300 ), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL ) 
        self.SetSizeHintsSz( wx.DefaultSize, wx.DefaultSize ) 
 
        self.statusbar = self.CreateStatusBar() 
        self.statusbar.SetFieldsCount(3) 
 
        self.progessBar = wx.Gauge(self.statusbar, -1, style=wx.GA_HORIZONTAL|wx.GA_SMOOTH) 
        rect = self.statusbar.GetFieldRect(1) 
        self.progessBar.SetPosition((rect.x+2, rect.y+2 )) 
        self.progessBar.SetSize((rect.width, rect.height-4)) 
 
        buttonPos = 20 
        for item in result: 
            label = wx.StaticText( self, wx.ID_ANY, item, wx.Point( 120 ,buttonPos+2 ), wx.DefaultSize, 0 ) 
            button = wx.Button(self, id=-1,label=u'Download', pos=(20, buttonPos)) 
            buttonPos = buttonPos + 30 
            self.Bind(wx.EVT_BUTTON, lambda x: self.Downloader(item, result[item]), button) 
 
        self.Centre( wx.BOTH ) 
 
 
    def progressUpdate(self, blockCount, blockSize, totalSize): 
        progressSoFar = int((float(blockCount) * float(blockSize) / float(totalSize)) * 100) 
        self.progessBar.SetValue(progressSoFar) 
 
    def doDownloade(self, realAddress, saveAsFilename): 
        urllib.urlretrieve(realAddress, saveAsFilename, self.progressUpdate) 
 
    def Downloader(self, title, url): 
        saveAsPath = wx.DirDialog(self, u"save to...") 
        if saveAsPath.ShowModal() == wx.ID_OK: 
            realAddress = self.getRealAddress(url) 
            saveAsFilename = os.path.join(saveAsPath.GetPath(), title + os.path.splitext(realAddress)[1]) 
            thread = threading.Thread(target=self.doDownloade(realAddress, saveAsFilename)) 
            thread.setDaemon(True) 
            thread.start() 
 
    def getRealAddress(self, url): 
        import httplib 
        siteUrl = 'www.yyets.com' 
        httpConnection = httplib.HTTPConnection(siteUrl) 
        httpConnection.request("GET", url) 
        resp = httpConnection.getresponse() 
        realAddress = resp.getheaders()[6][1] 
        return realAddress 
 
    def __del__( self ): 
        pass 

请您参考如下方法:

当你运行命令时:

thread = threading.Thread(target=self.doDownloade(realAddress, saveAsFilename)) 

它首先运行 self.doDownloade(realAddress, saveAsFilename) 然后将其返回值(将为 None)作为目标传递。

相反,你想要:

thread = threading.Thread(target=self.doDownloade, args=(realAddress, saveAsFilename)) 

注意,这里,我传入了function self.doDownloade,然后thread会调用这个函数,你当你调用 thread.start 时给它。

顺便说一句,您也可以使用 wx.Timer 来完成此操作。我通常发现这是更好的仪表工具,因为它更容易,而且您可以控制仪表更新的频率,因此可以控制仪表使用了多少资源。主要的 wxPython 演示的仪表示例使用 wx.Timer 是你想要一个好的起点。