FAQ Qt

Quelques questions fréquemment posées sur Qt …

Ce document est en cours de rédaction.
Dernière modification : 07/06/2017 (rev. 2)

Vous pouvez consulter la FAQ Qt (fr) très complète du site developpez.com.

QString et les chaînes de caractères

Comment convertir un nombre en QString ?

On utilise la méthode statique QString::number() pour convertir des nombres.

QString dix = QString::number(10); // en entier

QString a = QString::number(10, 16); // en hexadécimal

double d = 0.5;
QString unDemi = QString::number(d); // un double

QString unTiers = QString::number(1./3., 'f', 2); // avec une précision

Comment convertir un QString en nombre ?

La classe QString fournit des méthodes pour convertir une chaîne de caractères en nombre : toInt(), toLong(), toFloat(), toDouble(), …

QString dix = "10";
int i = dix.toInt();

QString unDemi = "0.5";
double d = unDemi.toDouble();

De plus ces méthodes possèdent des paramètres optionnels :

  • un pointeur vers un booléen permettra de vérifier si la conversion a été possible ou pas ;
  • la base pour les types entiers.
QString str = "FF";
bool ok;
int n = str.toInt(&ok, 16);
qDebug() << n << ok; // 255 true

Remarque : lire Comment afficher des messages de débogage ? pour voir l’utilisation de qDebug().

Comment formater une chaîne de caractères ?

La classe QString fournit la méthode arg() pour formater une chaîne de caractères.

int age = 20;
QString str = QString("J'ai %1 ans").arg(age); // "J'ai 20 ans"

int age = 20;
double taille = 1.99;
QString str = QString("J'ai %1 ans et je mesure %2.").arg(age).arg(taille); // "J'ai 20 ans et je mesure 1.99."

int n = 10;
QString str = QString("0x") + QString("%1").arg(n, 2, 16, QChar('0')).toUpper(); // en hexadécimal : "0x0A"

Remarque : La méthode arg() possède énormément de versions différentes. Documentation : doc.qt.io/qt-4.8/qstring.html

Comment convertir un QString en nombre hexadécimal et réciproquement ?

Pour obtenir une chaîne de caractères en hexadécimal :

int dix = 10; // en entier

QString a = QString::number(dix, 16); // a en hexadécimal

À partir d’une chaîne de caractères en hexadécimal :

QString str = "0A"; // une valeur en hexadécimal

bool ok;
int dix = str.toInt(&ok, 16);
qDebug() << n << ok; // 10 true

Remarque : lire Comment afficher des messages de débogage ? pour voir l’utilisation de qDebug().

Comment encoder les caractères avec QString ?

Par défaut, QString encode les chaînes de caractères en ISO 8859-1 (latin-1) remplaçant le standard ASCII mais il ne couvre pas complètement le français. En France, nous utilisons l’encodage ISO 8859-15 (latin-9) qui pallie ces problèmes. Sous Unix/Linux, l’encodage par défaut est l’UTF-8.

Il est possible d’encoder directement une chaîne de caractères en utilisant les méthodes statiques QString::fromAscii(), QString::fromLatin1(), QString::fromUtf8() et QString::fromLocal8Bit().

Si vous rencontrez des problèmes d’encodage (par exemple les accents), utilisez la méthode qui correspond :

QString str = QString::fromUtf8("Une chaîne de caractères");

La classe QTextCodec fournit des conversions entre les encodages de texte.

Il est possible de choisir son encodage de manière générale avec la méthode statique QTextCodec::setCodecForCStrings() :

QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));

Comment effectuer un traitement avec un QString ?

La classe QString contient de nombreuses méthodes pour manipuler des chaînes de caractère. Sa documentation : doc.qt.io/qt-4.8/qstring.html.

Quelques méthodes intéressantes pour faire un traitement sur une trame par exemple :

  • startsWith() et endsWith() pour vérifier les délimiteurs de début de trame (par exemple le dollar $) et de fin de trame (par exemple la séquence “\r\n”)
  • contains() ou count() pour détecter (ou compter) la présence de certains caractères (le plus souvent des délimiteurs comme la virgule ,, le point-virgule ; ou l’étoile *)
  • section() ou split() pour le découpage à partir de délimiteurs (comme la virgule ,, le point-virgule ; …) ou mid() pour une extraction sans délimiteur
  • replace() pour le remplacement et remove() pour la suppression de caractères
  • indexOf() pour obtenir la position d’un caractère

Vérifier le format d’une trame NMEA0183 GGA :

QString phrase = "$GPGGA,064036.289,4836.5375,N,00740.9373,E,1,04,3.2,200.2,M,,,,0000*0E";
// Faire des essais :
//QString phrase = "";
//QString phrase = "GPGGA,064036.289,4836.5375,N,00740.9373,E,1,04,3.2,200.2,M,,,,0000*0E";
//QString phrase = "$GPAAM,A,A,0.10,N,WPTNME*32";
//QString phrase = "$GPGGA,064036.289,4836.5375,N,00740.9373,E,1,04,3.2,200.2,M,,,,0000";

QString checksum;
const QString debutTrame = "$";
const QString typeTrame = "GPGGA";
const QString debutChecksum = "*";

// phrase vide ?
if(phrase.length() != 0)
{    
    // est-ce une phrase NMEA 0183 ?
    if(phrase.startsWith(debutTrame))
    {    
        // est-ce la bonne phrase ?
        if(phrase.startsWith(debutTrame + typeTrame))
        {
            // y-a-t-il un checksum ?
            if(phrase.contains(debutChecksum))
            {
                checksum = phrase.section(debutChecksum, 1, 1);
                qDebug() << "checksum extrait : 0x" << checksum;
            }
            else
                qDebug() << "Attention : il n'y a pas de checksum dans cette phrase !";
        }
        else
            qDebug() << "Erreur : ce n'est pas une trame GGA !";
    }
    else
        qDebug() << "Erreur : ce n'est pas une trame NMEA 0183 !";
}
else
    qDebug() << "Erreur : phrase vide !";

Remarque : lire Comment afficher des messages de débogage ? pour voir l’utilisation de qDebug().

Récupérer l’horodatage d’une trame NMEA0183 GGA :

QString phrase = "$GPGGA,064036.289,4836.5375,N,00740.9373,E,1,04,3.2,200.2,M,,,,0000*0E";    
QString horodatage;
unsigned int heure, minute;
double seconde;

// découpe la trame avec le délimiteur ',' et récupère le deuxième champ
horodatage = phrase.section(',', 1, 1); 
// découpe une chaine à partir d'une position et un nombre de caractères
heure = horodatage.mid(0, 2).toInt();
minute = horodatage.mid(2, 2).toInt();
seconde = horodatage.mid(4, 2).toDouble();

Comment convertir un QString en chaîne C (char *) et réciproquement ?

La classe QString ne fournit pas de méthode directe pour obtenir une chaîne de type char *. Il faut passer par les méthodes toAscii() (seulement en Qt4), toLatin1(), toUtf8(), toLocal8Bit() qui retournent un objet de type QByteArray. La classe QByteArray fournit les méthodes constData() pour obtenir un const char * et data() pour un char *.

QString str("Hello wordl!");
printf(str.toUtf8().constData());

Par contre, il existe un constructeur QString(const char * str) pour convertir une chaîne C (char *) en QString.

On peut aussi utiliser la fonction qPrintable() qui reçoit en paramètre une référence sur un QString et qui retourne un const char * : const char * qPrintable(const QString & str). C’est l’équivalent de str.toLocal8Bit().constData().

