1 回答
TA贡献2080条经验 获得超4个赞
该问题与线程无关,但 QPixmap 不是线程安全的,不应像文档指出的那样从另一个线程进行操作:
GUI线程和工作线程
如前所述,每个程序在启动时都有一个线程。该线程称为“主线程”(在 Qt 应用程序中也称为“GUI 线程”)。Qt GUI 必须在这个线程中运行。所有小部件和几个相关的类,例如 QPixmap,都不能在辅助线程中工作。辅助线程通常被称为“工作线程”,因为它用于从主线程卸载处理工作。
相反,您应该使用为 I/O 操作优化的 QImage,正如文档指出的那样:
Qt 提供了四个类来处理图像数据:QImage、QPixmap、QBitmap 和 QPicture。QImage 是为 I/O 和直接像素访问和操作而设计和优化的,而 QPixmap 是为在屏幕上显示图像而设计和优化的。QBitmap只是一个继承QPixmap的便利类,保证深度为1。如果QPixmap对象真的是位图,isQBitmap()函数返回true,否则返回false。最后,QPicture 类是一个绘制设备,用于记录和重放 QPainter 命令。
所以解决方案是:
self.imageLabel.pixmap().toImage()
代码:
import sys
import threading
from PyQt5 import QtCore, QtGui, QtWidgets
class SaveWorker(QtCore.QObject):
started = QtCore.pyqtSignal()
finished = QtCore.pyqtSignal()
def save(self, image, path):
threading.Thread(target=self._save, args=(image, path,), daemon=True).start()
def _save(self, image, path):
self.started.emit()
image.save(path, "PNG")
self.finished.emit()
class TrialWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(TrialWindow, self).__init__(parent)
self.imageLabel = QtWidgets.QLabel()
self.imageLabel.setSizePolicy(
QtWidgets.QSizePolicy.Ignored, QtWidgets.QSizePolicy.Ignored
)
self.imageLabel.setScaledContents(True)
self.setCentralWidget(self.imageLabel)
toolbar = QtWidgets.QToolBar("Controls")
toolbar.addAction(
QtWidgets.QAction(
"Do", self, shortcut="Ctrl+F", triggered=self.continue_in_foreground
)
)
toolbar.addAction(
QtWidgets.QAction(
"To background", self, shortcut="Ctrl+B", triggered=self.to_background
)
)
toolbar.addAction(
QtWidgets.QAction("Exit", self, shortcut="Ctrl+Q", triggered=self.close)
)
self.addToolBar(toolbar)
self.worker = SaveWorker()
self.worker.started.connect(self.on_started)
self.worker.finished.connect(self.on_finished)
def visualize(self, pxmp: QtGui.QPixmap):
self.imageLabel.setPixmap(pxmp)
@QtCore.pyqtSlot()
def continue_in_foreground(self):
print("Doing.")
@QtCore.pyqtSlot()
def on_started(self):
print("started")
@QtCore.pyqtSlot()
def on_finished(self):
print("finished")
@QtCore.pyqtSlot()
def to_background(self):
self.worker.save(self.imageLabel.pixmap().toImage(), "/tmp/target1.png")
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
# load pixmap
pixmap = QtGui.QPixmap("/tmp/sample.png")
window = TrialWindow()
window.show()
window.visualize(pixmap)
sys.exit(app.exec_())
添加回答
举报