PySide2 использует QProgressBar в качестве аргумента сигнала - PullRequest
0 голосов
/ 21 февраля 2020

Я пытаюсь решить проблему с PySide2, QThread и механизмом Signal / Slot.

Чего я хочу добиться, так это обновления указанного c индикатора выполнения, который передается в качестве эталона через механизм сигнала / слота .

Проблема заключается в вызове self.gui_connection.signal_progress_value.emit(lambda: self.progressbar, value) в моем классе ProgressBarThread.

Программа останавливается после выдачи сигнала с аргументом QProgressBar и значением int в качестве аргументов и вызывает ошибку сегмента. Если я просто передаю значение int в сигнал и вызываю emit в моем ProgressBarThread, все работает нормально.

Разве невозможно передать объект через механизм сигнала / слота?

(Сокращено ) Примеры кода:

GUISignal.py

from PySide2.QtCore import QObject, Signal
from PySide2.QtWidgets import QProgressBar

class GUISignal(QObject):
    signal_progress_value = Signal(QProgressBar, int)

main.py

# File: main.py
import sys
from PySide2.QtUiTools import QUiLoader
from PySide2.QtWidgets import QApplication, QPushButton
from PySide2.QtCore import QFile
from config.configManager import ConfigManager
from layout.srcConfigLayout import SrcConfigLayout
from layout.ingestLayout import IngestLayout

if __name__ == "__main__":
    app = QApplication(sys.argv)

    ui_file = QFile("main_window.ui")
    ui_file.open(QFile.ReadOnly)

    loader = QUiLoader()
    window = loader.load(ui_file)
    ui_file.close()
    window.show()

    src_config_layout = SrcConfigLayout(window)
    ingestLayout = IngestLayout(window)
    src_config_layout.load_config()
    ingestLayout.load_config()

    sys.exit(app.exec_())

ingestLayout.py

from PySide2.QtWidgets import QTableWidget, QTableWidgetItem, QPushButton, QProgressBar
from PySide2.QtCore import QObject, Slot

from util.ingestManager import IngestManager
from config.configManager import ConfigManager
from util.progressBarThread import ProgressBarThread

from functools import partial

class IngestLayout(QObject):    

    def __init__(self, parent):
        super().__init__()
        self.parent = parent

    def handleIngestClicked(self, srcpath, destpath, progressbar):
        ingestManager = IngestManager()
        ingestManager.copy_to_destination(self, srcpath, destpath)
        progressThread = ProgressBarThread(srcpath, destpath, progressbar, self.parent)
        progressThread.gui_connection.signal_progress_value.connect(self.updateProgressbar)
        progressThread.start()

    @Slot(QProgressBar, int)
    def updateProgressbar(self, progressbar: QProgressBar, value: int):
        pass
        # progressbar.setValue(value)

progressBarThread.py

from PySide2.QtCore import QThread
import os
import threading
import time
from signals.GUISignal import GUISignal

class ProgressBarThread(QThread):
    def __init__(self, srcpath, destpath, progressbar, parent):
        super(ProgressBarThread, self).__init__(parent)
        self.gui_connection = GUISignal()
        self.srcpath = srcpath
        self.destpath = destpath
        self.src_size = self.size(srcpath)
        self.progressbar = progressbar

    def run(self):
        self.periodically_compare_folder_size()

    def periodically_compare_folder_size(self):
        dest_size = self.size(self.destpath)
        while self.src_size > dest_size:
            value = self.calc_progress(self.src_size, dest_size)
            self.gui_connection.signal_progress_value.emit(lambda: self.progressbar, value)
            dest_size = self.size(self.destpath)
            time.sleep(2)
        else:
            self.gui_connection.signal_progress_value.emit(lambda: self.progressbar, 100)
            print(100)
            return

    def size(self, path, *, follow_symlinks=False):
        try:
            with os.scandir(path) as it:
                return sum(self.size(entry, follow_symlinks=follow_symlinks) for entry in it)
        except NotADirectoryError:
            return os.stat(path, follow_symlinks=follow_symlinks).st_size

    def calc_progress(self, src_size, dest_size):
        return dest_size / src_size * 100

Проблема заключается в том, что программа останавливается после выдачи сигнала с QProgressBar и значением в качестве аргументов и вызывает ошибку сегмента. Если я просто передаю значение int в сигнал и вызываю emit в моем ProgressBarThread, все работает нормально.

Разве просто невозможно передать объект через механизм сигнала / слота?

Ответы [ 2 ]

3 голосов
/ 21 февраля 2020

Нет необходимости отправлять сигнал как даты QProgressBar, кроме того, что GUI не является потокобезопасным, с другой стороны, нет необходимости использовать лямбду.

Учитывая выше, решение:

class GUISignal(QObject):
    signal_progress_value = <b>Signal(int)</b>
class ProgressBarThread(QThread):
    def __init__(self, srcpath, destpath, parent):
        super(ProgressBarThread, self).__init__(parent)
        self.gui_connection = GUISignal()
        self.srcpath = srcpath
        self.destpath = destpath
        self.src_size = self.size(srcpath)

    def run(self):
        self.periodically_compare_folder_size()

    def periodically_compare_folder_size(self):
        dest_size = self.size(self.destpath)
        while self.src_size > dest_size:
            value = self.calc_progress(self.src_size, dest_size)
            <b>self.gui_connection.signal_progress_value.emit(value)</b>
            dest_size = self.size(self.destpath)
            time.sleep(2)
        else:
            <b>self.gui_connection.signal_progress_value.emit(100)</b>
            print(100)
            return
    # ...
def handleIngestClicked(self, srcpath, destpath, progressbar):
    ingestManager = IngestManager()
    ingestManager.copy_to_destination(self, srcpath, destpath)
    <b>progressThread = ProgressBarThread(srcpath, destpath, self.parent)
    progressThread.gui_connection.signal_progress_value.connect(progressbar.setValue)</b>
    progressThread.start()

Обновление:

В предыдущей части моего ответа я отделяю GUI от бизнес логики c, так как это будет иметь более масштабируемое ПО. Но ОП, похоже, не хочет этого, поэтому простое решение состоит в том, чтобы не использовать лямбда-метод, поскольку он не нужен:

self.gui_connection.signal_progress_value.emit(self.progressbar, value)
self.gui_connection.signal_progress_value.emit(self.progressbar, 100)
0 голосов
/ 24 февраля 2020

решено: проблема была в лямбда-функции в функции emit внутри класса QThread. Кажется, что объект не был передан лямбда-функцией. Просто с помощью .emit(self,progressbar, 100) is working.

...