python - 使用 QThreadpool 进行多线程时,如何使用 QPainter 在 Qlabel 上绘图?
问题描述
如果我的描述不完美,请原谅,我对 PyQt 和 Python 还是很陌生。如果您有关于如何改进问题的建议,请告诉我。
我正在尝试使用 QPainter 绘制 Pixmap-QLabel,它是 QMainWindow 的一部分。QPainter 在循环中被调用,因为绘图会在固定持续时间后更新。在 Pixmap 上绘图按预期工作,我遇到的问题是标签总是在新窗口中打开,而不是放在原始 QMainWindow 内的 QLabel 上。
我怀疑其原因是我从由 QThreadpool 对象创建的 Worker-class-object 调用 QPainter。如果我从 GUI 的初始化内部调用 QPainter,则 Pixmap-label 会按预期创建为 QMainWindow 的一部分。不幸的是,多线程是必要的,因此 GUI 在 QLabel 更新时保持响应。
GUI 本身是用 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_()
我正在使用的图像:
解决方案
推荐阅读
- c++ - OpenMP 提高了部分的性能,但减慢了整体运行时间
- android - 是否可以使用 android 智能手机制作 ubertooth 的功能?
- c++ - 我的第一个 C++ 程序需要一点帮助(简单)
- python - 如何在熊猫中分组日期并创建与日期关联的时间列
- c# - 我在 serilog 中配置 app.config 时发现了一个问题
- python-3.x - 如何在 Grant 类中实现 validate_redirect_uri?
- php - cakephp 使用 ldap 进行身份验证并匹配到本地用户(或创建一个)
- sql - 如何在 SQL 中执行循环
- java - JavaFX:有没有办法在 LineChart 中添加中断?
- r - 计算两列中的值都为真的行数