Folco (./68) :
Par contre, une question de parentalité : pourquoi les parents des QWidgets sont-ils des QWidgets, et non des QObjects ? C'est pas grave, mais c'est juste pour comprendre, j'ai lu la doc sur la hiérarchie des objets dans un programme, donc je comprends pas trop pourquoi dans une application, on passe de l'un à l'autre.
Parce que la notion d'appartenance pour les QWidgets est particulière: En plus de l'appartenance de QObject, elle signifie aussi que le widget est contenu graphiquement dans son parent. (En particulier, une fenêtre n'a pas de parent.) Un widget ne peut pas être contenu dans un objet non graphique.
Si tu veux absolument insérer une fenêtre dans une hiérarchie de QObject, quelque chose comme ça devrait fonctionner:
class WidgetWrapper : public QObject, public QScopedPointer<QWidget> {
Q_OBJECT
public:
WidgetWrapper(QWidget *wrapped, QObject *parent = nullptr) : QObject(parent), QScopedPointer<QWidget>(wrapped) {}
virtual ~WidgetWrapper() {}
private:
Q_DISABLE_COPY(WidgetWrapper)
}
et ensuite là où tu voudrais écrire
new MyWidget(parent), tu écris
new WidgetWrapper(new MyWidget(), parent) à la place.
- est-ce qu'il vaut mieux utiliser les macros SIGNAL/SLOT, ou la forme &classe::méthode des connections ? Ou est-ce qu'on s'en fout ? En fait, je ne sais pas pourquoi la méthode est surchargée, il y a des cas où on ne peut pas faire sans l'un ou l'autre ?
Les macros SIGNAL/SLOT étaient la seule forme jusqu'à Qt 4, et a été gardée surtout pour des raisons de compatibilité. La nouvelle forme est la version C++11 (enfin, elle est aussi permise en C++98 si le slot n'a pas plus de 6 arguments, le C++11 rajoute les templates variadiques, ce qui permet un nombre arbitraire d'arguments). L'avantage de la nouvelle forme est qu'elle permet de vérifier les types en temps de compilation au lieu de travailler avec des chaînes de caractéres (les macros SIGNAL et SLOT stringifient (!) leur contenu, toutes les vérifications de type sont faites lors de l'appel) et est donc aussi plus rapide. Le désavantage est qu'il faut préciser le nom de la classe. De plus, (avantage) tant qu'il y a une seule surcharge de la méthode, on n'a pas besoin de préciser les arguments, mais (désavantage) quand il y en a plusieurs, choisir la bonne méthode devient compliqué (et on ne peut pas utiliser les arguments optionnels avec une valeur par défaut).
Cf.
http://wiki.qt.io/New_Signal_Slot_Syntax.
- la méthode se surcharge avec un "functor", c'est une simple fonction comme en C, ça ?
Un foncteur est un objet qui implémente
operator(). Ça peut être un simple pointeur de fonction (mais en général, dans ce cas, il vaut mieux utiliser une méthode avec la syntaxe précédente), mais aussi une expression lambda C++11 (c'est surtout pour ça que cette syntaxe existe), un objet
tr1::bind ou n'importe quel objet qui implémente un
operator() avec les bons arguments.
- j'appelle le slot "trigger" quand on clique sur le bouton, est-ce que ça pourrait etre un problème d'appeler directement le signal "triggered" de l'action ? ou est-ce que c'est strictement identique ?
Connecter un signal directement à un autre est possible en théorie, mais tu es censé faire ça uniquement pour connecter un signal d'une autre classe directement à un signal de
ta classe, pas l'inverse! Tu n'es pas censé appeler directement un signal d'une autre classe. Rien ne te dit que le slot
trigger ne fasse pas plus qu'émettre le signal
triggered. Donc la seule solution conforme á l'interface voulue est de connecter le signal reçu au slot
trigger de l'action.
- est-ce qu'un destructeur d'objet qui a établi des connexions doit les détruire manuellement dans le destructeur, ou est-ce automatique ?
C'est automatique.