FAQ Qt
FAQ QtConsultez toutes les FAQ
Nombre d'auteurs : 26, nombre de questions : 298, dernière mise à jour : 15 juin 2021
- Comment fonctionne le système de gestionnaire d'accès ?
- Comment envoyer un fichier par le protocole HTTP ?
- Comment utiliser un proxy ?
- Comment définir un proxy par défaut ?
- Comment récupérer l'avancement du téléchargement ?
- Comment récupérer la source d'une page Internet ?
- Comment mettre en place un cache ?
- Comment arrêter un téléchargement ?
Qt 4.4 nous fournit une alternative à QHttp et à QFtp : QNetworkAccessManager. Ce gestionnaire permet d'utiliser d'autres protocoles (HTTPS, par exemple), sans devoir changer autre chose que les URL, dans son code.
L'architecture de ce nouveau système est tout à fait différente : il y a un objet-maître, un QNetworkAccessManager, le gestionnaire. Il gère, entre autres, le cache, le proxy, les paramètres par défaut... C'est lui qui envoie les signaux de fin de téléchargement, aussi.
On ne crée plus un objet indépendant par requête : on instancie un manager, puis on lui demande de récupérer un fichier, grâce à son URL. Ce fichier est demandé sous la forme d'une requête QNetworkRequest. Cette requête ne contient pas que l'URL : elle contient aussi les en-têtes supplémentaires à envoyer au serveur, la configuration SSL...
Une fois que le fichier a été téléchargé, il est renvoyé, sous la forme d'une réponse, un QNetworkReply. Il s'agit d'un dérivé de QIODevice, et peut donc s'utiliser de la même manière. Il peut être envoyé en tant que paramètre du signal finished() du gestionnaire ou bien dès que l'ordre de téléchargement du fichier a été donné. Il est cependant déconseillé de procéder de la sorte, car le téléchargement n'aura probablement pas encore pu être initié.
QNetworkAccessManager
*
manager =
new
QNetworkAccessManager
;
QNetworkReply
*
reply =
manager->
get("http://qt.developpez.com"
);
Dès que le gestionnaire aura envoyé le signal finished(), la réponse contiendra le contenu du fichier.
Notez que l'on aurait pu aussi procéder de cette manière.
QNetworkAccessManager
*
manager =
new
QNetworkAccessManager
;
manager->
get("http://qt.developpez.com"
);
En effet, le gestionnaire enverra le signal finished() avec un argument, un pointeur vers la réponse.
Le protocole HTTP est principalement prévu pour la récupération de données (par les méthodes GET et HEAD), mais il peut aussi envoyer des données (par les méthodes POST et PUT). Il faut utiliser les méthodes du gestionnaire réseau homonymes à la méthode.
Pour l'envoi, elles prennent deux paramètres : une requête QNetworkRequest et des données QByteArray.
QNetworkAccessManager
*
manager =
new
QNetworkAccessManager
;
QUrl
url ("http://qt.developpez.com"
);
QNetworkRequest
request (url);
QByteArray
data =
"data"
;
manager->
post(request, data);
Qt nous fournit une classe, QNetworkProxy, qui représente un proxy. Vous pouvez en spécifier un à votre gestionnaire QNetworkAccessManager grâce à sa méthode setProxy(). Ce proxy peut être aussi utilisé par d'autres classes, plus anciennes, à chaque fois grâce à la méthode setProxy() : QHttp, QFtp, QAbstractSocket, QTcpSocket, QUdpSocket, QTcpServer...
Voici un exemple de création de proxy, assez explicite.
QNetworkProxy
proxy;
proxy.setType(QNetworkProxy
::
Socks5Proxy);
proxy.setHostName("proxy.exemple.com"
);
proxy.setPort(1080
);
proxy.setUser("username"
);
proxy.setPassword("password"
);
Le type du proxy est choisi dans l'énumération QNetworkProxy::ProxyType, que voici.
enum
ProxyType {
NoProxy, DefaultProxy, Socks5Proxy, HttpProxy,
HttpCachingProxy, FtpCachingProxy }
DefaultProxy oblige l'utilisation du proxy par défaut.
Maintenant, nous allons voir comment demander à un objet de passer par un proxy. Nous considérerons à la suite de l'exemple de création d'un proxy.
QNetworkAccessManager
manager;
manager->
setProxy (proxy);
QWebView
*
view =
new
QWebView
;
view->
page()->
networkAccessManager()->
setProxy(proxy);
La fonction statique QNetworkProxy::setApplicationProxy() est utilisée pour définir le proxy par défaut de l'application. Il sera utilisé par défaut dans l'application, mais il pourra être remplacé pour tous les objets en utilisant d'autres méthodes.
On peut aussi récupérer ce proxy par défaut grâce à la fonction statique QNetworkProxy::applicationProxy().
// QNetworkProxy::applicationProxy() == QNetworkProxy()
QNetworkProxy
::
setApplicationProxy (proxy);
// QNetworkProxy::applicationProxy() == proxy
Lien : Comment utiliser un proxy ?
Le gestionnaire de requête QNetworkAccessManager permet de télécharger des fichiers à l'aide de la méthode get.
Il est également possible de suivre l'évolution du téléchargement pour, par exemple, l'afficher dans une barre de progression. Il est nécessaire de connecter le signal downloadProgress à un slot à redéfinir.
QNetworkAccessManager
*
manager =
new
QNetworkAccessManager
;
QNetworkReply
*
reply =
manager->
get(QNetworkRequest
(QUrl
("http://qt.developpez.com/faq/images/FAQ-Qt.gif"
)));
connect
(reply, SIGNAL
(downloadProgress(qint64
, qint64
)), this
, SLOT
(requestDownloadProgress(qint64
, qint64
)));
// Le slot de réception
void
requestDownloadProgress(qint64
bytesReceived, qint64
bytesTotal)
{
qint64
pourcent =
(bytesReceived /
bytesTotal) *
100
;
}
Lien : Comment fonctionne le système de gestionnaire d'accès ?
QtNetwork et QtWebkit sont deux modules permettant chacun de récupérer un fichier de l'Internet, comme des pages Web. QtNetwork fournit la classe QNetworkReply, que nous traiterons, et QtWebkit, QWebFrame. QHttp étant obsolète, son cas ne sera pas traité ici.
Comme QNetworkReply hérite de QIODevice, il possède la fonction readAll(), qui permettra, dans l'exemple qui suit, de récupérer ce qui est souhaité, balises HTML comprises :
QNetworkAccessManager
*
manager =
new
QNetworkAccessManager
;
manager->
get(QNetworkRequest
(QUrl
("http://qt.developpez.com/faq/"
)));
connect
(manager, SIGNAL
(finished(QNetworkReply
*
)), this
, SLOT
(result(QNetworkReply
*
)));
void
Classe::
result(QNetworkReply
*
reply)
{
QString
source =
reply->
readAll();
doSomething(source);
}
Cette solution ne prend pas en compte les redirections !
La seconde solution, avec QWebFrame, est très pratique car elle permet, en plus de gérer les redirections, de récupérer la source de la page sous deux formats avec les fonctions toHtml(), qui retourne la source avec les balises HTML, et toPlainText(), qui retourne la source sans les balises HTML.
view =
new
QWebView
;
view->
load(QUrl
("http://qt.developpez.com/faq/"
));
connect
(view, SIGNAL
(loadFinished(bool
)), this
, SLOT
(result(bool
)));
void
Classe::
result(bool
)
{
QString
html =
view->
page()->
currentFrame()->
toHtml();
QString
plainText =
view->
page()->
currentFrame()->
toPlainText();
doSomething(html, plainText);
}
Si on décomposait le code de la fonction result(bool), située ci-dessus, on aurait ceci :
void
Classe::
result(bool
)
{
QWebPage
*
page =
view->
page();
QWebFrame
*
frame =
page->
currentFrame();
QString
html =
frame->
toHtml();
QString
plainText =
frame->
toPlainText();
doSomething(html, plainText);
}
Lorsque l'on souhaite afficher une ressource volumineuse n'étant pas située en local (par exemple, une image), on aime assez pouvoir la mettre en cache pour éviter qu'il y ait de multiples téléchargements ralentissant l'application.
QNetworkAccessManager possède une fonction setCache(), prenant pour argument une classe dérivée de QAbstractNetworkCache, qui permet de définir un cache pour toutes les requêtes effectuées par le gestionnaire d'accès.
Voici un exemple d'utilisation de la fonction setCache() avec une instance de QNetworkDiskCache, classe dérivée de QAbstractNetworkCache qui met à disposition un cache assez basique mais simple d'utilisation :
// Création d'une instance de QNetworkAccessManager :
QNetworkAccessManager
*
manager =
new
QNetworkAccessManager
(parent);
// Création d'une instance de QNetworkDiskCache :
QNetworkDiskCache
*
cache =
new
QNetworkDiskCache
(manager);
// L'emplacement où les fichiers de cache seront écrits :
cache->
setCacheDirectory(QDesktopServices
::
storageLocation(QDesktopServices
::
CacheLocation));
// Le cache accepte jusqu'à 10Mo :
cache->
setMaximumCacheSize(10
*
1024
*
1024
);
// On définit le cache du manager à notre objet cache :
manager->
setCache(cache);
Cela fait, on utilise le gestionnaire d'accès en précisant que l'on souhaite utiliser le cache, dans la mesure du possible :
// On connecte le signal finished() du gestionnaire d'accès à la méthode networkReplyFinished() de something :
QObject
::
connect
(manager, SIGNAL
(finished(QNetworkReply
*
)), something, SLOT
(networkReplyFinished(QNetworkReply
*
)));
// On crée une requête vers une image :
QNetworkRequest
request(QUrl
("http://qt.developpez.com/faq/images/FAQ-Qt.gif"
));
// On définit l'attribut CacheLoadControlAttribute à PreferCache
// pour demander à ce que le cache soit utilisé si disponible :
request.setAttribute(QNetworkRequest
::
CacheLoadControlAttribute, QNetworkRequest
::
PreferCache);
// On envoie une requête pour récupérer l'image :
manager->
get(request);
// ...
void
MyClass::
networkReplyFinished(QNetworkReply
*
reply)
{
// Affiche true si l'image a été chargée depuis le cache, sinon false :
qDebug
() <<
reply->
attribute(QNetworkRequest
::
SourceIsFromCacheAttribute).toBool();
}
Lors de la première exécution de l'application, l'image est chargée depuis l'extérieur. Lors des lancements suivants, elle ne charge plus l'image depuis l'url spécifiée mais depuis le cache.
QNetworkDiskCache est l'unique classe fournie par Qt qui permette de mettre en place un cache. Pour créer son propre système de cache, il suffit de créer une classe dérivée de la classe abstraite QAbstractNetworkCache, d'implémenter ses fonctions et d'utiliser setCache() avec.
Depuis un objet QNetworkReply obtenu du gestionnaire d'accès, il est possible d'arrêter la connexion qui en dépend. Évidemment, il est inutile de récupérer le QNetworkReply envoyé par le signal finished() de QNetworkAccessManager : si le signal est envoyé, c'est que le téléchargement est achevé et qu'il n'est plus possible de l'arrêter.
Vous pouvez utiliser la méthode abort() si vous désirez arrêter absolument toute activité de la réponse : cette méthode arrête tout, téléchargement ou téléversement. Elle finit toute connexion réseau.
Il existe aussi la méthode close(), qui prépare le périphérique à la lecture : les données non lues sont perdues mais les connexions réseau ne s'arrêtent pas tant qu'elles ne sont pas achevées. En particulier, un téléversement en cours ne sera pas arrêté.
QNetworkAccessManager
*
manager =
new
QNetworkAccessManager
();
QNetworkReply
*
reply =
manager->
get("http://qt.developpez.com"
);
reply->
close();
reply->
readAll(); // Cet appel ne renverra pas tout le contenu du fichier, juste ce qui aura été téléchargé, même s'il continue à être téléchargé
reply->
abort();
reply->
readAll(); // Cet appel ne renverra pas tout le contenu du fichier, juste ce qui aura été téléchargé mais le fichier ne continuera pas à être téléchargé