本章将开始学习Qt的图形视图框架中大多数最重要的类,QGraphicsScene、QGraphicsItem、QGraphicsView。在本章中将学习使用QGraphicsScene在场景中绘制图形,使用QGraphicsItem及其子类管理图形对象元素,使用QGraphicsView查看QGraphicsScene,同时开发放大、缩小以及其他图像编辑和查看的功能。最后完善第3章中的Computer_Vision项目。
场景,即QGraphicsScene,用于管理对象元素或QGraphicsItem(及其子类)的实例,包含它们,并将事件(如鼠标单击等)传递给对象元素。
视图,即QGraphicsView控件,用于可视化和显示QGraphicsScene的内容,还负责将事件传递给QGraphicsScene。这里需要重点注意,QGraphicsScene和QGraphicsView各有不同的坐标系统。可以想到,如果放大、缩小或经历不同的类似变换,场景中的某个位置将不会相
同。QGraphicsScene和QGraphicsView都提供了转换位置值的函数,以便相互适应。
对象元素,即QGraphicsItem子类的实例,是QGraphicsScene包含的对象元素。这些对象元素可以是线、矩形、图像、文本等。
下面我们从一个简单的Graphics_Viewer例子开始。
1.首先我们新建一个Graphics_Viewer项目,托一个QGraphicsView控件,对界面进行网格布局。
在MainWindow类中添加两个函数用于托拽图片
void MainWindow::dragEnterEvent(QDragEnterEvent *event)
{
QStringList acceptedFileTypes;
acceptedFileTypes.append("jpg");
acceptedFileTypes.append("png");
acceptedFileTypes.append("bmp");
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();
}
}
}
void MainWindow::dropEvent(QDropEvent *event)
{
QPoint viewPos = ui->graphicsView->mapFromParent(event->pos());
QPointF sceneDropPos = ui->graphicsView->mapToScene(viewPos);
QFileInfo file(event->mimeData()->urls().at(0).toLocalFile());
QPixmap pixmap;
if(pixmap.load(file.absoluteFilePath()))
{
QGraphicsPixmapItem *item = new QGraphicsPixmapItem(pixmap);
item->setPos(sceneDropPos);
item->setFlag(QGraphicsItem::ItemIsSelectable);
item->setAcceptedMouseButtons(Qt::LeftButton);
scene.addItem(item);
}
else
{
QMessageBox::critical(this, tr("Error"), tr("The image file cannot be read!"));
}
}
2.自定义一个QEnhancedGraphicsView继承QGraphicsView,添该类添加滚动鼠标放大缩小功能void wheelEvent(QWheelEvent *event);
重写mousePressEvent(QMouseEvent *event);函数添加右键菜单功能。
右键菜单包含
void clearAll(bool);
void clearSelected(bool);
void noEffect(bool);
void blurEffect(bool);
void dropShadowEffect(bool);
void colorizeEffect(bool);
void customEffect(bool);
QGraphicsEffect是Qt中所有图形效果的基类。它的子类包括 QGraphicsBlurEffect, QGraphicsColorizeEffect, QGraphicsDropShadowEffect, QGraphicsOpacityEffect
当然也可以对其进行子类化,创建自己的图形效果或滤波器,现在自定义一个QCustomGraphicsEffect继承QGraphicsEffect,重写draw函数,把图片转成灰度图
void QCustomGraphicsEffect::draw(QPainter *painter)
{
QImage image;
image = sourcePixmap().toImage();
image = image.convertToFormat(QImage::Format_Grayscale8);
for(int i = 0; i < image.sizeInBytes(); i++)
{
image.bits()[i] = image.bits()[i] < 100 ? 0 : 255;
}
painter->drawPixmap(0,0,QPixmap::fromImage(image));
}
完整的代码如下
工程 文件
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = Graphics_Viewer
TEMPLATE = app
# The following define makes your compiler emit warnings if you use
# any feature of Qt which as been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
#win环境配置
win32:{
CONFIG(debug, debug|release){
DESTDIR += $$PWD/../bin/win64d
LIBS += -L$$PWD/../lib/win64d -lopencv_world480d
}else{
DESTDIR += $$PWD/../bin/win64
LIBS += -L$$PWD/../lib/win64 -lopencv_world480
}
}
INCLUDEPATH += ../Include
SOURCES += \
main.cpp \
mainwindow.cpp \
qcustomgraphicseffect.cpp \
qenhancedgraphicsview.cpp
HEADERS += \
mainwindow.h \
qcustomgraphicseffect.h \
qenhancedgraphicsview.h
FORMS += \
mainwindow.ui
qcustomgraphicseffect.h文件
#ifndef QCUSTOMGRAPHICSEFFECT_H
#define QCUSTOMGRAPHICSEFFECT_H
#include <QObject>
#include <QGraphicsEffect>
#include <QPainter>
class QCustomGraphicsEffect : public QGraphicsEffect
{
Q_OBJECT
public:
explicit QCustomGraphicsEffect(QObject *parent = nullptr);
protected:
void draw(QPainter *painter);
signals:
public slots:
};
#endif // QCUSTOMGRAPHICSEFFECT_H
qcustomgraphicseffect.cpp文件
#include "qcustomgraphicseffect.h"
QCustomGraphicsEffect::QCustomGraphicsEffect(QObject *parent)
: QGraphicsEffect(parent)
{
}
void QCustomGraphicsEffect::draw(QPainter *painter)
{
QImage image;
image = sourcePixmap().toImage();
image = image.convertToFormat(QImage::Format_Grayscale8);
for(int i = 0; i < image.sizeInBytes(); i++)
{
image.bits()[i] = image.bits()[i] < 100 ? 0 : 255;
}
painter->drawPixmap(0,0,QPixmap::fromImage(image));
}
qenhancedgraphicsview.h文件
#ifndef QENHANCEDGRAPHICSVIEW_H
#define QENHANCEDGRAPHICSVIEW_H
#include <QWidget>
#include <QGraphicsView>
#include <QWheelEvent>
#include <QMouseEvent>
#include <QtMath>
#include <QContextMenuEvent>
#include <QMenu>
#include <QGraphicsItem>
#include <QDebug>
#include <QGraphicsEffect>
#include "qcustomgraphicseffect.h"
class QEnhancedGraphicsView : public QGraphicsView
{
Q_OBJECT
public:
explicit QEnhancedGraphicsView(QWidget *parent = nullptr);
protected:
void wheelEvent(QWheelEvent *event);
void mousePressEvent(QMouseEvent *event);
signals:
private slots:
void clearAll(bool);
void clearSelected(bool);
void noEffect(bool);
void blurEffect(bool);
void dropShadowEffect(bool);
void colorizeEffect(bool);
void customEffect(bool);
private:
QPointF sceneMousePos;
};
#endif // QENHANCEDGRAPHICSVIEW_H
qenhancedgraphicsview.cpp文件
#include "qenhancedgraphicsview.h"
QEnhancedGraphicsView::QEnhancedGraphicsView(QWidget *parent)
: QGraphicsView(parent)
{
}
void QEnhancedGraphicsView::wheelEvent(QWheelEvent *event)
{
if (event->orientation() == Qt::Vertical)
{
double angleDeltaY = event->angleDelta().y();
double zoomFactor = qPow(1.0015, angleDeltaY);
scale(zoomFactor, zoomFactor);
if(angleDeltaY > 0)
{
this->centerOn(sceneMousePos);
sceneMousePos = this->mapToScene(event->pos());
}
this->viewport()->update();
event->accept();
}
else
{
event->ignore();
}
}
void QEnhancedGraphicsView::mousePressEvent(QMouseEvent *event)
{
if(event->button() == Qt::RightButton)
{
QMenu menu;
QAction *clearAllAction = menu.addAction("Clear All");
connect(clearAllAction, SIGNAL(triggered(bool)), this, SLOT(clearAll(bool)));
QAction *clearSelectedAction = menu.addAction("Clear Selected");
connect(clearSelectedAction, SIGNAL(triggered(bool)), this, SLOT(clearSelected(bool)));
QAction *noEffectAction = menu.addAction("No Effect");
connect(noEffectAction, SIGNAL(triggered(bool)), this, SLOT(noEffect(bool)));
QAction *blurEffectAction = menu.addAction("Blur Effect");
connect(blurEffectAction, SIGNAL(triggered(bool)), this, SLOT(blurEffect(bool)));
QAction *dropShadEffectAction = menu.addAction("Drop Shadow Effect");
connect(dropShadEffectAction, SIGNAL(triggered(bool)), this, SLOT(dropShadowEffect(bool)));
QAction *colorizeEffectAction = menu.addAction("Colorize Effect");
connect(colorizeEffectAction, SIGNAL(triggered(bool)), this, SLOT(colorizeEffect(bool)));
QAction *customEffectAction = menu.addAction("Custom Effect");
connect(customEffectAction, SIGNAL(triggered(bool)), this, SLOT(customEffect(bool)));
menu.exec(event->globalPos());
event->accept();
}
else
{
QGraphicsView::mousePressEvent(event);
}
}
void QEnhancedGraphicsView::clearAll(bool)
{
scene()->clear();
}
void QEnhancedGraphicsView::clearSelected(bool)
{
while(scene()->selectedItems().count() > 0)
{
delete scene()->selectedItems().at(0);
scene()->selectedItems().removeAt(0);
}
}
void QEnhancedGraphicsView::noEffect(bool)
{
foreach(QGraphicsItem *item, scene()->selectedItems())
{
item->setGraphicsEffect(Q_NULLPTR);
}
}
void QEnhancedGraphicsView::blurEffect(bool)
{
foreach(QGraphicsItem *item, scene()->selectedItems())
{
item->setGraphicsEffect(new QGraphicsBlurEffect(this));
}
}
void QEnhancedGraphicsView::dropShadowEffect(bool)
{
foreach(QGraphicsItem *item, scene()->selectedItems())
{
item->setGraphicsEffect(new QGraphicsDropShadowEffect(this));
}
}
void QEnhancedGraphicsView::colorizeEffect(bool)
{
foreach(QGraphicsItem *item, scene()->selectedItems())
{
item->setGraphicsEffect(new QGraphicsColorizeEffect(this));
}
}
void QEnhancedGraphicsView::customEffect(bool)
{
foreach(QGraphicsItem *item, scene()->selectedItems())
{
item->setGraphicsEffect(new QCustomGraphicsEffect(this));
}
}
mainwindow.h文件
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QGraphicsScene>
#include <QGraphicsItem>
#include <QPixmap>
#include <QDragEnterEvent>
#include <QDropEvent>
#include <QMimeData>
#include <QFileInfo>
#include <QMessageBox>
#include <QDebug>
#include "qcustomgraphicseffect.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
protected:
void dragEnterEvent(QDragEnterEvent *event);
void dropEvent(QDropEvent *event);
private:
Ui::MainWindow *ui;
QGraphicsScene scene;
};
#endif // MAINWINDOW_H
mainwindow.cpp文件
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
this->setAcceptDrops(true);
ui->graphicsView->setAcceptDrops(false);
ui->graphicsView->setScene(&scene);
ui->graphicsView->setInteractive(true);
ui->graphicsView->setDragMode(QGraphicsView::RubberBandDrag);
ui->graphicsView->setRubberBandSelectionMode(Qt::ContainsItemShape);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::dragEnterEvent(QDragEnterEvent *event)
{
QStringList acceptedFileTypes;
acceptedFileTypes.append("jpg");
acceptedFileTypes.append("png");
acceptedFileTypes.append("bmp");
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();
}
}
}
void MainWindow::dropEvent(QDropEvent *event)
{
QPoint viewPos = ui->graphicsView->mapFromParent(event->pos());
QPointF sceneDropPos = ui->graphicsView->mapToScene(viewPos);
QFileInfo file(event->mimeData()->urls().at(0).toLocalFile());
QPixmap pixmap;
if(pixmap.load(file.absoluteFilePath()))
{
QGraphicsPixmapItem *item = new QGraphicsPixmapItem(pixmap);
item->setPos(sceneDropPos);
//设置对象可选中,可托动
item->setFlags(QGraphicsItem::ItemIsSelectable|QGraphicsItem::ItemIsMovable);
item->setAcceptedMouseButtons(Qt::LeftButton);
scene.addItem(item);
}
else
{
QMessageBox::critical(this, tr("Error"), tr("The image file cannot be read!"));
}
}
main.cpp文件
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
运行效果:
computer_vision项目添加插件,该项目分两个子项目,一个是插件项目,一个是应用项目,具体代码如下:
computer_vision.pro
TEMPLATE = subdirs
SUBDIRS += \
mainapp \
template_plugin
插件项目
template_plugin.pro
QT += widgets
TARGET = Template_Plugin
TEMPLATE = lib
CONFIG += plugin
DEFINES += TEMPLATE_PLUGIN_LIBRARY
# The following define makes your compiler emit warnings if you use
# any feature of Qt which as been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
#win环境配置
win32:{
CONFIG(debug, debug|release){
#插件生成目录
DESTDIR += $$PWD/../../bin/win64d/cvplugins
LIBS += -L$$PWD/../../lib/win64d -lopencv_world480d
}else{
DESTDIR += $$PWD/../../bin/win64/cvplugins
LIBS += -L$$PWD/../../lib/win64 -lopencv_world480
}
}
INCLUDEPATH += ../../Include
INCLUDEPATH += ../cvplugininterface
SOURCES += \
template_plugin.cpp
HEADERS += \
template_plugin.h \
template_plugin_global.h
unix {
target.path = /usr/lib
INSTALLS += target
}
win32: {
include("c:/dev/opencv/opencv.pri")
}
unix: !macx{
CONFIG += link_pkgconfig
PKGCONFIG += opencv
}
unix: macx{
INCLUDEPATH += "/usr/local/include"
LIBS += -L"/usr/local/lib" \
-lopencv_world
}
FORMS += \
plugin.ui
cvplugininterface.h文件
#ifndef CVPLUGIN_H
#define CVPLUGIN_H
#include <QObject>
#include <QWidget>
#include <QString>
#include "opencv2/opencv.hpp"
class CvPluginInterface
{
public:
virtual ~CvPluginInterface() {}
virtual QString title() = 0;
virtual QString version() = 0;
virtual QString description() = 0;
virtual QString help() = 0;
virtual void setupUi(QWidget *parent) = 0;
virtual void processImage(const cv::Mat &inputImage, cv::Mat &outputImage) = 0;
};
#define CVPLUGININTERFACE_IID "com.computervision.cvplugininterface"
Q_DECLARE_INTERFACE(CvPluginInterface, CVPLUGININTERFACE_IID)
#endif // CVPLUGIN_H
template_plugin_global.h文件
#ifndef TEMPLATE_PLUGIN_GLOBAL_H
#define TEMPLATE_PLUGIN_GLOBAL_H
#include <QtCore/qglobal.h>
#if defined(TEMPLATE_PLUGIN_LIBRARY)
# define TEMPLATE_PLUGINSHARED_EXPORT Q_DECL_EXPORT
#else
# define TEMPLATE_PLUGINSHARED_EXPORT Q_DECL_IMPORT
#endif
#endif // TEMPLATE_PLUGIN_GLOBAL_H
template_plugin.h文件
#ifndef TEMPLATE_PLUGIN_H
#define TEMPLATE_PLUGIN_H
#include "template_plugin_global.h"
#include "cvplugininterface.h"
namespace Ui {
class PluginGui;
}
//继承CvPluginInterface类,重写title(), version(), description(), help(), setupUi(QWidget *parent), processImage函数
class TEMPLATE_PLUGINSHARED_EXPORT Template_Plugin: public QObject, public CvPluginInterface
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "com.computervision.cvplugininterface")
Q_INTERFACES(CvPluginInterface)
public:
Template_Plugin();
~Template_Plugin();
QString title();
QString version();
QString description();
QString help();
void setupUi(QWidget *parent);
void processImage(const cv::Mat &inputImage, cv::Mat &outputImage);
signals:
void updateNeeded();
void errorMessage(QString msg);
void infoMessage(QString msg);
private:
Ui::PluginGui *ui;
};
#endif // TEMPLATE_PLUGIN_H
template_plugin.cpp文件
#include "template_plugin.h"
#include "ui_plugin.h"
Template_Plugin::Template_Plugin()
{
// Insert initialization codes here ...
}
Template_Plugin::~Template_Plugin()
{
// Insert cleanup codes here ...
}
QString Template_Plugin::title()
{
return this->metaObject()->className();
}
QString Template_Plugin::version()
{
return "1.0.0";
}
QString Template_Plugin::description()
{
return "A <b>Template</b> plugin";
}
QString Template_Plugin::help()
{
return "This is a <b>Template</b> plugin. Clone and use it to create new plugins.";
}
void Template_Plugin::setupUi(QWidget *parent)
{
ui = new Ui::PluginGui;
ui->setupUi(parent);
// Connect signals for GUI elemnts manually here since they won't be connected by name in a plugin
// ...
// emit updateNeeded(); should be added whenever parameters on the plugin GUI change
}
void Template_Plugin::processImage(const cv::Mat &inputImage, cv::Mat &outputImage)
{
// Replace the following line with the actual image processing task
inputImage.copyTo(outputImage);
// Otherwise, if the process doesn't affect the output image, update plugin GUI here ...
}
plugin.ui文件
app项目
mainapp.app
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = Computer_Vision
TEMPLATE = app
# The following define makes your compiler emit warnings if you use
# any feature of Qt which as been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
#win环境配置
win32:{
CONFIG(debug, debug|release){
DESTDIR += $$PWD/../../bin/win64d
LIBS += -L$$PWD/../../lib/win64d -lopencv_world480d
}else{
DESTDIR += $$PWD/../../bin/win64
LIBS += -L$$PWD/../../lib/win64 -lopencv_world480
}
}
INCLUDEPATH += ../../Include
INCLUDEPATH += ../cvplugininterface
SOURCES += \
main.cpp \
mainwindow.cpp \
qenhancedgraphicsview.cpp
HEADERS += \
mainwindow.h \
qenhancedgraphicsview.h
FORMS += \
mainwindow.ui
win32: {
include("c:/dev/opencv/opencv.pri")
}
unix: !macx{
CONFIG += link_pkgconfig
PKGCONFIG += opencv
}
unix: macx{
INCLUDEPATH += /usr/local/include
LIBS += -L"/usr/local/lib" \
-lopencv_world
}
# Add more language entries here, following the same naming rule
TRANSLATIONS = language_tr.ts
qenhancedgraphicsview.h文件
#ifndef QENHANCEDGRAPHICSVIEW_H
#define QENHANCEDGRAPHICSVIEW_H
#include <QWidget>
#include <QGraphicsView>
#include <QWheelEvent>
#include <QMouseEvent>
#include <QtMath>
#include <QContextMenuEvent>
#include <QMenu>
#include <QGraphicsItem>
#include <QDebug>
#include <QGraphicsEffect>
class QEnhancedGraphicsView : public QGraphicsView
{
Q_OBJECT
public:
explicit QEnhancedGraphicsView(QWidget *parent = nullptr);
protected:
void wheelEvent(QWheelEvent *event);
signals:
public slots:
private:
QPointF sceneMousePos;
};
#endif // QENHANCEDGRAPHICSVIEW_H
qenhancedgraphicsview.cpp文件
#include "qenhancedgraphicsview.h"
QEnhancedGraphicsView::QEnhancedGraphicsView(QWidget *parent)
: QGraphicsView(parent)
{
}
void QEnhancedGraphicsView::wheelEvent(QWheelEvent *event)
{
if (event->orientation() == Qt::Vertical)
{
double angleDeltaY = event->angleDelta().y();
double zoomFactor = qPow(1.0015, angleDeltaY);
scale(zoomFactor, zoomFactor);
if(angleDeltaY > 0)
{
this->centerOn(sceneMousePos);
sceneMousePos = this->mapToScene(event->pos());
}
this->viewport()->update();
event->accept();
}
else
{
event->ignore();
}
}
mainwindow.h文件
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QSettings>
#include <QCloseEvent>
#include <QMessageBox>
#include <QDir>
#include <QFileInfoList>
#include <QLibrary>
#include <QPluginLoader>
#include <QDebug>
#include <QFileDialog>
#include <QLabel>
#include <QGraphicsScene>
#include <QPushButton>
#include <QGraphicsProxyWidget>
#include <QTranslator>
#include <QThread>
#include <QThreadPool>
#include <QRunnable>
#include <QMutex>
#include <QWaitCondition>
#include "cvplugininterface.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
protected:
void closeEvent(QCloseEvent *event);
void changeEvent(QEvent *event);
private slots:
void onPluginActionTriggered(bool);
void onLanguageActionTriggered(bool);
void onThemeActionTriggered(bool);
void onCurrentPluginUpdateNeeded();
void onCurrentPluginErrorMessage(QString msg);
void onCurrentPluginInfoMessage(QString msg);
void on_actionAboutQt_triggered();
void on_actionExit_triggered();
void on_actionOpenImage_triggered();
void on_viewOriginalCheck_toggled(bool checked);
void on_actionSaveImage_triggered();
void on_action_Camera_triggered();
private:
Ui::MainWindow *ui;
void loadSettings();
void saveSettings();
QString currentThemeFile;
QString currentLanguageFile;
QString currentPluginFile;
void populatePluginsMenu();
void populateLanguagesMenu();
void populateThemesMenu();
QPointer<QPluginLoader> currentPlugin;
QPointer<QWidget> currentPluginGui;
QGraphicsScene scene;
QTranslator translator;
QGraphicsPixmapItem originalPixmap, processedPixmap;
cv::Mat originalMat, processedMat;
QImage originalImage, processedImage;
};
#endif // MAINWINDOW_H
mainwindow.cpp文件
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
#define PLUGINS_SUBFOLDER "/cvplugins/"
//#define PLUGINS_SUBFOLDER "/filter_plugins/"
#define LANGUAGES_SUBFOLDER "/languages/"
#define THEMES_SUBFOLDER "/themes/"
#define FILE_ON_DISK_DYNAMIC_PROPERTY "absolute_file_path"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
loadSettings(); // First thing's first, load settings
//加载插件菜单
populatePluginsMenu();
//加载多语言菜单
populateLanguagesMenu();
//加载主题菜单
populateThemesMenu();
ui->graphicsView->setScene(&scene);
scene.addItem(&originalPixmap);
scene.addItem(&processedPixmap);
ui->graphicsView->setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
}
MainWindow::~MainWindow()
{
delete currentPlugin;
delete ui;
}
void MainWindow::loadSettings()
{
QSettings settings("Packt", "Computer_Vision", this);
currentThemeFile = settings.value("currentThemeFile", "").toString();
currentLanguageFile = settings.value("currentLanguageFile", "").toString();
currentPluginFile = settings.value("currentPluginFile", "").toString();
}
void MainWindow::saveSettings()
{
QSettings settings("Packt", "Computer_Vision", this);
settings.setValue("currentThemeFile", currentThemeFile);
settings.setValue("currentLanguageFile", currentLanguageFile);
settings.setValue("currentPluginFile", currentPluginFile);
}
void MainWindow::changeEvent(QEvent *event)
{
if(event->type() == QEvent::LanguageChange)
{
ui->retranslateUi(this);
}
else
{
QMainWindow::changeEvent(event);
}
}
void MainWindow::closeEvent(QCloseEvent *event)
{
int result = QMessageBox::warning(this, tr("Exit"), tr("Are you sure you want to exit?"), QMessageBox::Yes, QMessageBox::No);
if(result == QMessageBox::Yes)
{
saveSettings();
event->accept();
}
else
{
event->ignore();
}
}
void MainWindow::populatePluginsMenu()
{
// Load all plugins and populate the menus
QDir pluginsDir(qApp->applicationDirPath() + PLUGINS_SUBFOLDER);
//QDir pluginsDir(qApp->applicationDirPath());
QFileInfoList pluginFiles = pluginsDir.entryInfoList(QDir::NoDotAndDotDot | QDir::Files, QDir::Name);
qDebug() << "MainWindow::populatePluginsMenu=====================pluginFiles.size========" << pluginFiles.size();
foreach(QFileInfo pluginFile, pluginFiles)
{
if(QLibrary::isLibrary(pluginFile.absoluteFilePath()))
{
QPluginLoader pluginLoader(pluginFile.absoluteFilePath(), this);
if(CvPluginInterface *plugin = dynamic_cast<CvPluginInterface*>(pluginLoader.instance()))
{
QAction *pluginAction = ui->menu_Plugins->addAction(plugin->title());
pluginAction->setProperty(FILE_ON_DISK_DYNAMIC_PROPERTY, pluginFile.absoluteFilePath());
connect(pluginAction, SIGNAL(triggered(bool)), this, SLOT(onPluginActionTriggered(bool)));
if(currentPluginFile == pluginFile.absoluteFilePath())
{
pluginAction->trigger();
}
}
else
{
QMessageBox::warning(this, tr("Warning"),
QString(tr("Make sure %1 is a correct plugin for this application<br>"
"and it's not in use by some other application!")).arg(pluginFile.fileName()));
}
}
else
{
QMessageBox::warning(this, tr("Warning"),
QString(tr("Make sure only plugins exist in %1 folder.<br>"
"%2 is not a plugin."))
.arg(PLUGINS_SUBFOLDER)
.arg(pluginFile.fileName()));
}
}
if(ui->menu_Plugins->actions().count() <= 0)
{
QMessageBox::critical(this, tr("No Plugins"), QString(tr("This application cannot work without plugins!"
"<br>Make sure that %1 folder exists "
"in the same folder as the application<br>and that "
"there are some filter plugins inside it")).arg(PLUGINS_SUBFOLDER));
this->setEnabled(false);
}
}
void MainWindow::populateLanguagesMenu()
{
QMenu *languagesMenu = new QMenu(this);
// Add default (english) language
QAction *defaultLanguageAction = languagesMenu->addAction("English - US");
defaultLanguageAction->setProperty(FILE_ON_DISK_DYNAMIC_PROPERTY, "");
connect(defaultLanguageAction, SIGNAL(triggered(bool)), this, SLOT(onLanguageActionTriggered(bool)));
// Load all languages and populate the menus
QDir languagesDir(qApp->applicationDirPath() + LANGUAGES_SUBFOLDER);
QFileInfoList languageFiles = languagesDir.entryInfoList(QStringList() << "*.qm", QDir::NoDotAndDotDot | QDir::Files, QDir::Name);
foreach(QFileInfo languageFile, languageFiles)
{
QAction *languageAction = languagesMenu->addAction(languageFile.baseName());
languageAction->setProperty(FILE_ON_DISK_DYNAMIC_PROPERTY, languageFile.absoluteFilePath());
connect(languageAction, SIGNAL(triggered(bool)), this, SLOT(onLanguageActionTriggered(bool)));
if(currentLanguageFile == languageFile.absoluteFilePath())
{
languageAction->trigger();
}
}
ui->actionLanguage->setMenu(languagesMenu);
}
void MainWindow::populateThemesMenu()
{
QMenu *themesMenu = new QMenu(this);
// Add default (native) theme
QAction *defaultThemeAction = themesMenu->addAction("Default");
defaultThemeAction->setProperty(FILE_ON_DISK_DYNAMIC_PROPERTY, "");
connect(defaultThemeAction, SIGNAL(triggered(bool)), this, SLOT(onThemeActionTriggered(bool)));
// Load all themes and populate the menus
QDir themesDir(qApp->applicationDirPath() + THEMES_SUBFOLDER);
QFileInfoList themeFiles = themesDir.entryInfoList(QStringList() << "*.thm", QDir::NoDotAndDotDot | QDir::Files, QDir::Name);
foreach(QFileInfo themeFile, themeFiles)
{
QAction *themeAction = themesMenu->addAction(themeFile.baseName());
themeAction->setProperty(FILE_ON_DISK_DYNAMIC_PROPERTY, themeFile.absoluteFilePath());
connect(themeAction, SIGNAL(triggered(bool)), this, SLOT(onThemeActionTriggered(bool)));
if(currentThemeFile == themeFile.absoluteFilePath())
{
themeAction->trigger();
}
}
ui->actionTheme->setMenu(themesMenu);
}
void MainWindow::on_actionAboutQt_triggered()
{
qApp->aboutQt();
}
void MainWindow::on_actionExit_triggered()
{
close();
}
//加载插件
void MainWindow::onPluginActionTriggered(bool)
{
if(!currentPlugin.isNull())
{
delete currentPlugin;
delete currentPluginGui;
}
qDebug() << "MainWindow::onPluginActionTriggered====================currentPlugin========" << currentPlugin.isNull();
currentPluginFile = QObject::sender()->property(FILE_ON_DISK_DYNAMIC_PROPERTY).toString();
currentPlugin = new QPluginLoader(currentPluginFile, this);
currentPluginGui = new QWidget(this);
ui->pluginLayout->addWidget(currentPluginGui);
CvPluginInterface *currentPluginInstance = dynamic_cast<CvPluginInterface*>(currentPlugin->instance());
if(currentPluginInstance)
{
currentPluginInstance->setupUi(currentPluginGui);
connect(currentPlugin->instance(), SIGNAL(updateNeeded()), this, SLOT(onCurrentPluginUpdateNeeded()));
connect(currentPlugin->instance(), SIGNAL(infoMessage(QString)), this, SLOT(onCurrentPluginInfoMessage(QString)));
connect(currentPlugin->instance(), SIGNAL(errorMessage(QString)), this, SLOT(onCurrentPluginErrorMessage(QString)));
}
}
void MainWindow::onLanguageActionTriggered(bool)
{
currentLanguageFile = QObject::sender()->property(FILE_ON_DISK_DYNAMIC_PROPERTY).toString();
qApp->removeTranslator(&translator);
if(!currentLanguageFile.isEmpty())
{
translator.load(currentLanguageFile);
qApp->installTranslator(&translator);
ui->retranslateUi(this);
}
}
void MainWindow::onThemeActionTriggered(bool)
{
currentThemeFile = QObject::sender()->property(FILE_ON_DISK_DYNAMIC_PROPERTY).toString();
QFile themeFile(currentThemeFile);
if(currentThemeFile.isEmpty())
{
qApp->setStyleSheet("");
}
else
{
themeFile.open(QFile::ReadOnly | QFile::Text);
QString styleSheet = themeFile.readAll();
qApp->setStyleSheet(styleSheet);
themeFile.close();
}
}
void MainWindow::on_actionOpenImage_triggered()
{
QString fileName = QFileDialog::getOpenFileName(this,
tr("Open Input Image"),
QDir::currentPath(),
tr("Images") + " (*.jpg *.png *.bmp)");
using namespace cv;
originalMat = imread(fileName.toStdString());
if(!originalMat.empty())
{
onCurrentPluginUpdateNeeded();
}
else if(!fileName.trimmed().isEmpty())
{
QMessageBox::critical(this,
tr("Error"),
tr("Make sure the image file exists "
"and it is accessible!"));
}
}
void MainWindow::on_viewOriginalCheck_toggled(bool checked)
{
originalPixmap.setVisible(checked);
processedPixmap.setVisible(!checked);
}
void MainWindow::onCurrentPluginUpdateNeeded()
{
if(!originalMat.empty())
{
if(!currentPlugin.isNull())
{
CvPluginInterface *currentPluginInstance = dynamic_cast<CvPluginInterface*>(currentPlugin->instance());
if(currentPluginInstance)
{
cv::TickMeter meter;
meter.start();
currentPluginInstance->processImage(originalMat, processedMat);
meter.stop();
qDebug() << "The process took " << meter.getTimeMilli() << "milliseconds";
}
}
else
{
processedMat = originalMat.clone();
}
originalImage = QImage(originalMat.data, originalMat.cols, originalMat.rows, originalMat.step, QImage::Format_RGB888);
originalPixmap.setPixmap(QPixmap::fromImage(originalImage.rgbSwapped()));
processedImage = QImage(processedMat.data, processedMat.cols, processedMat.rows, processedMat.step, QImage::Format_RGB888);
processedPixmap.setPixmap(QPixmap::fromImage(processedImage.rgbSwapped()));
}
}
void MainWindow::on_actionSaveImage_triggered()
{
if(!ui->viewOriginalCheck->isChecked() && !processedMat.empty())
{
QString fileName = QFileDialog::getSaveFileName(this, tr("Save Image"), QDir::currentPath(), "*.jpg;;*.png;;*.bmp");
if(!fileName.isEmpty())
{
cv::imwrite(fileName.toStdString(), processedMat);
}
}
else if(ui->viewOriginalCheck->isChecked() && !originalMat.empty())
{
QString fileName = QFileDialog::getSaveFileName(this, tr("Save Image"), QDir::currentPath(), "*.jpg;;*.png;;*.bmp");
if(!fileName.isEmpty())
{
cv::imwrite(fileName.toStdString(), originalMat);
}
}
else
{
QMessageBox::warning(this, tr("Warning"), tr("There is nothing to be saved!"));
}
}
void MainWindow::onCurrentPluginErrorMessage(QString msg)
{
qDebug() << "Plugin Error Message : " << msg;
}
void MainWindow::onCurrentPluginInfoMessage(QString msg)
{
qDebug() << "Plugin Info Message : " << msg;
}
void MainWindow::on_action_Camera_triggered()
{
}
main.cpp文件
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
a.setStyle("fusion");
MainWindow w;
w.showMaximized();
return a.exec();
}
language_tr.ts文件
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="tr_TR">
<context>
<name>MainWindow</name>
<message>
<location filename="mainwindow.ui" line="20"/>
<source>Computer Vision</source>
<translation>Computer Vision</translation>
</message>
<message>
<location filename="mainwindow.ui" line="35"/>
<source>Plugin UI</source>
<translation>Plugin Arayüzü</translation>
</message>
<message>
<location filename="mainwindow.ui" line="47"/>
<source>View</source>
<translation>Görüntü</translation>
</message>
<message>
<location filename="mainwindow.ui" line="72"/>
<source>&File</source>
<translation>&Dosya</translation>
</message>
<message>
<location filename="mainwindow.ui" line="85"/>
<source>&Plugins</source>
<translation>&Pluginler</translation>
</message>
<message>
<location filename="mainwindow.ui" line="90"/>
<source>O&ptions</source>
<translation>&Seçenekler</translation>
</message>
<message>
<location filename="mainwindow.ui" line="97"/>
<source>&Help</source>
<translation>&Yardım</translation>
</message>
<message>
<location filename="mainwindow.ui" line="108"/>
<source>&Open Image</source>
<translation>&Resim Seç</translation>
</message>
<message>
<location filename="mainwindow.ui" line="113"/>
<source>Open &Video</source>
<translation>&Video Seç</translation>
</message>
<message>
<location filename="mainwindow.ui" line="118"/>
<source>Open &Camera</source>
<translation>&Kamera</translation>
</message>
<message>
<location filename="mainwindow.ui" line="123"/>
<source>Open &RTSP</source>
<translation>&RTSP Seç</translation>
</message>
<message>
<location filename="mainwindow.ui" line="128"/>
<source>&Save Image</source>
<translation>Resim Ka&ydet</translation>
</message>
<message>
<location filename="mainwindow.ui" line="133"/>
<source>E&xit</source>
<translation>&Çıkış</translation>
</message>
<message>
<location filename="mainwindow.ui" line="138"/>
<source>&About Qt</source>
<translation>&Qt Hakkında</translation>
</message>
<message>
<location filename="mainwindow.ui" line="143"/>
<source>Language</source>
<translation>Dil</translation>
</message>
<message>
<location filename="mainwindow.ui" line="148"/>
<source>Theme</source>
<translation>Stil</translation>
</message>
<message>
<location filename="mainwindow.cpp" line="52"/>
<source>Exit</source>
<translation>Çıkış</translation>
</message>
<message>
<location filename="mainwindow.cpp" line="52"/>
<source>Are you sure you want to exit?</source>
<translation>Çıkmak istediğinizden emin misiniz?</translation>
</message>
<message>
<location filename="mainwindow.cpp" line="82"/>
<location filename="mainwindow.cpp" line="89"/>
<source>Warning</source>
<translation>Dikkat</translation>
</message>
<message>
<location filename="mainwindow.cpp" line="83"/>
<source>Make sure %1 is a correct plugin for this application<br>and it's not in use by some other application!</source>
<translation>%1 doğru bir plugin değil. Lütfen kontrol ediniz.<br>Başka bir program bu plugin'i kullanıyor olabilir!</translation>
</message>
<message>
<location filename="mainwindow.cpp" line="90"/>
<source>Make sure only plugins exist in %1 folder.<br>%2 is not a plugin.</source>
<oldsource>Make sure only plugins exist in plugins folder.<br>%1 is not a plugin.</oldsource>
<translation>Sadece pluginlerin %1 klasöründe olduğundan emin olunuz.<br>%2 bir plugin değildir.</translation>
</message>
<message>
<location filename="mainwindow.cpp" line="99"/>
<source>No Plugins</source>
<translation>Plugin bulunamadı</translation>
</message>
<message>
<location filename="mainwindow.cpp" line="99"/>
<source>This application cannot work without plugins!<br>Make sure that %1 folder exists in the same folder as the application<br>and that there are some filter plugins inside it</source>
<translation>Bu program pluginler olmadan çalışmaz.<br>%1 klasörünün programla aynı klasörde olduğundan emin olunuz<br>ve içinde en az bir plugin olduğunu kontrol ediniz</translation>
</message>
<message>
<source>This application cannot work without plugins!<br>Make sure that filter_plugins folder exists in the same folder as the application<br>and that there are some filter plugins inside it</source>
<translation type="obsolete">Bu program pluginler olmadan çalışmaz.<br></translation>
</message>
</context>
</TS>
mainwindow.ui文件