Comment transformer un QString en std::string et réciproquement ?

Pour transformer un std::string en QString, il faut utiliser la méthode statique QString::fromStdString().

Pour l’opération inverse, on utilisera la méthode toStdString().

Comment récupérer la date et l’heure courante sous forme de chaînes de caractères ?

On utilise un objet de la classe QDateTime (ou QDate ou QTime) que l’on initialise avec la méthode statique QDateTime::currentDateTime() (ou QDate::currentDate() ou QTime::currentTime()). On obtient une chaîne de caractères formatée en appelant la méthode toString(format) :

QDateTime maintenant = QDateTime::currentDateTime();
QString date = maintenant.toString("dd/MM/yyyy");
QString heure = maintenant.toString("hh:mm:ss");

Il existe plusieurs paramètres de format.

Remarque : il existe une fonction inverse fromString() qui permet d’initialiser un objet QDateTime (ou QDate ou QTime) à partir d’une chaîne de caractères formatée.

L’affichage de données sous forme de tableau (table)

Comment utiliser un QTableView ?

On peut utiliser le pattern Model-View de Qt pour associer des données (le modèle) à un affichage (une vue) sous forme de table.

Lire qt-modelview.pdf et tp-qt-5-calepin.pdf.

La classe QTableView fournit une implémentation par défaut d’un modèle/vue sous la forme d’une vue en table qui affiche les éléments contenus dans un modèle.

La personnalisation d’un QTableView se fait en utilisant les nombreuses méthodes offertes par cette classe : setColumnWidth(), setMinimumWidth(), setMaximumWidth(), setSelectionMode(), setSelectionBehavior(), setSortingEnabled(), sortByColumn(), setHorizontalScrollMode(), setVerticalScrollMode(), …

La classe QTableView possède un entête vertical et un entête horizontal qui sont accessibles par les méthodes : verticalHeader() et horizontalHeader(). Elles retournent un QHeaderView qui possède de nombreuses méthodes de personnalisation : hide(), setFixedWidth(), setFixedHeight(), setDefaultSectionSize(), setResizeMode(), setStretchLastSection(), …

Il existe d’autres types de vue : sous forme de liste (QListView) et sous forme d’arbre (QTreeView).

Si vous ne voulez pas utiliser votre propre modèle, vous pouvez utiliser la classe QTableWidget qui fournit une vue de table basée avec un modèle par défaut. Les éléments des cellules d’un QTableWidget sont des objets QTableWidgetItem.

Comment créer un QTableWidget ?

// un QTableWidget avec un nombre de lignes et de colonnes
tableWidget = new QTableWidget(4, 3, this);

// Ou un QTableWidget
tableWidget = new QTableWidget(this);
// on fixe le nombre de lignes
tableWidget->setRowCount(4);
// on fixe le nombre de colonnes
tableWidget->setColumnCount(3);

// Ou on peut insérer directement une ligne
tableWidget->insertRow(numeroLigne);

Comment insérer des éléments dans un QTableWidget ?

Un QString :

QTableWidgetItem *element = new QTableWidgetItem(QString("Une donnée"));
tableWidget->setItem(l, c, element); // l : ligne (row) et c : colonne

Un widget :

comboBox = new QComboBox(this);
comboBox->addItem("Item 1");
comboBox->addItem("Item 2");
// on peut ajouter des propriétés : l (ligne) et c (colonne)
comboBox->setProperty("l", l);
comboBox->setProperty("c", c);
// on peut connecter un slot
connect(comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(slot(int)));
tableWidget->setCellWidget(l, c, cb);

QPushButton *bouton = new QPushButton("Valider", this);
bouton->setProperty("l", l);
bouton->setProperty("c", c);
connect(bouton, SIGNAL(clicked()), this, SLOT(slot2()));
tableWidget->setCellWidget(l, c, bouton);

Par exemple, un slot :

void MaClasse::slot2()
{
    // on récupère la ligne et la colonne du bouton
    int r = sender()->property("l").toInt();
    int c = sender()->property("c").toInt();
    qDebug() << Q_FUNC_INFO << l << c;
    // ...
}

Comment gérer le mécanisme signal/slot des objets avec QSignalMapper ?

On insère des QCheckBox dans un QTableWidget :

QCheckBox *checkBox = new QCheckBox(this);
twItineraires->setCellWidget(l, c, checkBox);
// etc ...

Une alternative à la méthode sender() (vu ci-dessous) est l’utilisation d’un QSignalMapper. Cette classe permet d’associer un signal sans paramètre d’un objet à un autre signal pourvu d’un paramètre défini.

// Pour la gestion des checkbox dans les tables
mapperSelectionne = new QSignalMapper(this);

On connecte le signal déclencheur souhaité de chaque objet (ici clicked()) avec le slot map() du QSignalMapper :

connect(checkBox, SIGNAL(clicked()), mapperSelectionne, SLOT(map()));

On indique ensuite au QSignalMapper avec la méthode setMapping() le signal qui sera émis :

// le deuxième paramètre est ici de type QWidget*, 
// mais on peut aussi le faire avec des int, QObject* ou QString
mapperSelectionne->setMapping(checkBox, checkBox);

À chaque appel au slot map(), le QSignalMapper identifie l’objet qui déclenche le slot (avec sender()) et émet le signal mapped() défini avec setMapping() :

connect(mapperSelectionne, SIGNAL(mapped(QWidget *)), this, SLOT(activer(QWidget *)));

Il ne reste plus qu’à définir le slot activer(QWidget *). À la place d’un slot, on peut indiquer un signal qui sera alors émis.

Comment paramétrer le comportement d’un élément d’un QTableWidget ?

Avec la méthode setFlags() :

QTableWidgetItem *element = new QTableWidgetItem(QString("Une donnée"));
tableWidget->setItem(l, c, element); // l : ligne (row) et c : colonne

// Aucune propriété
item->setFlags(Qt::NoItemFlags);

// Qt::ItemIsSelectable
item->setFlags(Qt::ItemIsEnabled);

// Éditable
item->setFlags(Qt::ItemIsEditable);

// Activé
item->setFlags(Qt::ItemIsEnabled);

// Ou plusieurs
item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsEditable);

Comment récupérer un élément d’un QTableWidget ?

On peut détecter le changement d’une cellule

connect(tableWidget, SIGNAL(cellChanged(int,int)), this, SLOT(slot(int,int)));

Puis dans le slot, on peut récupérer le contenu de la cellule :

void MaClasse::slot(int l, int c)
{
    QTableWidgetItem *item;

    item = tableWidget->item(l, c);
    qDebug() << item->data(0).toString();
}

Comment modifier un élément d’un QTableWidget ?

QTableWidgetItem *item;

