我有一个小GUI,在显示的图像上显示不同的层。在某种程度上,我希望将当前图像以及所有可视化层存储到磁盘,同时继续使用GUI。图像相当大(存储大约需要5秒钟),因此我想将保存的内容转移到后台线程中
我尝试了不同的方法,但没有一种有效。最简单的工作示例(仍然需要PNG进行测试,抱歉):
import sys
import threading
from PIL import Image
from PIL.ImageQt import ImageQt
from PyQt5.QtCore import QThread, pyqtSignal, QRunnable, QThreadPool
from PyQt5.QtGui import QPixmap
from PyQt5.QtWidgets import QMainWindow, QApplication, QLabel, QSizePolicy, QAction, QToolBar
class StorageQRunnable(QRunnable):
def __init__(self,
pixmap: QPixmap,
target_path: str):
super(StorageQRunnable, self).__init__()
self.pixmap = pixmap
self.target_path = target_path
def run(self):
print("Starting to write image in QRunnable.")
self.pixmap.save(self.target_path, "PNG")
print("Done writing image in QRunnable.")
class StorageQThread(QThread):
signal = pyqtSignal("PyQt_PyObject")
def __init__(self,
pixmap: QPixmap,
target_path: str):
super(StorageQThread, self).__init__()
self.pixmap = pixmap
self.target_path = target_path
def run(self):
print("Starting to write image in QThread.")
self.pixmap.save(self.target_path, "PNG")
print("Done writing image in QThread.")
self.signal.emit(0)
class StorageThread(threading.Thread):
def __init__(self,
pixmap: QPixmap,
target_path: str):
super(StorageThread, self).__init__()
self.pixmap = pixmap
self.target_path = target_path
def run(self):
print("Starting to write image in threading.Thread.")
self.pixmap.save(self.target_path, "PNG")
print("Done writing image in threading.Thread.")
class TrialWindow(QMainWindow):
def __init__(self, *args, **kwargs):
super(TrialWindow, self).__init__(*args, **kwargs)
self.imageLabel = QLabel()
self.imageLabel.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)
self.imageLabel.setScaledContents(True)
self.setCentralWidget(self.imageLabel)
toolbar = QToolBar("Controls")
toolbar.addAction(QAction("Do", self, shortcut="Ctrl+F", triggered=self.continue_in_foreground))
toolbar.addAction(QAction("To background", self, shortcut="Ctrl+B", triggered=self.to_background))
toolbar.addAction(QAction("Exit", self, shortcut="Ctrl+Q", triggered=self.close))
self.addToolBar(toolbar)
self.bg_task_started = False
def continue_in_foreground(self):
print("Doing.")
def thread_done(self, status: int):
if status == 0:
print(":)")
def to_background(self):
print("Background.")
if not self.bg_task_started:
# print("I Pushing threading.Thread to background.")
# StorageThread(pixmap=self.imageLabel.pixmap().copy(), target_path="/tmp/target1.png").start()
# print("II Pushing QThread to background.")
# self.w2 = StorageQThread(pixmap=self.imageLabel.pixmap().copy(), target_path="/tmp/target1.png")
# self.w2.signal.connect(self.thread_done)
# self.w2.start()
print("III Pushing QRunnable to background.")
r = StorageQRunnable(pixmap=pixmap.copy(), target_path="/tmp/target1.png")
QThreadPool.globalInstance().start(r)
self.bg_task_started = True
def visualize(self, pxmp: QPixmap):
self.imageLabel.setPixmap(pxmp)
if __name__ == '__main__':
app = QApplication(sys.argv)
window = TrialWindow()
# load pixmap
img = Image.open("/tmp/sample.png")
image = ImageQt(img)
pixmap = QPixmap.fromImage(image)
window.show()
window.visualize(pixmap)
sys.exit(app.exec_())
简短手册:
请随意使用不同的方法进行评论,即使用threading.Thread
、使用QThread
或使用QRunnable
,所有这些都会产生相同的结果:将pixmap存储为PNG(实际上应该发生在后台线程中)会阻塞GUI
问题与线程无关,但QPixmap不是线程安全的,不应从另一个线程进行操作,正如the docs指出的:
相反,您应该使用为I/O操作优化的QImage,正如the docs所指出的:
因此,解决方案是:
代码:
相关问题 更多 >
编程相关推荐