Введение.
Анализируя замечания предыдущего поста (Qt Designer & Runtime Qt библиотеки на службе OpenCV...), пришлось более детально проработать устройство видеозахвата библиотеки OpenCV и методы разделения библиотек runtime и виджетов.
Работа с Qt Designer удобна (я — лентяй), поэтому и возник компонент проектирования интерфейса для CvCapture. После начала работы подтянулось и «научное » тому объяснение — удобно применить нечто похожее, скажем, при проектировании интерфейса свойств или параметров приложения, использующего устройство видеозахвата.
Пока идёт скачивание архива проекта, читайте далее.
Благодарности.
Спасибо всем, кто оставил свои замечания по предыдущему посту.
Библиотека времени выполнения.
Итак, библиотека OpenCV установлена, примеры кода просмотрены. Самое время «прикрутить» устройство видеозахвата к Qt. Да не просто так, а чтобы и изображения получать, меняя устройства динамически. Да, чтобы помнило все пути к изображению, видео. Да, чтобы и номера камер переключало. Да, чтобы и… пост покороче получился.
Библиотека.
Чего проще! Наследуем новый класс библиотеки от QObject, прячем ненужные разработчику поля и методы в приватный класс как элемент коллекции QScopedPointer, монтируем сигналы оповещения и слоты-обработчики.
Получаем файл заголовка cqtopencvcaptureobject.h
#ifndef CQTOPENCVCAPTUREOBJECT_H
#define CQTOPENCVCAPTUREOBJECT_H
#include "../../../include/qtopencv_global.h"
#include <opencv2/opencv.hpp>
#include <QObject>
#include <QScopedPointer>
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
/*----------------------------------------------------------------------------*/
/**
internal
class CQtOpenCVCaptureObjectPrivate
brief Класс скрытого для стороннего разработчика объявлений свойст и реализаций
механизмов работы с устройством видеозахвата типа CvCapture библиотеки OpenCV.
*/
class CQtOpenCVCaptureObjectPrivate;
/*----------------------------------------------------------------------------*/
/**
class CQtOpenCVCaptureObject
brief Класс Работы с устройством видеозахвата типа CvCapture библиотеки OpenCV.
*/
class
#if defined(QTOPENCV_LIB_EXPORT)
QTOPENCV_DECLARE_EXPORT
#else
Q_DECL_EXPORT
#endif
CQtOpenCVCaptureObject : public QObject
{
Q_OBJECT
Q_CLASSINFO("brief", "OpenCV Capture class.")
Q_CLASSINFO("author", "Vladimir N. Litvinenko")
Q_CLASSINFO("URL", "http://www.codepaint.ru")
Q_CLASSINFO("email", "litvinenko.vladimir@gmail.com")
Q_CLASSINFO("created", "21-JUN-2012")
Q_CLASSINFO("edited", "06-JUL-2012")
public:
explicit
CQtOpenCVCaptureObject ( QObject *parent = 0 );
virtual
~CQtOpenCVCaptureObject ();
CvCapture* getCapture () const;
QString getPath () const;
int getNumber () const;
int getTimeoutInterval () const;
IplImage* getImage () const;
int getFrameCount () const;
bool isInternal () const;
bool isExternal () const;
bool isActive () const;
bool isRecap () const;
signals:
/**
fn [SIGNAL] void CQtOpenCVCaptureObject::signal_Errno ( int errno, const QString& errmsg );
brief Сигнал оповещения о возникновении ошибочной ситуации.
param errno - номер ошибки
param errmsg - строка сообщения
*/
void signal_Errno ( int, const QString& );
/**
fn [SIGNAL] void CQtOpenCVCaptureObject::signal_CaptureChanged ()
brief Сигнал оповещения об изменении устройства видеозахвата
*/
void signal_CaptureChanged ();
/**
fn [SIGNAL] void CQtOpenCVCaptureObject::signal_CaptureChanged ( const CvCapture* value )
brief Сигнал оповещения об изменении устройства видеозахвата
param value - указател на новое устройство видеозахвата типа CvCapture
библиотеки OpenCV
*/
void signal_CaptureChanged ( const CvCapture* );
/**
fn [SIGNAL] void CQtOpenCVCaptureObject::signal_ImageChanged ( const IplImage* value )
brief Сигнал оповещения об изменении указателя на изображение типа IplImage
библиотеки OpenCV.
param value - новый указатель на изображение типа IplImage библиотеки OpenCV.
*/
void signal_ImageChanged ( const IplImage* );
/**
fn [SIGNAL] void CQtOpenCVCaptureObject::signal_TimeoutChanged ()
brief Сигнал оповещения об изменении таймаута запроса изображения
*/
void signal_TimeoutChanged ();
/**
fn [SIGNAL] void CQtOpenCVCaptureObject::signal_TimeoutChanged ( int value )
brief Сигнал оповещения об изменении таймаута запроса изображения
param value - новое значение таймаута запроса изображения
*/
void signal_TimeoutChanged ( int );
/**
fn [SIGNAL] void CQtOpenCVCaptureObject::signal_ActiveChanged ( bool value )
brief Сигнал оповещения смены статуса активности запроса изображения от
устройства видеозахвата по тайм-ауту.
param value - новое значение активности процесса запроса. Значение true
говорит о выполнении, а false - об останове процесса запроса
по тайм-ауту.
*/
void signal_ActiveChanged ( bool );
public slots:
void slot_SetNumber ( int );
void slot_SetPath ( const QString& );
void slot_SetAsInternal ( bool );
void slot_SetTimeout ( int );
void slot_captureOn ( bool );
void slot_Activate (bool);
void slot_SetRecap (bool);
protected:
virtual
void timerEvent(QTimerEvent *event);
private:
Q_DISABLE_COPY(CQtOpenCVCaptureObject)
Q_DECLARE_PRIVATE(CQtOpenCVCaptureObject)
QScopedPointer<CQtOpenCVCaptureObjectPrivate> d_ptr;
};
/*----------------------------------------------------------------------------*/
QT_END_NAMESPACE
QT_END_HEADER
#endif // CQTOPENCVCAPTUREOBJECT_H
Слоты:
- slot_SetNumber отвечает за установку номера камеры
- slot_SetPath нацеливает устройство видеозахвата файл изображения, видео или web-CGI URL
- slot_SetAsInternal указывает, что устройство видеозахвата — камера вашего компьютера (по-моему, лишнее. Сами решите)
- slot_SetTimeout устанавливает время извлечения фрейма из CvCapture в миллисекундах
- slot_captureOn включает/отключает работу CvCapture
- slot_Activate активирует/отключает режим запроса фрейма по таймауту
- slot_SetRecap указывает устройству видеозахвата, что перед извлечением фрейма (изображения) необходимо… пересоздаться. Нужно бывает при использовании web-интерфейса к камерам
Жизнь научила ставить комментарии. Думаю, вам всё понятно.
В файле .pro
подключим библиотеки OpenCV
unix: LIBS += -L/usr/lib/ -lopencv_core -lopencv_highgui
INCLUDEPATH += /usr/include/opencv2/core
/usr/include/opencv2/highgui
DEPENDPATH += /usr/include/opencv2/core
/usr/include/opencv2/highgui
Всё. Библиотека создана. Проверим её работу.
Тестовый пример.
Создадим графический интерфейс к нашему устройству видеозахвата. Зачем графический? Всё просто: мы используем его и компоненты форматирования при построении виджета в коллекции плагинов к Qt Designer.
Не буду утруждать рисунками, вы найдёте форму в каталоге examples проекта testCaptureRuntime
Укажем видеофайл:
Скорость кадров можно регулировать значением таймаута, «поиграйте» с ним.
Переключим на встроенную в компьютер камеру:
Переключим на внешнюю IP-камеру:
Библиотека работает.
Сегодня добавил в OpenCV поддержку камер Smartek Giganetix на основе их GigEVisionSDK. Возможно, скоро выйдет, но я обязательно напишу в дальнейшем, как подключать своё устройство к списку видеозахвата OpenCV.
Библиотека на основе QWidget.
Здесь всё так же несложно, как и при создании биьблиотеки времени исполнения. Только «родитель» у класса QWidget, и прячем в приватный класс экземпляр нашего runtime класса.
В .pro
файл помещаем
DEFINES += QDESIGNER_EXPORT_WIDGETS
Больше нет необходимости подключать библиотеку OpenCV, она пойдёт по зависимости от runtime-библиотеки.
А, вот, её, родимую, и прикрутим:
unix: LIBS += -L/usr/lib -lQtOpenCVCapture
INCLUDEPATH += $$PWD/../../runtime/capture/QtOpenCVCapture
DEPENDPATH += /usr/lib
Обратите внимание! Путь указывает на /usr/lib
. Это удобно. В дальнейшем, просто создайте символическую ссылку на вашу библиотеку в этом каталоге, и не будет проблем с линковкой!
Объявим свойства виджета для дизайнера:
...
Q_PROPERTY(
bool visible
READ isVisible
WRITE slot_setVisible
)
Q_PROPERTY(
bool internal
READ isInternal
WRITE slot_SetAsInternal
)
Q_PROPERTY(
QString path
READ getPath
WRITE slot_SetPath
)
Q_PROPERTY(
int number
READ getNumber
WRITE slot_SetNumber
)
Q_PROPERTY(
int numberMax
READ getNumberMax
WRITE slot_SetNumberMax
)
Q_PROPERTY(
int timeout
READ getTimeoutInterval
WRITE slot_SetTimeout
)
Q_PROPERTY(
int timeoutMax
READ getTimeoutMax
WRITE slot_SetTimeoutMax
)
Q_PROPERTY(
int timeoutStep
READ getTimeoutStep
WRITE slot_SetTimeoutStep
)
Q_PROPERTY(
bool recapture
READ isRecap
WRITE slot_SetRecap
)
Q_PROPERTY(
QString FrameTitle
READ getFrameTitle
WRITE slot_setFrameTitle
)
Q_PROPERTY(
QString GroupBoxTitle
READ getGroupBoxTitle
WRITE slot_setGroupBoxTitle
)
Q_PROPERTY(
QString RadioNumberTitle
READ getRadioNumberTitle
WRITE slot_setRadioNumberTitle
)
Q_PROPERTY(
QString RadioPathTitle
READ getRadioPathTitle
WRITE slot_setRadioPathTitle
)
Q_PROPERTY(
QString PathTitle
READ getPathTitle
WRITE slot_setPathTitle
)
Q_PROPERTY(
QString NumberTitle
READ getNumberTitle
WRITE slot_setNumberTitle
)
Q_PROPERTY(
QString TimeOutTitle
READ getTimeOutTitle
WRITE slot_setTimeOutTitle
)
Q_PROPERTY(
QString TimeOutExtTitle
READ getTimeOutExtTitle
WRITE slot_setTimeOutExtTitle
)
Q_PROPERTY(
QString RecaptureTitle
READ getRecaptureTitle
WRITE slot_setRecaptureTitle
)
...
Расширим набор слотов и методов для поддержки свойств:
...
//собственные методы доступа
bool isVisible () const;
QString getFrameTitle () const;
QString getGroupBoxTitle () const;
QString getRadioNumberTitle () const;
QString getRadioPathTitle () const;
QString getPathTitle () const;
QString getNumberTitle () const;
QString getTimeOutTitle () const;
QString getTimeOutExtTitle () const;
QString getRecaptureTitle () const;
...
//собственные слоты
void slot_setVisible( bool );
void slot_setFrameTitle( const QString& );
void slot_setGroupBoxTitle( const QString& );
void slot_setRadioNumberTitle( const QString& );
void slot_setRadioPathTitle( const QString& );
void slot_setPathTitle( const QString& );
void slot_setNumberTitle( const QString& );
void slot_setTimeOutTitle( const QString& );
void slot_setTimeOutExtTitle( const QString& );
void slot_setRecaptureTitle( const QString& );
void slot_SetNumberMax ( int );
void slot_SetTimeoutMax ( int );
void slot_SetTimeoutStep ( int );
...
Скопируем настройки окна из тестового примера runtime- библиотеки:
/*----------------------------------------------------------------------------*/
void
CQtOpenCVCaptureWidgetPrivate::setupUi ( QWidget* parent )
{
p_Frame = new QFrame(parent);
Q_ASSERT(p_Frame);
p_Frame->setObjectName(QString::fromUtf8("p_Frame"));
p_Frame->resize(550, 195);
p_Frame->setMinimumSize(QSize(550, 195));
// p_Frame->setMaximumSize(QSize(550, 195));
p_Frame->setFrameShape(QFrame::StyledPanel);
p_Frame->setFrameShadow(QFrame::Raised);
p_gridLayout_Frame = new QGridLayout(p_Frame);
Q_ASSERT(p_gridLayout_Frame);
p_gridLayout_Frame->setObjectName(QString::fromUtf8("p_gridLayout_Frame"));
p_groupBox_Capture = new QGroupBox(p_Frame);
Q_ASSERT(p_groupBox_Capture);
p_groupBox_Capture->setObjectName(QString::fromUtf8("p_groupBox_Capture"));
QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
sizePolicy.setHorizontalStretch(0);
sizePolicy.setVerticalStretch(0);
sizePolicy.setHeightForWidth(p_groupBox_Capture->sizePolicy().hasHeightForWidth());
p_groupBox_Capture->setSizePolicy(sizePolicy);
// p_groupBox_Capture->setMinimumSize(QSize(540, 190));
// p_groupBox_Capture->setMaximumSize(QSize(540, 185));
p_groupBox_Capture->setFlat(true);
p_gridLayout_GBox = new QGridLayout(p_groupBox_Capture);
Q_ASSERT(p_gridLayout_GBox);
p_gridLayout_GBox->setSpacing(1);
p_gridLayout_GBox->setContentsMargins(3, 3, 3, 3);
p_gridLayout_GBox->setObjectName(QString::fromUtf8("p_gridLayout_GBox"));
p_horLayout_Radio = new QHBoxLayout();
Q_ASSERT(p_horLayout_Radio);
p_horLayout_Radio->setSpacing(1);
p_horLayout_Radio->setObjectName(QString::fromUtf8("p_horLayout_Radio"));
p_radioButton_URL = new QRadioButton(p_groupBox_Capture);
Q_ASSERT(p_radioButton_URL);
p_radioButton_URL->setObjectName(QString::fromUtf8("p_radioButton_URL"));
p_horLayout_Radio->addWidget(p_radioButton_URL);
p_radioButton_Number = new QRadioButton(p_groupBox_Capture);
Q_ASSERT(p_radioButton_Number);
p_radioButton_Number->setObjectName(QString::fromUtf8("p_radioButton_Number"));
p_radioButton_Number->setChecked(true);
p_horLayout_Radio->addWidget(p_radioButton_Number);
p_gridLayout_GBox->addLayout(p_horLayout_Radio, 0, 0, 1, 1);
p_horLayout_PathNum = new QHBoxLayout();
Q_ASSERT(p_horLayout_PathNum);
p_horLayout_PathNum->setSpacing(3);
p_horLayout_PathNum->setObjectName(QString::fromUtf8("p_horLayout_PathNum"));
p_label_PathNum = new QLabel(p_groupBox_Capture);
Q_ASSERT(p_label_PathNum);
p_label_PathNum->setObjectName(QString::fromUtf8("p_label_PathNum"));
QSizePolicy sizePolicy1(QSizePolicy::Fixed, QSizePolicy::Preferred);
sizePolicy1.setHorizontalStretch(0);
sizePolicy1.setVerticalStretch(0);
sizePolicy1.setHeightForWidth(p_label_PathNum->sizePolicy().hasHeightForWidth());
p_label_PathNum->setSizePolicy(sizePolicy1);
p_label_PathNum->setMinimumSize(QSize(150, 0));
p_label_PathNum->setLayoutDirection(Qt::LeftToRight);
p_label_PathNum->setFrameShape(QFrame::NoFrame);
p_label_PathNum->setAlignment(Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter);
p_horLayout_PathNum->addWidget(p_label_PathNum);
p_spinBox_Number = new QSpinBox(p_groupBox_Capture);
Q_ASSERT(p_spinBox_Number);
p_spinBox_Number->setObjectName(QString::fromUtf8("p_spinBox_Number"));
sizePolicy.setHeightForWidth(p_spinBox_Number->sizePolicy().hasHeightForWidth());
p_spinBox_Number->setSizePolicy(sizePolicy);
p_spinBox_Number->setMinimum(0);
p_spinBox_Number->setMaximum(999999);
p_horLayout_PathNum->addWidget(p_spinBox_Number);
p_lineEdit = new QLineEdit(p_groupBox_Capture);
Q_ASSERT(p_lineEdit);
p_lineEdit->setObjectName(QString::fromUtf8("p_lineEdit"));
p_lineEdit->setEnabled(true);
p_horLayout_PathNum->addWidget(p_lineEdit);
p_gridLayout_GBox->addLayout(p_horLayout_PathNum, 1, 0, 1, 1);
p_horLayout_TOut = new QHBoxLayout();
Q_ASSERT(p_horLayout_TOut);
p_horLayout_TOut->setSpacing(3);
p_horLayout_TOut->setObjectName(QString::fromUtf8("p_horLayout_TOut"));
p_label_TOut = new QLabel(p_groupBox_Capture);
Q_ASSERT(p_label_TOut);
p_label_TOut->setObjectName(QString::fromUtf8("p_label_TOut"));
sizePolicy1.setHeightForWidth(p_label_TOut->sizePolicy().hasHeightForWidth());
p_label_TOut->setSizePolicy(sizePolicy1);
p_label_TOut->setMinimumSize(QSize(150, 0));
p_horLayout_TOut->addWidget(p_label_TOut);
p_spinBox_TOut = new QSpinBox(p_groupBox_Capture);
Q_ASSERT(p_spinBox_TOut);
p_spinBox_TOut->setObjectName(QString::fromUtf8("p_spinBox_TOut"));
sizePolicy.setHeightForWidth(p_spinBox_TOut->sizePolicy().hasHeightForWidth());
p_spinBox_TOut->setSizePolicy(sizePolicy);
p_spinBox_TOut->setMinimum(0);
p_spinBox_TOut->setMaximum(999999);
p_horLayout_TOut->addWidget(p_spinBox_TOut);
p_label_ms = new QLabel(p_groupBox_Capture);
Q_ASSERT(p_label_ms);
p_label_ms->setObjectName(QString::fromUtf8("p_label_ms"));
sizePolicy1.setHeightForWidth(p_label_ms->sizePolicy().hasHeightForWidth());
p_label_ms->setSizePolicy(sizePolicy1);
p_horLayout_TOut->addWidget(p_label_ms);
p_horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Preferred, QSizePolicy::Minimum);
Q_ASSERT(p_horizontalSpacer);
p_horLayout_TOut->addItem(p_horizontalSpacer);
p_gridLayout_GBox->addLayout(p_horLayout_TOut, 2, 0, 1, 1);
p_horLayout_Buttons = new QHBoxLayout();
Q_ASSERT(p_horLayout_Buttons);
p_horLayout_Buttons->setSpacing(3);
p_horLayout_Buttons->setObjectName(QString::fromUtf8("p_horLayout_Buttons"));
p_checkBox_Recap = new QCheckBox(p_groupBox_Capture);
Q_ASSERT(p_checkBox_Recap);
p_checkBox_Recap->setObjectName(QString::fromUtf8("p_checkBox_Recap"));
sizePolicy.setHeightForWidth(p_checkBox_Recap->sizePolicy().hasHeightForWidth());
p_checkBox_Recap->setSizePolicy(sizePolicy);
p_horLayout_Buttons->addWidget(p_checkBox_Recap);
p_pushButton_Test = new QPushButton(p_groupBox_Capture);
Q_ASSERT(p_pushButton_Test);
p_pushButton_Test->setObjectName(QString::fromUtf8("p_pushButton_Test"));
p_pushButton_Test->setCheckable(true);
p_pushButton_Test->setChecked(false);
p_horLayout_Buttons->addWidget(p_pushButton_Test);
p_gridLayout_GBox->addLayout(p_horLayout_Buttons, 3, 0, 1, 1);
p_gridLayout_Frame->addWidget(p_groupBox_Capture, 0, 0, 1, 1);
#ifndef QT_NO_SHORTCUT
p_label_PathNum->setBuddy(p_lineEdit);
#endif // QT_NO_SHORTCUT
retranslateUi();
QMetaObject::connectSlotsByName(p_Frame);
}
Подключим сигналы и слоты:
/*----------------------------------------------------------------------------*/
void
CQtOpenCVCaptureWidgetPrivate::setupConnections ()
{
// перенаправление сигналов runtime-объекта на выход виджета
q_obj->connect (q_obj, SIGNAL(signal_Errno(int,QString)), q_ptr, SIGNAL(signal_Errno(int,QString)));
q_obj->connect (q_obj, SIGNAL(signal_CaptureChanged()), q_ptr, SIGNAL(signal_CaptureChanged()));
q_obj->connect (q_obj, SIGNAL(signal_CaptureChanged(const CvCapture*)), q_ptr, SIGNAL(signal_CaptureChanged(const CvCapture*)));
q_obj->connect (q_obj, SIGNAL(signal_ImageChanged(const IplImage*)), q_ptr, SIGNAL(signal_ImageChanged(const IplImage*)));
q_obj->connect (q_obj, SIGNAL(signal_TimeoutChanged()), q_ptr, SIGNAL(signal_TimeoutChanged()));
q_obj->connect (q_obj, SIGNAL(signal_TimeoutChanged(int)), q_ptr, SIGNAL(signal_TimeoutChanged(int)));
q_obj->connect (q_obj, SIGNAL(signal_ActiveChanged(bool)), q_ptr, SIGNAL(signal_ActiveChanged(bool)));
// установка обработки переключения устройств получения видеоинформации
q_ptr->connect (p_radioButton_Number,SIGNAL(toggled(bool)), q_ptr, SLOT(slot_SetAsInternal(bool)));
q_ptr->connect (p_radioButton_URL, SIGNAL(toggled(bool)), q_ptr, SLOT(slot_SetAsExternal(bool)));
// обработка редактирования и ввода строки пути устроцства видеозахвата
q_ptr->connect (p_lineEdit, SIGNAL(textChanged(QString)), q_ptr, SLOT(slot_SetPath(QString)));
q_ptr->connect (p_lineEdit, SIGNAL(returnPressed()), q_ptr, SLOT(slot_PathComplete()));
// установка обработки изменения номера встроенной вебкамеры
q_ptr->connect (p_spinBox_Number, SIGNAL(valueChanged(int)), q_ptr, SLOT(slot_SetNumber(int)));
// установка обработки изменения тайм-аута опроса устройства
q_ptr->connect (p_spinBox_TOut, SIGNAL(valueChanged(int)), q_ptr, SLOT(slot_SetTimeout(int)));
// установка обработки изменения включения реинициализации устройства видеозахвата в каждом тайм-ауте
q_ptr->connect (p_checkBox_Recap, SIGNAL(toggled(bool)), q_ptr, SLOT(slot_SetRecap(bool)));
// установка обработки сигнала к тестированию
q_ptr->connect (p_pushButton_Test, SIGNAL(toggled(bool)), q_ptr, SLOT(slot_Test(bool)));
// q_ptr->connect (q_ptr, SIGNAL(signal_ImageChanged(const IplImage*)), q_ptr, SLOT(slot_ShowImage(const IplImage*)));
}
/*----------------------------------------------------------------------------*/
Собираем библиотеку на основе виджета.
Плагин к Дизайнеру.
Настало время подключить нашу QWidget-библиотеку к Qt Designer.
Создадим проект-коллекцию.
CONFIG += designer plugin debug_and_release
TARGET = $$qtLibraryTarget(CQtOpenCVCollection)
TEMPLATE = lib
DEFINES += QDESIGNER_EXPORT_WIDGETS
HEADERS = cqtopencvcapturewidgetplugin.h cqtopencvcollection.h
SOURCES = cqtopencvcapturewidgetplugin.cpp cqtopencvcollection.cpp
RESOURCES = icons.qrc
//target.path = $$[QT_INSTALL_PLUGINS]/designer
INSTALLS += target
#include(cqtopencvimagewidget.pri)
include(cqtopencvcapturewidget.pri)
#include(cqtopencvcannywidget.pri)
unix: LIBS += -L/usr/lib/ -lQtOpenCVCaptureWidget
INCLUDEPATH += $$PWD/
DEPENDPATH += $$PWD/
Объявим класс плагина.
#ifndef CQTOPENCVCAPTUREWIDGETPLUGIN_H
#define CQTOPENCVCAPTUREWIDGETPLUGIN_H
#include <QDesignerCustomWidgetInterface>
#include <QtDesigner/QDesignerExportWidget>
class
#if defined(QDESIGNER_EXPORT_WIDGETS)
QDESIGNER_WIDGET_EXPORT
#else
Q_DECL_EXPORT
#endif
CQtOpenCVCaptureWidgetPlugin : public QObject, public QDesignerCustomWidgetInterface
{
Q_OBJECT
Q_INTERFACES(QDesignerCustomWidgetInterface)
public:
CQtOpenCVCaptureWidgetPlugin(QObject *parent = 0);
bool isContainer() const;
bool isInitialized() const;
QIcon icon() const;
QString domXml() const;
QString group() const;
QString includeFile() const;
QString name() const;
QString toolTip() const;
QString whatsThis() const;
QWidget *createWidget(QWidget *parent);
void initialize(QDesignerFormEditorInterface *core);
private:
bool m_initialized;
};
Объявим класс коллекции:
#ifndef CQTOPENCVCOLLECTION_H
#define CQTOPENCVCOLLECTION_H
#include <QtDesigner/QtDesigner>
#include <QtCore/qplugin.h>
class CQtOpenCVCollection : public QObject, public QDesignerCustomWidgetCollectionInterface
{
Q_OBJECT
Q_INTERFACES(QDesignerCustomWidgetCollectionInterface)
public:
explicit CQtOpenCVCollection(QObject *parent = 0);
virtual QList<QDesignerCustomWidgetInterface*> customWidgets() const;
private:
QList<QDesignerCustomWidgetInterface*> m_widgets;
};
#endif
Реализация:
#include "cqtopencvcapturewidgetplugin.h"
//#include "cqtopencvimagewidgetplugin.h"
//#include "cqtopencvcannywidgetplugin.h"
#include "cqtopencvcollection.h"
CQtOpenCVCollection::CQtOpenCVCollection(QObject *parent)
: QObject(parent)
{
m_widgets.append(new CQtOpenCVCaptureWidgetPlugin(this));
// m_widgets.append(new CQtOpenCVImageWidgetPlugin(this));
// m_widgets.append(new CQtOpenCVCannyWidgetPlugin(this));
}
QList<QDesignerCustomWidgetInterface*> CQtOpenCVCollection::customWidgets() const
{
return m_widgets;
}
Q_EXPORT_PLUGIN2(CQtOpenCVCollection, CQtOpenCVCollection)
Обратите внимание на
// m_widgets.append(new CQtOpenCVImageWidgetPlugin(this));
// m_widgets.append(new CQtOpenCVCannyWidgetPlugin(this));
После реализаций плагинов CQtOpenCVImageWidgetPlugin
и CQtOpenCVCannyWidgetPlugin
комментарии можно будет убрать. И в группе OpenCV компонент Qt Designer появятся новые элементы.
Тестовый пример.
После сборки всех библиотек, корректного назначения ссылок и установки ссылки на коллекцию в каталог плагинов для Qt Designer можно создать тестовый пример.
В Дизайнере создаём MainWindow, помещаем наш виджет, собираем.
Видим:
Заключение.
- Ещё раз, Исходные коды проекта.
- Попробуйте добавить ComboBox для выбора типа камер
- НЕе пишите, пожалуйса, «а можно сделать так». Просто, сделайте. Коды в вашем распоряжении
Спасибо за внимание.
Автор: coffeesmoke