abbruch, stop wert übergeben im QThread

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Ernie1412
User
Beiträge: 161
Registriert: Freitag 10. Januar 2020, 20:38

ich denke das Problem ist nicht PyQt spezifisch, daher poste ich es im Allgemeine Fragen:
ich hab folgenden Code:

Code: Alles auswählen

from PyQt5 import QtWidgets, uic, QtCore,QtGui
from PyQt5.QtCore import QThread, pyqtSignal
import sys
from pathlib import Path
import time
import shutil
import os

class FileTransferThread(QThread):
    updateProgress = pyqtSignal(int, float,int) # Signal für Fortschrittsanzeige und Geschwindigkeitsanzeige
    transferFinished = pyqtSignal(float) # Signal für Geschwindigkeitsanzeige
    def __init__(self, source_path, target_path,parent=None):
        super().__init__(parent)
        QThread.__init__(self)        
        self.source_path = source_path
        self.target_path = target_path
        self.is_running = False  
        self.abort = False   
        self.avg_speed = 0.0  # initialize avg_speed here

    def run(self):
        self.is_running = True
        buffer_size = 1024 * 1024 # 1MB buffer
        bytes_transferred = 0
        start_time = time.time()        

        with open(self.source_path, 'rb') as source_file:
            with open(self.target_path, 'wb') as target_file:
                while self.is_running:
                    buffer = source_file.read(buffer_size)
                    if not buffer:
                        break
                    target_file.write(buffer)
                    bytes_transferred += len(buffer)
                    elapsed_time = time.time() - start_time                
                    self.avg_speed = bytes_transferred/buffer_size / elapsed_time
                    remaining_time=int(os.path.getsize(self.source_path)/(1024*1024)/self.avg_speed-elapsed_time)
                    progress = bytes_transferred / os.path.getsize(self.source_path) * 100
                    self.updateProgress.emit(int(progress), self.avg_speed,remaining_time)
                    if self.abort:
                        break
        shutil.copystat(self.source_path, self.target_path)
        self.is_running = False
        self.transferFinished.emit(self.avg_speed)

    def stop(self):        
        self.is_running = False
        self.abort = True
        self.wait()
        self.transferFinished.emit(self.avg_speed)   

class Transfer_File(QtWidgets.QDialog):    
    def __init__(self):
        super(Transfer_File, self).__init__()       
        uic.loadUi(Path(__file__).absolute().parent / "ui/Transfer.ui",self)
        dir="D:\\Downloads"
        move_file="serie-xy.mp4"
        destination_path="X:\\Serienl\\XY\\staffel"
        self.lbl_speed.setText('Speed: 0 MB/s')
        self.movie = QtGui.QMovie(str(Path(__file__).absolute().parent / "grafics/transfer.gif"))
        self.label_gif_transfer.setMovie(self.movie)
        self.movie.start()        
        self.lbl_move_file.setText(move_file)                             
        self.lbl_Source_Folder.setText(dir) 
        self.lbl_Dest_Folder.setText(destination_path)
        self.prgBar_Transfer.setValue(0)        
        self.startTransfer(dir +"/"+ move_file,destination_path +"/"+ move_file)        
    
    def startTransfer(self,source_path,dest_path):                
        self.transferThread = FileTransferThread(source_path, dest_path)
        self.transferThread.updateProgress.connect(self.updateProgress)
        self.transferThread.finished.connect(self.transferFinished)        
        self.transferThread.start()

        self.btn_Stop.clicked.connect(self.transferThread.stop)
       
    def updateProgress(self, value,speed,remaining_time):
        self.btn_OK.setVisible(False)
        #self.Btn_OK.clicked.connect(self.Ordner_Transfer_Zurueck)
        #self.exec_()
        self.prgBar_Transfer.setValue(value) 
        minutes, seconds = divmod(remaining_time, 60)       
        self.lbl_speed.setText(f"{speed:.2f} MB/s - geschätze Zeit bis Ende: {minutes:02d}:{seconds:02d}s")

    def transferFinished(self,avg_speed):        
        self.btn_OK.setVisible(True)
        self.transferThread.quit()
        self.transferThread.wait()
        self.movie.stop()
        self.label_gif_transfer.setPixmap(QtGui.QPixmap(str(Path(__file__).absolute().parent / "grafics/transfer.png")))
        self.lbl_speed.setText(f"{avg_speed:.2f} MB/s - geschätzte Zeit bis zum Ende: 00:00s > FERTIG !!!")  

