Gui is trotz QThread halb geblockt

Python und das Qt-Toolkit, erstellen von GUIs mittels des Qt-Designers.
Antworten
Hellstorm
User
Beiträge: 231
Registriert: Samstag 22. Juni 2013, 15:01

Hallo,

ich habe mir eine Klasse geschrieben, die einen Hochladevorgang simuliert. Damit die Gui nicht geblockt wird, habe ich einen QThread subclassed (wie sagt man das auf Deutsch? :D) und kommuniziere mit Signalen, um z.B. eine QProgressBar zu aktualisieren. Das klappt auch soweit ganz gut, allerdings mit dem Problem, dass ich in der Gui selber nichts berühren kann. Also die QProgressBar wird aktualisiert, aber ich kann währenddessen nichts anderes anklicken.

Code: Alles auswählen

class MockUpload(QtCore.QThread):
    """
    A QThread which will sequentially “upload” the files in the list.
    Accepts a list of dictionaries with the file data (Generated by the
    FileTableModel.file_data).


    Signals:

    file_upload_status(int, int)
    Emitted every time a new “step” is completed. Emits the file index and
    the transferred bytes for the current file.

    file_upload_completed(int)
    Emitted when a single file upload is completed. Emits the file index.

    finished()
    Emitted when the entire thread is completed.
    """

    file_upload_status = QtCore.pyqtSignal(int, int)  # File number, transferred bytes
    file_upload_completed = QtCore.pyqtSignal(int)  # File number

    def __init__(self, file_data):
        """
        Receives a list of dictionaries with the files to upload.
        """
        QtCore.QThread.__init__(self)

        self.files_data = file_data

        #For mock upload:
        self.steps = 10

    def run(self):
        for file_number, file_data in enumerate(self.files_data):
            self.mock_upload(file_number)

    def mock_upload(self, file_number):
        transferred = 0
        print("Starting mock upload of {}, taking {} steps.".format(
            self.files_data[file_number]["file_path"],
            self.steps))
        for i in range(self.steps):
            transferred += int(self.files_data[file_number]["file_size"] / self.steps)
            print("Transferred {} Bytes".format(transferred))
            self.file_upload_status.emit(file_number, transferred)
            time.sleep(1)
        self.file_upload_completed.emit(file_number)
        print("Completed upload of {}.".format(self.files_data[file_number]["file_path"]))
Das Objekt erstelle ich im MainWindow folgendermaßen:

Code: Alles auswählen

    def onUpload(self):
        """
        Slot for the upload button.
        """
        #TODO: Button should be disabled if model has no files.

        if self.files_model.has_files:
            self.overallProgress.setMaximum(self.files_model.overall_size)

            self.upload = MockUpload(self.files_model.file_data)
            self.upload.file_upload_status.connect(self._update_progress)
            self.upload.file_upload_completed.connect(self._set_completed)

            self.upload.run()
Hat jemand eine Idee, woran das wohl liegen könnte? Danke!
BlackJack

@Hellstorm: Du rufst `run()` selber direkt auf, damit wird kein Thread gestartet. Versuch's mal mit `start()`. :-)
Hellstorm
User
Beiträge: 231
Registriert: Samstag 22. Juni 2013, 15:01

Wow, tatsächlich, so einfach ist es :D Jetzt klappt es perfekt. Danke!

Ich hatte das früher bei meinen Threading-Versuchen schon einmal richtig gemacht, aber wohl jetzt wieder vergessen. Wieso implementiert man eigentlich run() aber führt dann start() aus? Gibt es da einen Grund für?
BlackJack

@Hellstorm: Weil bei `start()` die ”Magie” passiert dass da ein neuer Thread startet in dem dann die `run()`-Methode läuft.
Antworten