item = tableWidget->item(l, c);
item->setData(0, QString("Coucou !");

Comment personnaliser l’affichage d’un élément dans un QTableWidget ?

Ses couleurs d’arrière et d’avant plan :

QTableWidgetItem *item;

item = tableWidget->item(l, c);

QColor couleur1(Qt::blue);
QColor couleur2(Qt::yellow);
item->setBackgroundColor(couleur1);
item->setForeground(couleur2);

Sa police de caractères :

QTableWidgetItem *item;

item = tableWidget->item(l, c);

QFont font("Liberation Sans", 20, QFont::Normal);
font.setPointSize(22);
font.setBold(true);
font.setItalic(true);
font.setUnderline(true);
item->setFont(font);

Son alignement dans la cellule :

tableWidget->item(l, c)->setTextAlignment(Qt::AlignHCenter|Qt::AlignVCenter);

Comment se déplacer sur un élément ?

// Sur un élément
QTableWidgetItem *item;
item = tableWidget->item(l, c);
tableWidget->scrollToItem(item);

// sur une cellule
tableWidget->setCurrentCell(l, c);

Comment effacer le contenu d’un QTableWidget ?

int nb = tableWidget->rowCount();
// on efface les lignes du tableau une par une
for(int i = 0; i < nb; i++)
{    
    tableWidget->removeRow(0);
}

Ou :

// on efface les QTableWidgetItem contenus dans le tableau
tableWidget->clear();
// on efface toutes les lignes du tableau
tableWidget->setRowCount(0);

Comment paramétrer l’affichage d’un QTableWidget ?

Il existe de nombreuses méthode de paramétrage d’un QTableWidget :

QTableWidget *tableWidget = new QTableWidget(this);

QStringList header; // nom des colonnes
header << "Nom" << "Prénom"; // ...

// On fixe le nombre de colonnes
tableWidget->setColumnCount(header.size());
// On applique les noms des colonnes
tableWidget->setHorizontalHeaderLabels(header);

// on cache les numéros de ligne
tableWidget->verticalHeader()->setHidden(true);

QHeaderView * headerView = tableWidget->horizontalHeader();
// on redimensionne automatiquement la colonne pour occuper l'espace disponible
// Qt 5 :
headerView->setSectionResizeMode(QHeaderView::Stretch);
// Qt 4 :
headerView->setResizeMode(QHeaderView::Stretch);

Comment redimensionner un QTableWidget ?

A adapter :

void IHMItineraire::resizeTW(QTableWidget *tw)
{
    int w = 0, h = 0;

    // redimensionner les colonnes en fonction du contenu
    tw->resizeColumnsToContents();
    // redimensionner les lignes en fonction du contenu
    //tw->resizeRowsToContents();

    // les barres de défilements
    tw->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    tw->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);

    // calcul largeur (w) et hauteur (h)
    w += tw->contentsMargins().left() + tw->contentsMargins().right();
    h += tw->contentsMargins().top() + tw->contentsMargins().bottom();
    w += tw->verticalHeader()->width();
    h += tw->horizontalHeader()->height();
    for (int i=0; i<tw->columnCount(); ++i)
        w += tw->columnWidth(i);
    for (int i=0; i<tw->rowCount(); ++i)
        h += tw->rowHeight(i);

    // fixe largeur (w) et hauteur (h)
    tw->setMinimumWidth(w);
    tw->setMaximumWidth(w);
    //tw->setMinimumHeight(h);
    //tw->setMaximumHeight(h);
    
    //qDebug() << "w =" << w << "h =" << h;
}

Application

Comment afficher la version de Qt ?

qDebug() << qVersion();

Remarque : lire Comment afficher des messages de débogage ? pour voir l’utilisation de qDebug().

Comment afficher mon application en plein écran ?

Il existe plusieurs méthodes :

  • en appelant la méthode showFullScreen()

  • en utilisant la méthode desktop() de la classe QApplication puis en appelant resize()

const int width = qApp->desktop()->availableGeometry(this).width(); // ou : qApp->desktop()->width()
const int height = qApp->desktop()->availableGeometry(this).height(); // ou : qApp->desktop()->height()
resize(width, height);

Comment afficher mon application au centre de l’écran ?

setGeometry(QStyle::alignedRect(Qt::LeftToRight, Qt::AlignCenter, size(), qApp->desktop()->availableGeometry()));

Sinon, il faudra utiliser la méthode move() et faire quelques calculs …

Comment afficher un écran de démarrage ?

On utilisera la classe QSplashScreen pour afficher un écran de démarrage.

#include <QApplication>
#include "mainwindow.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;

    // Le splash
    QSplashScreen splash;
    // En avant-plan et sans décoration (titre ...)
    splash.setWindowFlags(Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint);
    // L'image de l'écran de démarrage
    splash.setPixmap(QPixmap("splash.png"));

    // On affiche
    splash.show();

    // On peut afficher un message sur l'image
    splash.showMessage(QString::fromUtf8("Lancement de l'application ..."), Qt::AlignHCenter | Qt::AlignTop, Qt::black);
    
    // On ferme le splash après un certain temps (ici 2 s)
    QTimer::singleShot(2000, &splash, SLOT(close()));
    // On affiche l'application
    QTimer::singleShot(2000, &w, SLOT(show()));
   
    return a.exec();
}

Il est aussi possible de synchroniser les 2 affichages :

#include <QApplication>
#include "mainwindow.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;

    // Le splash
    QSplashScreen splash;
    
    QStringList chargement;
    chargement << "" << QString::fromUtf8("Lancement de l'application ...") << QString::fromUtf8("Chargement des paramètres ...") << QString::fromUtf8("Chargement des styles ...") << QString::fromUtf8("Chargement des widgets ...");

    // En avant-plan et sans décoration (titre ...)
    splash.setWindowFlags(Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint);
    splash.setPixmap(QPixmap("/home/tv/Documents/cours/BTS-Avignon/divers/logos/splash.png"));

    splash.show();

    for(int i = 0;i < chargement.size();i++)
    {
        // On peut afficher un message sur l'image
        splash.showMessage(chargement.at(i), Qt::AlignHCenter | Qt::AlignTop, Qt::black);
        
        // on fait quelque chose
        usleep(500000);
        
        a.processEvents();
    }

    // On affiche l'application
    w.show();

    // On ferme le splash lorsque l'e MainWindo'application sera affichée
    splash.finish(&w);
    
    return a.exec();
}

Comment mettre en français les boîtes fournies par Qt ?

Il faut charger le fichier de traduction adapté dans la fonction main() de votre application :

#include <QApplication>
#include <QTranslator>
#include <QLocale>
#include <QLibraryInfo>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QString locale = QLocale::system().name().section(’_’, 0, 0);
    QTranslator translator;
    translator.load(QString("qt_") + locale, QLibraryInfo::location(QLibraryInfo::TranslationsPath));
    a.installTranslator(&translator);
    
    // ...
    
    return a.exec();
}

Comment supprimer les widgets contenus dans un layout ?

QLayoutItem *itemL;
while ((itemL = mainLayout->takeAt(0)) != 0)
{
    QWidget * widget = widget = itemL->widget();
    mainLayout->removeItem(itemL);
    if(widget != 0)
    {
        delete widget;
    }
}

Comment appliquer une feuille de style Qt ?

Qt permet la personnalistion des widgets par l’utilisation de feuilles de style. Les feuilles de style Qt et les règles syntaxiques sont presque identiques à celles du CSS de l’HTML. Si vous connaissez déjà le CSS, vous pouvez rapidement les mettre en oeuvre pour Qt.

Lire la documentation Style Sheets Qt5 ou Qt4.

Modification d’un attribut de style pour un widget (ici un QLineEdit) :

// Pour l'application
qApp->setStyleSheet("QLineEdit { background-color: yellow }");

// Pour le widget
nameEdit->setStyleSheet("background-color: yellow");

On peut regrouper l’ensemble des paramètres dans un fichier externe (.qss par exemple) :

QLineEdit { 
    background-color: yellow;
}

QLineEdit:focus {
    border-width: 2px;
    padding: 0px;
}

