Threading für Anfänger
@BlackJack: Ein Blick in meinem Beitrag, und du siehst, dass alles behoben wurde. Das mit dem i habe ich bereits selbst gefunden. Und ich habe die Funktion on_progress hinzugefügt. Also on_start startet den Thread und in on_progress erwarte ich, dass der Prozessbalken sich entsprechend aktualisiert. Tut er aber nicht.
Ich weiß zwar nicht ob ich die Lösung korrekt gefunden habe, aber der Prozessbalken bewegt sich jetzt:
Ich habe hier Zeile 17 und 18 auskommentiert, und schon macht der Balken was er soll. Aber wie gesagt, ob es nun korrekt ist? Ich bin mir deswegen nicht sicher, weil BlackJack und Sirius3 die ganze Zeit von anderen Problemen sprachen.
Code: Alles auswählen
import os
import requests
import sys
from PyQt4.QtCore import QThread, pyqtSignal, Qt
from PyQt4.QtGui import QVBoxLayout, QPushButton, QDialog, QProgressBar, QApplication
class MyCustomDialog(QDialog):
def __init__(self, parent=None):
super(MyCustomDialog, self).__init__(parent)
layout = QVBoxLayout(self)
# Create a progress bar and a button and add them to the main layout
self.progressBar = QProgressBar(self)
self.progressBar.setAlignment(Qt.AlignCenter)
#self.progressBar.setValue(0)
#self.progressBar.setRange(0, 1)
layout.addWidget(self.progressBar)
button = QPushButton("Start", self)
layout.addWidget(button)
button.clicked.connect(self.check_folder_exists)
# Set data for download and saving in path
self.location = os.path.abspath(os.path.join('temp', 'example-app-0.3.win32.zip'))
self.url = 'http://sophus.bplaced.net/download/example-app-0.3.win32.zip'
self.download_task = Download_Thread(self.location, self.url)
self.download_task.notify_progress.connect(self.on_progress)
def on_progress(self, i):
self.progressBar.setValue(i)
def on_start(self):
self.download_task.start()
def check_folder_exists(self):
location = os.path.abspath(os.path.join('temp'))
if not os.path.exists(location):
os.makedirs(location)
print "Folder was created"
self.on_start()
else:
print "Folder already exists"
self.on_start()
def onFinished(self):
# Stop the pulsation
self.progressBar.setRange(0, 1)
class Download_Thread(QThread):
finished_thread = pyqtSignal()
notify_progress = pyqtSignal(int)
def __init__(self, loc, link):
QThread.__init__(self)
self.url = link
self.location = loc
def run(self):
print self.url
print self.location
file = requests.get(self.url, stream=True)
file_size = int(requests.head(self.url).headers.get('content-length', [0]))
chunk_size = (10000)
downloaded_bytes = 0
block_size = 1024*8
with open(self.location, 'wb') as fd:
for chunk in file.iter_content(chunk_size):
fd.write(chunk)
downloaded_bytes += block_size
print (float(downloaded_bytes)/file_size*100)
self.notify_progress.emit(float(downloaded_bytes)/file_size*100)
print "Finish"
self.finished_thread.emit()
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MyCustomDialog()
window.resize(600, 400)
window.show()
sys.exit(app.exec_())
@Sophus: Was soll sich denn bei den Werten 0 und 1 auch grossartig bewegen‽ Gibt ja nur zwei mögliche Werte, 0 (der Balken ist ”leer”) und 1 (der Balken ist 100% ”voll”).
@BlackJack: Ach, das meintest du vorhin mit Werte? Aber ich habe ein weiteres Problem. Eher ein mathematisches Problem. Wie kriege ich das korrekt auf dem Balken angezeigt, sprich, die herunterzuladende Datei ist sagen wir mal 65 MB groß. Bei meinem Beispiel hält mein Programm immer bei 81 Prozent an. Das heißt, die Datei ist komplett heruntergeladen, und der Prozessbalken müssten dann auch 100 Prozent anzeigen und nicht 81 Prozent?Hättest du da eine Idee?
@Sophus: Ich würde ”mathematisch” gar nichts (selber) machen. Man kann den Wertebereich für den Balken ja beliebig setzen. Zum Beispiel auch auf 0 und die Dateigrösse in Bytes. Und dann als aktuellen Wert einfach die aktuelle Anzahl von Bytes setzen.
@Sophus: Es ist schlicht falsch was Du da als aktuelle Byteanzahl ermittelst. Wenn die Balkenanzeige nicht stimmt wäre dass doch das erste was mal mal *selber* überprüft: Ob die Werte die man da setzt überhaupt stimmen.
@Sophus: Na die stimmen halt nicht. Wie zwei Zahlen halt nicht übereinstimmen können. Die sind nicht gleich. Also sind sie ungleich. Weil der Code nicht das aufaddiert was empfangen/gespeichert wurde. Aber so wirklich *gar nicht*.
@BlackJack: Redest du gern in Rätseln? Viel geschrieben, wenig gesagt.
Nun, ich habe mal geschaut, und zwar:
Ausgabe
Nun, ich habe mal geschaut, und zwar:
Code: Alles auswählen
file_size = int(requests.head(self.url).headers.get('content-length', [0]))
print "%s Byte" %file_size
Die Datei ist also 62,2 MB groß. Und nun nochmal, was soll daran nicht stimmen?65250090 Byte
@Sophus: Daran ist nichts falsch. Da wird auch nichts falsches aufaddiert. Da wird nämlich gar nichts addiert. Du hast da aber Code bei dem wird aufaddiert. Und zwar was völlig falsches. Und *das* ist auch der *Wert* der beim Fortschrittsbalken *gesetzt* wird. `file_size` dagegen wird *nicht* als *Wert* beim Fortschrittsbalken *gesetzt*. Ich spreche nicht in Rätseln sondern in Deutsch und IMHO ziemlich eindeutig. Das liegt hier am Empfänger und nicht am Sender.
@BlackJack: Wie mal mein alter Latein-Lehrer so schön sagte, wenn die Schüler nichts verstehen, dann hat der Lehrer es nicht richtig erklärt.Weise Worte Es wäre also sehr kurzsichtig alles auf den Empfänger zu schieben. Aber egal. Kommen wir zurück zum Code. Ich habe die ganze Zeit die chunk-Größe missachtet, weil ich davon ausging, dass ich diese Größe nur brauche, damit Python weiß, in welchen Häppchen er die Bytes laden soll, damit der Arbeitsspeicher nicht in einem Rutsch vollgestopft wird. Also habe ich mir gedacht, nimmst du die Chunks dafür:
Ich denke mal, mit deinem Rätsel meintest du es so? Für mein Verständnis habe ich deshalb die Chunks-Größen genommen, weil die Bytes-Häppchen solange geladen werden, bis die Datei vollständig ist. Wenn du das nicht meinst, dann bin ich etwas überfragt.
Code: Alles auswählen
chunk_size = (8127)
downloaded_bytes = 0
with open(self.location, 'wb') as fd:
for chunk in file.iter_content(chunk_size):
fd.write(chunk)
downloaded_bytes += chunk_size
print (float(downloaded_bytes)/file_size*100)
self.notify_progress.emit(float(downloaded_bytes)/file_size*100)
@Sophus: Ja das liegt wahrscheinlich an mir das Du ziemlich gezielt nichts oder etwas falsch verstehst…
Ich verstehe immer noch nicht wie man auf die Idee kommen kann das wenn man bei einer Methode `chunk_size` angibt, erwarten kann das in jedem Schleifendurchlauf `block_size` Bytes gelesen wurden, wobei `block_size` ansonsten nirgends benutzt oder bekannt gemacht wird. Das ist wohl einfach so ein supermagischer Name. Oder Python ist eine Sprache die nicht das macht was man schreibt sondern das was man meint. Also eine die Gedanken lesen kann…
Fehlerfrei ist das immer noch nicht. Was Dir eigentlich bei Deiner Testdatei hätte auffallen müssen. Oder mit ein bisschen Nachdenken…
Ich verstehe immer noch nicht wie man auf die Idee kommen kann das wenn man bei einer Methode `chunk_size` angibt, erwarten kann das in jedem Schleifendurchlauf `block_size` Bytes gelesen wurden, wobei `block_size` ansonsten nirgends benutzt oder bekannt gemacht wird. Das ist wohl einfach so ein supermagischer Name. Oder Python ist eine Sprache die nicht das macht was man schreibt sondern das was man meint. Also eine die Gedanken lesen kann…
Fehlerfrei ist das immer noch nicht. Was Dir eigentlich bei Deiner Testdatei hätte auffallen müssen. Oder mit ein bisschen Nachdenken…
- Hyperion
- Moderator
- Beiträge: 7478
- Registriert: Freitag 4. August 2006, 14:56
- Wohnort: Hamburg
- Kontaktdaten:
Wieso "zu spät"? Das Beispiel rennt ja nicht wegSophus hat geschrieben:Hallo Hyperion und BlackJack, danke für die Hinweise, und für das beste Beispiel der Welt, Hyperion. Aber ich habe zu spät bemerkt, dass du mir ein Beispiel präsentierst, ...
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
assert encoding_kapiert
@Sophus: wenn Du Dir diese beiden Zeilen anschaust:
was ist da das naheliegendste, die Bytes, die gerade heruntergeladen wurden, zu ermitteln?
Code: Alles auswählen
fd.write(chunk)
downloaded_bytes += chunk_size
@Sirius3: Meinst du etwa 'chunk'? Sprichst du hier das Problem an, was BlackJack meinte, von wegen nicht "Fehlerfrei"? Aber was spricht dagegen die chunk_size zu verwenden? Ich meine, die Häppchen werden ja solange heruntergeladen, bis die Datei komplett ist, also 100%. Und der Prozessbalken verhält sich auch "korrekt".
EDIT:
Ich habe mich mit dem 'chunk' auseinandergesetzt, udn wie zu vermuten war, hatte es auch nicht geklappt. Hier die beiden Versionen:
Version 1
Hier dachte ich, könnte man die heruntergeladenen Bytes (chunk) zu den downloaded_bytes hinzuaddieren. Klappt aber nicht.
Version 2
Hier wollte ich nicht addieren, sondern die 'chunks' direkt benutzen.
Beide Versionen funktionieren nicht.
EDIT:
Ich habe mich mit dem 'chunk' auseinandergesetzt, udn wie zu vermuten war, hatte es auch nicht geklappt. Hier die beiden Versionen:
Version 1
Code: Alles auswählen
with open(self.location, 'wb') as fd:
for chunk in file.iter_content(chunk_size):
fd.write(chunk)
downloaded_bytes += chunk
print (float(downloaded_bytes)/file_size*100)
self.notify_progress.emit(float(downloaded_bytes)/file_size*100)
Version 2
Code: Alles auswählen
with open(self.location, 'wb') as fd:
for chunk in file.iter_content(chunk_size):
fd.write(chunk)
self.notify_progress_emit(chunk)
Beide Versionen funktionieren nicht.