【问题标题】:signal with QThread in PyQt在 PyQt 中使用 QThread 发出信号
【发布时间】:2021-12-17 23:23:33
【问题描述】:

我有一个程序需要在 windows 中测量用户配置文件的大小。

我做了一个QObject类来测量大小:

class TailleRep(QObject):
    size_ready = pyqtSignal(int)

    def __init__(self, repertoire):
        super(TailleRep, self).__init__()
        self.repertoire = repertoire

    def work(self):
        size = self.getFolderSize(self.repertoire)
        print(size)
        self.size_ready.emit(size)

    def getFolderSize(self, folder_path):
        start_path = Path(os.path.join(folder_path, '.'))
        return sum(f.stat().st_size for f in start_path.glob('**/*') if f.is_file())

在控制台打印的size结果是正确的,但是我在ui中使用这个就不一样了:

import sys
import os

from PyQt5.QtCore import Qt, QObject, pyqtSignal, QThread
from PyQt5.QtWidgets import QApplication, QLabel, QMainWindow, \
    QPushButton, QVBoxLayout, QWidget
from pathlib import Path

class Window(QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setupUi()

    def setupUi(self):
        self.resize(300, 80)
        self.centralWidget = QWidget()
        self.setCentralWidget(self.centralWidget)
        self.sizeLabel = QLabel("Size: ---", self)
        self.sizeLabel.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter)
        self.getSizeBtn = QPushButton("Get size", self)
        self.getSizeBtn.clicked.connect(self.GetSize)
        layout = QVBoxLayout()
        layout.addWidget(self.sizeLabel)
        layout.addWidget(self.getSizeBtn)
        layout.addStretch()
        self.centralWidget.setLayout(layout)

    def GetSize(self):
        self.getSizeBtn.setEnabled(False)
        self.thread = QThread()
        self.worker = TailleRep(os.getenv('USERPROFILE'))
        self.worker.moveToThread(self.thread)
        self.thread.started.connect(self.worker.work)  
        self.worker.size_ready.connect(self.size_ready)
        self.thread.start()

    def size_ready(self, size):
        self.sizeLabel.setText("Size: {}".format(size))
        self.getSizeBtn.setEnabled(True)

app = QApplication(sys.argv)
win = Window()
win.show()
sys.exit(app.exec())

你能告诉我我的错误在哪里吗?

【问题讨论】:

  • 控制台打印什么值,GUI显示什么值?
  • 实际上我在控制台中有 13345396442(来自 TailleRep 类中的打印)和 GUI 中有 460494554。

标签: python multithreading pyqt pyqt5


【解决方案1】:

问题似乎是一个 PyQt5 的 bug,它将 python 整数转换为 C++ 整数,而后者的最大值为 2147483647,导致溢出,因为大小大于该值。一个可能的解决方案是创建一个以整数作为字段的python类,以便传递python对象并且不进行转换。

from dataclasses import dataclass


@dataclass
class Data:
    size: int
class TailleRep(QObject):
    size_ready = pyqtSignal(Data)

    # ...

    def work(self):
        ize = self.getFolderSize(self.repertoire)
        print(size)
        data = Data(size=size)
        self.size_ready.emit(data)
    def size_ready(self, data):
        size = data.size
        self.sizeLabel.setText("Size: {}".format(size))
        self.getSizeBtn.setEnabled(True)

【讨论】:

  • 另一种选择:将类型设置为object 而不是int 也会强制PyQt 传输python 对象并避免C++ 转换:size_ready = pyqtSignal(object)
猜你喜欢
  • 1970-01-01
  • 2014-03-10
  • 2020-11-17
  • 1970-01-01
  • 2022-10-04
  • 1970-01-01
  • 2017-10-13
  • 2015-11-30
  • 1970-01-01
相关资源
最近更新 更多