Russian Qt Forum
Апрель 18, 2024, 22:31 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: [РЕШЕНО]Проблема с Singleton  (Прочитано 3965 раз)
Hvzh
Гость
« : Сентябрь 22, 2014, 09:11 »

Доброе время суток!

Пишу софт для удаленного управления фотокамерами Cannon. Использую связку EDSDK + OpenCV + Qt. Для сборки проекта - QtCreator + MSVC 2013 в качестве компайлера. Суть: переключить аппарат в режим LiveView и по картинке, показываемой в режиме реального времени ни экране компа, настраивать параметры фотокамеры. По достижении удобоваримой картинки  сфоткать ее и положить на HD компа.
Теперь о проблемах. EDSDK реализован в виде сишных вызовов плюс нужно зарегистрировать две Callback-функции для получения событий от фотокамеры. Сначала я быстро написал тестовый пример, состоящий из двух классов. Один отвечал за все, другой содержал только данные для настройки параметров фотокамеры. Для реализации callback'ов пришлось прибегнуть к синглтону. Вот как это выглядело в тестовом софте:
Код:
QtEOS.h
...
class QtEOS : public QMainWindow
{
    Q_OBJECT

public:
    virtual ~QtEOS();
    static QtEOS *getInstance();
    QtEOS();
    bool loadFile(const QString &);
    EdsCameraRef getCamera(){return camera;};
    boolean isEDSDKLoaded = false;