Et l’appliquer au démarrage de l’application :

int main( int argc, char **argv )
{
    QApplication a( argc, argv );
    
    QFile file("default.qss");
    if(file.open(QFile::ReadOnly))
    {
        QString styleSheet = QLatin1String(file.readAll());
        a.setStyleSheet(styleSheet);
    }

    // ...
    
    return a.exec();
}

Ou dans un fichier ressource intégré à l’application :

int main( int argc, char **argv )
{
    QApplication a( argc, argv );
    
    QFile file(":/stylesheet/default.qss");
    if(file.open(QFile::ReadOnly))
    {
        QString styleSheet = QLatin1String(file.readAll());
        a.setStyleSheet(styleSheet);
    }

    // ...
    
    return a.exec();
}

Le fichier ressource .qrc :

<RCC>
    <qresource prefix="/stylesheet">
        <file>default.qss</file>
    </qresource>
</RCC>

Comment assurer l’internationalisation d’une application Qt ?

La procédure est décrite dans ce document : qt-internationalisation.pdf.

Comment afficher une page web ?

WebKit est un moteur web open source capable de charger le contenu d’une page web et d’en faire le rendu. Le module QtWebkit est l’intégration du moteur WebKit pour Qt. Il faut l’activer dans son fichier de projet .pro :

QT += webkit

Dans ce module, Qt fournit de nombreuses classes dont la classe QWebView :

QWebView *webView = new QWebView(this);

// sans les barres de défilement (au choix)
webView->page()->mainFrame()->setScrollBarPolicy(Qt::Horizontal, Qt::ScrollBarAlwaysOff);
webView->page()->mainFrame()->setScrollBarPolicy(Qt::Vertical, Qt::ScrollBarAlwaysOff);

// avec les barres de défilement (au choix)
webView->page()->mainFrame()->setScrollBarPolicy(Qt::Horizontal, Qt::ScrollBarAlwaysOn);
webView->page()->mainFrame()->setScrollBarPolicy(Qt::Vertical, Qt::ScrollBarAlwaysOn);

// Lire un paramètre
//qDebug() << webView->page()->settings()->testAttribute( QWebSettings::JavascriptEnabled );

// Modifier des paramètres
QWebSettings::globalSettings()->setAttribute(QWebSettings::PluginsEnabled,true );
QWebSettings::globalSettings()->setAttribute(QWebSettings::JavaEnabled,true );
QWebSettings::globalSettings()->setAttribute(QWebSettings::JavascriptEnabled,true );
QWebSettings::globalSettings()->setAttribute(QWebSettings::AutoLoadImages,true);

// un slot :
//connect(webView, SIGNAL(urlChanged(QUrl)), this, SLOT(webview_changed(const QUrl &)));

// L'url de la page
QUrl URL = QString("http://www.google.fr");

// une authentification
//URL.setUserName(username);
//URL.setPassword(password);

// modifier le zoom
//webView->setZoomFactor(1.0);

// on charge la page
webView->load(URL);

Divers

Comment afficher des messages de débogage ?

Qt comprend des macros globales pour écrire des messages d’avertissement et de débogage :

  • qDebug() pour écrire des sorties de débogage personnalisées.
  • qInfo() pour les messages d’information.
  • qWarning() pour signaler des avertissements et des erreurs récupérables dans votre application.
  • qCritical() pour écrire des messages d’erreur critiques et des erreurs de système de rapports.
  • qFatal() pour écrire des messages d’erreur fatale peu avant la sortie.

Si vous incluez le fichier d’en-tête <QtDebug>, la macro qDebug() peut également être utilisée comme un flux de sortie (comme cout par exemple).

Des espaces et un saut de ligne sont automatiquement ajoutés :

qDebug() << "QLabel" << pLabel << "at position" << pLabel->pos(); // QLabel QLabel(0x1a58dd0) at position QPoint(0,0) 
qDebug().nospace() << "QLabel" << pLabel << "at position" << pLabel->pos(); // QLabelQLabel(0x1631720) at position QPoint(0,0)

On peut l’utiliser aussi comme la fonction C printf() :

int a = 10;
double pi = 3.141592;
qDebug("a = %d et pi = %.3f", a, pi); // a = 10 et pi = 3.142

Remarque : Sous Windows, le message est envoyé à la console, s’il s’agit d’une application console sinon, il est envoyé au débogueur. Il faut donc ajouter console à la variable QT de votre fichier .pro si vous voulez l’affichage dans la console.

qDebug(), qInfo(), et qWarning() sont des outils de débogage. Ils ne font rien si QT_NO_DEBUG_OUTPUT, QT_NO_INFO_OUTPUT ou QT_NO_WARNING_OUTPUT ont été respectivement définis lors de la compilation, par exemple pour une version release.

Si vous ne voulez plus les affichage de débogage, mettre dans le fichier .pro :

DEFINES += QT_NO_DEBUG_OUTPUT

L’opérateur de flux de qDebug() gère la plupart des types standards et Qt. Par contre, il vous faudra le surcharger pour vos propres types :

Exemple pour type Coordonnees possédant deux membres x et y :

QDebug operator<<(QDebug dbg, const Coordonnees &c)
{
    QDebugStateSaver saver(dbg);
    dbg.nospace() << "(" << c.x() << ", " << c.y() << ")";

    return dbg;
}

Comment générer un nombre aléatoirement ?

Il faut tout d’abord initialiser le générateur de nombres pseudo-aléatoire :

qsrand(QTime::currentTime().msec());

Puis, on utilise qrand() : on peut générer un nombre entre 0 et 9 par exemple :

// un nombre entre 0 et RAND_MAX
int nombre1 = qrand();

// un nombre entre 0 et 9
int nombre2 = qrand() % 10;

Ou encore mieux utiliser une fonction qui retourne un nombre compris entre une valeur min et une valeur max :

int generateur(int min, int max)
{
    return static_cast<int>(min + (static_cast<float>(qrand()) / RAND_MAX * (max - min)));
}

float generateur(float min, float max)
{
    return static_cast<float>(min + static_cast<float>(qrand()) / (static_cast<float>(RAND_MAX/(max - min))));
}

Comment comparer correctement des réels ?

À cause de l’approximation des nombres réels, tester l’égalité de deux nombres réels avec == n’est pas possible.

Il faudra donc utiliser la fonction qFuzzyCompare() qui retourne vrai si deux éléments sont égaux. Il existe aussi qFuzzyIsNull() qui retourne vrai si le nombre réel est nul.

Voir d’autres fonctions intéressantes.

Comment effectuer des actions périodiques avec un minuteur ?

Qt fournit un minuteur ou temporisateur avec la classe QTimer. Cette classe est relativement simple à utiliser grâce aux méthodes suivantes :

  • int interval() const : permet de connaître l’intervalle de temps (en ms) entre chaque déclenchement du minuteur
  • void setInterval(int msec) : permet de fixer l’intervalle en millisecondes entre deux déclenchements successifs du minuteur
  • bool isActive() const : permet de déterminer si le minuteur est activé ou pas
  • void start() : démarre le minuteur
  • void stop() : arrête le minuteur
// on met à zéro un compteur représentant le nombre de secondes
int compteur = 0;

// on crée un minuteur
QTimer *timer = new QTimer(this);
        
// on connecte le signal d'expiration timeout() de la minuterie à un slot
connect(timer, SIGNAL(timeout()), this, SLOT(compter()));

// on choisit un intervalle en ms
timer->setInterval(1000);
        
