In this tutorial, we will download a file by HTTP and display the downloading progress by progress bar. The final screenshot is like this:

Downloading File
To display the downloading progress, we need know file size and currently downloaded bytes size.
So how to get the size of file need download? If you're familiar with HTTP, it will go easy. When downloading a file, first client will send a HTTP request to server for the file URL, then the server will send back a HTTP response to client. If requested URL is valid, the response body will be the file content.In the response header, there's a field called "Content-Length", which is used to indicate size of the response body. Since response body here is the file content, so this "Content-Length" is what we're looking for.
First we need use urllib2.urlopen() to open an url, this method returns a response object. Chain method info().get_headers() of response object can fetch the response header.So we can get file size like this:
|
file_size = r.meta().get_headers(['Content-Length'])[0] |
And next, we need know how many bytes we have downloaded.
the read(n) method of response object will receive n bytes of data from server. Actually read() can be called with no parameter, then it will receive all data sent by server. But calling read() method like that will let urllib2 module to handle the whole transferring progress. we cannot know how many bytes have been downloaded until downloading is finished.
To get currently downloaded bytes size, we need download fixed size of bytes everytime and update the downloaded bytes size after that block of bytes are downloaded. Then continue downloading until all data is received. You got the idea? so lets implement it.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
import urllib2 import os u = urllib2.urlopen('http://ck.kolivas.org/apps/cgminer/3.3/cgminer-3.3.0-windows.zip') meta = u.info() file_size = int(meta.getheaders('Content-Length')[0]) # save downloaded file to TEMP directory f = open(os.path.join(os.environ['TEMP'], 'cgminer.zip'), 'wb') downloaded_bytes = 0 block_size = 1024*8 while True: buffer = u.read(block_size) if not buffer: break f.write(buffer) downloaded_bytes += block_size print downloaded_bytes f.close() |
Display Progress Bar
Now we need QProgressBar to display our downloading progress. set_value() method of QProgressBar is used to set value of progress bar. The default value range is 0-100. and you can modify them by using setMinimum() and setMaximum() of QProgressBar.
Following code will create a window and put a progress bar in it. a setProgress() method is provided to set the progress bar value, so the downloading thread can set progress bar value by calling this method.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
|
import os import sys from PySide.QtCore import * from PySide.QtGui import * class DownloadingWindow(QWidget): def __init__(self): QWidget.__init__(self) vbox = QVBoxLayout() label = QLabel('downloading..') label.setAlignment(Qt.AlignCenter) vbox.addWidget(label) self.progress_bar = QProgressBar() self.progress_bar.setAlignment(Qt.AlignCenter) vbox.addWidget(self.progress_bar) self.setLayout(vbox) self.setGeometry(300, 300, 300, 50) def setProgress(self, value): if value > 100: value = 100 self.progress_bar.setValue(value) def closeEvent(self, event): os._exit(0) if __name__ == '__main__': app = QApplication(sys.argv) w = DownloadingWindow() w.show() app.exec_() |
Integration
We will need put downloading part in a separate thread, otherwise it will block UI.
So here's the complete source code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
|
import threading import sys import urllib2 import os from PySide.QtCore import * from PySide.QtGui import * class DownloadThread(threading.Thread): def __init__(self, url, tmp_file_name, downloading_window): threading.Thread.__init__(self) self.url = url self.tmp_file_name = tmp_file_name self.downloading_window = downloading_window def run(self): u = urllib2.urlopen(self.url) meta = u.info() file_size = int(meta.getheaders('Content-Length')[0]) print file_size f = open(os.path.join(os.environ['TEMP'], self.tmp_file_name), 'wb') downloaded_bytes = 0 block_size = 1024*8 while True: buffer = u.read(block_size) if not buffer: break f.write(buffer) downloaded_bytes += block_size print downloaded_bytes self.downloading_window.setProgress(float(downloaded_bytes)/file_size*100) f.close() return class DownloadingWindow(QWidget): def __init__(self): QWidget.__init__(self) vbox = QVBoxLayout() label = QLabel('downloading..') label.setAlignment(Qt.AlignCenter) vbox.addWidget(label) self.progress_bar = QProgressBar() self.progress_bar.setAlignment(Qt.AlignCenter) vbox.addWidget(self.progress_bar) self.setLayout(vbox) self.setGeometry(300, 300, 300, 50) def setProgress(self, value): if value > 100: value = 100 self.progress_bar.setValue(value) def closeEvent(self, event): os._exit(0) app = QApplication(sys.argv) w = DownloadingWindow() w.show() DownloadThread('http://ck.kolivas.org/apps/cgminer/3.3/cgminer-3.3.0-windows.zip', 'cgminer.zip', w).start() app.exec_() |