Qt GUI的背景线程

问题描述 投票:0回答:1

我有一个小的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_())

简短手册:

  • 开始
  • Ctrl + F查看GUI线程的控制台输出(一次或多次)
  • Ctrl + B开始在后台线程中存储大PNG
  • 继续按Ctrl + F,直到存储图像并且之后仅处理所有事件(GUI无法使用)之后,什么也没发生]
  • 通过Ctrl]退出> + Q
  • [随意发表评论,即threading.Thread的使用,QThread的使用或QRunnable的使用,所有结果都是相同的:将像素图存储为PNG(实际上应该在一个后台线程)阻止了GUI。

我有一个小的GUI,在显示的图像上方显示了不同的层。在某个时候,我想将具有所有可视化层的当前图像存储到磁盘,同时继续使用GUI。 ...

python python-3.x multithreading pyqt pyqt5
1个回答
2
投票

该问题与线程无关,但是QPixmap不是线程安全的,并且不应the docs指出从另一个线程进行操作:

© www.soinside.com 2019 - 2024. All rights reserved.