简体   繁体   中英

PySide2 use QProgressBar as signal argument

I am trying to solve a problem with PySide2, QThread and the Signal/Slot mechanism.

What I want to achieve is updating a specific progressbar which is passed as reference via signal/slot mechanism.

The problem is the call of self.gui_connection.signal_progress_value.emit(lambda: self.progressbar, value) in my ProgressBarThread class.

The program stops after emitting the signal with a QProgressBar and an int value as arguments and causes a Seg Fault. If I just pass an int value to the signal and call emit in my ProgressBarThread everything is working fine.

Is it just not possible to pass an Object via Signal/Slot mechanism?

(Reduced) Code Samples:

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

The problem is that the program stops after emitting the signal with a QProgressBar and a value as arguments and causes a Seg Fault. If I just pass an int value to the signal and call emit in my ProgressBarThread everything is working fine.

Is it just not possible to pass Object via Signal/Slot mechanism?

It is not necessary for the signal to send as QProgressBar dates, in addition to the GUI is not thread-safe, on the other hand it is not necessary to use a lambda.

Considering the above, the solution is:

class GUISignal(QObject):
    signal_progress_value = 
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)
            
            dest_size = self.size(self.destpath)
            time.sleep(2)
        else:
            
            print(100)
            return
    # ...
def handleIngestClicked(self, srcpath, destpath, progressbar):
    ingestManager = IngestManager()
    ingestManager.copy_to_destination(self, srcpath, destpath)
    
    progressThread.start()

Update:

In the previous part of my answer I separate the GUI from the business logic as this will have a more scalable SW. But the OP seems to not want that so the simple solution is not to use the lambda method since it is unnecessary:

self.gui_connection.signal_progress_value.emit(self.progressbar, value)
self.gui_connection.signal_progress_value.emit(self.progressbar, 100)

SOLVED: The problem was the lambda function in the emit function inside the QThread class. It seems like the object was not passed by the lambda function. Just using .emit(self,progressbar, 100) is working.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM