2016-02-25 3 views
3

Je travaille sur une application utilisant Qt version 4.8 en C++.Comment créer un gestionnaire dans Qt?

J'ai besoin d'utiliser une fonction C qui nécessite un pointeur vers une fonction libre:

void handler(int dummy) 

Je dois changer les valeurs affichées dans mon interface graphique en fonction de ce qui se passe à l'intérieur de la fonction. J'ai donc lu sur la façon de convertir une fonction membre à une fonction gratuite. J'ai découvert que je ne peux le faire que si ma fonction de membre est statique.

Mais je ne peux pas le rendre statique - je ne pourrai pas changer de widget si je le rend statique.

Alors, comment puis-je résoudre le problème? Comment puis-je passer une fonction membre non statique en tant que pointeur vers une fonction libre. Si ce n'est pas possible, comment faire une solution de contournement?

Je serai reconnaissant pour toute suggestion différente que utilise une autre bibliothèque.

+0

devez-vous passer la fonction à une « interface c » ou pouvez-vous utiliser des modèles? Si les templates fonctionnent, vous pouvez utiliser un objet functor – Zaiborg

+0

Non, je ne peux pas utiliser les templates. Il doit s'agir d'une fonction. – user2738748

+0

D'où vient la valeur du paramètre 'dummy'? – Ilya

Répondre

1

Oui, C++ ne permet pas de transmettre des fonctions membres en tant que pointeur de fonction aux bibliothèques C.

Dans ce cas, une approche commune utilise une fonction d'assistance qui agit comme un pont entre la bibliothèque C et notre instance de classe. Cette fonction d'assistance est une fonction libre qui prend un pointeur sur l'instance actuelle de la classe et appelle dans son corps la méthode membre correspondante de l'instance de classe.

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

Et où vous invoquez une fonction de cette bibliothèque C, vous devez passer handler_helper comme le pointeur de fonction et (int) this comme argument.

+1

Est-ce que '(int) this' est toujours correct? – Ilya

+0

@Ilya En supposant que tous les pointeurs et entiers ont 4 octets, oui. –

+0

La présomption de 4 octets pour les pointeurs est très dangereuse. Je dirais que «(int) this» est probablement UB. – Ilya

2

Puisque la fonction C prend un argument, vous pouvez utiliser l'argument comme un indice dans un tableau de foncteurs:

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(); 
}; 

Les getHandler renvoie l'adresse de la fonction de gestionnaire. Le getIndexFor renvoie l'argument à transmettre au gestionnaire pour exécuter un foncteur donné. Le foncteur peut encapsuler des appels aux méthodes du widget. Ici, nous appellerons setWindowTitle sur le widget:

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

Bien! Mais êtes-vous sûr de pouvoir contrôler la valeur du paramètre 'dummy'? Il pourrait être défini par la bibliothèque C ...?Aussi, êtes-vous sûr que son compilateur comprendra cette construction (il est sur Qt 4.8, pour le compilateur qu'il n'a pas dit)? – Ilya

+0

@Ilya Le paramètre 'dummy' est un idiome. L'API serait inutilisable autrement. De plus, Qt 4.8 ne vous empêche pas d'utiliser un compilateur moderne. Ce qui précède fonctionne très bien sous Qt 4.8 et MSVC 2012, par exemple. –

+0

"Qt 4.8 ne vous empêche pas d'utiliser un compilateur moderne", cela ne vous empêche pas non plus d'être bloqué dans une ancienne chaîne d'outils (par exemple, du matériel embarqué). – Ilya