// on démarre le minuteur
timer->start();  
// timer->start(1000);

L’action périodique (le slot) :

// Méthode appelée toutes les secondes par le QTimer
void MaClasse::compter()
{
    // on incrémente le compteur de secondes
    compteur++;
    qDebug() << compteur;
}

Comment effectuer une action temporisée avec un minuteur ?

Qt fournit un minuteur ou temporisateur avec la classe QTimer. Cette classe est relativement simple à utiliser grâce aux méthodes suivantes :

  • bool isSingleShot() const : permet de déterminer si le timer est en mode de déclenchement unique (temporisateur) ou pas (minuteur)
  • void setSingleShot(bool singleShot) : permet de mettre le minuteur en mode déclenchement unique (temporisateur)

On peut aussi utiliser la méthode statique QTimer::singleShot() :

// on ferme l'application après un certain temps (ici 1s)
QTimer::singleShot(1000, qApp, SLOT(quit()));

Compilation

Comment assurer une comptabilité Qt4 / Qt5 ?

Qt 5.0 est sorti le 19 décembre 2012. Bien que marquant des changements majeurs sur bien des points, le passage à Qt5 casse au minimum la compatibilité au niveau des sources. Lire : Transition_from_Qt_4.x_to_Qt5.

En Qt 5, il faut intégrer la module QtWidgets qui est un module séparé dans le fichier .pro :

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

Ensuite, il faut corriger les erreurs de compilation comme ‘error: QPushButton: No such file or directory’.

#include <QtWidgets/QPushButton> /* pour Qt5 */

Pour cela, on peut tester QT_VERSION et assurer une comptabilité Qt4 / Qt5 :

#include <QtGlobal> /* déclare QT_VERSION */
#if QT_VERSION >= 0x050000
    #include <QtWidgets> /* les widgets de Qt5 */
#else
    #include <QtGui> /* les widgets de Qt4 */
#endif

Erreur d’édition des liens undefined reference to ‘vtable for xxx’ ?

Pour bénéficier des mécanismes de Qt (les signaux et les slots par exemple) dans vos propres classes, il faudra que celles-ci héritent de QObject (ou d’une classe fille de QObject) et intègrent la macro Q_OBJECT dans leur déclaration :

class MaClasse : public QObject
{
    Q_OBJECT
    
public:
    MaClasse( QObject *parent=0 ) : QObject(parent) {}
    
private:

signals:
    
public slots:
};

Cette classe ne pourra pas être compilée directement par un compilateur C++. Elle doit d’abord être traitée par l’outil moc de Qt. L’utilitaire qmake détectera si vos classes ont besoin du moc et génèrera le fichier Makefile qui contiendra les règles de fabrication.

Si vous obtenez l’erreur d’édition des liens undefined reference to 'vtable for xxx', vous devez :

  • Tout nettoyer (make clean)
  • Exécutez qmake
  • Tout recompiler

Comment récupérer et utiliser l’objet qui a déclenché un slot ?

Dans un slot, la méthode sender() retourne l’adresse de l’objet qui a déclenché ce slot (en émettant un signal).

Par exemple, deux clics de boutons connectés à un même slot :

QPushButton *bouton1 = new QPushButton("Bouton 1");
QObject::connect(btn, SIGNAL(clicked()), this, SLOT(monSlot()));
QPushButton *bouton2 = new QPushButton("Bouton 2");
QObject::connect(btn, SIGNAL(clicked()), this, SLOT(monSlot()));

Dans le slot, il est possible de récupérer l’adresse de l’objet bouton qui a déclenché le slot :

MaClasse::monSlot()
{
    QPushButton *bouton = qobject_cast<QPushButton*>(sender());
}

Gestion des données

Comment lire des paramètres dans un fichier .ini ?

Pour cela, on utilise la classe QSettings :

// Le nom du fichier INI : nom-executable.ini
QString fichierINI = qApp->applicationName() + ".ini";

QSettings parametres(fichierINI, QSettings::IniFormat);

// Lecture des paramètres de configuration
QString adresseIP = parametres.value("connexion/adresse","127.0.0.1").toString();
int port = parametres.value("connexion/port", "5000").toInt();

qDebug() << QString("adresse ip : %1").arg(adresseIP);
qDebug() << QString("port : %1").arg(port);

Comment écrire des paramètres dans un fichier .ini ?

Pour cela, on utilise la classe QSettings :

// Le nom du fichier INI : nom-executable.ini
QString fichierINI = qApp->applicationName() + ".ini";

QSettings parametres(fichierINI, QSettings::IniFormat);

// Les paramètres à enregistrer
QString adresseIP = "127.0.0.1";
int port = 5000;

// Écriture des paramètres de configuration (version 1)
//parametres.beginGroup("connexion"); // cf. endGroup()
//parametres.setValue("adresse", adresseIP);
//parametres.setValue("port", port);
//parametres.endGroup();

// Écriture des paramètres de configuration (version 1)
parametres.setValue("connexion/adresse", adresseIP);
parametres.setValue("connexion/port", port);

Comment créer un fichier XML ?

XML signifie eXtensible Markup Language (Langage de balisage extensible). Le langage est standardisé par la spécification W3C XML 1.0 du 10/02/98.

Un document XML bien formé signifie que le texte XML obéit aux règles syntaxiques de XML. Le document considéré comme valide (facultatif) signifie que le texte XML est bien formé et répond à une structure définie par une DTD (Definition Type Document).

Un document XML est composé d’éléments désignés par des balises et structuré sous la forme d’un arbre avec un et un seul élément racine (root).

Exemple de fichier XML :

<?xml version="1.0" encoding="UTF-8"?>
<interfaces>
  <interface id="100">
    <peripherique>/dev/ttyUSB0</peripherique>
  </interface>
</interfaces>

Qt fournit un module QtXml qu’il faut activer dans son fichier de projet .pro :

QT += xml

Dans ce module, Qt fournit de nombreuses classes qui permettent de gérer des documents XML :

On utilise la classe QFile pour la gestion de fichier. On utilise un objet DOM (Document Objet Model) de la classe QDomDocument pour agir sur le document XML :

// Le fichier XML
QFile fichierXML("test.xml");

