[英]Can't display PyQt5 GUI with threading FlaskAPI
我有一个 PyQt5 应用程序。 该应用程序比我现在分享的示例要大。 为方便起见,我共享以下代码。
示例应用程序由 GUI class、FlaskAPI class、class 组成,提供视频 ZF7B44CFAFD5C62223DB549A2E。 GUI class 使用继承 QLabel class 的 class 并称为 ImageLabel ,这部分与我的问题无关。 在 GUI 上显示视频 stream 时,我想启用 C# 应用程序与我的 Python 应用程序交互。 所以我决定使用 Flask 为 C# 应用程序提供一个 REST 接口。 但是,我现在有一个问题。 由于 PyQt5 主线程和 FlaskAPI 的冲突,我试图应用多线程,但我遇到了一个问题。
我的问题是,如果我启动 FlaskAPI 线程,我将无法显示 GUI。 如何使用 GUI 运行 Flask API 并在 GUI class 中通信方法?
主文件
import sys
from PyQt5.QtCore import Qt, pyqtSlot, QThread
from PyQt5.QtGui import QImage, QPixmap
from PyQt5.QtWidgets import QApplication, QVBoxLayout, QWidget, QPushButton, QHBoxLayout
from FlaskAPI import FlaskAPI
from ImageLabel import ImageLabel
from StreamThread import StreamThread
class MainWindow(QWidget):
def __init__(self):
super(MainWindow, self).__init__()
self.init_UI()
def init_UI(self):
self.setFixedSize(690, 530)
self.image_lbl = ImageLabel()
th = StreamThread()
th.changePixmap.connect(self.setImage, Qt.QueuedConnection)
th.start()
btn_cnt = QPushButton("Continue")
btn_pa = QPushButton("Pause")
hbox = QHBoxLayout()
hbox.addWidget(btn_cnt)
hbox.addWidget(btn_pa)
vbox = QVBoxLayout()
vbox.addWidget(self.image_lbl)
vbox.addLayout(hbox)
self.setLayout(vbox)
btn_pa.clicked.connect(lambda: self.btn_pa_clicked(th))
self.show()
self.start_api()
def start_api(self):
"""
Start Flask API
"""
self.thread = QThread()
self.api = FlaskAPI()
self.api.moveToThread(self.thread)
self.thread.start()
@pyqtSlot(QImage)
def setImage(self, image):
"""
Set frame on the ImageLabel instance (inherits QLabel to display video stream)
"""
self.image_lbl.pixmap = QPixmap.fromImage(image).scaled(720, 540)
self.image_lbl.setPixmap(QPixmap.fromImage(image).scaled(720, 540))
def btn_pa_clicked(self, th):
th.terminate() # terminates the video stream
image = QImage("img/default.jpg") # self.image_lbl.pixmap
image = image.convertToFormat(QImage.Format_RGB888)
# image = image.toImage()
if image is not None:
#(h, w, c) = image.shape
#qimage = QImage(image.data, h, w, 3 * h, QImage.Format_RGB888)
self.image_lbl.pixmap = QPixmap.fromImage(image)
self.image_lbl.repaint()
def main():
app = QApplication(sys.argv)
main_form = MainWindow()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
FlaskAPI.py
from PyQt5.QtCore import QObject
from flask import Flask
class FlaskAPI(QObject):
def __init__(self):
"""
Run Flask API and set the example route.
"""
self.app = Flask(__name__)
self.app.add_url_rule('/get_value', 'get_value', self.get_value)
self.app.run(debug=True)
def get_value(self):
"""
Return example data.
"""
data = {"id": "value"}
return data
流线程.py
import cv2
from PyQt5.QtCore import QThread, pyqtSignal, Qt
from PyQt5.QtGui import QImage
#https://stackoverflow.com/a/44404713/13080899
class StreamThread(QThread):
changePixmap = pyqtSignal(QImage)
def __init__(self):
super(StreamThread, self).__init__()
def run(self):
"""
Start video stream on thread and emit the captured frame
"""
self.capt = cv2.VideoCapture(0, cv2.CAP_DSHOW)
while(True):
ret, frame = self.capt.read()
if ret:
rbgImage = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
h, w, ch = rbgImage.shape
bytesPerLine = ch*w
convertToQtFormat = QImage(rbgImage.data, w, h, bytesPerLine, QImage.Format_RGB888)
p = convertToQtFormat.scaled(640, 480, Qt.KeepAspectRatio)
self.changePixmap.emit(p)
图像标签.py
from PyQt5 import QtGui, QtCore
from PyQt5.QtCore import Qt, QSize, pyqtSignal, QObject, QPoint, pyqtSlot
from PyQt5.QtWidgets import QLabel
class Communicate(QObject):
cor_update = pyqtSignal()
cor_curr = pyqtSignal()
class ImageLabel(QLabel):
def __init__(self, width=720, height=540):
super(ImageLabel, self).__init__()
self.setMouseTracking(True)
self.pixmap = QtGui.QPixmap("img/im.jpg")
#### initialize coordinates ####
self.x1 = 0
self.y1 = 0
self.x_curr = 0
self.y_curr = 0
self.x2 = 0
self.y2 = 0
##### enable state to allow user for drawing
self.enable_labelling = False
##### enable state to track coordinates for drawing
self.enable_cor = False
################################
self.source = Communicate()
def paintEvent(self, event):
qp = QtGui.QPainter(self)
qp.drawPixmap(self.rect(), self.pixmap)
if self.enable_labelling == True:
self.paintRect(event, qp)
qp.end()
def paintRect(self, event, qp):
br = QtGui.QBrush(QtGui.QColor(50, 255, 255, 40))
qp.setBrush(br)
if self.enable_cor == True:
qp.drawRect(QtCore.QRect(QPoint(self.x1, self.y1), QSize(self.x_curr - self.x1, self.y_curr - self.y1)))
else:
qp.drawRect(QtCore.QRect(QPoint(self.x1, self.y1), QSize(self.x2 - self.x1, self.y2 - self.y1)))
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton and self.enable_labelling == True:
self.x1 = event.x()
self.y1 = event.y()
self.enable_cor = True
self.source.cor_update.emit()
def mouseMoveEvent(self, event):
self.x_curr = event.x()
self.y_curr = event.y()
self.source.cor_curr.emit()
def mouseReleaseEvent(self, event):
if event.button() == Qt.LeftButton and self.enable_labelling == True:
self.x2 = event.x()
self.y2 = event.y()
self.source.cor_update.emit()
self.enable_cor = False
根据@musicamante 的反馈,我在 FlaskAPI.py 的__init__
中删除了self.app.run()
。 我创建了一个新方法,然后在线程启动时启动它。
这是我在新线程上的 main.py 中启动 FlaskAPI 的方法。 主文件
class MainWindow(QWidget):
def __init__(self):
super(MainWindow, self).__init__()
self.init_UI()
self.start_api()
def start_api(self):
"""
Start Flask API
"""
self.thread = QThread()
self.api = FlaskAPI()
self.api.moveToThread(self.thread)
self.thread.started.connect(self.api.start)
self.thread.start()
更新的 FlaskAPI 模块。
FlaskAPI.py
from PyQt5.QtCore import QObject
from flask import Flask
class FlaskAPI(QObject):
def __init__(self):
"""
Run Flask API and set the example route.
"""
super(FlaskAPI, self).__init__()
self.app = Flask(__name__)
self.app.add_url_rule('/get_value/', 'get_value', self.get_value)
def start(self):
self.app.run()
def get_value(self):
"""
Return example data.
"""
data = {"id": "value"}
return data
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.