添加列表小部件项异步Pyside

时间:2016-05-17 18:13:17

标签: python qt pyqt 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)

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

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

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

2 个答案:

答案 0 :(得分:1)

有一些问题

1。你的线程实际上没有运行

您需要致电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)

答案 1 :(得分:1)

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

 downloader = ...

 self.downloader = ...

你应该没事。

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