    //Callback's definitions
    static EdsError EDSCALLBACK handleObjectEvent(EdsObjectEvent event, EdsBaseRef object, EdsVoid * context);
    static EdsError EDSCALLBACK handleStateEvent(EdsStateEvent event, EdsUInt32 parameter, EdsVoid * context);
signals:
    void newImage(EdsBaseRef obj);
...
private:
    static QtEOS *m_instance;
...


Реализация:
Код:
QtEOS.cpp

QtEOS::QtEOS() : QMainWindow(0)
{
...
    m_instance = this;
...
    openEDSDK();
}

QtEOS* QtEOS::getInstance()
{
    if(m_instance == 0)
        m_instance = new QtEOS;
    return m_instance;
}

EdsError QtEOS::openEDSDK()
{
...
    err = EdsSetCameraStateEventHandler(camera, kEdsStateEvent_All, handleStateEvent, NULL);
...
Реализация хендлера:
Код:
EdsError EDSCALLBACK QtEOS::handleStateEvent(EdsStateEvent event, EdsUInt32 parameter, EdsVoid * context)
{
    switch(event) {
    case kEdsStateEvent_CaptureError:
        qDebug("Event: kEdsStateEvent_CaptureError,");
    case kEdsStateEvent_JobStatusChanged:
        qDebug("Event: kEdsStateEvent_JobStatusChanged,");
        break;
    case kEdsStateEvent_WillSoonShutDown:
        qDebug("Event: kEdsStateEvent_WillSoonShutDown,");
        getInstance()->EmitStatusSignal(kEdsStateEvent_WillSoonShutDown);
        break;
    default:
        break;
    }
    return EDS_ERR_OK;
}

При таком раскладе все работало. Теперь я решил для нормального проекта разобрать эту кашу, раскидав различный функционал по различным классам. В частности, в отдельный класс решил выделить все, что связано с удаленной работой с фотокамерой. В итоге получился такой класс:

Код:
CameraController.h

class CameraController : public QObject
{
    Q_OBJECT

public:
    virtual ~CameraController();
    static CameraController *getInstance();
    CameraController(QObject *parent = 0);
    static EdsError EDSCALLBACK handleObjectEvent(EdsObjectEvent event, EdsBaseRef object, EdsVoid * context);
    static EdsError EDSCALLBACK handleStateEvent(EdsStateEvent event, EdsUInt32 parameter, EdsVoid * context);
signals:
    void newImage(EdsBaseRef obj);
...
Реализация:
Код:
CameraController.cpp

CameraController::CameraController(QObject *parent) : QObject(parent)
{
    m_instance = this;
}

CameraController* CameraController::getInstance()
{
    if(m_instance == 0)
        m_instance = new CameraController;
    return m_instance;
}
...
EdsError EDSCALLBACK CameraController::handleStateEvent(EdsStateEvent event, EdsUInt32 parameter, EdsVoid * context)
{
    switch(event) {
    case kEdsStateEvent_CaptureError:
        qDebug("Event: kEdsStateEvent_CaptureError,");

    case kEdsStateEvent_JobStatusChanged:
        qDebug("Event: kEdsStateEvent_JobStatusChanged,");
        break;
    case kEdsStateEvent_WillSoonShutDown:
        qDebug("Event: kEdsStateEvent_WillSoonShutDown,");
        getInstance()->EmitStatusSignal(kEdsStateEvent_WillSoonShutDown);
        break;
    default:
        break;
    }
    return EDS_ERR_OK;
}


Теперь при компиляции получаю такую ошибку:
cameracontroller.obj:-1: error: LNK2001: неразрешенный внешний символ ""private: static class CameraController * CameraController::m_instance" (?m_instance@CameraController@@0PAV1@A)"
« Последнее редактирование: Сентябрь 26, 2014, 13:15 от Hvzh » Записан
alex312
Хакер
*****
Offline Offline

Сообщений: 606



Просмотр профиля
« Ответ #1 : Сентябрь 22, 2014, 09:34 »

http://www.c-cpp.ru/books/staticheskie-chleny-klassa
Записан
StLynx
Гость
« Ответ #2 : Сентябрь 22, 2014, 09:37 »

Добавте

Код:
CameraController * CameraController ::m_instance = 0;

в реализацию.
« Последнее редактирование: Сентябрь 22, 2014, 09:40 от StLynx » Записан
Hvzh
Гость
« Ответ #3 : Сентябрь 22, 2014, 09:58 »

alex312, StLynx,
Спасибо!
Записан
Hvzh
Гость
« Ответ #4 : Сентябрь 26, 2014, 09:42 »

Реанимирую данную тему, поскольку возникла еще одна проблема. В коде две callback - функции:

Код:
EdsError EDSCALLBACK CameraController::handleStateEvent(EdsStateEvent event, EdsUInt32 parameter, EdsVoid * context)
{
    switch(event) {
    case kEdsStateEvent_CaptureError:
        qDebug("Event: kEdsStateEvent_CaptureError");

    case kEdsStateEvent_JobStatusChanged:
        qDebug("Event: kEdsStateEvent_JobStatusChanged");
        break;
    case kEdsStateEvent_WillSoonShutDown:
        qDebug("Event: kEdsStateEvent_WillSoonShutDown");
        getInstance()->EmitStatusSignal(kEdsStateEvent_WillSoonShutDown);
        break;
    case kEdsStateEvent_Shutdown:
        qDebug("Event: kEdsStateEvent_Shutdown");
        getInstance()->EmitStatusSignal(kEdsStateEvent_Shutdown);
        break;
    default:
        break;
    }

    qDebug("Event code: 0x%X.\n", (int)event);

    return EDS_ERR_OK;
}

и

Код:
EdsError EDSCALLBACK CameraController::handleObjectEvent(EdsObjectEvent event, EdsBaseRef object, EdsVoid * context) {
    if(event == kEdsObjectEvent_DirItemCreated || event == kEdsObjectEvent_DirItemRequestTransfer || event == kEdsObjectEvent_DirItemRequestTransferDT)
    {
        getInstance()->EmitSignal(object);
    }

    return EDS_ERR_OK;
}

Обе посылают сигналы посредством, соответственно, getInstance()->EmitStatusSignal и getInstance()->EmitSignal. Однако в случае первой callback - функции сигнал не шлется почему-то... Функции выглядят следующим образом:

Код:
void CameraController::EmitStatusSignal(long status)
{
    switch (status) {
    case kEdsStateEvent_WillSoonShutDown:
        sendShutdownTimer();
        break;
    case kEdsStateEvent_Shutdown:
        qDebug() << "CameraController::takeStatus before emit";
        emit cameraOff();
        qDebug() << "CameraController::takeStatus after emit";
        break;
    default:
        break;
    }
}

Код:
void CameraController::EmitSignal(EdsBaseRef obj)
{
    emit newImage(obj);
}

В итоге сигнал newImage нормально ловится классом, который ответственен за интерфейс пользователя, а сигнал cameraOff до него не доходит. Вот вывод с консоли:
Код:
Event: kEdsStateEvent_Shutdown
CameraController::takeStatus before emit
CameraController::takeStatus after emit
Event code: 0x301.
Записан
Hvzh
Гость
« Ответ #5 : Сентябрь 26, 2014, 13:12 »

Решилось путем отказа от синглтона
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.373 секунд. Запросов: 23.