if __name__ == "__main__":
    app,QtWidgets.QDialog =(QtWidgets.QApplication(sys.argv),Transfer_File())      
    QtWidgets.QDialog.show()
    sys.exit(app.exec_())
ich bekomme nach Stop button click: TypeError: Transfer_File.transferFinished() missing 1 required positional argument: 'avg_speed'
wahrscheinlich kann er kein self übergeben, zumindest denke ich mir das.
sobald er an dieser Zeile "def transferFinished(self,avg_speed): " kommt und die Funtion aufrufen will, kommt der Fehler.
in der stop() Funktion ist ja self.transferFinished.emit(self.avg_speed) also mit übergabe von self.avg_speed und nicht mit avg_speed
allerdings so:

Code: Alles auswählen

def stop(self): 
        avg_speed=self.avg_speed       
        self.is_running = False
        self.abort = True
        self.wait()
        self.transferFinished.emit(avg_speed) 
gehts auch nicht.

ich hoffe einer weiss ein Rat :D
Ernie1412
User
Beiträge: 161
Registriert: Freitag 10. Januar 2020, 20:38

Ich habe festgestellt, das nur wenn self.is_running= true, kann man per emit(...) etwas übertragen. wenn false sind jeglichen Werte auf None bei der Übertragung. Ich versteh aber nicht warum
Benutzeravatar
__blackjack__
User
Beiträge: 13110
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Ein Fehler ist auf jeden Fall, das die `__init__()` von `QThread` zweimal aufgerufen wird und das das `parent`-Objekt von dem Objekt das Objekt selbst ist.

Anstatt `time.time()` verwendet man für so etwas `time.monotonic()`.

Das mit dem `is_running` und `abort` sieht redundant aus. Ob ein Thread läuft kann man schon vom Thread abrufen, und für's abbrechen gibt es auf `QThread` schon `requestInterruption()` und `isInterruptionRequested()`
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Ernie1412
User
Beiträge: 161
Registriert: Freitag 10. Januar 2020, 20:38

Anstatt `time.time()` verwendet man für so etwas `time.monotonic()`.
meinste ich ändere die Systemuhr jemals ? und dann wärend ich etwas kopiere ?
Das programm was ich schreibe ist rein für mich, Hobby.
Aber danke für den tip. Erklärung, bzw Unterschied hab ich dann selber gegooglet. :D
wenn ich das ausserhab der while Schleife mache , kann ich keine Emit(...) Daten weitergeben. Das geht nur in der While schleife, also ist es in dem Fall nicht "redudant". Man hätte auch sagen können überflüssig, doppeltgemoppelt. Aber natürlich redudant hört sich sehr schlau an.
und für's abbrechen gibt es auf `QThread` schon `requestInterruption()` und `isInterruptionRequested() <-- kannst du auch ein Beispiel geben wo dann auch .emit(...) werte übergeben kann ?
Ich denke, der hat keine Werte, weil nach finished (ende der while Schleife) der qthread gelöscht wird, ehe emit ausgeführt wird und deswegen die Werte in den emit(...) Null sind.
Benutzeravatar
sparrow
User
Beiträge: 4193
Registriert: Freitag 17. April 2009, 10:28

@Ernie1412: Meinst du, deine Uhrzeit läuft immer einheitlich? Auch während du kopierst? Zum Beispiel bei der Zeitumstellung? Nicht? Genau, deshalb verwendet man das Richtige und nicht das Falsche. Auch im Hobby. :D

Ich schlage mal vor, die Anmerkungen von __blackjack__ umzusetzen, gucken ob das Problem weg ist, und - falls das nicht so ist - den neuen Code zu posten.
Benutzeravatar
__blackjack__
User
Beiträge: 13110
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Noch was extrem schräges in dem Code: QtWidgets.QDialog wird ein neuer Wert zugewiesen.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
__deets__
User
Beiträge: 14540
Registriert: Mittwoch 14. Oktober 2015, 14:29

Na das der Fehler in Zeile

Code: Alles auswählen

        self.transferThread.finished.connect(self.transferFinished)        
steckt, ist ja nicht besonders schwer zu erkennen. Aber der neue beste Freund von Ernie, ChatGPT, hat das wohl noch nicht drauf, ihm das zu erklaeren. Da muss er dann doch auf die Leutz hier zurueckgreifen, die er an anderen Stelle ausgiebig als wenig hilfsbereit und abgehoben diffamiert. Oh, schwieriges wort. Beschimpft sollte ich wohl eher sagen, sonst hoere ich mich wieder zu schlau an....
Antworten