我正在使用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循环完成,而不是按预期在自己的线程上。任何帮助都是极好的!
答案 0 :(得分:1)
有一些问题
您需要致电QThread.start()
以实际运行QThread.run()
。话虽这么说,你可能不想像这样设计你的应用程序。没有理由创建数十个或数百个不同的线程 - 每个图像下载一个。创建一个下载队列中所有图像的工作线程会更有效。请参阅下面的示例。
您无法在主线程外创建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 question或this one。