if(!(fichierXML.open(QIODevice::ReadWrite | QIODevice::Truncate)))
{
    QMessageBox::critical(0,"Erreur","Erreur ouverture fichier XML !");
    return false;
}
else
{
    QDomDocument documentXML;

    documentXML.setContent(&fichierXML, false);
    QDomNode xmlNode = documentXML.createProcessingInstruction("xml","version=\"1.0\" encoding=\"UTF-8\"");
    documentXML.insertBefore(xmlNode, documentXML.firstChild());

    // crée l'élément racine
    QDomElement root = documentXML.createElement("interfaces");
    documentXML.appendChild(root);

    // crée et ajoute un élément
    QDomElement elementInterface = documentXML.createElement("interface");
    // ajoute un attribut à cete élément
    elementInterface.setAttribute("id", 100);
    root.appendChild(elementInterface);

    // crée et ajoute un sous-élément
    QDomElement elementPeripherique = documentXML.createElement("peripherique");
    elementInterface.appendChild(elementPeripherique);
    QDomText text = documentXML.createTextNode("/dev/ttyUSB0);
    elementPeripherique.appendChild(text);

    // écrit le fichier XML
    QTextStream out(&fichierXML);
    documentXML.save(out, 2);

    fichierXML.close();
}

Comment lire un fichier XML ?

XML signifie eXtensible Markup Language (Langage de balisage extensible). Le langage est standardisé par la spécification W3C XML 1.0 du 10/02/98.

Un document XML bien formé signifie que le texte XML obéit aux règles syntaxiques de XML. Le document considéré comme valide (facultatif) signifie que le texte XML est bien formé et répond à une structure définie par une DTD (Definition Type Document).

Un document XML est composé d’éléments désignés par des balises et structuré sous la forme d’un arbre avec un et un seul élément racine (root).

Exemple de fichier XML :

<?xml version="1.0" encoding="UTF-8"?>
<interfaces>
  <interface id="100">
    <peripherique>/dev/ttyUSB0</peripherique>
  </interface>
</interfaces>

Qt fournit un module QtXml qu’il faut activer dans son fichier de projet .pro :

QT += xml

Dans ce module, Qt fournit de nombreuses classes qui permettent de gérer des documents XML :

On utilise la classe QFile pour la gestion de fichier. On utilise un objet DOM (Document Objet Model) de la classe QDomDocument pour agir sur le document XML :

// Le fichier XML
QFile fichierXML("test.xml");

if(!(fichierXML.open(QIODevice::ReadOnly)))
{
    QMessageBox::critical(0,"Erreur","Le fichier XML n'a pas pu être ouvert !");
    return false;
}
else
{
    QDomDocument documentXML;

    documentXML.setContent(&fichierXML, false);
    
    // lit l'élément racine
    QDomElement racine = documentXML.documentElement(); // <interfaces>
    if(racine.isNull())
    {
        qDebug() << "Erreur racine !";
        return;
    }

    // récupère le premier élément
    QDomNode noeudInterface = racine.firstChild();
    if(noeudInterface.isNull())
    {
        qDebug() << "Erreur racine vide !";
        return;
    }

    while(!noeudInterface.isNull())
    {
        QDomElement elementInterface = noeudInterface.toElement(); // <interface>
        if(elementInterface.isNull())
        {
            qDebug() << "Erreur element !";
            break;
        }

        QDomNode noeudPeripherique = elementInterface.firstChild();
        if(!noeudPeripherique.isNull())
        {
            QDomElement elementPeripherique = noeudPeripherique.toElement(); // <peripherique>
            qDebug() << elementInterface.attribute("id").toInt(); // l'id
            qDebug() << interface.peripherique = elementPeripherique.text(); // le périphérique
        }

        // au suivant
        noeudInterface = noeudInterface.nextSibling();
    }

    fichierXML.close();
}

Comment écrire des données dans un fichier CSV ?

Le format CSV (Comma-separated values) est un format informatique ouvert représentant des données tabulaires sous forme de valeurs séparées par un délimiteur (initialement des virgules). Les séparateurs ne sont pas standardisés (virgules, points-virgules, etc…) rend ce format peu pratique pour une utilisation autre que des échanges de données ponctuels. Ce format est toutefois très populaire parce qu’il est très facile à générer.

Les fichiers CSV sont des fichiers texte : ils peuvent donc être manipulés avec un éditeur de texte. Mais les fichiers CSV sont essentiellement utilisés par des logiciels de type tableur (Microsoft Excel, LibreOffice/OpenOffice calc, …).

Chaque ligne du texte correspond à une ligne du tableau et les virgules correspondent aux séparations entre les colonnes. Les portions de texte séparées par une virgule correspondent ainsi aux contenus des cellules du tableau.

Une ligne est une suite ordonnée de caractères terminée par un caractère de fin de ligne (CRLF), la dernière ligne pouvant en être exemptée.

Exemple de fichier CSV :

Sexe;Prénom;Année de naissance
M;Alphonse;1932

On utilise la classe QFile pour la gestion de fichier. Il n’existe pas de classe Qt native pour gérer le format CSV.

// Le fichier CSV
QFile *fichierCSV = new QFile("datas.csv");

// Ouverture du fichier en mode texte et en écriture seule
if (fichierCSV->open(QFile::WriteOnly | QIODevice::Text))
{
    // Ecriture de l'en-tête
    QTextStream entete(fichierCSV);
    
    entete << QString::fromUtf8("Sexe;Prénom;Année de naissance") << endl;
    
    // Ecriture des données
    QTextStream datas(fichierCSV);

    datas << "\"" << "M" << "\""; // on protège la data avec des "
    datas << ";";
    datas << "\"" << "Alphonse" << "\""; // on protège la data avec des "
    datas << ";";
    datas << "\"" << "1932" << "\""; // on protège la data avec des "
    datas << ";";
    datas << endl;

    // On ferme le fichier
    fichierCSV->close();

    delete fichierCSV;
}
else
{
    QMessageBox::critical(0,"Erreur !",("Impossible d'ouvrir le fichier datas.csv"));
    delete fichierCSV;
}

Remarque : voir aussi la classe qcsv

Comment lire des données dans un fichier CSV ?

Le format CSV (Comma-separated values) est un format informatique ouvert représentant des données tabulaires sous forme de valeurs séparées par un délimiteur (initialement des virgules). Les séparateurs ne sont pas standardisés (virgules, points-virgules, etc…) rend ce format peu pratique pour une utilisation autre que des échanges de données ponctuels. Ce format est toutefois très populaire parce qu’il est très facile à générer.

Les fichiers CSV sont des fichiers texte : ils peuvent donc être manipulés avec un éditeur de texte. Mais les fichiers CSV sont essentiellement utilisés par des logiciels de type tableur (Microsoft Excel, LibreOffice/OpenOffice calc, …).

Chaque ligne du texte correspond à une ligne du tableau et les virgules correspondent aux séparations entre les colonnes. Les portions de texte séparées par une virgule correspondent ainsi aux contenus des cellules du tableau.

Une ligne est une suite ordonnée de caractères terminée par un caractère de fin de ligne (CRLF), la dernière ligne pouvant en être exemptée.

Exemple de fichier CSV :

Sexe;Prénom;Année de naissance
M;Alphonse;1932

On utilise la classe QFile pour la gestion de fichier. Il n’existe pas de classe Qt native pour gérer le format CSV.

// Le fichier CSV
QFile *fichierCSV = new QFile("datas.csv");

// Ouverture du fichier en mode texte et en écriture seule
if (fichierCSV->open(QFile::ReadOnly | QIODevice::Text))
{
    // Lecture des données
    QTextStream datas(fichierCSV);
    QString ligne;

    while(!datas.atEnd())
    {
        ligne = datas.readLine();
        qDebug() << ligne;
    }
    
    // On ferme le fichier
    fichierCSV->close();
    delete fichierCSV;
}
else
{
    QMessageBox::critical(0, "Erreur !", ("Impossible d'ouvrir le fichier datas.csv"));
    delete fichierCSV;
}

Remarque : voir aussi la classe qcsv

Comment remplacer le point (‘.’) par la virgule (‘,’) dans un nombre réel ?

QString data = QString::number(2.5);
// A la française ?
data.replace(QString("."), QString(","));

Comment se connecter à une base de données ?

Qt fournit de nombreuses classes pour la gestion des base de données. Il faudra activer le module dans son fichier de projet .pro pour pouvoir accéder aux classes :

QT += sql

Remarque : Il faudra aussi disposer d’un pilote de base de données comme pour MySQL (QMYSQL) ou SQLite (QSQLITE).

On utilisera la classe QSqlDatabase qui permet la connexion à une base de données.

Et ensuite la classe QSqlQuery pour exécuter des requêtes SQL :

Exemple pour base de données MySQL :

QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL");

db.setHostName("localhost");
db.setUserName("root");
db.setPassword("password");
db.setDatabaseName("test"); // mettre le nom de la base de données

if(db.open())
{
   qDebug() << "Connexion réussie à " << db.hostName().toStdString();
}
else
{
   qDebug() << db.lastError().text();
}

Exemple pour base de données SQLite :

QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");

db.setDatabaseName("test.sqlite"); // mettre le nom du fichier sqlite

if(db.open())
{
   qDebug() << "Connexion réussie à " << db.hostName().toStdString();
}
else
{
   qDebug() << db.lastError().text();
}

Comment effectuer une requête SQL SELECT sur une base de données ?

Qt fournit de nombreuses classes pour la gestion des base de données. Il faudra activer le module dans son fichier de projet .pro pour pouvoir accéder aux classes :

QT += sql

Remarque : Il faudra aussi disposer d’un pilote de base de données comme pour MySQL (QMYSQL) ou SQLite (QSQLITE).

On utilisera la classe QSqlDatabase qui permet la connexion à une base de données.

Et ensuite la classe QSqlQuery pour exécuter des requêtes SQL :

QSqlQuery query;
QString requete = "SELECT * FROM mesures";
bool retour = query.exec(requete);
if(retour)
{
  while (query.next())
  {  
     qDebug() << "enregistrement -> ";
     for(int i=0;i<query.record().count();i++)
        qDebug() << query.value(i).toString();
  } 
}
else  qDebug() << query.lastError().text();

Comment effectuer une requête SQL UPDATE, INSERT ou DELETE sur une base de données ?

Qt fournit de nombreuses classes pour la gestion des base de données. Il faudra activer le module dans son fichier de projet .pro pour pouvoir accéder aux classes :

QT += sql

Remarque : Il faudra aussi disposer d’un pilote de base de données comme pour MySQL (QMYSQL) ou SQLite (QSQLITE).

On utilisera la classe QSqlDatabase qui permet la connexion à une base de données.

Et ensuite la classe QSqlQuery pour exécuter des requêtes SQL :

Il existe plusieurs façons :

QSqlQuery query;
QString requete;

requete = "UPDATE Seuils SET niveauTemperature='23'";
if (!query.exec())
{
   qDebug() << r.lastError().text();
}

requete = "DELETE FROM mesures";
if (!query.exec())
{
   qDebug() << r.lastError().text();
}

// idem pour INSERT
QSqlQuery query;

// Utilisation des marqueurs '?'
// INSERT INTO `mesures` (`id`, `date`, `heure`, `temperature`) VALUES (...)
query.prepare("INSERT INTO mesures (id, date, heure, temperature) VALUES ('', ?, ?, ?)");

// id en auto-incrément
query.addBindValue("2009-09-10");
query.addBindValue("09:01:00");
query.addBindValue(35.12);

if (query.exec())
{
   qDebug() << "Insertion réussie";
}
else
{
   qDebug() << r.lastError().text();
}

// Utilisation des marqueurs nominatifs
query.prepare("INSERT INTO mesures (id, date, heure, temperature) VALUES (:id, :date, :heure, :temperature)");

query.bindValue(":id", ""); // auto-incrément
query.bindValue(":date", "2009-09-10");
query.bindValue(":heure", "09:01:00");
query.bindValue(":temperature", 34.92);
if (query.exec())
{
   qDebug() << "Insertion réussie";
}
else
{
   qDebug() << r.lastError().text();
}

Communication

Comment gérer un port série sous Qt ?

Suivant votre version de Qt :

  • Qt 4 : la version 4 de Qt ne fournit pas de classes pour gérer un port série nativement. On va donc devoir utiliser une bibliothèque logicielle externe à Qt : la classe QextSerialPort disponible ici.
#include "qextserialport.h"

#define PORT_LINUX "/dev/ttyUSB0"
#define PORT_WINDOWS "COM1"

// instanciation du port en mode synchrone -> QextSerialPort::EventDriven
QextSerialPort *port = new QextSerialPort(QLatin1String(PORT_LINUX), QextSerialPort::EventDriven);
// Ou :
// instanciation du port en mode asynchrone -> QextSerialPort::Polling
QextSerialPort *port = new QextSerialPort(QLatin1String(PORT_LINUX), QextSerialPort::Polling);
    
// configuration
port->setBaudRate(BAUD9600);
port->setDataBits(DATA_8);
port->setParity(PAR_NONE);
port->setStopBits(STOP_1);
port->setFlowControl(FLOW_OFF);

// ouverture du port en lecture/écriture
port->open(QIODevice::ReadWrite);

/** @todo : réceptionner et/ou envoyer des données sur le port */

// fermeture du port
port->close();    
  • Qt 5 : le problème n’existe plus en Qt5 car on dispose alors de la classe QSerialPort ! Il faudra ajouter le module serialport à la variable QT dans le fichier .pro (QT += serialport)
#include <QSerialPort>

#define PORT_LINUX "/dev/ttyUSB0"
#define PORT_WINDOWS "COM1"


// instanciation du port 
QSerialPort *port = new QSerialPort(QLatin1String(PORT_LINUX));

// configuration
port->setBaudRate(QSerialPort::Baud9600);
port->setDataBits(QSerialPort::Data8);
port->setParity(QSerialPort::NoParity);
port->setStopBits(QSerialPort::OneStop);
port->setFlowControl(QSerialPort::NoFlowControl);

// ouverture
port->open(QIODevice::ReadWrite);

/** @todo : réceptionner et/ou envoyer des données sur le port */

// fermeture du port
port->close();

Les fonctions d’écriture sont les suivantes :

  • qint64 write(const char * data, qint64 maxSize)
  • qint64 write(const char * data)
  • qint64 write(const QByteArray & byteArray)

Pour aller plus loin, on dispose :

  • du signal bytesWritten(qint64 bytes) : ce signal est émis chaque fois bytes octets de données ont été écrits sur le périphérique.
  • de la méthode waitForBytesWritten(int msecs) : elle attend jusqu’à ce que le signal bytesWritten() ait été émis ou que msecs millisecondes soient passées. Il est déconseillé de l’utiliser à partir du thread GUI.
  • de la méthode setTimeout(long millisec) : elle définit les délais d’attente d’écriture (et aussi de lecture) pour le port en millisec millisecondes. C’est un délai d’expiration par caractère individuel et non pour l’opération entière.

Les fonctions de lecture sont très nombreuses :

  • qint64 read(char * data, qint64 maxSize)
  • QByteArray read(qint64 maxSize)
  • QByteArray readAll()
  • qint64 readLine(char * data, qint64 maxSize)
  • QByteArray readLine(qint64 maxSize = 0)

La classe QextSerialPort (Qt4) ou QSerialPort (Qt5) fournit le signal readyRead(). Ce signal est émis une fois que de nouvelles données sont disponibles pour la lecture à partir du périphérique.

Comment créer une socket UDP ?

Qt fournit un module QtNetwork qu’il faut activer dans son fichier de projet .pro :

QT += network

Dans ce module, Qt fournit de nombreuses classes dont la classe QUdpSocket :

Création d’une socket et son attachement sur le port 5000 des interfaces locales de la machine :

QUdpSocket udpSocket = new QUdpSocket(this);
   
// Attachement locale de la socket UDP :
udpSocket->bind(QHostAddress((QString)"0.0.0.0"), 5000);
udpSocket->bind(QHostAddress::LocalHost, 5000);

// ...    

// on ferme la socket
udpSocket->close();

Comment recevoir des datagrammes sur une socket UDP ?

Qt fournit un module QtNetwork qu’il faut activer dans son fichier de projet .pro :

QT += network

Dans ce module, Qt fournit de nombreuses classes dont la classe QUdpSocket :

On réalise la connexion du signal readyRead() au slot ReceptionnerDatagrammes() :

connect(udpSocket, SIGNAL(readyRead()), this, SLOT(ReceptionnerDatagrammes()));

La méthode ReceptionnerDatagrammes() assure donc la réception des datagrammes UDP. Pour cela, elle réalise un boucle d’attente sur la présence de données dans la socket.

void MaClasse::ReceptionnerDatagrammes()
{
   int nbOctets = 0;   
   int etat;
 
   // datagramme en attente d'être lu ?
   while (udpSocket->hasPendingDatagrams())
   {
      QByteArray donneesDatagramme;
      QHostAddress emetteurAdresse;
      quint16 emetteurPort;      

      // Fixe la taille du tableau au nombre d'octets reçus en attente
      donneesDatagramme.resize(udpSocket->pendingDatagramSize());
      
      // Lit le datagramme en attente
      //nbOctets = udpSocket->readDatagram(datagram.data(), datagram.size());
      nbOctets = udpSocket->readDatagram(donneesDatagramme.data(), donneesDatagramme.size(), &emetteurAdresse, &emetteurPort);      
      
      QString qs_emetteurAdresse = emetteurAdresse.toString();
      qDebug() << "<" << qs_emetteurAdresse.toStdString() << ":" << emetteurPort 
               << "> datagramme de " << nbOctets << " octet(s) reçu(s)";      
   }
}

Comment envoyer des datagrammes sur une socket UDP ?

Qt fournit un module QtNetwork qu’il faut activer dans son fichier de projet .pro :

QT += network

Dans ce module, Qt fournit de nombreuses classes dont la classe QUdpSocket :

int MaClasse::EnvoyerDatagramme()
{
  int nbOctets;
  QByteArray datagramme = "WIDD";
  
  //nbOctets = udpSocket->writeDatagram(datagramme.data(), datagramme.size(), QHostAddress::Broadcast, 5000);
  nbOctets = udpSocket->writeDatagram(datagramme.data(), datagramme.size(), QHostAddress((QString)"10.7.89.95"), 5000);
  
  return nbOctets;
}

Comment créer une socket TCP côté client ?

Qt fournit un module QtNetwork qu’il faut activer dans son fichier de projet .pro :

QT += network

Dans ce module, Qt fournit de nombreuses classes dont la classe QTcpSocket :

Création d’une socket TCP et sa connexion vers un serveur TCP :

QTcpSocket *socket = new QTcpSocket(this);

QHostAddress adresseServeur("127.0.0.1");
int portServeur = 5000;

//socket->connectToHost("127.0.0.1", portServeur);
socket->connectToHost(adresseServeur, portServeur);

if(!socket->isOpen())
{
    qDebug() << socket->errorString());
}
else
{
    // quelques signaux
    connect(socket, SIGNAL(connected()), this, SLOT(estConnecte()));
    connect(socket, SIGNAL(disconnected()), this, SLOT(estDeconnecte()));
    connect(socket, SIGNAL(readyRead()), this, SLOT(recevoir()));

    if(!socket->waitForConnected(5000))
    {
        qDebug() << socket->errorString());
    }
}

