添加列表小部件项目异步 Pyside

Adding list widget items async Pyside

我正在使用 gphoto2 拍摄照片,并希望在拍摄照片时将它们异步添加到列表小部件,但由于某种原因,它没有按预期工作。它在 QThread 上拍摄照片,但直到拍摄完所有照片(如批量添加)后才将照片添加到列表中。我该怎么做?

这里是相关的源代码(它不会编译,因为有太多的依赖关系不适合这个问题):

class DownloadThread(QThread):

    data_downloaded = Signal(object)

    def __init__(self, photo_name):
        QThread.__init__(self)
        self.photo_name = photo_name

    def run(self):
        image_location = capture_image.take_photo(self.photo_name)
        image = QImage(image_location)
        to_pixmap = QPixmap.fromImage(image).scaled(200, 200)
        to_qicon = QIcon(to_pixmap)

        self.data_downloaded.emit(QListWidgetItem(to_qicon, image_location))


class MainWindow(QMainWindow, Ui_MainWindow):

    def take_photo(self):
        import time
        for x in range(2):
            photo_name = str(x) +'.jpg'   
            downloader = DownloadThread(photo_name)
            downloader.data_downloaded.connect(self.on_photo_ready)
            downloader.start()
            time.sleep(5)

    def on_photo_ready(self, photo):
        print "WHY"
        self.listWidget.addItem(photo)

我在被调用的函数中有一些简单的打印语句,所以终端看起来像这样:

照片 照片 照片 照片 照片 照片 为什么 为什么 为什么 为什么 为什么 为什么

这意味着它会等待实际调用 emit 直到 for 循环完成,而不是按预期在它自己的线程上。任何帮助都是极好的!

有几个问题

1。您的主题实际上不是 运行ning

您需要调用 QThread.start() 才能实际 运行 QThread.run()。也就是说,您可能不想这样设计您的应用程序。没有理由创建几十个或数百个不同的线程——一个用于每个图像下载。如果创建一个工作线程来下载队列中的所有图像,效率会高得多。请参阅下面的示例。

2。您不能在辅助线程中创建 QPixmaps 或 GUI 项目

您不能在主线程外创建 QPixmap。您不能为此创建 QListWidgetItem 或任何 GUI 元素;它们只能在主线程中创建(并安全地操作)。您可以使用其他类似的元素(如 QImage),但实际上,您唯一需要传回主线程的是下载的文件路径;主线程可以处理 QPixmap 和项目创建。

class DownloadWorker(QObject):

    data_downloaded = Signal(object)

    @QtCore.Slot(str)
    def download_image(self, name):
        image_location = capture_image.take_photo(name)
        self.data_downloaded.emit(image_location)


class MainWindow(QMainWindow, Ui_MainWindow):

    request_download = QtCore.Signal(str)

    def __init__(self, ...)
        ...
        self.worker = DownloadWorker()
        self.thread = QThread(self)
        self.request_download.connect(self.worker.download_image)
        self.worker.data_downloaded.connect(self.on_photo_ready)
        self.worker.moveToThread(self.thread)
        self.thread.start()

        self.timer = QTimer(self)
        self.timer.timeout.connect(self.take_photo)
        self.timer.start(5000)

    def take_photo(self):
        import time
        photo_name = str(time.time()) +'.jpg'  
        self.request_download.emit(photo_name) 

    @QtCore.Slot(str)
    def on_photo_ready(self, filepath):
        item = QListWidgetItem(QIcon(filepath))
        self.listWidget.addItem(item)

您是在告诉主线程在辅助线程工作时休眠。这会将您的所有信号排队,以便它们立即到达。删除 time.sleep(5) 并更改

 downloader = ...

 self.downloader = ...

你应该没事。

也就是说,工人模型是一件好事。有关详细信息,请参阅 or