Différences entre les connexions basées sur des chaînes de caractères et celles basées sur des foncteurs
Qt propose deux façons différentes d'écrire des connexions signal-slot en C++ : la syntaxe de connexion basée sur des chaînes de caractères et la syntaxe de connexion basée sur des foncteurs. Ces deux syntaxes présentent chacune des avantages et des inconvénients. Le tableau ci-dessous résume leurs différences.
| Caractéristique | Basée sur des chaînes de caractères | Basée sur les foncteurs |
|---|---|---|
| Vérification des types | Effectuée à l'exécution | Effectuée à la compilation |
| Permet d'effectuer des conversions de types implicites. | Non | Oui |
| Permet de lier des signaux à des expressions lambda. | Non | Oui |
| Permet de relier des signaux à des slots comportant plus d'arguments que le signal (en utilisant des paramètres par défaut). | Oui | Non |
| Permet de connecter des fonctions C++ à des fonctions QML. | Oui | Non |
Les sections suivantes expliquent ces différences en détail et montrent comment utiliser les fonctionnalités propres à chaque syntaxe de connexion.
Vérification des types et conversions implicites de types
Les connexions basées sur des chaînes de caractères effectuent la vérification des types en comparant les chaînes lors de l'exécution.
Les limitations suivantes s'appliquent :
| Limitation | Raison |
|---|---|
| Les erreurs de connexion ne peuvent être détectées qu'une fois que le programme a commencé à s'exécuter. | Sans objet |
| Les conversions implicites ne sont pas possibles entre les signaux et les slots. | Le comparateur de chaînes n'a pas accès aux informations de type C++ ; il s'appuie donc sur la correspondance exacte des chaînes. |
| Les définitions de type (typedefs) et les espaces de noms ne peuvent pas être résolus. |
En revanche, les connexions basées sur des foncteurs sont vérifiées par le compilateur. Ce dernier détecte les erreurs lors de la compilation, autorise les conversions implicites entre types compatibles et reconnaît les différents noms d'un même type.
Par exemple, seule la syntaxe basée sur les foncteurs peut être utilisée pour connecter un signal transportant une ` int ` à un slot acceptant une ` double`. Une ` QSlider ` contient une valeur de type ` int `, tandis qu’une ` QDoubleSpinBox ` contient une valeur de type ` double `. L’extrait de code suivant montre comment les synchroniser :
auto slider = new QSlider(this);
auto doubleSpinBox = new QDoubleSpinBox(this);
// OK: The compiler can convert an int into a double
connect(slider, &QSlider::valueChanged,
doubleSpinBox, &QDoubleSpinBox::setValue);
// ERROR: The string table doesn't contain conversion information
connect(slider, SIGNAL(valueChanged(int)),
doubleSpinBox, SLOT(setValue(double)));L'exemple suivant illustre l'absence de résolution de nom. La fonction `QAudioInput::stateChanged()` est déclarée avec un argument de type « `QAudio::State` ». Ainsi, les connexions basées sur des chaînes de caractères doivent également spécifier « `QAudio::State` », même si ` "State" ` est déjà visible. Ce problème ne concerne pas les connexions basées sur des foncteurs, car les types d’arguments ne font pas partie de la connexion.
auto audioInput = new QAudioInput(QAudioFormat(), this);
auto widget = new QWidget(this);
// OK
connect(audioInput, SIGNAL(stateChanged(QAudio::State)),
widget, SLOT(show()));
// ERROR: The strings "State" and "QAudio::State" don't match
using namespace QAudio;
connect(audioInput, SIGNAL(stateChanged(State)),
widget, SLOT(show()));
// ...Établir des connexions vers des expressions lambda
La syntaxe de connexion basée sur les foncteurs permet de relier des signaux à des expressions lambda, qui sont en réalité des slots en ligne. Cette fonctionnalité n'est pas disponible avec la syntaxe basée sur des chaînes de caractères.
Dans l'exemple suivant, la classe `TextSender` émet un signal ` textCompleted() ` qui transporte un paramètre ` QString `. Voici la déclaration de la classe :
class TextSender : public QWidget {
Q_OBJECT
QLineEdit *lineEdit;
QPushButton *button;
signals:
void textCompleted(const QString& text) const;
public:
TextSender(QWidget *parent = nullptr);
};Voici la connexion qui émet « TextSender::textCompleted() » lorsque l'utilisateur clique sur le bouton :
TextSender::TextSender(QWidget *parent) : QWidget(parent) {
lineEdit = new QLineEdit(this);
button = new QPushButton("Send", this);
connect(button, &QPushButton::clicked, [=] {
emit textCompleted(lineEdit->text());
});
// ...
}Dans cet exemple, la fonction lambda a simplifié la connexion, même si QPushButton::clicked() et TextSender::textCompleted() ont des paramètres incompatibles. En revanche, une implémentation basée sur des chaînes de caractères nécessiterait du code de routine supplémentaire.
Remarque : la syntaxe de connexion basée sur les foncteurs accepte les pointeurs vers toutes les fonctions, y compris les fonctions autonomes et les fonctions membres classiques. Toutefois, pour des raisons de lisibilité, les signaux ne doivent être connectés qu’à des slots, des expressions lambda et d’autres signaux.
Connexion d'objets C++ à des objets QML
La syntaxe basée sur les chaînes de caractères permet de connecter des objets C++ à des objets QML, contrairement à la syntaxe basée sur les functors. En effet, les types QML sont résolus lors de l'exécution et ne sont donc pas disponibles pour le compilateur C++.
Dans l'exemple suivant, cliquer sur l'objet QML provoque l'affichage d'un message par l'objet C++, et inversement. Voici le type QML (dans QmlGui.qml) :
Rectangle {
width: 100; height: 100
signal qmlSignal(string sentMsg)
function qmlSlot(receivedMsg) {
console.log("QML received: " + receivedMsg)
}
MouseArea {
anchors.fill: parent
onClicked: qmlSignal("Hello from QML!")
}
}Voici la classe C++ :
class CppGui : public QWidget {
Q_OBJECT
QPushButton*button;
signals:
void cppSignal(const QVariant& sentMsg) const;
public slots:
void cppSlot(const QString& receivedMsg) const {
qDebug() << "C++ received:" << receivedMsg;
}
public:
CppGui(QWidget*parent = nullptr) : QWidget(parent) {
button = new QPushButton("Cliquez ici !", this);
connect(button, &QPushButton::clicked, [=] {
emit cppSignal("Bonjour depuis C++ !");
});
}
};Voici le code qui établit les connexions signal-slot :
auto cppObj = new CppGui(this);
auto quickWidget = new QQuickWidget(QUrl("QmlGui.qml"), this);
auto qmlObj = quickWidget->rootObject();
// Connect QML signal to C++ slot
connect(qmlObj, SIGNAL(qmlSignal(QString)),
cppObj, SLOT(cppSlot(QString)));
// Connect C++ signal to QML slot
connect(cppObj, SIGNAL(cppSignal(QVariant)),
qmlObj, SLOT(qmlSlot(QVariant)));Remarque : toutes les fonctions JavaScript dans QML prennent des paramètres de type var, qui correspond au type QVariant en C++, sauf si elles utilisent des annotations de type. Voir Appel de méthodes QML pour plus de détails.
Lorsque l'on clique sur l'QPushButton, la console affiche « QML a reçu : "Bonjour depuis C++ !" ». De même, lorsque l'on clique sur le Rectangle, la console affiche « C++ a reçu : "Bonjour depuis QML !" ».
Consultez la section Interagir avec des objets QML depuis C++ pour découvrir d’autres moyens de permettre aux objets C++ d’interagir avec des objets QML.
Utilisation des paramètres par défaut dans les slots pour se connecter à des signaux avec moins de paramètres
En règle générale, une connexion ne peut être établie que si le slot possède le même nombre d'arguments que le signal (ou moins), et si tous les types d'arguments sont compatibles.
La syntaxe de connexion sous forme de chaîne de caractères offre une solution de contournement à cette règle : si le slot dispose de paramètres par défaut, ceux-ci peuvent être omis dans le signal. Lorsque le signal est émis avec moins d'arguments que le slot, Qt exécute le slot en utilisant les valeurs par défaut des paramètres.
Les connexions basées sur des foncteurs ne prennent pas en charge cette fonctionnalité.
Supposons qu’il existe une classe appelée ` DemoWidget ` avec un slot ` printNumber() ` qui comporte un argument par défaut :
public slots:
void printNumber(int number = 42) {
qDebug() << "Lucky number" << number;
}En utilisant une connexion basée sur une chaîne de caractères, DemoWidget::printNumber() peut être connecté à QApplication::aboutToQuit(), même si cette dernière ne prend aucun argument. La connexion basée sur un foncteur générera une erreur de compilation :
DemoWidget::DemoWidget(QWidget*parent) : QWidget(parent) {
// OK : printNumber() sera appelée avec une valeur par défaut de 42
connect(qApp, SIGNAL(aboutToQuit()),
this, SLOT(printNumber()));
// ERREUR : le compilateur exige des arguments compatibles
connect(qApp, &QCoreApplication::aboutToQuit,
this, &DemoWidget::printNumber);
}Pour contourner cette limitation avec la syntaxe basée sur les foncteurs, connectez le signal à une fonction lambda qui appelle le slot. Reportez-vous à la section ci-dessus, « Établir des connexions avec des expressions lambda ».
Sélection des signaux et slots surchargés
Avec la syntaxe basée sur des chaînes de caractères, les types de paramètres sont explicitement spécifiés. Par conséquent, l’instance souhaitée d’un signal ou d’un slot surchargé ne prête à aucune ambiguïté.
En revanche, avec la syntaxe basée sur les foncteurs, vous devez spécifier explicitement à quelle version d’un signal ou d’un slot surchargé vous souhaitez vous connecter.
Par exemple, QLCDNumber propose trois versions du slot « display() » :
QLCDNumber::display(int)QLCDNumber::display(double)QLCDNumber::display(QString)
Pour connecter la version de ` int ` à ` QSlider::valueChanged()`, les deux syntaxes sont les suivantes :
auto slider = new QSlider(this);
auto lcd = new QLCDNumber(this);
// String-based syntax
connect(slider, SIGNAL(valueChanged(int)),
lcd, SLOT(display(int)));
// Functor-based syntax
connect(slider, &QSlider::valueChanged,
lcd, qOverload<int>(&QLCDNumber::display));Pour des exemples complets de connexion à des signaux et des slots surchargés à l’aide de ` qOverload()`, `static_cast` et des lambdas, consultez la section Connexion à des signaux et des slots surchargés.
Voir également ` qOverload()`.
© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.