Quelques slots :

void MaClasse::estConnecte()
{
   QTcpSocket *serveur = qobject_cast<QTcpSocket *>(sender());
   if (serveur == 0) // aucun ?
        return;

   qDebug() << QString::fromUtf8("Connexion réussie au serveur (") + serveur->peerAddress().toString() + QString::fromUtf8(":") + QString::number(serveur->peerPort()) + QString::fromUtf8(")");
}

void MaClasse::estDeconnecte()
{
   QTcpSocket *serveur = qobject_cast<QTcpSocket *>(sender());
   if (serveur == 0) // aucun ?
      return;

   qDebug() << QString::fromUtf8("Déconnexion du serveur (") + serveur->peerAddress().toString() + QString::fromUtf8(":") + QString::number(serveur->peerPort()) + QString::fromUtf8(")");
}

Comment envoyer des données avec une socket TCP ?

Qt fournit un module QtNetwork qu’il faut activer dans son fichier de projet .pro :

QT += network

Dans ce module, Qt fournit de nombreuses classes dont la classe QTcpSocket :

Avec la méthode write() par exemple :

QString message = "Hello world !\n";

socket->write(qPrintable(message));

Comment recevoir des données avec une socket TCP ?

Qt fournit un module QtNetwork qu’il faut activer dans son fichier de projet .pro :

