2016-02-25 3 views
3

Я работаю над приложением, использующим Qt версии 4.8 в C++.Как создать обработчик в Qt?

мне нужно использовать функцию C, которая требует указатель на свободную функцию:

void handler(int dummy) 

Мне нужно изменить отображаемые значения в моем GUI в зависимости от того, что происходит внутри функции.

Итак, я читал о том, как преобразовать функцию-член в свободную функцию. Я узнал, что могу сделать это, только если моя функция-член статична.

Но я не могу сделать его статическим - я не смогу изменить какие-либо виджеты, если стану его статичным.

Итак, как я могу справиться с проблемой? Как передать нестационарную функцию-член как указатель на свободную функцию. Если это невозможно, как сделать обходной путь?

Буду благодарен за любые предложения, отличающиеся тем, что используйте другую библиотеку.

+0

вам нужно передать функции в «C» интерфейса или вы можете использовать шаблоны? если шаблоны будут работать, вы можете использовать объект-функтор – Zaiborg

+0

Нет, я не могу использовать шаблоны. Это должна быть функция. – user2738748

+0

Откуда берется значение параметра 'dummy'? – Ilya

ответ

1

Да, C++ не позволяет передавать функции-члены в качестве указателя функции на библиотеки C.

В этом случае общий подход использует вспомогательную функцию, которая действует как мост между библиотекой C и нашим экземпляром класса. Эта вспомогательная функция является свободной функцией, которая берет указатель на текущий экземпляр класса и в своем теле вызывает соответствующий метод-член экземпляра класса.

void handler_helper(int data){ 
    MyClass *obj = (MyClass *) data; 
    obj->handler(); // This is the corresponding member method 
} 

А где вы вызываете функции из этой библиотеки C, вы должны пройти handler_helper как указатель функции и (int) this в качестве аргумента.

+1

Действительно ли '(int) это правильно? – Ilya

+0

@Ilya Предполагая, что все указатели и целые числа равны 4 байтам, да. –

+0

Предположение 4 байта для указателей довольно опасно. Я бы сказал, что '(int) это, вероятно, UB. – Ilya

2

Поскольку функция C принимает аргумент, вы можете использовать аргумент в качестве индекса в массиве функторов:

class MyWidget : public QWidget { 
    using vector_t = QVector<std::function<void()>>; 
    static vector_t m_functions; 
public: 
    using function_type = void(*)(int); 
    using size_type = vector_t::size_type; 

    static function_type getHandler() { 
    return +[](int index){ MyWidget::m_functions[index]; }; 
    } 
    template <typename F> static size_type getIndexFor(F && fun) { 
    m_functions.append(std::forward<F>(fun)); 
    return m_functions.size() - 1; 
    } 
    //... 
    size_type getIndexForSetTitle(); 
}; 

The getHandler возвращает адрес функции обработчика. getIndexFor возвращает аргумент, который должен быть передан обработчику для запуска заданного функтора. Функтор может инкапсулировать вызовы методам виджетов. Здесь мы будем называть setWindowTitle на виджете:

MyWidget::size_type MyWidget::getIndexForSetTitle() { 
    static size_type index = getIndexFor([this]{ setWindowTitle("Foo"); }); 
    return index; 
} 
+0

Ницца! Но уверены ли вы, что вы можете контролировать значение параметра 'dummy'? Он может быть установлен библиотекой C ...?Кроме того, вы уверены, что его компилятор поймет эту конструкцию (он на Qt 4.8, для компилятора он не сказал)? – Ilya

+0

@Ilya Параметр 'dummy' - это идиома. В противном случае API будет непригодным для использования. Кроме того, Qt 4.8 не мешает вам использовать современный компилятор. Вышеприведенное прекрасно работает под Qt 4.8 и MSVC 2012, например. –

+0

«Qt 4.8 не мешает вам использовать современный компилятор», это также не мешает вам застревать в старой инструментальной цепочке (например, некоторые встроенные элементы). – Ilya