我正在尝试使用 PyQt5 制作一个利用网络摄像头的桌面应用程序。我在 YouTube 上看到了一个视频,其中那个人使用线程来实现这一点。我根据我的用例修改了代码。修改后的代码如下:-
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import cv2
class MainWindow(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("Ayyo")
self.GL = QGridLayout()
self.feedLabel = QLabel()
self.GL.addWidget(self.feedLabel, 0, 0, 1, 2)
self.lineEdit = QLineEdit()
self.GL.addWidget(self.lineEdit, 1, 0, 1, 1)
self.button1 = QPushButton("Confirm")
self.button1.clicked.connect(self.confirm)
self.GL.addWidget(self.button1, 1, 1, 1, 1)
self.textEdit = QTextEdit()
self.GL.addWidget(self.textEdit, 2, 0, 2, 1)
self.button2 = QPushButton("Clear")
self.button2.clicked.connect(self.clear)
self.GL.addWidget(self.button2, 2, 1, 1, 1)
self.button3 = QPushButton("Copy")
self.GL.addWidget(self.button3, 3, 1, 1, 1)
self.webcam = Webcam()
self.webcam.start()
self.webcam.ImageUpdate.connect(self.ImageUpdateSlot)
self.setLayout(self.GL)
self.show()
def ImageUpdateSlot(self, image):
self.feedLabel.setPixmap(QPixmap.fromImage(image))
def confirm(self):
current = self.textEdit.toPlainText()
self.textEdit.setPlainText(current + self.lineEdit.text())
def clear(self):
self.textEdit.setPlainText("")
class Webcam(QThread):
ImageUpdate = pyqtSignal(QImage)
def run(self):
self.ThreadActive = True
vid = cv2.VideoCapture(0)
while True:
ret, frame = vid.read()
frame1 = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
image = QImage(frame1, frame1.shape[1], frame1.shape[0], frame1.strides[0], QImage.Format_RGB888)
self.ImageUpdate.emit(image)
app = QApplication(sys.argv)
mw = MainWindow()
# mw.show()
sys.exit(app.exec_())
当我运行此程序时,实际程序运行良好,但几秒钟后它会自动关闭
进程已完成,退出代码为 -1073741819 (0xC0000005)
块引用
奇怪的是,在 PyCharm 中调试代码时,它没有关闭。但每当我运行代码时,它都会在几秒钟后自动关闭。任何帮助将不胜感激。
这些总是很难排除故障,但我发现您应该在初始化应用程序时避免使用 QThreads,因为它有时会导致随机关闭。
尝试:
如果您想让此功能线程化,这样就不会锁定 UI,请查看 PyQt5 的 QThreadPool (https://www.mfitzp.com/tutorials/multithreading-pyqt-applications-qthreadpool/)
使用QTHereadPool 这是在 PyQt5 中使用 QThreadPool 的示例:
导入系统 从 PyQt5.QtCore 导入 QThreadPool、QRunnable、pyqtSignal、QObject、QTimer 从 PyQt5.QtWidgets 导入 QApplication、QMainWindow、QLabel、QVBoxLayout、QPushButton、QWidget
class WorkerSignals(QObject):
finished = pyqtSignal()
class Worker(QRunnable):
def __init__(self):
super().__init__()
self.signals = WorkerSignals()
def run(self):
import time
time.sleep(5) # Simulating a long-running task
self.signals.finished.emit()
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("QThreadPool Example")
self.setGeometry(100, 100, 400, 200)
self.central_widget = QWidget()
self.setCentralWidget(self.central_widget)
self.label = QLabel("Waiting")
self.button = QPushButton("Start Thread Pool")
self.button.clicked.connect(self.start_thread_pool)
layout = QVBoxLayout()
layout.addWidget(self.label)
layout.addWidget(self.button)
self.central_widget.setLayout(layout)
self.threadpool = QThreadPool()
def start_thread_pool(self):
self.label.setText("Thread Pool Started")
self.button.setEnabled(False)
# Submitting tasks to the thread pool
for _ in range(5):
worker = Worker()
worker.signals.finished.connect(self.worker_finished)
self.threadpool.start(worker)
def worker_finished(self):
QTimer.singleShot(0, lambda: self.label.setText("All tasks completed"))
self.button.setEnabled(True)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
在这个例子中,我们创建了一个继承自QRunnable的Worker类。每个工作人员模拟一个长时间运行的任务(睡眠 5 秒),并在任务完成时发出完成信号。我们将此信号连接到主窗口 (worker_finished) 中的一个槽,我们在其中更新标签以指示所有任务均已完成。
当点击“Start Thread Pool”按钮时,我们创建多个 Worker 实例,并使用 start() 方法将它们提交到 QThreadPool。然后,线程池有效地管理这些任务的执行。
PyQt(或一般 Qt)中
QThread
和 QThreadPool
之间的主要区别在于它们的用途和使用场景:
QThread:
QThreadPool:
QThread
相比,提供了更高级别的抽象,抽象出线程管理的细节,让开发人员专注于定义要执行的任务。总而言之,虽然
QThread
适合管理单个线程和执行单个任务,但QThreadPool
更适合通过有效利用线程池来同时管理多个任务。它们之间的选择取决于应用程序的具体要求和要执行的任务的性质。