Как рисовать Qlabel с QPainter при многопоточности с QThreadpool? - PullRequest
0 голосов
/ 04 ноября 2019

Пожалуйста, извините, если мое описание не идеально, я все еще новичок в PyQt и Python в целом. Если у вас есть рекомендации по улучшению вопроса, пожалуйста, дайте мне знать.

Я пытаюсь использовать Pixmap-QLabel, который является частью QMainWindow, с QPainter. QPainter вызывается в цикле, потому что чертеж обновляется после фиксированной продолжительности. Рисование на Pixmap работает как задумано, проблема у меня в том, что метка всегда открывается в новом окне, а не помещается на QLabel внутри исходного QMainWindow.

Я подозреваю, что причина в том, чтоЯ вызываю QPainter из объекта класса Worker, который создается объектом QThreadpool. Если я вызываю QPainter изнутри инициализации GUI, метка Pixmap создается как часть QMainWindow, как и предполагалось. К сожалению, многопоточность необходима, поэтому графический интерфейс остается отзывчивым во время обновления QLabel.

Сам графический интерфейс создается с помощью QtCreator и просто загружается в сценарий.

Вот мой код:


import os
import sys
import time

from PyQt5 import QtWidgets, QtCore, uic
from PyQt5.QtWidgets import QLabel, QPushButton, QMainWindow
from PyQt5.QtGui import QPixmap, QPainter, QPen, QPaintEvent
from PyQt5.QtCore import *

class Ui(QMainWindow):
    def __init__(self):
        super(Ui, self).__init__()
        self.counter = 0

        # load ui which can be designed with Qt Creator
        uic.loadUi("ui/paintEvent_Loop.ui", self)

        # find the QLabel where the picture should be placed
        self.pixmap_label = self.findChild(QtWidgets.QLabel, "pixmap_label")

        # creating the pixmap-label here works as intended
        '''self.draw_label = PixmapLabel(self.pixmap_label)
        self.draw_label.setGeometry(130, 50, 911, 512)
        self.draw_label.show()'''

        self.label = self.findChild(QLabel, "label")

        # find the button with the name "cancel_button"
        self.cancel_button = self.findChild(QtWidgets.QPushButton, "cancel_button")
        self.cancel_button.clicked.connect(self.close_application)

        # find the start_button button
        self.start_button = self.findChild(QtWidgets.QPushButton, "start_button")
        self.start_button.clicked.connect(self.start_loop)

        self.pause_cont_button = self.findChild(QPushButton, "pause_cont_button")
        self.pause_cont_button.clicked.connect(self.toggle_pause_continue)
        self.pause_cont_button.hide()

        # create the QThreadPool object to manage multiple threads
        self.threadpool = QThreadPool()
        print("Multithreading with maximum %d threads" % self.threadpool.maxThreadCount())

        self.run_loop = True

        # show application
        self.show()

    def close_application(self):
        app.quit()

    def toggle_pause_continue(self):
        """
        changes the value of boolean run_loop to pause and continue the loop through the samples in the chosen scene
        :return:
        """
        if self.run_loop:
            self.run_loop = False
        else:
            self.run_loop = True

    def start_loop(self):
        # hide start_button and show pause_cont_button
        self.start_button.hide()
        self.pause_cont_button.show()
        self.pause_cont_button.setCheckable(True)

        # start one further thread managed by threadpool
        worker = Worker()
        self.threadpool.start(worker)


class PixmapLabel(QLabel):

    def __init__(self, parent=None):
        super(PixmapLabel, self).__init__(parent=parent)

    def paintEvent(self, a0: QPaintEvent) -> None:

        # initiate QPainter instance
        painter = QPainter(window.draw_label)

        # open image
        picture = QPixmap(os.getcwd() + '/test-image.png')
        myPicturePixmap = picture.scaled(self.size(), QtCore.Qt.KeepAspectRatio)
        self.setPixmap(myPicturePixmap)

        # draw red box on it
        painter.drawPixmap(self.rect(), myPicturePixmap)
        pen = QPen(Qt.red, 3)
        painter.setPen(pen)
        painter.drawRect(10, 10, 100, 100)


class Worker(QRunnable):
    # worker thread
    def __init__(self):
        super().__init__()

    @pyqtSlot()
    def run(self):
        print("Thread start")

        for self.i in range(0, 50):

            # create pixmap_label with drawings
            # FIXME: make pixmap-label part of original GUI
            window.draw_label = PixmapLabel(window.pixmap_label)
            window.draw_label.setGeometry(130, 50, 911, 512)
            window.draw_label.show()

            window.label.setText(str(self.i))

            while window.run_loop == False:
                time.sleep(0.05)

            # show image for 0.5 seconds, then update image
            time.sleep(0.5)
            window.draw_label.destroy()
            time.sleep(0.05)



        # print in terminal to know that we are finished
        print("Thread complete")


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    window = Ui()
    app.exec_()

Изображение, которое я использую:

test-image.png

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...