QT += network

Dans ce module, Qt fournit de nombreuses classes dont la classe QTcpSocket :

On réalise la connexion du signal readyRead() au slot recevoir() :

connect(socket, SIGNAL(readyRead()), this, SLOT(recevoir()));

Puis avec la méthode readAll() par exemple :

void MaClasse::recevoir()
{
   QTcpSocket *serveur = qobject_cast<QTcpSocket *>(sender());
   if (serveur == 0) // aucun ?
      return;

    QByteArray donneesRecues;
    donneesRecues = serveur->readAll();
    QString reponse(donneesRecues.constData());

    qDebug() << donneesRecues;
}

Comment créer une socket TCP côté serveur ?

Qt fournit un module QtNetwork qu’il faut activer dans son fichier de projet .pro :

QT += network

Dans ce module, Qt fournit de nombreuses classes dont la classe QTcpServer :

Création d’une socket TCP et sa connexion vers un serveur TCP :

QTcpServer *serveur = new QTcpServer(this);

// Démarrage du serveur sur toutes les IP locales disponibles et sur le port 5000
if (!serveur->listen(QHostAddress::Any, 5000)) 
{
    qDebug() QString::fromUtf8("Erreur démarrage serveur : ") + serveur->errorString();
}
else
{
    // slot pour gérer la connxion des clients
    connect(serveur, SIGNAL(newConnection()), this, SLOT(connecterClient()));
}

Le slot pour gérer la connexion des clients :

void MaClasse::connecterClient()
{
    QTcpSocket *nouveauClient = serveur->nextPendingConnection();

    qDebug() << QString::fromUtf8("<Dialogue> Connexion client (") + nouveauClient->peerAddress().toString() + QString::fromUtf8(":") + QString::number(nouveauClient->peerPort()) + QString::fromUtf8(")");

    // envisager de stocker ce nouveau client

    // quelques slots
    connect(nouveauClient, SIGNAL(readyRead()), this, SLOT(recevoir()));
    connect(nouveauClient, SIGNAL(disconnected()), this, SLOT(deconnecterClient()));
}

void MaClasse::deconnecterClient()
{
    // On détermine quel client se déconnecte
    QTcpSocket *client = qobject_cast<QTcpSocket *>(sender());
    if (client == 0) // aucun client ?
        return;

    dQebug() << QString::fromUtf8("<Dialogue> Déconnexion client (") + client->peerAddress().toString() + QString::fromUtf8(":") + QString::number(client->peerPort()) + QString::fromUtf8(")");

    // supprimer le client stocké précedemment

    client->deleteLater();
}

Retour au sommaire