一、概述
背景:Qt+OpenCV项目改造,之前项目中的OpenCV算法都是在主线程中执行,导致部分操作或者重复点击的时候界面卡顿。现在想对这块进行改造。
集合QThread和QWidget设计一个QWidget基类用于方便的执行耗时任务并显示执行结果。子类只需要继承这个QWidget基类,只需要重写一个handle方法用于执行耗时任务(在子线程执行),调用execute()方法开启耗时任务的执行即可。
现成切换全封装到基类中。
设计需要的类:
1.Handler.h定义一个handle接口,子类需要实现它。作用是通过继承关系父类调用子类方法
2.HandlerThread.h/.cpp 继承QThread,并把Handler类传入,在run方法中调用Handler执行耗时操作,执行完成会通过emit updateUI发送信号
3.BaseSceneView.h/.cpp此类是基类,此类中会导入HandlerThread类,并继承Handler类。此类会捕获HandlerThread的run方法发出的信号,然后通过updateImage更新UI
4.子类实现BaseSenceView,重写handle方法,如果有耗时任务则放入handle方法即可。耗时任务是通过父类的execute()方法执行的
二、示例代码
1.Handler.h
#pragma once #include <QPixmap> class Handler { public: virtual QPixmap handle() { return NULL; } };
2.HandlerThread.h/.cpp
#pragma once #include <QThread> #include <QPixmap> #include "Handler.h" class HandlerThread : public QThread { Q_OBJECT public: HandlerThread(QObject* parent, Handler* handler); ~HandlerThread(); private: Handler* handler; protected: void run();//线程执行体 signals: void updateUI(QPixmap pixmap);//发送更新UI的信号 };
#include "HandlerThread.h" HandlerThread::HandlerThread(QObject* parent, Handler* handler) : QThread(parent) { this->handler = handler; } void HandlerThread::run() { QPixmap pixmap = handler->handle(); emit updateUI(pixmap); } HandlerThread::~HandlerThread() { }
3.BaseSenceView.h/.cpp
#pragma once #include <stdint.h> #include <QWidget> #include <QGraphicsScene> #include <QDragEnterEvent> #include <QDropEvent> #include <QResizeEvent> #include <QSize> #include <QGraphicsView> #include <QMessageBox> #include <QMimeData> #include <QFileInfo> #include <QStringList> #include <QGraphicsPixmapItem> #include <QDebug> #include <QGraphicsEllipseItem> #include <QGraphicsLineItem> #include <QGraphicsRectItem> #include <QGraphicsPolygonItem> #include <QSlider> #include <QDebug> #include <QPixmap> #include <QImage> #include <opencv2/opencv.hpp> #include "../utils/ImageUtils.h" #include "HandlerThread.h" class BaseSceneView : public QWidget,public Handler { Q_OBJECT public: BaseSceneView(QWidget* parent = nullptr); ~BaseSceneView(); private: HandlerThread* mThread; QGraphicsView* view; QGraphicsScene scene; protected: void dragEnterEvent(QDragEnterEvent* event); void dropEvent(QDropEvent* event); void resizeEvent(QResizeEvent* event); public: //调用此方法开始执行耗时任务,此方法必须调用否则耗时任务不执行, //此处的耗时任务就是,handle()方法中的代码块 void execute();//执行耗时任务 //此方法必须要重写,需要把耗时任务放进去 virtual QPixmap handle() { return NULL; } private: //向场景中添加Bitmap void addPixmap(QPixmap pixmap); void addImage(QImage image); void addMat(cv::Mat mat); //更新UI4 void updateImage(QPixmap pixmap); public slots: void onHSliderValueChanged(int value); private: };
#include "BaseSceneView.h" BaseSceneView::BaseSceneView(QWidget* parent) : QWidget(parent) { this->setAcceptDrops(true);//允许往窗口拖放 this->setFixedSize(QSize(320, 480)); view = new QGraphicsView(this);//实例化View view->setMouseTracking(true); view->setFixedSize(this->size()); view->setAcceptDrops(false); view->setScene(&scene);//给View设置场景 mThread = new HandlerThread(this, this);//子线程,用于处理耗时任务,处理完成后发送信号 //接收上面线程执行完成后发出的信号 connect(mThread, &HandlerThread::updateUI, this, [=](QPixmap pixmap) { updateImage(pixmap); }); } void BaseSceneView::dragEnterEvent(QDragEnterEvent* event) { QStringList acceptedFileTypes; acceptedFileTypes.append("jpeg"); acceptedFileTypes.append("png"); acceptedFileTypes.append("bmp"); acceptedFileTypes.append("jpg");//设置可以接受的文件格式类型 if (event->mimeData()->hasUrls() && event->mimeData()->urls().count() == 1) { QFileInfo file(event->mimeData()->urls().at(0).toLocalFile()); if (acceptedFileTypes.contains(file.suffix().toLower())) { event->acceptProposedAction(); } } else { QMessageBox::critical(this, "Error", "count not load mulit files"); } } //拖动内容到窗口 void BaseSceneView::dropEvent(QDropEvent* event) { scene.clear(); QFileInfo file(event->mimeData()->urls().at(0).toLocalFile()); } void BaseSceneView::resizeEvent(QResizeEvent* event) { } void BaseSceneView::onHSliderValueChanged(int value) { } void BaseSceneView::addPixmap(QPixmap pixmap) { scene.clear(); QGraphicsPixmapItem* item = new QGraphicsPixmapItem(pixmap.scaled(this->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation)); scene.addItem(item);//给场景添加内容 } void BaseSceneView::addImage(QImage image) { scene.clear(); QPixmap pixmap = QPixmap::fromImage(image); QGraphicsPixmapItem* item = new QGraphicsPixmapItem(pixmap.scaled(this->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation)); scene.addItem(item);//给场景添加内容 } void BaseSceneView::addMat(cv::Mat mat) { scene.clear(); QImage image = ImageUtils::matToQImage(mat); QPixmap pixmap = QPixmap::fromImage(image); QGraphicsPixmapItem* item = new QGraphicsPixmapItem(pixmap.scaled(this->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation)); scene.addItem(item);//给场景添加内容 } void BaseSceneView::updateImage(QPixmap pixmap) { addPixmap(pixmap); } //执行耗时任务(执行耗时任务前需要调用) void BaseSceneView::execute() { mThread->start(); } BaseSceneView::~BaseSceneView() { }
标签:pixmap,Qt,耗时,void,HandlerThread,QWidget,基类,include,BaseSceneView From: https://www.cnblogs.com/tony-yang-flutter/p/17869505.html