<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>C++, Qt et GPU &#187; Qt</title>
	<atom:link href="https://blog.developpez.com/gpu/?cat=9&#038;feed=rss2" rel="self" type="application/rss+xml" />
	<link>https://blog.developpez.com/gpu</link>
	<description></description>
	<lastBuildDate>Fri, 24 May 2013 17:02:21 +0000</lastBuildDate>
	<language>fr-FR</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=4.1.42</generator>
	<item>
		<title>Développez en natif pour Android avec Qt 5.1</title>
		<link>https://blog.developpez.com/gpu/?p=522</link>
		<comments>https://blog.developpez.com/gpu/?p=522#comments</comments>
		<pubDate>Thu, 23 May 2013 11:24:04 +0000</pubDate>
		<dc:creator><![CDATA[gbdivers]]></dc:creator>
				<category><![CDATA[C++]]></category>
		<category><![CDATA[Facile]]></category>
		<category><![CDATA[Qt5]]></category>
		<category><![CDATA[QtQuick]]></category>

		<guid isPermaLink="false">http://blog.developpez.com/gpu/?p=522</guid>
		<description><![CDATA[La sortie de Qt 5.1 est prévue en release candidat pour le 27 mai. Cette version propose le support d&#8217;Android et iOS, bien qu&#8217;il était déjà possible de porter sur Android avec Qt 4.8 et le projet Necessitas. Je vais &#8230; <a href="https://blog.developpez.com/gpu/?p=522">Lire la suite <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>La sortie de Qt 5.1 est prévue en release candidat pour le 27 mai. Cette version propose le support d&rsquo;Android et iOS, bien qu&rsquo;il était  déjà possible de porter sur Android avec Qt 4.8 et le projet <a href="http://www.developpez.net/forums/d1278983/plateformes/android-necessitas-port-android-qt-integre-au-qt-project/">Necessitas</a>. Je vais vous présenter ici comment créer une application Qt pour Android sous Ubuntu 13.04.</p>
<p><span id="more-522"></span></p>
<h1>Vue d&rsquo;ensemble</h1>
<p>Avant de commencer, une remarque sur Windows. À priori, il est possible de travailler sur Windows. Cependant, les binaires Qt pour Android ne sont disponibles que pour Linux. Comme la compilation de Qt pour Windows est pénible et que je ne l&rsquo;ai pas faite depuis longtemps, je présente seulement l&rsquo;utilisation de Linux. Pour ceux qui aimeraient pouvoir utiliser Windows&#8230; tant pis pour vous <img src="https://blog.developpez.com/gpu/wp-includes/images/smilies/icon_smile.gif" alt=":)" class="wp-smiley" /></p>
<p>Je n&rsquo;avais pas testé Qt sur Android depuis quelques temps, en fait depuis Qt 4.8 et Necessitas. Du coup, j&rsquo;ai découvert le portage Android dans Qt 5.1 en même temps que je prenais des notes pour cet article. Comme base de travail, je suis parti des pages des pages de documentation de Qt : <a href="http://doc-snapshot.qt-project.org/qt5-stable/qtdoc/android-support.html">Qt &#8211; Android support</a>.</p>
<p>L&rsquo;utilisation de Qt sur Android nécessite l&rsquo;installation de plusieurs outils :</p>
<ul>
<li>la version de <a href="http://download.qt-project.org/development_releases/qt/5.1/5.1.0-beta1/">Qt 5.1 pour Android</a> : ok, on s&rsquo;y attendait un peu. Contient la bibliothèque complète et Qt Creator ;</li>
<li>le <a href="http://developer.android.com/sdk/index.html">kit de développement (SDK) pour Android</a> : permet de créer des applications Java pour Android et un simulateur pour tester ses applications ;</li>
<li>le <a href="http://developer.android.com/tools/sdk/ndk/index.html">kit de développement natif (NDK) pour Android</a> : permet de créer des applications C++ pour Android ;</li>
<li>l&rsquo;<a href="http://openjdk.java.net/install/index.html">environnement d&rsquo;exécution de Java (JRE)</a> : nécessaire pour le SDK Android ;</li>
<li><a href="http://ant.apache.org/bindownload.cgi">Apache Ant</a> : pour faire beau. (bon ok, ce n&rsquo;est pas que pour faire beau, ça sert au déploiement. Mais comme c&rsquo;est un outil Java, je ne connais pas du tout).</li>
</ul>
<p>Dans ce tutoriel, je vais montrer l&rsquo;utilisation de Qt Creator, mais il doit être possible d&rsquo;utiliser d&rsquo;autres outils.</p>
<h1>Installations</h1>
<h2>Installation de OpenJDK 7</h2>
<p>Pour commencer, il faut installer l&rsquo;environnement d&rsquo;exécution de Java. Il est fort possible qu&rsquo;il soit déjà installé. Dans la documentation, il est indiqué qu&rsquo;il faut par exemple OpenJDK en version 6 ou plus récente.</p>
<p><del datetime="2013-05-24T14:58:09+00:00">Personnellement, j&rsquo;avais la version 7. Cependant, j&rsquo;ai eu des problème avec Apache Ant, qui me retournait une erreur. J&rsquo;ai donc dû installer la version 6 en plus. Comme j&rsquo;ai pas mal bidouillé, je ne suis pas sûr de la procédure. Si des personnes testent et remarquent des problèmes, n&rsquo;hésitez pas à me le signaler.</del></p>
<p><em>Merci à <a href="http://www.developpez.net/forums/u657013/rotoom/">rotoOm</a> qui m&rsquo;a indiqué l&rsquo;origine du problème. Il suffit en fait d&rsquo;installer le JDK en plus du JRE. Merci à lui pour l&rsquo;information.</em></p>
<p>Vous pouvez tester si Java est installé avec la ligne de commande suivante :</p>
<div class="codecolorer-container text blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">java -version</div></div>
<p>Pour l&rsquo;installation, j&rsquo;ai donc utilisé les paquets fournis par Ubuntu. Il faut donc juste taper ces lignes de commande :</p>
<div class="codecolorer-container text blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">sudo apt-get install openjdk-6-jre<br />
sudo apt-get install openjdk-7-jdk</div></div>
<p>Pour les autres systèmes Linux, vous pouvez consulter la page de documentation d&rsquo;OpenJDK : <a href="http://openjdk.java.net/install/index.html">How to download and install prebuilt OpenJDK packages</a>.</p>
<h2>Installation d&rsquo;Apache Ant</h2>
<p>Pour l&rsquo;installation d&rsquo;Apache Ant, même méthode, j&rsquo;utilise les paquets Ubuntu :</p>
<div class="codecolorer-container text blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">sudo apt-get -u install ant</div></div>
<p>Pour tester l&rsquo;installation d&rsquo;Apache Ant, vous pouvez taper la ligne de commande suivante :</p>
<div class="codecolorer-container text blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">ant -version</div></div>
<h2>Installation du SDK Android</h2>
<h3>Pourquoi installer le kit de développement Java ?</h3>
<p>Pour commencer, on ne peut se poser une question : pourquoi installer le kit de développement Java et le kit de développement natif et pas simplement ce dernier ? La réponse est simple : parce qu&rsquo;on ne peut développer que en Java pour Android !</p>
<p>Ok&#8230;</p>
<p>Donc cela veut dire qu&rsquo;il faudra utiliser le binding Java de Qt ? On parlait pas de développement C++ dans ce tutoriel ?</p>
<p>Oui, pas d&rsquo;inquiétude <img src="https://blog.developpez.com/gpu/wp-includes/images/smilies/icon_wink.gif" alt=";)" class="wp-smiley" /> En fait, il y a un point à savoir sur les applications natives C++ sur Android. C&rsquo;est une application Java qui appelle un &laquo;&nbsp;module&nbsp;&raquo; écrit en C++ (on utilise le terme &laquo;&nbsp;activité&nbsp;&raquo; en Java). Avec Qt, on va donc simplement créer notre code C++/Qt et Qt Creator va s&rsquo;occuper de créer l&rsquo;application Java qui appelle notre code.</p>
<p>Ouf !</p>
<h3>Installation</h3>
<p>L&rsquo;installation du SDK Android est simple aussi&#8230; puisqu&rsquo;il n&rsquo;y a pas d&rsquo;installation à faire. Vous devez simplement télécharger le <a href="http://developer.android.com/sdk/index.html">kit de développement pour Android</a> et décompresser l&rsquo;archive. Ce SDK contient les outils de développement Android, des plateformes de compilation, l&rsquo;éditeur Eclipse ADT (Android Developer Tools, configuré spécialement pour Android), un simulateur Android pour tester ses applications.</p>
<p>Pour installer d&rsquo;autres outils, par exemple d&rsquo;autres versions de plateforme, vous pouvez utiliser le SDK Manager. Dans Eclipse ADT, allez dans le menu Windows puis Android SDK Manager.</p>
<h3>Tester Eclipse</h3>
<p>Comme je suis curieux et que j&rsquo;ai envie de voir un peu comment fonctionne une application Java sur Android, j&rsquo;ai testé un peu Eclipse et Java. Ceux qui ne sont pas intéressés, vous pouvez passer directement à l&rsquo;installation du NDK.</p>
<p>Pour cela, j&rsquo;ai simplement suivi le tutoriel : <a href="http://developer.android.com/training/basics/firstapp/index.html">Building Your First App</a> (il faut reconnaître que la documentation est très claire et simple à suivre, même pour un développeur C++ comme moi).</p>
<p>Allez dans le répertoire d&rsquo;installation du SDK Android puis dans le répertoire eclipse/. Celui-ci contient un binaire eclipse, que vous lancez. Si c&rsquo;est la première utilisation d&rsquo;Eclipse, il va falloir faire quelques réglages de configuration. En premier le Workspace (l&rsquo;espace de travail d&rsquo;Eclipse, dans lequel il range les fichiers). Personnellement, j&rsquo;ai accepté toutes les valeurs par défaut.</p>
<p>Une fois qu&rsquo;Eclipse est lancé, créez un nouveau projet de type &laquo;&nbsp;Android Application Project&nbsp;&raquo; dans Fichier puis Créer un projet. Un dialogue permet de donner un nom à votre application (c&rsquo;est le nom qui apparaîtra sur le téléphone), la version minimale d&rsquo;Android à prendre en charge et la version Android de destination. J&rsquo;ai laissé par défaut. Vous pouvez ensuite choisir l&rsquo;icône de l&rsquo;application et le type d&rsquo;activité. Choisissez BlanckActivity, qui va créer une activité &laquo;&nbsp;hello world&nbsp;&raquo;.</p>
<p>Après quelques minutes (je vais rien dire que la lenteur d&rsquo;Eclipse&#8230;), un projet est créé, qui contient quelques fichiers et répertoires. Les plus importants sont :</p>
<ul>
<li>le fichier AndroidManifest.xml : contient les informations sur l&rsquo;application, en particulier les versions minimale et ciblée de la plateforme ;</li>
<li>le répertoire res/layout/ : contient les interfaces de l&rsquo;application, décrites dans des fichiers XML ;</li>
<li>le répertoire src/ : contient les sources Java du projet. Dans ce projet par défaut, il lance simplement une activité, qui affiche l&rsquo;interface décrite dans le fichier XML de layouts/ ;</li>
<li>les répertoires res/drawable-xxx/ : contient les images de l&rsquo;application.</li>
</ul>
<p>Comme c&rsquo;est une application Android, vous ne pouvez pas simplement la lancer comme une application de Bureau classique. Il existe deux méthodes pour la lancer : utiliser un simulateur ou déployer sur un téléphone.</p>
<h3>Tester l&rsquo;application sur simulateur</h3>
<p>Pour cela, il faut dans un premier temps créer un simulateur. Le SDK Android est fournit avec un gestionnaire, permettant de créer différentes configurations pour le simulateur, permettant ainsi de tester l&rsquo;application sur plusieurs types de téléphone.</p>
<p>Allez dans le menu Windows puis Android Virtual Device Manager. Dans le dialogue, créez un nouveau périphérique en cliquant sur &laquo;&nbsp;New&nbsp;&raquo;, puis configurez selon le type de téléphone que vous voulez tester. Par exemple, comme j&rsquo;ai un téléphone Samsung Galaxy S1, j&rsquo;ai choisit un écran 4&Prime; en 480*800. Après la création du périphérique, lancez-le.</p>
<p>Lancez ensuite l&rsquo;application en ouvrant le fichier java (dans src/) puis en cliquant sur le bouton Run. Un dialogue &laquo;&nbsp;Run As&#8230;&nbsp;&raquo; s&rsquo;ouvre pour choisir comment exécuter l&rsquo;application. Choisissez Android Application. Normalement, l&rsquo;application devrait se lancer.</p>
<h3>Tester l&rsquo;application sur téléphone</h3>
<p>Bon, un simulateur, c&rsquo;est bien, mais on aimerait avoir l&rsquo;application sur un vrai téléphone pour tester. Ce n&rsquo;est pas très compliqué non plus, mais il va falloir faire une manipulation sur le téléphone. Celle-ci permet d&rsquo;activer les fonctionnalités de développement du téléphone, en particulier le Debug Mode USB, qui permet de déployer des applications via un cable USB.</p>
<p>Pour Android 4.2, allez dans les paramètres puis dans le menu À propos du téléphone. Cliquez plusieurs fois sur Numéro de build par activer le mode développeur. Vous allez avoir un message confirmant le passage en mode Debug. Revenez ensuite à l&rsquo;écran précédent et allez dans les options de développeur. Activez le mode Debug USB. Pour les autres versions d&rsquo;Android, vous pouvez consulter la page suivante : <a href="http://developer.android.com/training/basics/firstapp/running-app.html#RealDevice">Run on a Real Device</a>.</p>
<p>Pour terminer, il suffit de brancher le téléphone sur l&rsquo;ordinateur avec un câble USB puis de lancer l&rsquo;application comme précédemment. L&rsquo;application devrait se lancer sur le téléphone.</p>
<h2>Installation du NDK Android</h2>
<p>Rien de compliqué ici non plus, il n&rsquo;y a pas d&rsquo;installation à faire, il faut simplement décompresser l&rsquo;archive.</p>
<h2>Installation de Qt Android</h2>
<p>Le plus simple, comme indiqué au début de ce tutoriel, est d&rsquo;utiliser les binaires fournis de <a href="http://download.qt-project.org/development_releases/qt/5.1/5.1.0-beta1/">Qt 5.1 pour Android</a>. Si vous n&rsquo;utilisez pas Ubuntu, il vous faudra compiler Qt vous-même. Bon courage <img src="https://blog.developpez.com/gpu/wp-includes/images/smilies/icon_smile.gif" alt=":)" class="wp-smiley" /></p>
<p>Lancez le binaire Qt pour Android. Le processus d&rsquo;installation est classique, avec une particularité : le SDK propose par défaut l&rsquo;installation de Qt Desktop, mais pour Android (versions ARM ou x86), il faut l&rsquo;activer soi-même. Une fois l&rsquo;installation finie, allez dans les répertoires Tools, QtCreator, bin puis lancez qtcreator.</p>
<p>La première étape va être de configurer Android. Pour cela, allez dans le menu Outils puis Options. Dans la liste de gauche, allez dans Android, puis configurez les répertoires du SDK et du NDK. Cochez la case pour laisser Qt Creator créer automatiquement les kits de compilation.</p>
<p><a href="http://blog.developpez.com/gpu/files/2013/05/android.png"><img src="http://blog.developpez.com/gpu/files/2013/05/android-300x188.png" alt="android" width="300" height="188" class="aligncenter size-medium wp-image-555" /></a></p>
<p>Il faut ensuite créer un périphérique pour le simulateur si ce n&rsquo;est pas encore fait. Pour cela, cliquez sur le bouton Start Android AVD Manager. </p>
<p><a href="http://blog.developpez.com/gpu/files/2013/05/avd-manager.png"><img src="http://blog.developpez.com/gpu/files/2013/05/avd-manager.png" alt="avd manager" width="680" height="500" class="aligncenter size-full wp-image-556" /></a></p>
<p>Cliquez sur New pour créer un nouveau périphérique. Choisissez le type de Device (pour simuler mon Galaxy S, j&rsquo;ai donc choisit un 4&Prime; en 480*800). N&rsquo;oubliez pas d&rsquo;activer la prise en charge du GPU (Use Host GPU) pour que Qt puisse utiliser OpenGL ES.</p>
<p><a href="http://blog.developpez.com/gpu/files/2013/05/new-device.png"><img src="http://blog.developpez.com/gpu/files/2013/05/new-device.png" alt="new device" width="480" height="709" class="aligncenter size-full wp-image-558" /></a></p>
<p>Pour créer une application Qt, allez dans le menu Fichier puis Nouveau projet. Choisissez un projet compatible avec Android (par exemple Application Graphique Qt ou Application Qt Quick 2 (élément de base)).</p>
<p><a href="http://blog.developpez.com/gpu/files/2013/05/new-project.png"><img src="http://blog.developpez.com/gpu/files/2013/05/new-project.png" alt="new project" width="1440" height="900" class="aligncenter size-full wp-image-559" /></a></p>
<p>Dans un premier temps, le simulateur se lance.</p>
<p><a href="http://blog.developpez.com/gpu/files/2013/05/simulator.png"><img src="http://blog.developpez.com/gpu/files/2013/05/simulator.png" alt="simulator" width="481" height="827" class="aligncenter size-full wp-image-561" /></a></p>
<p>Puis l&rsquo;application à la fin du déploiement.</p>
<p><a href="http://blog.developpez.com/gpu/files/2013/05/run-simulator.png"><img src="http://blog.developpez.com/gpu/files/2013/05/run-simulator.png" alt="run simulator" width="714" height="829" class="aligncenter size-full wp-image-560" /></a></p>
<p>Pour déployer sur un téléphone (préalablement passé en mode Debug USB, voir au début), il suffit simplement de le brancher, Qt Creator lancera alors l&rsquo;application dessus.</p>
<p><a href="http://blog.developpez.com/gpu/files/2013/05/IMG_4736.jpg"><img src="http://blog.developpez.com/gpu/files/2013/05/IMG_4736.jpg" alt="IMG_4736" width="477" height="900" class="aligncenter size-full wp-image-557" /></a></p>
<h1>Conclusion</h1>
<p>Rien de très compliqué finalement. Le déploiement est relativement simple une fois que les outils sont configurés. Reste plus qu&rsquo;à tester les performances. <img src="https://blog.developpez.com/gpu/wp-includes/images/smilies/icon_wink.gif" alt=";)" class="wp-smiley" /></p>
<p>Pour ceux qui sont intéressés par Qt Quick, je rappelle le livre auquel je participe : <a href="http://www.d-booker.fr/110-qt-5-les-essentiels.html">Créer des applications avec Qt 5 &#8211; Les essentiels</a>. J&rsquo;ai en particulier participé à la rédaction de Qt Quick. C&rsquo;est encore une pré-version du livre final, mais il y a déjà pas mal de choses sur Qt Quick. Et n&rsquo;hésitez pas à me dire s&rsquo;il y a des points que vous souhaiteriez voir abordés dans ce livre.</p>
<p>Si vous êtes intéressé par Qt Quick sur mobile, je fais une présentation le 5 juin à Paris. Contactez-moi par MP pour plus d&rsquo;informations.</p>
<p>Merci à <a href="http://www.developpez.net/forums/u39401/prgasp77/">prgasp77</a> et <a href="http://www.developpez.net/forums/u329028/winjerome/">winjerome</a> pour leur relecture orthographique.</p>
<p><a href="http://www.developpez.net/forums/d1346162/qt/developpez-en-natif-pour-android-avec-qt-51/">N&rsquo;hésitez pas à commenter cet article sur le forum.</a></p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Vidéos d&#8217;installation de Qt 5</title>
		<link>https://blog.developpez.com/gpu/?p=411</link>
		<comments>https://blog.developpez.com/gpu/?p=411#comments</comments>
		<pubDate>Fri, 10 May 2013 22:29:56 +0000</pubDate>
		<dc:creator><![CDATA[gbdivers]]></dc:creator>
				<category><![CDATA[Facile]]></category>
		<category><![CDATA[Qt]]></category>
		<category><![CDATA[Qt5]]></category>
		<category><![CDATA[QtQuick]]></category>

		<guid isPermaLink="false">http://blog.developpez.com/gpu/?p=411</guid>
		<description><![CDATA[Bonjour à tous Un problème que l&#8217;on revoit souvent sur le forum est l&#8217;installation de Qt 5. J&#8217;ai réalisé, dans le cadre du livre sur Qt auquel je participe (Créer des applications avec Qt 5 &#8211; Les essentiels), plusieurs vidéos &#8230; <a href="https://blog.developpez.com/gpu/?p=411">Lire la suite <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Bonjour à tous</p>
<p>Un problème que l&rsquo;on revoit souvent sur le forum est l&rsquo;installation de Qt 5. J&rsquo;ai réalisé, dans le cadre du livre sur Qt auquel je participe (<a href="http://www.d-booker.fr/110-qt-5-les-essentiels.html">Créer des applications avec Qt 5 &#8211; Les essentiels</a>), plusieurs vidéos pour expliquer comment installer et tester l&rsquo;installation.</p>
<p>Il y a quatre vidéos pour le moment : </p>
<ul>
<li>installation sur Windows avec Microsoft Visual C++ 2010 ;</li>
<li>installation sur Windows avec MinGW ;</li>
<li>installation sur Linux en utilisant les binaires ;</li>
<li>installation sur Ubuntu en utilisant les dépôts.</li>
</ul>
<p>Les vidéos sont disponibles sur le site de l&rsquo;éditeur : <a href="http://www.youtube.com/playlist?list=PLJ0RWFYCJZYF1pxD5FlAFqQVYkmebeTUY">D-booker.fr (YouTube)</a>.</p>
<p>Je n&rsquo;ai pas fait de prise son, donc penser à activer les sous-titres pour avoir les explications. J’essaierais de proposer prochainement d&rsquo;autres vidéos d&rsquo;installation (sur Mac, sur Raspberry Pi) ou des démos.</p>
<p>Bonne visualisation (et bonne lecture à ceux qui liront le livre ;))</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Un ColorPicker avec Qt – Benchmark et optimisations</title>
		<link>https://blog.developpez.com/gpu/?p=390</link>
		<comments>https://blog.developpez.com/gpu/?p=390#comments</comments>
		<pubDate>Fri, 15 Feb 2013 18:52:59 +0000</pubDate>
		<dc:creator><![CDATA[gbdivers]]></dc:creator>
				<category><![CDATA[C++]]></category>
		<category><![CDATA[Intermédiaire]]></category>
		<category><![CDATA[OpenGL]]></category>
		<category><![CDATA[Qt]]></category>

		<guid isPermaLink="false">http://blog.developpez.com/gpu/?p=390</guid>
		<description><![CDATA[Le sujet du premier exercice proposé par la rubrique Qt de Developpez.com consistait à créer un widget permettant de sélectionner les différentes nuances de gris à partir d&#8217;une teinte définie. Deux méthodes ont été proposer pour générer ces nuances de &#8230; <a href="https://blog.developpez.com/gpu/?p=390">Lire la suite <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Le sujet du premier exercice proposé par la rubrique Qt de Developpez.com consistait à créer un widget permettant de sélectionner les différentes nuances de gris à partir d&rsquo;une teinte définie.<br />
<span id="more-390"></span><br />
Deux méthodes ont été proposer pour générer ces nuances de gris :</p>
<ul>
<li>utiliser deux boucles for imbriquées pour parcourir chaque pixel du widget et calculer la couleur correspondante, en faisant varier les paramètres S et V dans l&rsquo;espace colorimétrique HSV ;</li>
<li>utiliser deux gradient (à l&rsquo;aide de la classe QLinearGradient), le premier, horizontal, allant du blanc à gauche à la teinte choisie à droite, et le second, vertical, allant du transparent en haut au noir en bas.</li>
</ul>
<p>Je vais présenter ici comment implémenter un benchmark avec Qt pour tester la rapidité de ces différentes méthodes et présenter deux autres méthodes pour accélérer le rendu : l&rsquo;accès direct au tampon mémoire contenant l&rsquo;image finale et l&rsquo;accélération matériel sur carte graphique.</p>
<h1>Création du programme Benchmark</h1>
<p>Qt offre différents outils facilitant la création de tests unitaires et de benchmarks, rassemblés dans le module <a href="http://qt.developpez.com/doc/4.6/QtTest/">QtTest</a>. Différents tutoriels permettent de se familiariser progressivement avec ce module.</p>
<h2>Benchmark.pro</h2>
<p>Pour créer notre programme Benchmark, commençons par créer un fichier de projet Benchmark.pro. Ce fichier de projet contient les déclarations de base suivantes : la liste des modules utilisés (core, gui puisse que l&rsquo;on teste les fonctions de dessin et testlib) et le nom et le type de binaire généré (une application Benchmark dans notre cas) :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">QT <span style="color: #000040;">+</span><span style="color: #000080;">=</span> core gui testlib<br />
TARGET <span style="color: #000080;">=</span> Benchmark<br />
TEMPLATE <span style="color: #000080;">=</span> app</div></td></tr></tbody></table></div>
<p>On ajoute ensuite la liste des fichiers à inclure dans notre projet. On va simplement créer une classe Benchmark : on ajoute donc les fichiers d&rsquo;en-tête et d&rsquo;implémentation :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">SOURCES <span style="color: #000040;">+</span><span style="color: #000080;">=</span> benchmark.<span style="color: #007788;">cpp</span><br />
HEADERS &nbsp;<span style="color: #000040;">+</span><span style="color: #000080;">=</span> benchmark.<span style="color: #007788;">h</span></div></td></tr></tbody></table></div>
<h2>benchmark.h</h2>
<p>La classe Benchmark hérite de QObject (pour pourvoir utiliser le système de signaux et slots) et contient deux slots privés, un pour chaque méthode que l&rsquo;on souhaite tester. Ces slots seront automatiquement appelés à l&rsquo;exécution du programme. A part cela, le contenu de la classe est minimaliste :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #339900;">#ifndef BENCHMARK_H</span><br />
<span style="color: #339900;">#define BENCHMARK_H</span><br />
<span style="color: #339900;">#include &lt;QtTest/QtTest&gt;</span><br />
<span style="color: #0000ff;">class</span> Benchmark <span style="color: #008080;">:</span> <span style="color: #0000ff;">public</span> QObject<br />
<span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; Q_OBJECT<br />
<span style="color: #0000ff;">private</span> slots<span style="color: #008080;">:</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">void</span> hsvGradient<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">void</span> doubleLinearGradient<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span><br />
<span style="color: #339900;">#endif // BENCHMARK_H</span></div></td></tr></tbody></table></div>
<h2>benchmark.cpp</h2>
<p>Dans le fichier d&rsquo;implémentation, on ajoute chaque méthode dans les slots correspondants :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #339900;">#include &quot;benchmark.h&quot;</span><br />
<br />
<span style="color: #0000ff;">void</span> Benchmark<span style="color: #008080;">::</span><span style="color: #007788;">hsvGradient</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
<span style="color: #008000;">&#125;</span><br />
<span style="color: #0000ff;">void</span> Benchmark<span style="color: #008080;">::</span><span style="color: #007788;">doubleLinearGradient</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
<span style="color: #008000;">&#125;</span></div></td></tr></tbody></table></div>
<p>Il faut également ajouter la macro QTEST_MAIN, qui crée une fonction main, qui aura pour fonction de créer une instance de la classe Benchmark et d&rsquo;exécuter les slots privés :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">QTEST_MAIN<span style="color: #008000;">&#40;</span>Benchmark<span style="color: #008000;">&#41;</span></div></td></tr></tbody></table></div>
<h2>Méthode des deux boucles for</h2>
<p>Pour mesurer le temps d&rsquo;exécution d&rsquo;une méthode, on utilise la macro BENCHMARK. Le temps du reste du code contenu dans le slot mais en dehors du bloc précédent la macro n&rsquo;est pas évalué. Pour vérifier que le code généré correctement les nuances de gris, on enregistre les images produites :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #339900;">#include &lt;QtGui/QPainter&gt;</span><br />
<span style="color: #0000ff;">const</span> <span style="color: #0000ff;">int</span> width <span style="color: #000080;">=</span> <span style="color: #0000dd;">500</span><span style="color: #008080;">;</span><br />
<span style="color: #0000ff;">const</span> <span style="color: #0000ff;">int</span> height <span style="color: #000080;">=</span> <span style="color: #0000dd;">500</span><span style="color: #008080;">;</span><br />
<span style="color: #0000ff;">const</span> QColor m_main_color <span style="color: #000080;">=</span> Qt<span style="color: #008080;">::</span><span style="color: #007788;">red</span><span style="color: #008080;">;</span><br />
<span style="color: #0000ff;">void</span> Benchmark<span style="color: #008080;">::</span><span style="color: #007788;">hsvGradient</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; QImage image <span style="color: #000080;">=</span> QImage<span style="color: #008000;">&#40;</span>QSize<span style="color: #008000;">&#40;</span>width, height<span style="color: #008000;">&#41;</span>, QImage<span style="color: #008080;">::</span><span style="color: #007788;">Format_ARGB32</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; QBENCHMARK<br />
&nbsp; &nbsp; <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">float</span> h <span style="color: #000080;">=</span> m_main_color.<span style="color: #007788;">hsvHueF</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">for</span> <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> s<span style="color: #000080;">=</span><span style="color: #0000dd;">0</span><span style="color: #008080;">;</span> s<span style="color: #000080;">&lt;</span>width<span style="color: #008080;">;</span> <span style="color: #000040;">++</span>s<span style="color: #008000;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">for</span> <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> v<span style="color: #000080;">=</span><span style="color: #0000dd;">0</span><span style="color: #008080;">;</span> v<span style="color: #000080;">&lt;</span>height<span style="color: #008080;">;</span> <span style="color: #000040;">++</span>v<span style="color: #008000;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; QColor color <span style="color: #000080;">=</span> QColor<span style="color: #008080;">::</span><span style="color: #007788;">fromHsvF</span><span style="color: #008000;">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; h,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color:#800080;">1.0</span> <span style="color: #000040;">*</span> s <span style="color: #000040;">/</span> <span style="color: #008000;">&#40;</span>width<span style="color: #000040;">-</span><span style="color: #0000dd;">1</span><span style="color: #008000;">&#41;</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color:#800080;">1.0</span> <span style="color: #000040;">-</span> <span style="color: #008000;">&#40;</span><span style="color:#800080;">1.0</span> <span style="color: #000040;">*</span> v <span style="color: #000040;">/</span> <span style="color: #008000;">&#40;</span>height<span style="color: #000040;">-</span><span style="color: #0000dd;">1</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; image.<span style="color: #007788;">setPixel</span><span style="color: #008000;">&#40;</span>s, v, color.<span style="color: #007788;">rgb</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #008000;">&#125;</span><br />
&nbsp; &nbsp; image.<span style="color: #007788;">save</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;hsvGradient.png&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span></div></td></tr></tbody></table></div>
<h2>Méthode des deux gradients linéaires</h2>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #0000ff;">void</span> Benchmark<span style="color: #008080;">::</span><span style="color: #007788;">doubleLinearGradient</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; QImage image<span style="color: #008080;">;</span><br />
&nbsp; &nbsp; QPixmap pixmap<span style="color: #008000;">&#40;</span>QSize<span style="color: #008000;">&#40;</span>width, height<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; QPainter painter<span style="color: #008000;">&#40;</span><span style="color: #000040;">&amp;</span>pixmap<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; painter.<span style="color: #007788;">setPen</span><span style="color: #008000;">&#40;</span>QPen<span style="color: #008000;">&#40;</span>Qt<span style="color: #008080;">::</span><span style="color: #007788;">NoPen</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; QBENCHMARK<br />
&nbsp; &nbsp; <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; QLinearGradient h_gradient<span style="color: #008000;">&#40;</span>QPointF<span style="color: #008000;">&#40;</span><span style="color:#800080;">1.0</span>, <span style="color:#800080;">0.0</span><span style="color: #008000;">&#41;</span>, QPointF<span style="color: #008000;">&#40;</span>width, <span style="color:#800080;">0.0</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; h_gradient.<span style="color: #007788;">setColorAt</span><span style="color: #008000;">&#40;</span><span style="color: #0000dd;">0</span>, Qt<span style="color: #008080;">::</span><span style="color: #007788;">white</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; h_gradient.<span style="color: #007788;">setColorAt</span><span style="color: #008000;">&#40;</span><span style="color: #0000dd;">1</span>, m_main_color<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; painter.<span style="color: #007788;">setBrush</span><span style="color: #008000;">&#40;</span>QBrush<span style="color: #008000;">&#40;</span>h_gradient<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; painter.<span style="color: #007788;">drawRect</span><span style="color: #008000;">&#40;</span>QRect<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">0</span>, <span style="color: #0000dd;">0</span>, width, height<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; QLinearGradient v_gradient<span style="color: #008000;">&#40;</span>QPointF<span style="color: #008000;">&#40;</span><span style="color:#800080;">1.0</span>, <span style="color:#800080;">0.0</span><span style="color: #008000;">&#41;</span>, QPointF<span style="color: #008000;">&#40;</span><span style="color:#800080;">0.0</span>, height<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; v_gradient.<span style="color: #007788;">setColorAt</span><span style="color: #008000;">&#40;</span><span style="color: #0000dd;">0</span>, Qt<span style="color: #008080;">::</span><span style="color: #007788;">transparent</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; v_gradient.<span style="color: #007788;">setColorAt</span><span style="color: #008000;">&#40;</span><span style="color: #0000dd;">1</span>, Qt<span style="color: #008080;">::</span><span style="color: #007788;">black</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; painter.<span style="color: #007788;">setBrush</span><span style="color: #008000;">&#40;</span>QBrush<span style="color: #008000;">&#40;</span>v_gradient<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; painter.<span style="color: #007788;">drawRect</span><span style="color: #008000;">&#40;</span>QRect<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">0</span>, <span style="color: #0000dd;">0</span>, width, height<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; <span style="color: #008000;">&#125;</span><br />
&nbsp; &nbsp; image <span style="color: #000080;">=</span> pixmap.<span style="color: #007788;">toImage</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; image.<span style="color: #007788;">save</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;doubleLinearGradient.png&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span></div></td></tr></tbody></table></div>
<p>Le code étant expliqué dans la solution de l&rsquo;exercice, je n&rsquo;entre pas dans le détail ici.</p>
<h2>Résultat du benchmark</h2>
<p>Lorsque le programme est exécuté, des messages sont générés automatiquement à chaque étape du processus. L&rsquo;en-tête décrit simplement le nom du programme et les versions de QtTest et de Qt utilisées :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000040;">*********</span> Start testing of Benchmark <span style="color: #000040;">*********</span><br />
Config<span style="color: #008080;">:</span> Using QTest library 4.7.0, Qt 4.7.0</div></td></tr></tbody></table></div>
<p>Le premier slot que lance le programme est un slot spécifique, initTestCase, généré par défaut et ne faisant rien. Ce slot permet, si on le souhaite, d&rsquo;initialiser des objets pour l&rsquo;ensemble du programme :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">PASS <span style="color: #008080;">:</span> Benchmark<span style="color: #008080;">::</span><span style="color: #007788;">initTestCase</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span></div></td></tr></tbody></table></div>
<p>Vient ensuite les différents slots que l&rsquo;on a créé. Le premier est hsvGradient. Lorsque le temps d&rsquo;exécution du slots est trop petit, la mesure risque de ne pas être précise. Pour palier à cet inconvénient, le code contenu dans le bloc de code suivant la macro BENCHMARK peut être exécuté plusieurs fois, le temps indiqué correspondant au temps moyen mesuré. Ici, le slot hsvGradient a été exécuté deux fois et le temps moyen est de 47 millisecondes :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">RESULT <span style="color: #008080;">:</span> Benchmark<span style="color: #008080;">::</span><span style="color: #007788;">hsvGradient</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">:</span><br />
<span style="color: #0000dd;">47</span> msecs per iteration <span style="color: #008000;">&#40;</span>total<span style="color: #008080;">:</span> <span style="color: #0000dd;">94</span>, iterations<span style="color: #008080;">:</span> <span style="color: #0000dd;">2</span><span style="color: #008000;">&#41;</span><br />
PASS <span style="color: #008080;">:</span> Benchmark<span style="color: #008080;">::</span><span style="color: #007788;">hsvGradient</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span></div></td></tr></tbody></table></div>
<p>Pour le slot doubleLinearGradient, le code a été exécuté une seule fois et le temps mesuré est de 57 millisecondes. On voit donc ici que cette méthode est plus lente que la première version (sur le système testé ! C&rsquo;est à dire Linux dans mon cas. Sous Windows ou Max OS X, il est possible que les résultats soient différents). Cette différence peut s&rsquo;expliquer par le fait que la génération de deux gradients et la gestion de la transparence est plus lente que l&rsquo;accès directe aux pixels, sur le système de rendu par défaut (le système Raster) :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">RESULT <span style="color: #008080;">:</span> Benchmark<span style="color: #008080;">::</span><span style="color: #007788;">doubleLinearGradient</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">:</span><br />
<span style="color: #0000dd;">57</span> msecs per iteration <span style="color: #008000;">&#40;</span>total<span style="color: #008080;">:</span> <span style="color: #0000dd;">57</span>, iterations<span style="color: #008080;">:</span> <span style="color: #0000dd;">1</span><span style="color: #008000;">&#41;</span><br />
PASS <span style="color: #008080;">:</span> Benchmark<span style="color: #008080;">::</span><span style="color: #007788;">doubleLinearGradient</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span></div></td></tr></tbody></table></div>
<p>Le programme exécute ensuite un slot pour libérer les ressources initialisées dans la fonction initTestCase :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">PASS <span style="color: #008080;">:</span> Benchmark<span style="color: #008080;">::</span><span style="color: #007788;">cleanupTestCase</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span></div></td></tr></tbody></table></div>
<p>Pour terminer, le programme indique le nombre de slot exécutés sans incident (passed), ceux qui ont échoué (failed) et ceux qui n&rsquo;ont pas été exécutés (skipped) :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">Totals<span style="color: #008080;">:</span> <span style="color: #0000dd;">4</span> passed, <span style="color: #0000dd;">0</span> failed, <span style="color: #0000dd;">0</span> skipped<br />
<span style="color: #000040;">*********</span> Finished testing of Benchmark <span style="color: #000040;">*********</span></div></td></tr></tbody></table></div>
<h1>Rendu dans un tampon mémoire</h1>
<p>Dans la première méthode, on utilise la fonction Qimage::setPixel pour modifier chaque pixel un par un. Cette méthode permet d&rsquo;utiliser une interface sécurisée et simple. Malheureusement, les calculs (calcul de l&rsquo;adresse mémoire correspondant au pixel, conversion de l&rsquo;espace colorimétrique HSV en RGB) et tests effectués en interne (la position du pixel est bien dans l&rsquo;image ? Les valeurs de la couleurs sont-elles correctes ?) peuvent ralentir fortement l&rsquo;exécution.<br />
Il est alors possible d&rsquo;optimiser le rendu en accédant directement à la mémoire à l&rsquo;aide de pointeurs : on créer un bloc mémoire de taille suffisante que l&rsquo;on alloue à une image puis on accède à chaque octet un par un.</p>
<p>ATTENTION : ce type d&rsquo;approche peut comporter certains risques : en cas d&rsquo;erreur dans le code, il est possible que l&rsquo;on écrive dans une zone mémoire qui ne correspond pas à l&rsquo;image. Aucun test n&rsquo;est effectué pour vérifier que le pointeur pointe vers une zone valide. L&rsquo;application peut devenir instable. De plus, il est possible que le code ne soit pas portable et donne des résultats différents en fonction des systèmes d&rsquo;exploitation utilisés (je l&rsquo;ai testé uniquement sur Linux, pensez à bien enregistrer tous vos documents avant de lancer le programme sur un autre système:) ).</p>
<p>La première chose a faire est de créer une zone mémoire de taille suffisante : un pixel étant codé sur 32 bits (un octet par composante de la couleur et quatre composantes : rouge, vert, bleu et alpha), il faudra donc réserver un bloc mémoire de width * height * 4 pour contenir toute l&rsquo;image :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #0000ff;">void</span> Benchmark<span style="color: #008080;">::</span><span style="color: #007788;">drawInBuffer</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; uchar buffer<span style="color: #008000;">&#91;</span>width <span style="color: #000040;">*</span> height <span style="color: #000040;">*</span> <span style="color: #0000dd;">4</span><span style="color: #008000;">&#93;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; QImage image<span style="color: #008000;">&#40;</span>buffer, width, height, QImage<span style="color: #008080;">::</span><span style="color: #007788;">Format_ARGB32</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>Il n&rsquo;est pas nécessaire d&rsquo;initialiser chaque octet du bloc mémoire (avec memset par exemple) puisque l&rsquo;algorithme utilisé garanti que chaque octet sera initialisé durant l&rsquo;exécution de celui-ci.</p>
<p>Pour commencer, on crée un pointeur pointant vers le premier octet du bloc mémoire :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; &nbsp; QBENCHMARK<br />
&nbsp; &nbsp; <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; uchar<span style="color: #000040;">*</span> pbuffer <span style="color: #000080;">=</span> <span style="color: #000040;">&amp;</span>buffer<span style="color: #008000;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #008000;">&#93;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>On utilise deux boucle for, comme dans la première méthode, pour parcourir chaque pixel (en fait, on parcourt le bloc mémoire linéairement, en « déplaçant » le pointeur octet par octet et non en accédant aux coordonnées (x, y) comme dans le cas d&rsquo;une image) :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">for</span> <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> i<span style="color: #000080;">=</span><span style="color: #0000dd;">0</span><span style="color: #008080;">;</span> i<span style="color: #000080;">&lt;</span>width<span style="color: #008080;">;</span> <span style="color: #000040;">++</span>i<span style="color: #008000;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666;">//uchar green_blue = red;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">for</span> <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> j<span style="color: #000080;">=</span><span style="color: #0000dd;">0</span><span style="color: #008080;">;</span> j<span style="color: #000080;">&lt;</span>height<span style="color: #008080;">;</span> <span style="color: #000040;">++</span>j<span style="color: #008000;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">&#123;</span></div></td></tr></tbody></table></div>
<p>Les valeurs de composantes RGB sont calculés par la méthode présentée dans la version QML de la solution de l&#039;exercice :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">float</span> a <span style="color: #000080;">=</span> <span style="color:#800080;">255.0</span> <span style="color: #000040;">*</span> <span style="color: #008000;">&#40;</span><span style="color:#800080;">1.0</span> <span style="color: #000040;">-</span> <span style="color: #008000;">&#40;</span><span style="color:#800080;">1.0</span> <span style="color: #000040;">*</span> i <span style="color: #000040;">/</span> width<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">float</span> b <span style="color: #000080;">=</span> a <span style="color: #000040;">*</span> <span style="color: #008000;">&#40;</span><span style="color:#800080;">1.0</span> <span style="color: #000040;">-</span> <span style="color: #008000;">&#40;</span><span style="color:#800080;">1.0</span> <span style="color: #000040;">*</span> j <span style="color: #000040;">/</span> height<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>Ensuite, pour chaque composante, on affecte la valeur calculée (sous forme de uchar pour être sur qu&#039;elle occupe bien à un octet en mémoire) à l&#039;octet pointé par le pointeur (en dé-référençant celui-ci) puis on « avance » le pointeur d&rsquo;un octet :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000040;">*</span>pbuffer <span style="color: #000080;">=</span> <span style="color: #008000;">&#40;</span>uchar<span style="color: #008000;">&#41;</span> b<span style="color: #008080;">;</span> <span style="color: #666666;">// blue</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000040;">++</span>pbuffer<span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>On fait de même pour les autres composantes :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000040;">*</span>pbuffer <span style="color: #000080;">=</span> <span style="color: #008000;">&#40;</span>uchar<span style="color: #008000;">&#41;</span> b<span style="color: #008080;">;</span> <span style="color: #666666;">// green</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000040;">++</span>pbuffer<span style="color: #008080;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000040;">*</span>pbuffer <span style="color: #000080;">=</span> <span style="color: #008000;">&#40;</span>uchar<span style="color: #008000;">&#41;</span> a<span style="color: #008080;">;</span> <span style="color: #666666;">// red</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000040;">++</span>pbuffer<span style="color: #008080;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000040;">*</span>pbuffer <span style="color: #000080;">=</span> <span style="color: #008000;">&#40;</span>uchar<span style="color: #008000;">&#41;</span> <span style="color: #0000dd;">255</span><span style="color: #008080;">;</span> <span style="color: #666666;">// alpha</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000040;">++</span>pbuffer<span style="color: #008080;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #008000;">&#125;</span></div></td></tr></tbody></table></div>
<p>Pour terminer, on enregistre l&rsquo;image générée :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; &nbsp; image.<span style="color: #007788;">save</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;buffured.png&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span></div></td></tr></tbody></table></div>
<h2>Résultat du benchmark</h2>
<p>Les messages de sortie d&rsquo;application générés par le slot drawInBuffer indique que cette méthode est plus rapide d&rsquo;un facteur 10 que les deux autres méthodes, avec un temps d&rsquo;exécution moyen de 3,9 millisecondes :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">RESULT <span style="color: #008080;">:</span> Benchmark<span style="color: #008080;">::</span><span style="color: #007788;">drawInBuffer</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">:</span><br />
<span style="color:#800080;">3.9</span> msecs per iteration <span style="color: #008000;">&#40;</span>total<span style="color: #008080;">:</span> <span style="color: #0000dd;">63</span>, iterations<span style="color: #008080;">:</span> <span style="color: #0000dd;">16</span><span style="color: #008000;">&#41;</span><br />
PASS <span style="color: #008080;">:</span> Benchmark<span style="color: #008080;">::</span><span style="color: #007788;">drawInBuffer</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span></div></td></tr></tbody></table></div>
<h1>Optimisation de l&rsquo;algorithme</h1>
<p>Jusqu&rsquo;à présent, nous avons simplement travailler sur l&rsquo;implémentation pour optimiser le rendu des nuances de gris. Une autre approche consiste à travailler sur l&rsquo;algorithme utilisé et d&rsquo;essayer de diminuer les calculs effectués.<br />
Quelque soit l&rsquo;approche utilisée, il sera nécessaire de parcourir l&rsquo;ensemble des pixels du widget, soit explicitement, comme dans le cas de la première méthode présentée, soit implicitement, comme dans le cas des deux QLinearGradient. On ne pourra donc pas optimiser cette partie (on peut au mieux éviter de parcourir plusieurs fois chaque pixel, comme on fait avec la méthode avec les deux QLinearGradient).<br />
On peut remarquer que, dans chaque méthode présentée jusqu&rsquo;ici, on travaille avec des nombres réels, ce qui n&rsquo;est pas optimal. L&rsquo;idéal serait de travailler qu&rsquo;avec des nombres entiers, mieux gérés par les processeurs, et d&rsquo;effectuer que des opérations élémentaires : addition, soustraction et multiplication.</p>
<p>Regardons en détail ce que l&rsquo;on souhaite faire lorsque l&rsquo;on parcourt un ligne pour une composante en particulier. La composante est une valeur entière allant de 0 à 255 (ou de 255 à 0) pour les pixels allant de 0 à N (avec N &gt; 256 pour être sur d&rsquo;afficher toutes les nuances). Il faut donc parcourir chaque pixel et incrémenter, quand c&rsquo;est nécessaire, la composante. Si on représente cela avec un graphique 2D, on obtient :</p>
<p><img src="http://blog.developpez.com/gpu/files/2013/02/droite.png" class="aligncenter" /></p>
<p>avec x, l&rsquo;index des pixels, et y, la composante de la couleur (source : <a href="http://commons.wikimedia.org/wiki/File:Bresenham_run-based.svg">Wikipédia</a>).</p>
<p>Le lecteur averti aura compris l&rsquo;idée sous-jacente : calculer la composante de la couleur revient à dessiner une ligne dans un espace (x, y) discret. Or, il existe un algorithme très performant pour réaliser cela : <a href="http://fr.wikipedia.org/wiki/Algorithme_de_trac.%C3%A9_de_segment_de_Bresenham">l&rsquo;algorithme de Bresenham</a>. Il suffit juste de remplacer y par la composante de la couleur. Le lecteur se reportera à l&rsquo;article de Wikipédia pour l&rsquo;explication du principe de cet algorithme.</p>
<p>L&rsquo;implémentation de l&rsquo;algorithme est assez triviale à partir du pseudo-code. On fera attention aux notations utilisées, qui correspondent au pseudo-code, c&rsquo;est à dire que y1 correspondent à la composante de la couleur et non à la position verticale du pixel. La variable i est utilisée pour parcourir verticalement l&rsquo;image dans une boucle for :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">QImage image<span style="color: #008000;">&#40;</span>width, height, Qimage<span style="color: #008080;">::</span><span style="color: #007788;">Format_ARGB32</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<br />
<span style="color: #0000ff;">int</span> x1 <span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span> <span style="color: #666666;">// premier pixel</span><br />
<span style="color: #0000ff;">int</span> y1 <span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span> <span style="color: #666666;">// composante dans le premier pixel</span><br />
<span style="color: #0000ff;">const</span> <span style="color: #0000ff;">int</span> x2 <span style="color: #000080;">=</span> width <span style="color: #000040;">-</span> <span style="color: #0000dd;">1</span><span style="color: #008080;">;</span> <span style="color: #666666;">// dernier pixel</span><br />
<span style="color: #0000ff;">const</span> <span style="color: #0000ff;">int</span> y2 <span style="color: #000080;">=</span> <span style="color: #0000dd;">255</span><span style="color: #008080;">;</span> <span style="color: #666666;">// composante dans le dernier pixel</span><br />
<span style="color: #0000ff;">int</span> e <span style="color: #000080;">=</span> x2 <span style="color: #000040;">-</span> x1<span style="color: #008080;">;</span><br />
<span style="color: #0000ff;">const</span> <span style="color: #0000ff;">int</span> dx <span style="color: #000080;">=</span> <span style="color: #0000dd;">2</span> <span style="color: #000040;">*</span> e<span style="color: #008080;">;</span><br />
<span style="color: #0000ff;">const</span> <span style="color: #0000ff;">int</span> dy <span style="color: #000080;">=</span> <span style="color: #0000dd;">2</span> <span style="color: #000040;">*</span> <span style="color: #008000;">&#40;</span>y2 <span style="color: #000040;">-</span> y1<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<span style="color: #0000ff;">while</span> <span style="color: #008000;">&#40;</span>x1 <span style="color: #000080;">&lt;=</span> x2<span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">for</span> <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> i<span style="color: #000080;">=</span><span style="color: #0000dd;">0</span><span style="color: #008080;">;</span> i<span style="color: #000080;">&lt;</span>height<span style="color: #008080;">;</span> <span style="color: #000040;">++</span>i<span style="color: #008000;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; image.<span style="color: #007788;">setPixel</span><span style="color: #008000;">&#40;</span>QPoint<span style="color: #008000;">&#40;</span>x1, i<span style="color: #008000;">&#41;</span>, qRgb<span style="color: #008000;">&#40;</span>y1, y1, y1<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; <span style="color: #000040;">++</span>x1<span style="color: #008080;">;</span><br />
&nbsp; &nbsp; e <span style="color: #000040;">-</span><span style="color: #000080;">=</span> dy<span style="color: #008080;">;</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>e <span style="color: #000080;">&lt;=</span> <span style="color: #0000dd;">0</span><span style="color: #008000;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000040;">++</span>y1<span style="color: #008080;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; e <span style="color: #000040;">+</span><span style="color: #000080;">=</span> dx<span style="color: #008080;">;</span><br />
&nbsp; &nbsp; <span style="color: #008000;">&#125;</span><br />
<span style="color: #008000;">&#125;</span><br />
image.<span style="color: #007788;">save</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;bresenham.png&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>L&#039;image générée est un gradient allant du noir au blanc :</p>
<p><img src="http://blog.developpez.com/gpu/files/2013/02/gradient.png" class="aligncenter" /></p>
<p>Pour générer toutes les nuances, il va falloir imbriquer deux fois algorithme, le premier allant du blanc à la teinte choisie (première ligne de pixels) et le second allant de la teinte (pixel de  la première ligne) au noir (pixel de la dernière ligne). Il faut également gérer chaque composante indépendamment.</p>
<p>Pour terminer, il est possible de combiner cette méthode avec la méthode utilisant un tampon mémoire. Le code est très proche du précédent.</p>
<h2>Résultat du benchmark</h2>
<p>La méthode utilisant l&rsquo;algorithme amélioré permet de gagner un facteur 3 à 4 par rapport aux premières méthodes :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">RESULT <span style="color: #008080;">:</span> Benchmark<span style="color: #008080;">::</span><span style="color: #007788;">bresenham</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">:</span><br />
<span style="color: #0000dd;">14</span> msecs per iteration <span style="color: #008000;">&#40;</span>total<span style="color: #008080;">:</span> <span style="color: #0000dd;">58</span>, iterations<span style="color: #008080;">:</span> <span style="color: #0000dd;">4</span><span style="color: #008000;">&#41;</span><br />
PASS <span style="color: #008080;">:</span> Benchmark<span style="color: #008080;">::</span><span style="color: #007788;">bresenham</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span></div></td></tr></tbody></table></div>
<p>La version combinant les deux approches permet un gain de performance d&rsquo;un facteur 4 par rapport à la méthode utilisant un tampon mémoire et un facteur 50 par rapport au premières méthodes :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">RESULT <span style="color: #008080;">:</span> Benchmark<span style="color: #008080;">::</span><span style="color: #007788;">bresenhamInBuffer</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">:</span><br />
<span style="color:#800080;">1.1</span> msecs per iteration <span style="color: #008000;">&#40;</span>total<span style="color: #008080;">:</span> <span style="color: #0000dd;">72</span>, iterations<span style="color: #008080;">:</span> <span style="color: #0000dd;">64</span><span style="color: #008000;">&#41;</span><br />
PASS <span style="color: #008080;">:</span> Benchmark<span style="color: #008080;">::</span><span style="color: #007788;">bresenhamInBuffer</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span></div></td></tr></tbody></table></div>
<h1>Accélération matériel sur carte graphique</h1>
<p>Pour réaliser le rendu des nuances de gris sur carte graphique, on utilise une classe dérivée de QGLWidget. Il suffit de dessiner un rectangle s&rsquo;adaptant à la taille du widget, le reste du travail de rendu est réalisé dans le fragment shader : on calcule le rapport entre la position du pixel et la largeur du widget (passé en paramètre) pour calculer la nuance de gris correspondante :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #FF0000;">&quot;uniform vec4 main_color;<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><br />
<span style="color: #FF0000;">&quot;uniform vec2 size;<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><br />
<span style="color: #FF0000;">&quot;vec4 pixel_color;<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><br />
<span style="color: #FF0000;">&quot;void main(void)<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><br />
<span style="color: #FF0000;">&quot;{<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><br />
<span style="color: #FF0000;">&quot; &nbsp; &nbsp;pixel_color.r = (gl_FragCoord.y / size.y) * (1.0 + (gl_FragCoord.x / size.x) * (main_color.r - 1.0));<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><br />
<span style="color: #FF0000;">&quot; &nbsp; &nbsp;pixel_color.g = (gl_FragCoord.y / size.y) * (1.0 + (gl_FragCoord.x / size.x) * (main_color.g - 1.0));<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><br />
<span style="color: #FF0000;">&quot; &nbsp; &nbsp;pixel_color.b = (gl_FragCoord.y / size.y) * (1.0 + (gl_FragCoord.x / size.x) * (main_color.b - 1.0));<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><br />
<span style="color: #FF0000;">&quot; &nbsp; &nbsp;pixel_color.a = main_color.a;<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><br />
<span style="color: #FF0000;">&quot; &nbsp; &nbsp;gl_FragColor = pixel_color;<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><br />
<span style="color: #FF0000;">&quot;}<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>Pour que le fragment shader soit appliqué sur chaque pixel du widget, il suffit de dessiner un quadrilatère sur la totalité de la surface :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">glClear<span style="color: #008000;">&#40;</span>GL_COLOR_BUFFER_BIT<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
glBegin<span style="color: #008000;">&#40;</span>GL_QUADS<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; glVertex2f<span style="color: #008000;">&#40;</span><span style="color: #000040;">-</span><span style="color:#800080;">1.0</span>, <span style="color: #000040;">-</span><span style="color:#800080;">1.0</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; glVertex2f<span style="color: #008000;">&#40;</span><span style="color: #000040;">-</span><span style="color:#800080;">1.0</span>, <span style="color:#800080;">1.0</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; glVertex2f<span style="color: #008000;">&#40;</span><span style="color:#800080;">1.0</span>, <span style="color:#800080;">1.0</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; glVertex2f<span style="color: #008000;">&#40;</span><span style="color:#800080;">1.0</span>, <span style="color: #000040;">-</span><span style="color:#800080;">1.0</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
glEnd<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>Les différents paramètres utilisés dans le fragment shader sont définis à l&rsquo;aide des fonctions uniformLocation et setUniformValue. Par exemple, pour mettre à jour la taille du widget :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">position_location <span style="color: #000080;">=</span> program<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>uniformLocation<span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;position&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<br />
QVector2D s <span style="color: #000080;">=</span> QVector2D<span style="color: #008000;">&#40;</span>width, height<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
program<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>setUniformValue<span style="color: #008000;">&#40;</span>size_location, s<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>Par contre, je n&rsquo;ai pas réussit à utiliser les fonctions de benchmarks de Qt Test pour tester la rapidité du rendu par cette méthode. Pour pouvoir mesurer le temps, j&rsquo;ai ajouté un calcul du nombre de FPS (frame par seconde) avec un simple compteur, incrémenté à chaque cycle et remis à zéro toutes les secondes :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #0000ff;">int</span> delay <span style="color: #000080;">=</span> m_time.<span style="color: #007788;">msecsTo</span><span style="color: #008000;">&#40;</span>QTime<span style="color: #008080;">::</span><span style="color: #007788;">currentTime</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span> delay <span style="color: #000080;">&gt;=</span> <span style="color: #0000dd;">1000</span> <span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>m_fps <span style="color: #000080;">&gt;</span> m_fps_max<span style="color: #008000;">&#41;</span> m_fps_max <span style="color: #000080;">=</span> m_fps<span style="color: #008080;">;</span><br />
&nbsp; &nbsp; setWindowTitle<span style="color: #008000;">&#40;</span>QString<span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;fps:%1 - max:%2 - w:%3 - h:%4&quot;</span><span style="color: #008000;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; .<span style="color: #007788;">arg</span><span style="color: #008000;">&#40;</span>m_fps<span style="color: #008000;">&#41;</span>.<span style="color: #007788;">arg</span><span style="color: #008000;">&#40;</span>m_fps_max<span style="color: #008000;">&#41;</span>.<span style="color: #007788;">arg</span><span style="color: #008000;">&#40;</span>width<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span>.<span style="color: #007788;">arg</span><span style="color: #008000;">&#40;</span>height<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; m_fps <span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; m_time <span style="color: #000080;">=</span> QTime<span style="color: #008080;">::</span><span style="color: #007788;">currentTime</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span><br />
<span style="color: #0000ff;">else</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000040;">++</span>m_fps<span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span></div></td></tr></tbody></table></div>
<p>Pour mettre à jour la widget, j&rsquo;utilise un QTimer avec un délai de 0.</p>
<p>ATTENTION : Il en faut pas laisser le programme tourner trop longtemps avec cette méthode. Le programme tourne en boucle et utilise la carte graphique au maximum de ses capacités, ce qui augmente progressivement sa température. Personnellement, je n&rsquo;ai pas pris le risque de tester si cela pouvait endommager la carte graphique.</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">m_timer <span style="color: #000080;">=</span> <span style="color: #0000dd;">new</span> QTimer<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">this</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
connect<span style="color: #008000;">&#40;</span>m_timer, SIGNAL<span style="color: #008000;">&#40;</span>timeout<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span>, <span style="color: #0000dd;">this</span>, SLOT<span style="color: #008000;">&#40;</span>timerUpdate<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
m_timer<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>start<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">20</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<br />
<span style="color: #0000ff;">void</span> GradientWidget<span style="color: #008080;">::</span><span style="color: #007788;">timerUpdate</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; updateGL<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span></div></td></tr></tbody></table></div>
<h2>Performances</h2>
<p>J&rsquo;ai réalisé le test sur un ordinateur portable équipé d&rsquo;une carte Nvidia 8600M GT avec 512 Mo et un widget de 256 x 256 pixels. Avec cette configuration, les mesures donnent un FPS moyen de 5000 fps avec de pointes à 5200 fps, c&rsquo;est à dire des temps de rendu de l&rsquo;ordre de 0,2 millisecondes (soit 250 fois plus rapide que les premières versions).</p>
<h1>Les sources</h1>
<p><a href="http://www.developpez.net/forums/attachments/p67224d1284552523/c-cpp/bibliotheques/qt/exercice-qt-color-picker-deuxieme-partie-lancee/benchmark.zip/">Télécharger les sources des benchmarks.</a></p>
<p><a href="http://www.developpez.net/forums/attachments/p67225d1284552535/c-cpp/bibliotheques/qt/exercice-qt-color-picker-deuxieme-partie-lancee/colorpickeropengl.zip/">Télécharger les sources de la version OpenGL.</a></p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Un ColorPicker avec Qt – Version QML</title>
		<link>https://blog.developpez.com/gpu/?p=366</link>
		<comments>https://blog.developpez.com/gpu/?p=366#comments</comments>
		<pubDate>Fri, 15 Feb 2013 18:31:20 +0000</pubDate>
		<dc:creator><![CDATA[gbdivers]]></dc:creator>
				<category><![CDATA[C++]]></category>
		<category><![CDATA[Facile]]></category>
		<category><![CDATA[Qt]]></category>
		<category><![CDATA[QtQuick]]></category>

		<guid isPermaLink="false">http://blog.developpez.com/gpu/?p=366</guid>
		<description><![CDATA[Cet article est la solution que j’avais proposé à l’exercice Qt sur la création d’un ColorPicker (voir le première article de cette série). Dans cette partie, j&#8217;utilise le QML pour créer le ColorPicker. L&#8217;objet QML ColorPicker L&#8217;objet ColorPicker permet d&#8217;afficher &#8230; <a href="https://blog.developpez.com/gpu/?p=366">Lire la suite <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Cet article est la solution que j’avais proposé à l’exercice Qt sur la création d’un ColorPicker (<a href="http://blog.developpez.com/gpu/p11791/difficulte/facile/un-colorpicker-avec-qt-enonce-de-lexercice">voir le première article de cette série</a>). Dans cette partie, j&rsquo;utilise le QML pour créer le ColorPicker.<br />
<span id="more-366"></span></p>
<h1>L&rsquo;objet QML ColorPicker</h1>
<p>L&rsquo;objet ColorPicker permet d&rsquo;afficher les nuances de gris d&rsquo;une couleur et de sélectionner une nuance directement en cliquant dans l&rsquo;item. Les composantes des couleurs sont manipulées directement puisqu&rsquo;il n&rsquo;est pas possible d&rsquo;extraire les composantes d&rsquo;une couleur donnée en QML.<br />
La couleur principale est définie par les variables main_red, main_green et main_blue. La couleur sélectionnée est récupérée grâce aux variables selected_red, selected_green et selected_blue dans le contexte ColorPickerContext.</p>
<p>La taille de l&rsquo;item est fixée à 256&#215;256 :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">import Qt <span style="color:#800080;">4.7</span><br />
Item<br />
<span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; width<span style="color: #008080;">:</span> <span style="color: #0000dd;">256</span><br />
&nbsp; &nbsp; height<span style="color: #008080;">:</span> <span style="color: #0000dd;">256</span></div></td></tr></tbody></table></div>
<p>Pour dessiner les nuances de gris, on va utiliser deux gradients linéaires :</p>
<ul>
<li>le premier, horizontal, va du blanc à la couleur principale ;</li>
<li>le second, vertical, va du transparent au noir.</li>
</ul>
<p>Pour créer les gradients, on commence par définir un rectangle ayant les mêmes dimensions et position que l&rsquo;item :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; &nbsp; Rectangle<br />
&nbsp; &nbsp; <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; anchors.<span style="color: #007788;">fill</span><span style="color: #008080;">:</span> parent<br />
&nbsp; &nbsp; <span style="color: #008000;">&#125;</span></div></td></tr></tbody></table></div>
<p>On utilise ensuite l&rsquo;objet gradient pour remplir le rectangle avec le dégradé. Par exemple pour le second gradient :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; &nbsp; Rectangle<br />
&nbsp; &nbsp; <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; anchors.<span style="color: #007788;">fill</span><span style="color: #008080;">:</span> parent<br />
&nbsp; &nbsp; &nbsp; &nbsp; gradient<span style="color: #008080;">:</span> Gradient<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; GradientStop <span style="color: #008000;">&#123;</span> position<span style="color: #008080;">:</span> <span style="color:#800080;">0.0</span><span style="color: #008080;">;</span> color<span style="color: #008080;">:</span> Qt.<span style="color: #007788;">rgba</span><span style="color: #008000;">&#40;</span><span style="color: #0000dd;">0</span>, <span style="color: #0000dd;">0</span>, <span style="color: #0000dd;">0</span>, <span style="color: #0000dd;">0</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; GradientStop <span style="color: #008000;">&#123;</span> position<span style="color: #008080;">:</span> <span style="color:#800080;">1.0</span><span style="color: #008080;">;</span> color<span style="color: #008080;">:</span> Qt.<span style="color: #007788;">rgba</span><span style="color: #008000;">&#40;</span><span style="color: #0000dd;">0</span>, <span style="color: #0000dd;">0</span>, <span style="color: #0000dd;">0</span>, <span style="color: #0000dd;">1</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #008000;">&#125;</span></div></td></tr></tbody></table></div>
<p>On obtient ainsi un gradient vertical allant du transparent au noir. Pour le premier gradient, il faut donc effectuer une rotation du rectangle de 90° après l&rsquo;avoir correctement dimensionné et positionné :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; &nbsp; Rectangle<br />
&nbsp; &nbsp; <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; width<span style="color: #008080;">:</span> parent.<span style="color: #007788;">height</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; height<span style="color: #008080;">:</span> parent.<span style="color: #007788;">width</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; transform<span style="color: #008080;">:</span> Rotation <span style="color: #008000;">&#123;</span> angle<span style="color: #008080;">:</span> <span style="color: #0000dd;">90</span><span style="color: #008000;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; x<span style="color: #008080;">:</span> parent.<span style="color: #007788;">width</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; y<span style="color: #008080;">:</span> <span style="color: #0000dd;">0</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; gradient<span style="color: #008080;">:</span> Gradient<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; GradientStop <span style="color: #008000;">&#123;</span> position<span style="color: #008080;">:</span> <span style="color:#800080;">0.0</span><span style="color: #008080;">;</span> color<span style="color: #008080;">:</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Qt.<span style="color: #007788;">rgba</span><span style="color: #008000;">&#40;</span>main_red, main_green, main_blue, <span style="color: #0000dd;">1</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; GradientStop <span style="color: #008000;">&#123;</span> position<span style="color: #008080;">:</span> <span style="color:#800080;">1.0</span><span style="color: #008080;">;</span> color<span style="color: #008080;">:</span> <span style="color: #FF0000;">&quot;white&quot;</span> <span style="color: #008000;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #008000;">&#125;</span></div></td></tr></tbody></table></div>
<p>Pour visualiser la position de la couleur sélectionnée, on va afficher un cercle entourant la dernière position connue. Cependant, dessiner un cercle en QML est un peu complexe (il faut créer des objets path pour dessiner des courbes quadratiques et constituer le cercle). Pour simplifier, on va afficher une image de taille 8&#215;8 pixels représentant un cercle avec le fond transparent :</p>
<p><img src="http://blog.developpez.com/gpu/files/2013/02/curseur.png" class="aligncenter" /></p>
<p>On crée un objet image en indiquant la source du fichier. Par défaut, la taille de l&rsquo;image est celle du fichier chargé :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; &nbsp; Image<br />
&nbsp; &nbsp; <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; source<span style="color: #008080;">:</span> <span style="color: #FF0000;">&quot;cursor.png&quot;</span><br />
&nbsp; &nbsp; <span style="color: #008000;">&#125;</span></div></td></tr></tbody></table></div>
<p>Par défaut, on souhaite que le curseur soit placé au centre de l&rsquo;item. Pour cela, on utilise les variables x et y :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; &nbsp; Image<br />
&nbsp; &nbsp; <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; x<span style="color: #008080;">:</span> width<span style="color: #000040;">/</span><span style="color: #0000dd;">2</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; y<span style="color: #008080;">:</span> height<span style="color: #000040;">/</span><span style="color: #0000dd;">2</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; source<span style="color: #008080;">:</span> <span style="color: #FF0000;">&quot;cursor.png&quot;</span><br />
&nbsp; &nbsp; <span style="color: #008000;">&#125;</span></div></td></tr></tbody></table></div>
<p>Pour déplacer, le curseur en fonction de la position de la souris, il faut pouvoir identifier cette image :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; &nbsp; Image<br />
&nbsp; &nbsp; <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; id<span style="color: #008080;">:</span> cursor<br />
&nbsp; &nbsp; &nbsp; &nbsp; x<span style="color: #008080;">:</span> width<span style="color: #000040;">/</span><span style="color: #0000dd;">2</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; y<span style="color: #008080;">:</span> height<span style="color: #000040;">/</span><span style="color: #0000dd;">2</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; source<span style="color: #008080;">:</span> <span style="color: #FF0000;">&quot;cursor.png&quot;</span><br />
&nbsp; &nbsp; <span style="color: #008000;">&#125;</span></div></td></tr></tbody></table></div>
<p>On pourra alors déplacer l&rsquo;image en modifiant les variables x et y, en ajoutant le code suivant n&rsquo;importe où dans notre item :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; &nbsp; cursor.<span style="color: #007788;">x</span> <span style="color: #000080;">=</span> <span style="color: #0000dd;">100</span><br />
&nbsp; &nbsp; cursor.<span style="color: #007788;">y</span> <span style="color: #000080;">=</span> <span style="color: #0000dd;">100</span></div></td></tr></tbody></table></div>
<p>Pour terminer, il faut pouvoir récupérer les évènements souris survenant sur notre item. Cela est réalisé en créer un objet MouseArea de même dimension que l&rsquo;item :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; &nbsp; MouseArea<br />
&nbsp; &nbsp; <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; anchors.<span style="color: #007788;">fill</span><span style="color: #008080;">:</span> parent<br />
&nbsp; &nbsp; <span style="color: #008000;">&#125;</span></div></td></tr></tbody></table></div>
<p>Il faut ensuite demander à cette MouseArea de récupérer les clics sur le bouton gauche de la souris :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; &nbsp; MouseArea<br />
&nbsp; &nbsp; <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; anchors.<span style="color: #007788;">fill</span><span style="color: #008080;">:</span> parent<br />
&nbsp; &nbsp; &nbsp; &nbsp; acceptedButtons<span style="color: #008080;">:</span> Qt.<span style="color: #007788;">LeftButton</span><br />
&nbsp; &nbsp; <span style="color: #008000;">&#125;</span></div></td></tr></tbody></table></div>
<p>On va réagir à deux types d’évènements : un clic sur le bouton gauche, qui déclenche un évènement de type onPressed, et le déplacement de la souris avec le bouton enfoncé, qui déclenche un évènement de type onPositionChanged.<br />
Lors de ces évènements, on récupère la position de la souris grâce aux variables mouseX et mouseY que l&rsquo;on affecte aux positions de l&rsquo;image avec cursor.x et cursor.y. Cependant, il ne faut pas oublier que la position de cursor correspond au coin en haut à gauche de l&rsquo;image alors que la souris correspond au centre de l&rsquo;image. Il faut donc corriger en fonction des dimensions de l&rsquo;image :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; &nbsp; cursor.<span style="color: #007788;">x</span> <span style="color: #000080;">=</span> mouseX <span style="color: #000040;">-</span> <span style="color: #0000dd;">4</span><br />
&nbsp; &nbsp; cursor.<span style="color: #007788;">y</span> <span style="color: #000080;">=</span> mouseY – <span style="color: #0000dd;">4</span></div></td></tr></tbody></table></div>
<p>Pour terminer, après un changement de la couleur sélectionnée, il faut recalculer les variables selected_red, selected_green et selected_blue. Pour cela, on appelle un fonction JavaScript updateSelectedColor(), qu&rsquo;il faudra créer :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; &nbsp; MouseArea<br />
&nbsp; &nbsp; <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; anchors.<span style="color: #007788;">fill</span><span style="color: #008080;">:</span> parent<br />
&nbsp; &nbsp; &nbsp; &nbsp; acceptedButtons<span style="color: #008080;">:</span> Qt.<span style="color: #007788;">LeftButton</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; onPressed<span style="color: #008080;">:</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; cursor.<span style="color: #007788;">x</span> <span style="color: #000080;">=</span> mouseX <span style="color: #000040;">-</span> <span style="color: #0000dd;">4</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; cursor.<span style="color: #007788;">y</span> <span style="color: #000080;">=</span> mouseY <span style="color: #000040;">-</span> <span style="color: #0000dd;">4</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; updateSelectedColor<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; onPositionChanged<span style="color: #008080;">:</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; cursor.<span style="color: #007788;">x</span> <span style="color: #000080;">=</span> mouseX <span style="color: #000040;">-</span> <span style="color: #0000dd;">4</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; cursor.<span style="color: #007788;">y</span> <span style="color: #000080;">=</span> mouseY <span style="color: #000040;">-</span> <span style="color: #0000dd;">4</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; updateSelectedColor<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #008000;">&#125;</span></div></td></tr></tbody></table></div>
<p>Pour connaître la couleur sélectionnée, on ne dispose pas de fonction équivalente à Qimage::pixel(). Les seuls éléments que l&rsquo;on dispose sont : la position (x, y) de la couleur sélectionnée dans le widget de taille (width, height) et les composantes RGB de la couleur principale.<br />
Il faut donc calculer les composantes RGB de la couleur sélectionnée à partir de ces éléments et de la méthode utilisée pour dessiner l&rsquo;item.</p>
<p>Lorsque l&rsquo;on dessine le premier gradient, on va du blanc (1, 1, 1) à la couleur principale (R, G, B). Le rapport entre la position cursor.x et la largeur est équivalent au rapport entre la composante de la couleur principale et le blanc :</p>
<p><img src="http://blog.developpez.com/gpu/files/2013/02/composantes.png" class="alignnone" /></p>
<p>On obtient alors l&rsquo;équivalence suivante :</p>
<p>{r &#8211; 1} over {X} ~ = ~ {R &#8211; 1} over {width} ~ = ~ pente de la droite</p>
<p>Alors :</p>
<p>r ~ = ~ 1 ~ + ~ (R-1) {X} over {width} </p>
<p>De même pour les autres composantes :</p>
<p>g ~ = ~ 1 ~ + ~ (G-1) {X} over {width} newline<br />
b ~ = ~ 1 ~ + ~ (B-1) {X} over {width} </p>
<p>Lorsque l&rsquo;on dessine le second gradient, on va du transparent (alpha = 0) au noir (0, 0, 0, 1). La couleur final s&rsquo;écrit :</p>
<p>couleur finale ~ = ~ couleur initiale * (1 &#8211; alpha) ~ + ~ noir * alpha ~ = ~ couleur initiale * (1-alpha)</p>
<p>La transparence alpha est liée à la position cursor.y par :</p>
<p>alpha ~ = ~ {Y} over {height} </p>
<p>On obtient donc la formule suivante pour la composante rouge :</p>
<p>r&rsquo; ~ = ~ r * (1 &#8211; {Y} over {height} ) newline<br />
r&rsquo; ~ = ~ (1 + (R-1) {X} over {width}) * (1 &#8211; {Y} over {height} )</p>
<p>De même pour les autres composantes :</p>
<p>g&rsquo; ~ = ~ (1 + (G-1) {X} over {width}) * (1 &#8211; {Y} over {height} ) newline<br />
b&rsquo; ~ = ~ (1 + (B-1) {X} over {width}) * (1 &#8211; {Y} over {height} )</p>
<p>La fonction JavaScript s&rsquo;écrit alors, en utilisant ces formules :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; &nbsp; function updateSelectedColor<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; ColorPickerContext.<span style="color: #007788;">selected_red</span> <span style="color: #000080;">=</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">&#40;</span><span style="color: #0000dd;">1</span> <span style="color: #000040;">-</span> <span style="color: #008000;">&#40;</span>cursor.<span style="color: #007788;">y</span> <span style="color: #000040;">/</span> height<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span> <span style="color: #000040;">*</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">&#40;</span><span style="color: #0000dd;">1</span> <span style="color: #000040;">+</span> <span style="color: #008000;">&#40;</span>cursor.<span style="color: #007788;">x</span> <span style="color: #000040;">/</span> width<span style="color: #008000;">&#41;</span> <span style="color: #000040;">*</span> <span style="color: #008000;">&#40;</span>main_red <span style="color: #000040;">-</span> <span style="color: #0000dd;">1</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; ColorPickerContext.<span style="color: #007788;">selected_green</span> <span style="color: #000080;">=</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">&#40;</span><span style="color: #0000dd;">1</span> <span style="color: #000040;">-</span> <span style="color: #008000;">&#40;</span>cursor.<span style="color: #007788;">y</span> <span style="color: #000040;">/</span> height<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span> <span style="color: #000040;">*</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">&#40;</span><span style="color: #0000dd;">1</span> <span style="color: #000040;">+</span> <span style="color: #008000;">&#40;</span>cursor.<span style="color: #007788;">x</span> <span style="color: #000040;">/</span> width<span style="color: #008000;">&#41;</span> <span style="color: #000040;">*</span> <span style="color: #008000;">&#40;</span>main_green <span style="color: #000040;">-</span> <span style="color: #0000dd;">1</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; ColorPickerContext.<span style="color: #007788;">selected_blue</span> <span style="color: #000080;">=</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">&#40;</span><span style="color: #0000dd;">1</span> <span style="color: #000040;">-</span> <span style="color: #008000;">&#40;</span>cursor.<span style="color: #007788;">y</span> <span style="color: #000040;">/</span> height<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span> <span style="color: #000040;">*</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">&#40;</span><span style="color: #0000dd;">1</span> <span style="color: #000040;">+</span> <span style="color: #008000;">&#40;</span>cursor.<span style="color: #007788;">x</span> <span style="color: #000040;">/</span> width<span style="color: #008000;">&#41;</span> <span style="color: #000040;">*</span> <span style="color: #008000;">&#40;</span>main_blue <span style="color: #000040;">-</span> <span style="color: #0000dd;">1</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #008000;">&#125;</span></div></td></tr></tbody></table></div>
<h1>La classe GradientWidget</h1>
<p>Pour utiliser cet item QML dans du code C++, il est nécessaire d&rsquo;écrire un wrapper pour récupérer les signaux et slots de l&rsquo;item. Cette classe n&rsquo;est pas un widget et dérive donc de QObject (pour pouvoir utiliser le système de signaux et slots) :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #0000ff;">class</span> GradientWidget <span style="color: #008080;">:</span> <span style="color: #0000ff;">public</span> QObject<br />
<span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; Q_OBJECT</div></td></tr></tbody></table></div>
<p>Pour récupérer la couleur sélectionnée, il faut créer une variable pour chaque composante et utiliser la macro Q_PROPERTY pour la rendre accessible en QML. Il faut également définir les fonctions d&rsquo;écriture (pour modifier la variable depuis le QML) et de lecture (pour lire la variable à l&rsquo;extérieur de la classe) :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #0000ff;">public</span><span style="color: #008080;">:</span><br />
&nbsp; &nbsp; Q_PROPERTY<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">float</span> &nbsp; &nbsp;selected_red<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;READ &nbsp; &nbsp; selectedRed<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;WRITE &nbsp; &nbsp;setSelectedRed<span style="color: #008000;">&#41;</span><br />
<br />
<span style="color: #0000ff;">private</span><span style="color: #008080;">:</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">float</span> &nbsp; selected_red<span style="color: #008080;">;</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">float</span> &nbsp; selectedRed<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #0000ff;">const</span> <span style="color: #008000;">&#123;</span> <span style="color: #0000ff;">return</span> selected_red<span style="color: #008080;">;</span> <span style="color: #008000;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">void</span> &nbsp; &nbsp;setSelectedRed<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> <span style="color: #0000ff;">float</span> red<span style="color: #008000;">&#41;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">&#123;</span> selected_red <span style="color: #000080;">=</span> red<span style="color: #008080;">;</span> selectedColorChanged<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #008000;">&#125;</span></div></td></tr></tbody></table></div>
<p>Après avoir mis à jour la couleur avec la fonction setSelectedColor(), il faut émettre un signal contenant la couleur créée à partir des composantes :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">signals<span style="color: #008080;">:</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">void</span> &nbsp; &nbsp;colorSelected<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> QColor <span style="color: #000040;">&amp;</span>color<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<span style="color: #0000ff;">private</span><span style="color: #008080;">:</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">void</span> &nbsp; &nbsp;selectedColorChanged<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; emit colorSelected<span style="color: #008000;">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; QColor<span style="color: #008080;">::</span><span style="color: #007788;">fromRgbF</span><span style="color: #008000;">&#40;</span>selected_red, selected_green, selected_blue<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; <span style="color: #008000;">&#125;</span></div></td></tr></tbody></table></div>
<p>Il faut également définir les variables et fonctions pour les deux autres composantes :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; &nbsp; Q_PROPERTY<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">float</span> &nbsp; &nbsp;selected_green<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;READ &nbsp; &nbsp; selectedGreen<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;WRITE &nbsp; &nbsp;setSelectedGreen<span style="color: #008000;">&#41;</span><br />
&nbsp; &nbsp; Q_PROPERTY<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">float</span> &nbsp; &nbsp;selected_blue<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;READ &nbsp; &nbsp; selectedBlue<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;WRITE &nbsp; &nbsp;setSelectedBlue<span style="color: #008000;">&#41;</span></div></td></tr></tbody></table></div>
<p>La création de l&rsquo;item ColorPicker est réalisée dans le constructeur de la classe :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #0000ff;">public</span><span style="color: #008080;">:</span><br />
&nbsp; &nbsp; GradientWidget<span style="color: #008000;">&#40;</span>QWidget <span style="color: #000040;">*</span>parent <span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>Dans ce constructeur, il faut créer un objet QDeclarativeView pour afficher l&rsquo;item QML puis fournir le code QML à l&rsquo;aide la fonction setSource. La taille est fixée à 256&#215;256, comme dans le code QML. Dans cet exemple, le code QML est fournit dans un fichier .qml et référencé dans un fichier ressource .qrc :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">GradientWidget<span style="color: #008080;">::</span><span style="color: #007788;">GradientWidget</span><span style="color: #008000;">&#40;</span>QWidget <span style="color: #000040;">*</span>parent<span style="color: #008000;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #008080;">:</span> QObject<span style="color: #008000;">&#40;</span>parent<span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; view <span style="color: #000080;">=</span> <span style="color: #0000dd;">new</span> QdeclarativeView<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; view<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>resize<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">256</span>, <span style="color: #0000dd;">256</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; view<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>setSource<span style="color: #008000;">&#40;</span>QUrl<span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;qrc:/qml/colorpicker.qml&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>Pour permettre au code QML de transmettre les variables contenant les composantes de la couleur sélectionnée, il faut récupérer le contexte par défaut de la vue et définir une propriété ColorPickerContext dans celui-ci. Cette propriété permet d&rsquo;accéder à l&rsquo;objet dans le code QML à partir de la variable ColorPickerContext et permettre ainsi d&rsquo;accéder aux propriétés définies ci-dessus :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; &nbsp; context <span style="color: #000080;">=</span> view<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>rootContext<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; context<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>setContextProperty<span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;ColorPickerContext&quot;</span>, <span style="color: #0000dd;">this</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>Les variables view et context sont définies dans l&rsquo;en-tête de la classe par :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #0000ff;">private</span><span style="color: #008080;">:</span><br />
&nbsp; &nbsp; QDeclarativeView<span style="color: #000040;">*</span> &nbsp; &nbsp; &nbsp; view<span style="color: #008080;">;</span><br />
&nbsp; &nbsp; QDeclarativeContext<span style="color: #000040;">*</span> &nbsp; &nbsp;context<span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>Lors de la création de l&rsquo;item, on attribue également une couleur principale par défaut à l&rsquo;aide de la fonction setMainColor() :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; &nbsp; setMainColor<span style="color: #008000;">&#40;</span>Qt<span style="color: #008080;">::</span><span style="color: #007788;">red</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span></div></td></tr></tbody></table></div>
<p>Cette fonction setMainColor() est un slot ayant un paramètre, la couleur a attribuer :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #0000ff;">public</span> slots<span style="color: #008080;">:</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">void</span> &nbsp; &nbsp;setMainColor<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> QColor <span style="color: #000040;">&amp;</span>color<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>Pour transmettre cette couleur au code QML, on utilise la fonction setContextProperty(), qui permet d&rsquo;attribuer une valeur à une variable QML :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #0000ff;">void</span> GradientWidget<span style="color: #008080;">::</span><span style="color: #007788;">setMainColor</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> QColor <span style="color: #000040;">&amp;</span>color<span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; context<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>setContextProperty<span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;main_red&quot;</span>, color.<span style="color: #007788;">redF</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; context<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>setContextProperty<span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;main_green&quot;</span>, color.<span style="color: #007788;">greenF</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; context<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>setContextProperty<span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;main_blue&quot;</span>, color.<span style="color: #007788;">blueF</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span></div></td></tr></tbody></table></div>
<p>Pour terminer, il faut créer les fonctions show() et move() pour pouvoir afficher et déplacer la vue :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #0000ff;">public</span><span style="color: #008080;">:</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">void</span> &nbsp; &nbsp;show<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">void</span> &nbsp; &nbsp;move<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> x, <span style="color: #0000ff;">int</span> y<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<br />
<span style="color: #0000ff;">void</span> GradientWidget<span style="color: #008080;">::</span><span style="color: #007788;">show</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; view<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>show<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span><br />
<span style="color: #0000ff;">void</span> GradientWidget<span style="color: #008080;">::</span><span style="color: #007788;">move</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> x, <span style="color: #0000ff;">int</span> y<span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; view<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>move<span style="color: #008000;">&#40;</span>x, y<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span></div></td></tr></tbody></table></div>
<h1>Le résultat final</h1>
<p>Voici le rendu obtenu :</p>
<p><img src="http://qt.developpez.com/exercices/01-colorpicker/1-degrade/gbdivers_qml/gbdivers_qml_capture.png" class="aligncenter" /></p>
<p><a href="http://qt.developpez.com/exercices/01-colorpicker/1-degrade/gbdivers_qml/gbdivers_qml_sources.zip">Télécharger les sources de cet article.</a></p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Un ColorPicker avec Qt &#8211; Version Qt</title>
		<link>https://blog.developpez.com/gpu/?p=353</link>
		<comments>https://blog.developpez.com/gpu/?p=353#comments</comments>
		<pubDate>Fri, 15 Feb 2013 18:04:33 +0000</pubDate>
		<dc:creator><![CDATA[gbdivers]]></dc:creator>
				<category><![CDATA[C++]]></category>
		<category><![CDATA[Facile]]></category>
		<category><![CDATA[Qt]]></category>
		<category><![CDATA[QtQuick]]></category>

		<guid isPermaLink="false">http://blog.developpez.com/gpu/?p=353</guid>
		<description><![CDATA[Cet article est la solution que j&#8217;avais proposé à l&#8217;exercice Qt sur la création d&#8217;un ColorPicker (voir l&#8217;article précédent du blog). Il décrit la création d&#8217;un widget permettant d&#8217;afficher et sélectionner les nuances de gris d&#8217;une couleur. Conception Le widget &#8230; <a href="https://blog.developpez.com/gpu/?p=353">Lire la suite <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Cet article est la solution que j&rsquo;avais proposé à l&rsquo;exercice Qt sur la création d&rsquo;un ColorPicker (voir <a href="http://blog.developpez.com/gpu/p11791/difficulte/facile/un-colorpicker-avec-qt-enonce-de-lexercice">l&rsquo;article précédent du blog</a>). Il décrit la création d&rsquo;un widget permettant d&rsquo;afficher et sélectionner les nuances de gris d&rsquo;une couleur.<br />
<span id="more-353"></span></p>
<h1>Conception</h1>
<p>Le widget devra simplement afficher un fond (les nuances de gris d&rsquo;une couleur) et gérer les évènements de la souris (clique et déplacement pour sélectionner une nuance de gris).</p>
<p>Il est possible de partir de plusieurs classes différentes pour créer le nouveau widget. Voyons les avantages et inconvénients de chacune :</p>
<ol>
<li>QWidget est la classe parent de tous les widgets de Qt. Elle fournit l&rsquo;interface de base commune de tous les objets visibles. Par défaut, elle n&rsquo;affiche rien et ne fait rien.</li>
<li>QScrollArea est destinée à afficher le contenu d&rsquo;un widget dans un autre, en gérant les barres de déplacement horizontale et verticale. Dans cet exercice, la présence de barre de déplacement n&rsquo;est pas souhaitée et il est préférable d&rsquo;ajuster la taille de la zone de dessin à la taille du widget.</li>
<li>QLabel permet d&rsquo;afficher un texte ou une image sans interaction avec l&rsquo;utilisateur. Même s&rsquo;il est possible de surcharger les fonctions de gestion des évènements souris, utiliser cette classe pour créer noter widget revient à ne pas respecter la conception de QLabel.</li>
<li>QpushButton permet également d&rsquo;afficher des images mais gère aussi les évènements souris. Mais cette classe n&rsquo;est pas destiner à gérer la position précise des évènements souris et de réagir différemment en fonction de celle-ci.</li>
</ol>
<p>Au final, même si certaine classe présentent des fonctionnalités qui seraient intéressantes (affichage d&rsquo;images, gestion des clics), seule l&rsquo;utilisation de QWidget respecte la conception des objets Qt.</p>
<p>En partant de QWidget, quels seront les fonctions qu&rsquo;il faudra implémenter ?</p>
<ol>
<li>L&rsquo;affichage des nuances de gris sera réalisée dans la fonction paintEvent(), qui prend en charge le dessin du widget. Il suffit de dessiner les nuances de gris puis la position de la couleur sélectionnée par un petit cercle.</li>
<li>La création des nuances de gris peut être réalisée directement dans paintEvent(). Cependant, cela implique de redessiner l&rsquo;image à chaque déplacement de la souris, ce qui peut rendre le widget non fluide. De plus, la récupération de la couleur sélectionnée utilisera la fonction QImage::pixel(). Au final, il est donc préférable de dessiner les nuances de gris dans une QImage et d&rsquo;afficher cette QImage dans la fonction paintEvent(). Cette image sera recalculée que lors d&rsquo;un changement de la couleur principale ou lors du redimensionnement du widget.</li>
<li>La fonction resizeEvent() sera utilisée pour mettre à jour l&rsquo;image contenant les nuances de gris.<br />
Les évènements souris seront gérés par les fonctions mousePressEvent(), mouseMoveEvent() et mouseReleaseEvent().</li>
<li>Le changement de couleur principale et la sélection d&rsquo;une couleur utilisera le système de signaux et slots, pour faciliter l&rsquo;interaction entre les widgets.</li>
</ol>
<p>Pour dessiner les différentes nuances de gris d&rsquo;un couleur, deux méthodes sont envisageables :</p>
<ol>
<li>Dessiner deux gradients superposés : un premier gradient linéaire, horizontal, allant du blanc (à gauche) à la couleur principale (à droite) ; un second gradient linéaire, horizontal, allant du transparent (en haut) au noir (en bas).</li>
<li>Faire varier les composantes S (saturation) et V (valeur) d&rsquo;une couleur en fonction des coordonnées (x, y) d&rsquo;un pixel. La saturation permet d&rsquo;aller du blanc (S=0) à la couleur (S=255) et correspond donc à l&rsquo;axe horizontal. La valeur permet d&rsquo;aller du noir (V=0) à la couleur (V=255) et correspond donc à l&rsquo;axe vertical.</li>
</ol>
<p>Ces deux méthodes sont identique visuellement (mais présentent en réalité des petites différences) et permettent toute deux d&rsquo;afficher toutes les nuances de gris d&rsquo;une couleur.</p>
<h1>Interface</h1>
<p>Pour créer l&rsquo;interface de notre classe, on crée une classe GradientWidget héritant de Qwidget, avec son constructeur :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #0000ff;">class</span> GradientWidget <span style="color: #008080;">:</span> <span style="color: #0000ff;">public</span> QWidget<br />
<span style="color: #008000;">&#123;</span><br />
<span style="color: #0000ff;">public</span><span style="color: #008080;">:</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">explicit</span> GradientWidget<span style="color: #008000;">&#40;</span>QWidget <span style="color: #000040;">*</span>parent <span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>Les fonctions de gestion des évènements surchargent les fonctions de même nom de QWidget :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #0000ff;">protected</span><span style="color: #008080;">:</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">void</span> &nbsp; &nbsp;mouseMoveEvent<span style="color: #008000;">&#40;</span>QMouseEvent <span style="color: #000040;">*</span>event<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">void</span> &nbsp; &nbsp;mousePressEvent<span style="color: #008000;">&#40;</span>QMouseEvent <span style="color: #000040;">*</span>event<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">void</span> &nbsp; &nbsp;mouseReleaseEvent<span style="color: #008000;">&#40;</span>QMouseEvent <span style="color: #000040;">*</span>event<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">void</span> &nbsp; &nbsp;paintEvent<span style="color: #008000;">&#40;</span>QPaintEvent <span style="color: #000040;">*</span>event<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">void</span> &nbsp; &nbsp;resizeEvent<span style="color: #008000;">&#40;</span>QResizeEvent <span style="color: #000040;">*</span>event<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>La connexion avec les autres widgets est assurée par le signal envoyé lors de la sélection d&rsquo;une couleur et le slot reçu lors du changement de couleur principale :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">signals<span style="color: #008080;">:</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">void</span> &nbsp; &nbsp;colorSelected<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> QColor <span style="color: #000040;">&amp;</span>color<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<span style="color: #0000ff;">public</span> slots<span style="color: #008080;">:</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">void</span> &nbsp; &nbsp;setMainColor<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> QColor <span style="color: #000040;">&amp;</span>color<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>Les variables privées permettent de conserver les couleurs principale et sélectionnée, l&rsquo;image dans laquelle on dessine les nuances de gris, la position du curseur et une variable boolean indiquant si la mouvement de la souris correspond à un clic ou non :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #0000ff;">private</span><span style="color: #008080;">:</span><br />
&nbsp; &nbsp; QColor &nbsp;m_main_color<span style="color: #008080;">;</span><br />
&nbsp; &nbsp; QColor &nbsp;m_selected_color<span style="color: #008080;">;</span><br />
&nbsp; &nbsp; QImage &nbsp;m_gradient_image<span style="color: #008080;">;</span><br />
&nbsp; &nbsp; QPen &nbsp; &nbsp;m_cursor_pen<span style="color: #008080;">;</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">int</span> &nbsp; &nbsp; m_cursor_diameter<span style="color: #008080;">;</span><br />
&nbsp; &nbsp; QPoint &nbsp;m_cursor_position<span style="color: #008080;">;</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">bool</span> &nbsp; &nbsp;m_tracking<span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>Les variab Pour finir, deux fonctions privées, permettant de redessiner les nuances de gris et de mettre à jour la couleur sélectionnée :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; &nbsp; <span style="color: #666666;">// private membres</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">void</span> &nbsp; &nbsp;updateGradientImage<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">void</span> &nbsp; &nbsp;updateSelectedColor<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<h1>Implémentation</h1>
<p>Commençons par l&rsquo;implémentation de la fonction updateSelectedColor(). Celle-ci récupère simplement la couleur du pixel de m_gradient_image à la position m_cursor_position, émet le signal colorSelected() puis appelle la fonction update() pour mettre ajour le widget :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #0000ff;">void</span> GradientWidget<span style="color: #008080;">::</span><span style="color: #007788;">updateSelectedColor</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; m_selected_color <span style="color: #000080;">=</span> m_gradient_image.<span style="color: #007788;">pixel</span><span style="color: #008000;">&#40;</span>m_cursor_position<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; emit colorSelected<span style="color: #008000;">&#40;</span>m_selected_color<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; update<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span></div></td></tr></tbody></table></div>
<h2>Création des nuances avec QLinearGradient</h2>
<p>La première version de la fonction updateGradientImage() utilise l&rsquo;approche à deux gradients :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #0000ff;">void</span> GradientWidget<span style="color: #008080;">::</span><span style="color: #007788;">updateGradientImage</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span></div></td></tr></tbody></table></div>
<p>On crée une QPixmap de la taille du widget puis un QPainter pour dessiner dedans. Par défaut, nous n&rsquo;avons pas besoin de dessiner des traits donc on supprime le QPen :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; &nbsp; QPixmap pixmap<span style="color: #008000;">&#40;</span>size<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; QPainter painter<span style="color: #008000;">&#40;</span><span style="color: #000040;">&amp;</span>pixmap<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; painter.<span style="color: #007788;">setPen</span><span style="color: #008000;">&#40;</span>QPen<span style="color: #008000;">&#40;</span>Qt<span style="color: #008080;">::</span><span style="color: #007788;">NoPen</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>Pour dessiner des gradients linéaires, Qt propose une classe QLinearGradient. Il suffit donc de préciser les positions des points du gradient et les couleurs de ces points. Pour le premier gradient, les couleurs doivent aller du blanc (Qt::white) à la position (0, 0) à la couleur m_main_color à la position (with, 0) :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; &nbsp; QLinearGradient h_gradient<span style="color: #008000;">&#40;</span>QPointF<span style="color: #008000;">&#40;</span><span style="color:#800080;">0.0</span>, <span style="color:#800080;">0.0</span><span style="color: #008000;">&#41;</span>, QPointF<span style="color: #008000;">&#40;</span>width<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, <span style="color:#800080;">0.0</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; h_gradient.<span style="color: #007788;">setColorAt</span><span style="color: #008000;">&#40;</span><span style="color: #0000dd;">0</span>, Qt<span style="color: #008080;">::</span><span style="color: #007788;">white</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; h_gradient.<span style="color: #007788;">setColorAt</span><span style="color: #008000;">&#40;</span><span style="color: #0000dd;">1</span>, m_main_color<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>Puis on dessine un rectangle de la taille du widget :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; &nbsp; painter.<span style="color: #007788;">setBrush</span><span style="color: #008000;">&#40;</span>QBrush<span style="color: #008000;">&#40;</span>h_gradient<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; painter.<span style="color: #007788;">drawRect</span><span style="color: #008000;">&#40;</span>rect<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>Pour le second gradient, les couleurs doivent aller du transparent (Qt::transparent) à la position (0, 0) au noir (Qt::black) couleur m_main_color à la position (0, height) :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; &nbsp; QLinearGradient v_gradient<span style="color: #008000;">&#40;</span>QPointF<span style="color: #008000;">&#40;</span><span style="color:#800080;">0.0</span>, <span style="color:#800080;">0.0</span><span style="color: #008000;">&#41;</span>, QPointF<span style="color: #008000;">&#40;</span><span style="color:#800080;">0.0</span>, height<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; v_gradient.<span style="color: #007788;">setColorAt</span><span style="color: #008000;">&#40;</span><span style="color: #0000dd;">0</span>, Qt<span style="color: #008080;">::</span><span style="color: #007788;">transparent</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; v_gradient.<span style="color: #007788;">setColorAt</span><span style="color: #008000;">&#40;</span><span style="color: #0000dd;">1</span>, Qt<span style="color: #008080;">::</span><span style="color: #007788;">black</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; painter.<span style="color: #007788;">setBrush</span><span style="color: #008000;">&#40;</span>QBrush<span style="color: #008000;">&#40;</span>v_gradient<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; painter.<span style="color: #007788;">drawRect</span><span style="color: #008000;">&#40;</span>rect<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>On convertit ensuite la Qpixmap en Qimage et on la conserve dans m_gradient_image :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; &nbsp; m_gradient_image <span style="color: #000080;">=</span> pixmap.<span style="color: #007788;">toImage</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>Pour finir, puisse que le gradient à été mis à jour, on met également à jour la couleur sélectionnée :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; &nbsp; updateSelectedColor<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span></div></td></tr></tbody></table></div>
<h2>Création des nuances avec HSV</h2>
<p>La seconde version de updateGradientImage() utilise deux boucles imbriquées qui parcourent l&rsquo;ensemble des pixels de l&rsquo;image et qui calcul la couleur en faisant varier la saturation et la valeur en fonction de la position (x, y). Pour commencer, il faut redimensionner l&rsquo;image de destination si celle-ci n&rsquo;est pas identique aux dimensions du widget :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #0000ff;">void</span> GradientWidget<span style="color: #008080;">::</span><span style="color: #007788;">updateGradientImage</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>m_gradient_image.<span style="color: #007788;">rect</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #000040;">!</span><span style="color: #000080;">=</span> rect<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; m_gradient_image <span style="color: #000080;">=</span> QImage<span style="color: #008000;">&#40;</span>size<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, Qimage<span style="color: #008080;">::</span><span style="color: #007788;">Format_RGB32</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>La teinte est obtenue à partir de la couleur principale :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; &nbsp; <span style="color: #0000ff;">float</span> h <span style="color: #000080;">=</span> m_main_color.<span style="color: #007788;">hsvHueF</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>On parcourt l&rsquo;ensemble des pixels de l&rsquo;image à l&rsquo;aide de deux boucles imbriquées :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; &nbsp; <span style="color: #0000ff;">for</span> <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> s<span style="color: #000080;">=</span><span style="color: #0000dd;">0</span><span style="color: #008080;">;</span> s<span style="color: #000080;">&lt;</span>width<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #000040;">++</span>s<span style="color: #008000;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">for</span> <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> v<span style="color: #000080;">=</span><span style="color: #0000dd;">0</span><span style="color: #008080;">;</span> v<span style="color: #008000;">&#40;</span>height<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #000040;">/</span><span style="color: #0000dd;">3</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span> <span style="color: #008080;">?</span> Qt<span style="color: #008080;">::</span><span style="color: #007788;">white</span> <span style="color: #008080;">:</span> Qt<span style="color: #008080;">::</span><span style="color: #007788;">black</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>Il reste plus qu&rsquo;a dessiner un cercle à la position m_cursor_position :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; &nbsp; painter.<span style="color: #007788;">setPen</span><span style="color: #008000;">&#40;</span>m_cursor_pen<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; painter.<span style="color: #007788;">setBrush</span><span style="color: #008000;">&#40;</span>QBrush<span style="color: #008000;">&#40;</span>Qt<span style="color: #008080;">::</span><span style="color: #007788;">NoBrush</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; painter.<span style="color: #007788;">drawEllipse</span><span style="color: #008000;">&#40;</span>m_cursor_position, defaut_diameter, defaut_diameter<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span></div></td></tr></tbody></table></div>
<p>Le diamètre du cercle est une constante définie en début du fichier d&rsquo;implémentation :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #0000ff;">const</span> <span style="color: #0000ff;">int</span> defaut_diameter <span style="color: #000080;">=</span> <span style="color: #0000dd;">5</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>Lors d&rsquo;un évènement souris de type mousePressEvent, on teste si l&rsquo;utilisateur a cliqué sur le bouton gauche :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #0000ff;">void</span> GradientWidget<span style="color: #008080;">::</span><span style="color: #007788;">mousePressEvent</span><span style="color: #008000;">&#40;</span>QMouseEvent <span style="color: #000040;">*</span>event<span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>event<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>button<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #000080;">==</span> Qt<span style="color: #008080;">::</span><span style="color: #007788;">LeftButton</span><span style="color: #008000;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #008000;">&#123;</span></div></td></tr></tbody></table></div>
<p>Si c&rsquo;est le cas, on active le suivi des mouvements de la souris, on récupère la positon de la souris dans m_cursor_position puis on met à jour la couleur sélectionnée :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; &nbsp; &nbsp; &nbsp; m_tracking <span style="color: #000080;">=</span> <span style="color: #0000ff;">true</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; m_cursor_position <span style="color: #000080;">=</span> event<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>pos<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; updateSelectedColor<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; <span style="color: #008000;">&#125;</span><br />
<span style="color: #008000;">&#125;</span></div></td></tr></tbody></table></div>
<p>Lors d&rsquo;un évènement de type mouseReleaseEvent, on déssactive le suivi de la souris et on met à jour la couleur sélectionnée :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #0000ff;">void</span> GradientWidget<span style="color: #008080;">::</span><span style="color: #007788;">mouseReleaseEvent</span><span style="color: #008000;">&#40;</span>QMouseEvent <span style="color: #000040;">*</span>event<span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>event<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>button<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #000080;">==</span> Qt<span style="color: #008080;">::</span><span style="color: #007788;">LeftButton</span><span style="color: #008000;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; m_tracking <span style="color: #000080;">=</span> <span style="color: #0000ff;">false</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; m_cursor_position <span style="color: #000080;">=</span> event<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>pos<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; updateSelectedColor<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; <span style="color: #008000;">&#125;</span><br />
<span style="color: #008000;">&#125;</span></div></td></tr></tbody></table></div>
<p>Les mouvements de la souris sont détectés par l’évènement mouseMoveEvent. Pour que ces événements soient pris en compte pour le widget, il faut les activer en utilisant la fonction setMouseTracking(true) dans le constructeur. Ces évènements mouseMoveEvent sont activés même lorsqu&rsquo;aucun bouton n&rsquo;est appuyé. C&rsquo;est la fonction de la variable m_tracking d&rsquo;indiquer si on déplace la souris en conservant un bouton cliqué ou non.<br />
Lorsque l&rsquo;on maintient appuyé un bouton de la souris et que l&rsquo;on déplace celle-ci en dehors du widget, des évènements mouseMoveEvent continuent d&rsquo;être envoyé. Si on prend en compte ces évènements, on risque de demander la couleur de pixels en dehors de la taille de m_gradient_image, ce qui provoquera des erreurs. Il faut donc tester si la position de la souris est dans le widget. Au final, le code de mouseMoveEvent sera :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #0000ff;">void</span> GradientWidget<span style="color: #008080;">::</span><span style="color: #007788;">mouseMoveEvent</span><span style="color: #008000;">&#40;</span>QMouseEvent <span style="color: #000040;">*</span>event<span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>m_tracking <span style="color: #000040;">&amp;&amp;</span> rect<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>.<span style="color: #007788;">contains</span><span style="color: #008000;">&#40;</span>event<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>pos<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; m_cursor_position <span style="color: #000080;">=</span> event<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>pos<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; updateSelectedColor<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; <span style="color: #008000;">&#125;</span><br />
<span style="color: #008000;">&#125;</span></div></td></tr></tbody></table></div>
<p>Lors d&rsquo;un changement de taille du widget, il suffit de remettre à jour le gradient :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #0000ff;">void</span> GradientWidget<span style="color: #008080;">::</span><span style="color: #007788;">resizeEvent</span><span style="color: #008000;">&#40;</span>QResizeEvent <span style="color: #000040;">*</span>event<span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; Q_UNUSED<span style="color: #008000;">&#40;</span>event<span style="color: #008000;">&#41;</span><br />
&nbsp; &nbsp; m_cursor_position <span style="color: #000080;">=</span> rect<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>.<span style="color: #007788;">center</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; updateGradientImage<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span></div></td></tr></tbody></table></div>
<p>Il ne reste plus qu&rsquo;a implémenter le constructeur :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">GradientWidget<span style="color: #008080;">::</span><span style="color: #007788;">GradientWidget</span><span style="color: #008000;">&#40;</span>QWidget <span style="color: #000040;">*</span>parent<span style="color: #008000;">&#41;</span> <span style="color: #008080;">:</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; QWidget<span style="color: #008000;">&#40;</span>parent<span style="color: #008000;">&#41;</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; m_cursor_position<span style="color: #008000;">&#40;</span>rect<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>.<span style="color: #007788;">center</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; m_tracking<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">false</span><span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; setAttribute<span style="color: #008000;">&#40;</span>Qt<span style="color: #008080;">::</span><span style="color: #007788;">WA_OpaquePaintEvent</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; setMouseTracking<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">true</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; updateGradientImage<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span></div></td></tr></tbody></table></div>
<p>Ainsi que le slot setMainColor() :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #0000ff;">void</span> GradientWidget<span style="color: #008080;">::</span><span style="color: #007788;">setMainColor</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> QColor <span style="color: #000040;">&amp;</span>color<span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; m_main_color <span style="color: #000080;">=</span> color<span style="color: #008080;">;</span><br />
&nbsp; &nbsp; updateGradientImage<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span></div></td></tr></tbody></table></div>
<h1>Le résultat final</h1>
<p>Voici le rendu obtenu :</p>
<p style="text-align: center"><img src="http://qt.developpez.com/exercices/01-colorpicker/1-degrade/gbdivers/gbdivers_capture_ecran.png" alt="null" /></p>
<p><a href="http://www.developpez.net/forums/attachments/p66806d1283512715/c-cpp/bibliotheques/qt/exercice-qt-color-picker-deuxieme-partie-lancee/colorpicker.zip/">Télécharger les sources de cet article.</a></p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Un ColorPicker avec Qt &#8211; Enoncé de l&#8217;exercice</title>
		<link>https://blog.developpez.com/gpu/?p=340</link>
		<comments>https://blog.developpez.com/gpu/?p=340#comments</comments>
		<pubDate>Fri, 15 Feb 2013 17:49:30 +0000</pubDate>
		<dc:creator><![CDATA[gbdivers]]></dc:creator>
				<category><![CDATA[C++]]></category>
		<category><![CDATA[Facile]]></category>
		<category><![CDATA[Qt]]></category>
		<category><![CDATA[QtQuick]]></category>

		<guid isPermaLink="false">http://blog.developpez.com/gpu/?p=340</guid>
		<description><![CDATA[Cet article est une reprise des sujets écris par johnlamericain et des documents que j&#8217;avais rédigé pour un exercice Qt. Cette première partie est un rappel (copié-collé) du sujet de l&#8217;exercice, posté sur le forum. Première partie : créer une &#8230; <a href="https://blog.developpez.com/gpu/?p=340">Lire la suite <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Cet article est une reprise des sujets écris par <a href="http://www.developpez.net/forums/u44506/johnlamericain/">johnlamericain</a> et des documents que j&rsquo;avais rédigé pour un <a href="http://www.developpez.net/forums/d965869/c-cpp/bibliotheques/qt/exercice-qt-color-picker-deuxieme-partie-lancee/">exercice Qt</a>. Cette première partie est un rappel (copié-collé) du sujet de l&rsquo;exercice, posté sur le forum.</p>
<p><span id="more-340"></span></p>
<h1>Première partie : créer une zone de sélection avec gradient</h1>
<p>Bonjour à tous,</p>
<p>Nous savons que vous attendez avec impatience le prochain défi Qt, cependant un défi de qualité prends du temps à organiser et mettre en place. Pour palier à votre envie de développer et de vous faire les dents sur un nouveau projet, nous vous proposons un nouveau concept : les exercices Qt.</p>
<h2>Le principe</h2>
<p>Des petits sujets réguliers pour lesquels vous pouvez apporter une solution en détaillant quelques étapes clés imposés. La durée de l&rsquo;exercice dépendra de la difficulté de l&rsquo;énoncé. Il est possible qu&rsquo;un sujet conséquent en travail soit proposé et ainsi découpé en plusieurs parties représentant une suite d&rsquo;exercices sur le même thème.</p>
<p>Tout le monde peut ainsi proposer une solution pour répondre à l&rsquo;exercice posé. Dans le cas d&rsquo;un exercice en plusieurs parties, la meilleure solution pourra être utilisée par les autres participants pour la suite de l&rsquo;exercice.</p>
<p>Il est impossible pour l&rsquo;équipe de réunir un jury et réaliser un barème aussi poussé que celui des défis Qt. La meilleure solution sera ainsi désignée d&rsquo;un point de vue plus subjectif que pour les défis Qt par les responsables de la rubrique Qt, à savoir dourouc05 et moi-même et éventuellement d&rsquo;autres membres de l&rsquo;équipe Qt en fonction des disponibilités de chacun.</p>
<p>Les exercices seront ainsi proposés le vendredi (vous permettant d&rsquo;y travailler dès le week end après avoir découvert le nouveau sujet). La fin du dépôt des propositions aura lieu le vendredi soir à 23h59, un certain nombre de semaines (dépendant de la difficulté de celui-ci) après la présentation du sujet et le vainqueur sera désigné dans la semaine suivante avant la proposition du nouvel exercice.</p>
<p>Nous essayerons de faire attention à ce qu&rsquo;il n&rsquo;y ait pas de copie entre les codes des participants en appliquant la règle que le premier code publié sur le forum &laquo;&nbsp;appartient&nbsp;&raquo; au membre l&rsquo;ayant posté. Il existe bien sur des réponses à ces solutions sur internet, mais quel est l&rsquo;intérêt pour vous de les utiliser ?</p>
<p>Le premier sujet !</p>
<h2>Le thème</h2>
<p>Ce premier exercice fait parti d&rsquo;un thème qui est la réalisation d&rsquo;un color picker. Ci-dessous, quelques color pickers connus mais libre à vous de faire travailler votre imagination pour nous donner une meilleure solution au final :</p>
<p style="text-align: center"><img src="http://qt.developpez.com/exercices/01-colorpicker/images/ColorPicker1.png" alt="null" /></p>
<p style="text-align: center"><img src="http://qt.developpez.com/exercices/01-colorpicker/images/ColorPicker2.png" alt="null" /></p>
<p style="text-align: center"><img src="http://qt.developpez.com/exercices/01-colorpicker/images/ColorPicker3.png" alt="null" /></p>
<p>Ce thème est découpé en trois parties qui toutes durent deux semaines. Un nouvel énoncé d&rsquo;exercice sera donc publié toutes les trois semaines (en comptant la semaine de correction).</p>
<h2>Première partie : widget personnalisé pour affiche et sélectionner la nuance de gris d&rsquo;une couleur</h2>
<p>Création d&rsquo;un widget permettant de sélectionner la nuance de gris à partir d&rsquo;une couleur. Seul le widget affichant le gradient de la nuance de gris sur une couleur sera évalué mais votre fenêtre peut afficher la couleur en cours et les valeurs de celle-ci pour démontrer le bon fonctionnement de celui-ci.</p>
<p>Le widget peut être carré, rectangulaire, sphérique, en cercle, libre à votre imagination.</p>
<p>Les étapes d&rsquo;explications imposées :</p>
<ol>
<li>Mise en place de la structure du widget (héritage, composition&#8230;) ;</li>
<li>Réalisation du gradient ;</li>
<li> Sélection et récupération de la couleur à partir du gradient.</li>
</ol>
<p>Vous avez donc jusqu&rsquo;au vendredi 3 septembre 23h59 pour nous fournir une solution. Le dépôt des solutions ce fait sur le forum à la suite de ce message.</p>
<p>J&rsquo;espère que l&rsquo;idée vous plait, n&rsquo;hésitez pas également à nous faire part de votre participation à la suite de ce message, de présenter votre solution en avant première et je finirai par dire : à vos claviers !</p>
<h1>Seconde partie : accompagner le widget d&rsquo;un sélecteur de couleur et amélioration de celui-ci</h1>
<p>L&rsquo;objectif est de continuer le widget en l&rsquo;améliorant et ajoutant d&rsquo;autres fonctionnalités. Pour ceux qui n&rsquo;auraient pas un widget fonctionnel, voici une archive contenant la classe du widget du vainqueur de la première partie à savoir gbdivers, améliorée par mes soins pour prendre en compte les malus qui lui ont été mis à la correction !</p>
<p>La première amélioration requise pour la partie deux est la création d&rsquo;un slider permettant la création de la couleur principale (teinte ou hue en anglais). L&rsquo;image ci-jointe vous montre de quoi je parle :</p>
<p style="text-align: center"><img src="http://qt.developpez.com/exercices/01-colorpicker/images/partie2_hue.png" alt="null" /></p>
<p>Ce slider peut faire partie du widget ou être un widget indépendant. Je vous conseille de regarder la classe QSlider et les paramètres pour la personnalisée.</p>
<p>De plus un ensemble de champ QLineEdit respectant un certain format QIntValidator devra permettre d&rsquo;afficher et de modifier la valeur de la teinte, saturation ou valeur. En cas de modification, le changement se répercutera sur le widget par le déplacement du point de sélection. Il existe donc une connexion dans les deux sens entre ces différents éléments.</p>
<p>Par la suite, il faudra modifier le widget existant pour permettre également d&rsquo;afficher les dégradés de la saturation et de la valeur (et non plus la teinte, hue en anglais).</p>
<p>Exemples : </p>
<p style="text-align: center"><img src="http://qt.developpez.com/exercices/01-colorpicker/images/partie2_saturation.png" alt="null" /></p>
<p style="text-align: center"><img src="http://qt.developpez.com/exercices/01-colorpicker/images/partie2_value.png" alt="null" /></p>
<p>C&rsquo;est tout pour les étapes imposées dans cette seconde partie qui durera deux semaines.</p>
<p>Pour les personnes qui ont de l&rsquo;avance, vous pouvez réfléchir à n&rsquo;afficher que les couleurs disponibles pour le web et la représentation des dégradés dans les autres espaces colorimétriques.</p>
<p style="text-align: center"><img src="http://qt.developpez.com/exercices/01-colorpicker/images/partie2_web.png" alt="null" /></p>
<p>Si vous avez besoin d&rsquo;explications supplémentaires, n&rsquo;hésitez pas à poser des questions à la suite de ce message. De plus la correction et le code source de l&rsquo;ensemble des candidats pour la première partie est disponible dans ce sujet.</p>
<p>Bon courage !</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Les modules de Qt 5</title>
		<link>https://blog.developpez.com/gpu/?p=25</link>
		<comments>https://blog.developpez.com/gpu/?p=25#comments</comments>
		<pubDate>Tue, 04 Sep 2012 15:24:25 +0000</pubDate>
		<dc:creator><![CDATA[gbdivers]]></dc:creator>
				<category><![CDATA[Facile]]></category>
		<category><![CDATA[Qt]]></category>
		<category><![CDATA[Qt5]]></category>

		<guid isPermaLink="false">http://blog.developpez.com/gpu/?p=25</guid>
		<description><![CDATA[L&#8217;un des principaux changements que l&#8217;on trouvera dans Qt 5 est la réorganisation des modules. Les modules sont regroupés en deux groupes : les Essentials, installés automatiquement, et les Add-ons, installés à la demande. Puisque Qt 5 n’est pas encore &#8230; <a href="https://blog.developpez.com/gpu/?p=25">Lire la suite <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>L&rsquo;un des principaux changements que l&rsquo;on trouvera dans Qt 5 est la réorganisation des modules. Les modules sont regroupés en deux groupes : les <em>Essentials</em>, installés automatiquement, et les <em>Add-ons</em>, installés à la demande. Puisque Qt 5 n’est  pas encore en version finale, les informations données dans cet article sont susceptibles d&rsquo;être modifiées.<br />
<span id="more-25"></span></p>
<h1>Les modules Essentials</h1>
<h2>Le module Qt Core</h2>
<p>Ce module fournit les fonctionnalités de base de Qt, excepté ce qui concerne l&rsquo;interface graphique. Tous les autres modules sont liés à ce module. Voici la liste de quelques ajouts dans Qt 5 :</p>
<ul>
<li><em>QStandardPaths</em> : permet de récupérer les répertoires par défaut en fonction de la plateforme. C&rsquo;est une évolution de <em>QDesktopServices</em> avec plus de fonctionnalités, sur le modèle de KStandardDirs de KDE. Cela permet par exemple de faire une recherche de toutes les occurrences d&rsquo;un fichier dans les différents répertoires ;</li>
<li>support de JSON : permet de créer ou de lire un fichier JSON à partir d&rsquo;une représentation binaire en mémoire ;</li>
<li>extension prise en charge MIME : permet de déterminer le type mime d&rsquo;un fichier ou de données en mémoire, en fonction de l&rsquo;extension et/ou du contenu. Ce module utilise une base de données des types MIME par <em>QMimeDatabase</em> fourni par freedesktop.org shared-mime-info project. Cette base de données est incluse par défaut dans le système sous Linux et fourni par Qt sur Windows et Mac OS X ;</li>
<li>vérification des connexions signaux/slots à la compilation : vérifie l&rsquo;existence du signal et du receveur et que les arguments sont compatibles. Cette fonctionnalité utilise les templates et est compatible avec C++11. Il est possible de connecter un signal à des fonctions lambda, des fonctions membres ou des fonctions statiques, sans avoir besoin de déclarer comme slots. Voir l&rsquo;article détaillé sur le sujet : <a href="http://blog.developpez.com/gpu/p10958/langages-frameworks/c/les_signaux_et_slots_dans_qt5" target="_blank">Les signaux et slots dans Qt 5</a> ;</li>
<li><em>QRegularExpression</em> : nouveau moteur d&rsquo;expressions régulières compatible Perl, plus puissante et rapide que <em>QRegExp</em>, avec plus de fonctionnalités (lazy and possessive quantifiers, lookbehinds, named capturing groups and iteration of matches) ;</li>
<li>amélioration des performances, en particulier pour les structures de données ;</li>
<li>amélioration du support C++11 quand c&rsquo;est possible (mais compatibilité avec C++98) ;</li>
<li>support des boutons supplémentaires sur les souris (souris pour joueurs), jusque 27 boutons pour XCB, XLIB ou DirectFB, jusque 16 pour Wayland, Evdev ou OS-X, jusque 8 pour BlackBerry/QNX et 5 sur Windows (limitation due au système).</li>
</ul>
<h2>Le module Qt Gui</h2>
<p>Ce module fournit les fonctionnalités de base pour créer une interface utilisateur. Les anciennes classes <em>QWidget</em> et dérivées sont séparées dans un module indépendant. Ce module contient de nouvelles classes comme  <em>QWindow</em>, <em>QScreen</em>, <em>QSurfaceFormat</em> permettant le support de fonctionnalités de base et est surtout destiné à être utilisé par les autres modules (QWidget, QQuickView, Qt 3D View, etc.).<br />
En particulier, ce module fournit les classes <em>QOpenGLxxx</em> (<em>QOpenGLFramebufferObject</em>, <em>QOpenGLShaderProgram</em>, <em>QOpenGLFunctions</em>, <em>QOpenGLContext</em>, etc.) permettant de fournir l&rsquo;accélération matérielle pour tous les modules graphiques (widgets traditionnels, Qt Quick). La classe <em>QOpenGLContext</em> est plus générique que <em>QGLContext</em> et est découplée de <em>QWindow</em>, pour permettre d&rsquo;utiliser un contexte commun pour plusieurs affichages. <em>QOpenGLPaintDevice</em> permet d&rsquo;utiliser directement <em>QPainter</em> sur un contexte OpenGL sans devoir dériver de <em>QWindow</em> ou <em>QOpenGLFramebufferObject</em>.<br />
Voir l&rsquo;article <a href="http://blog.developpez.com/gpu/p10904/langages-frameworks/opengl/opengl_dans_qt5" target="_blank">OpenGL dans Qt 5</a> pour plus de détails.</p>
<h2>Le module Qt QML</h2>
<p>Ce module permet d&rsquo;utiliser le langage de script déclaratif QML grâce au <em>QML engine</em>. Il présente des améliorations des performances et des ajouts de fonctionnalités par rapport celui inclus dans Qt 4.</p>
<h2>Le module Qt Js backend (JavaScript)</h2>
<p>Ce module fournit un interpréteur JavaScript, permettant de scripter les applications écrites en C++ et en QML. Il utilise un nouveau moteur <a href="http://code.google.com/p/v8/" target="_blank">JS v8</a> plus rapide. Il inclut de nouvelles classes (<em>QJSEngine</em>, <em>QJSValue</em>), le support de nouveaux types (<em>QColor</em> avec les propriétés r, g, b et a, <em>QVector4D</em> constructible avec Qt.vector4d()). Il est possible d&rsquo;ajouter des fonctionnalités dans un namespace avec la fonction qmlRegisterModuleApi et d&rsquo;importer du QML et du JS directement dans un fichier JS.</p>
<h2>Le module Qt Quick</h2>
<p>Ce module permet de créer des interfaces dynamiques riches, en utilisant les modules QML et le JS. Cette nouvelle version de Qt Quick correspond au module &laquo;&nbsp;qtquick2&Prime; alors que l&rsquo;ancienne version correspond au module &laquo;&nbsp;qtquick1&Prime;. L&rsquo;interface graphique de Qt Quick 2 se base maintenant sur scenegraph et permet l&rsquo;accélération matérielle en utilisant les classes <em>QOpenGLxxx</em> de Qt Gui.<br />
On trouve de nouvelles classes (<em>QQuickView</em>, <em>QQuickCanvas</em>, <em>QQuickItem</em> et <em>QQuickPaintedItem</em> qui remplacent les classes équivalentes de <em>QDeclarative</em>), de nouveaux items (<em>Canvas</em> permet le support de l&rsquo;API <em>Context2D</em> de HTML 5, le rendu est réalisé dans Canvas.Image et Canvas.FramebufferObject, avec support multithread en arrière-plan). Le moteur de particules 2D Qt Quick.Particles 2.0 et la collection d&rsquo;effets de shaders qui étaient avant des projets séparés dans Qt Labs sont maintenant inclus dans Qt.</p>
<h2>Le module Qt 3D</h2>
<p>Le module Qt 3D est également un ancien projet provenant de Qt Labs et est inclus dans Qt 5. Il a permis dans Qt 4 l&rsquo;ajout de nombreuses fonctionnalités de calculs 3D comme les classes <em>QMatrix4×4</em>, <em>QGLShaderProgram</em> et <em>QVector3D</em>. Il utilise en interne le module Qt QML et le support OpenGL de Qt Gui. Ce module contient deux bibliothèques : Qt 3D (pour utiliser directement la 3D en C++) et Qt 3D Quick (pour l&rsquo;utilisation dans Qt Quick).</p>
<p>Plusieurs fonctionnalités sont ajoutées :</p>
<ul>
<li>gestion de scènes 3D, avec rendu en OpenGL ;</li>
<li>lecture de fichiers 3D (par exemple .obj et .3ds) ;</li>
<li>gestion des lumières, des meshs, des textures, des matériaux, des animations, des caméras, des vues ;</li>
<li>ajout de shader directement ou par fichier dans les propriétés QML ;</li>
</ul>
<h2>Le module Qt Location</h2>
<p>Ce module est un ajout dans Qt 5, mais il existait déjà depuis des années comme sous-ensemble de Qt Mobility. Il fournit les services nécessaires pour la localisation : GPS, cartographie, etc.<br />
Il inclut une fonctionnalité permettant d&rsquo;afficher des cartes avec <em>MapQuickItem</em>. L&rsquo;affichage se base sur une approche modèle/vue et bénéficie de l&rsquo;accélération OpenGL dans scenegraph. Les gestuelles pour les zooms et les panoramas dynamiques, le routage et le géocodage, l&rsquo;ajout de repères sur les cartes sont pris en charge.</p>
<h2>Le module Qt Network</h2>
<p>Ce module fournit une interface portable pour utiliser les réseaux. Parmi les évolutions :</p>
<ul>
<li>amélioration du support IPv6 et des réseaux utilisant les types d’adresse IP, de manière transparente par défaut. En réception, QTcpServer et QUdpSocket lancés avec QHostAddress::Any permet de recevoir dans les deux modes ; avec QHostAddress::AnyIPv4 et QHostAddress::AnyIPv6 permet de travailler sur un mode uniquement. En émission, QNetworkAccessManager tente d&rsquo;utiliser les deux modes et garde le premier qui réussit ;</li>
<li>QTcpSocket peut maintenant être attaché à un socket existant avant de lancer une connexion, pour limiter les connexions dans un environnement multihôte ;</li>
<li>QDnsLookup permet de rechercher des enregistrements DNS. Il ne remplace pas QHostInfo, qui permet de résoudre les noms en adresse IP, mais permet principalement d&rsquo;utiliser les autres types d&rsquo;enregistrements DNS : SRV, TXT et MX ;</li>
<li>les classes QFtp et QHttp ne sont pas conservées dans ce module, mais restent disponibles dans un module indépendant pour la compatibilité. Elles sont remplacées par QNetworkAccessManager.</li>
<li>extensions et vérifications des certificats SSL : prise en charge des extensions des certificats. La vérification des certificats ne se fait plus uniquement lors de la connexion à un serveur ;</li>
<li>support des clés privées masquées : permet de lire une clé privée à partir d&rsquo;un périphérique, par exemple un dongle PKCS#11.</li>
</ul>
<h2>Les autres modules</h2>
<ul>
<li>Qt Multimedia : fournit les fonctionnalités de base pour lire l&rsquo;audio, la vidéo, la radio et gérer les caméras ;</li>
<li>Qt SQL : fournit une prise en charge portable des bases de données SQL ;</li>
<li>Qt Test : fournit les outils nécessaires pour implémenter des tests unitaires ;</li>
<li>Qt WebKit : basé sur WebKit 2, mais sans changement de l&rsquo;API C++. Ce module continue l&rsquo;amélioration de prise en charge HTML 5 et des performances.</li>
</ul>
<h1>Les modules Add-ons</h1>
<h2>Le module Qt Widget</h2>
<p>Ce module fournit l&rsquo;ensemble des classes QWidget et dérivées pour la compatibilité avec Qt 4. Il utilise la nouvelle architecture <a href="http://qt-project.org/wiki/Qt-Platform-Abstraction" target="_blank">Qt Platform Abstraction</a> (QPA).</p>
<h2>Le module Qt Quick 1</h2>
<p>Ce module permet d&rsquo;utiliser la version de Qt Quick disponible dans Qt 4, pour compatibilité. Pour utiliser ce module, il suffit d&rsquo;ajouter dans le .pro :</p>
<div class="codecolorer-container text blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">QT += quick1</div></td></tr></tbody></table></div>
<p>Et d&rsquo;inclure les fichiers d&rsquo;en-têtes :</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #339900;">#include QtQuick1/QDeclarativeView</span><br />
<span style="color: #339900;">#include QtQuick1/QDeclarativeItem</span></div></td></tr></tbody></table></div>
<h2>Les autres modules</h2>
<ul>
<li>Qt Script : permet de rendre les applications scriptables, compatibilité avec Qt 4. Il utilise les classes QJSxxx du module Qt Js ;</li>
<li>Qt Bluetooth : prise en charge du Bluetooth ;</li>
<li>Qt D-Bus : interprocessus communication avec D-Bus ;</li>
<li>Qt Graphical Effects : collection d&rsquo;effets graphiques ;</li>
<li>Qt Image Formats : prise en charge de formats d&rsquo;images supplémentaires (TIFF, MNG, TGA, WBMP) ;</li>
<li>Qt OpenGL : module 3D OpenGL compatible avec Qt 4 ;</li>
<li>Qt Print Support : support pour l&rsquo;impression ;</li>
<li>Qt Publish and Subscribe ;</li>
<li>Qt Script Tools : outils supplémentaires pour scripter ;</li>
<li>Qt Sensor : gestion des capteurs (accéléromètre, détecteur de lumière ambiante, compas, etc.) ;</li>
<li>Qt Service Framework : permet de fournir des services en ligne ;</li>
<li>Qt SVG : prise en charge du format d&rsquo;image SVG (image vectorielle) ;</li>
<li>Qt System Info : informations sur le système (profile utilisateur, batterie, stockage, etc.) ;</li>
<li>Qt Tools : outils divers (Qt Designer, Qt Help, etc.) ;</li>
<li>Qt Pim : contacts, organiseur, vCard, etc. ;</li>
<li>Qt WebKit Widgets : version de wekbit 1, pour compatibilité avec Qt 4 ;</li>
<li>Qt XML : fichier XML avec SAX et DOM. Ce module est déprécié, il faut maintenant utiliser QXmlStreamReader/Writer ;</li>
<li>Qt XML Patterns : support pour XPath, XQuery, XSLT et XML Schema validation.</li>
</ul>
<h1>Les modules accessoires</h1>
<p>Le support de ces modules n&rsquo;est pas encore déterminé.</p>
<ul>
<li>Active Qt : support des ActiveX et Com (Windows) ;</li>
<li>Qt Feedback ;</li>
<li>Qt JSON DB ;</li>
<li>Phonon : support du framework phonon pour la vidéo et audio ;</li>
<li>Qt QA : auto test, pour gestion automatique des tests ;</li>
<li>Qt QLALR : interpréteur LALR.</li>
</ul>
<h1>Commentaires et remerciements</h1>
<p><a href="http://www.developpez.net/forums/d1259378/c-cpp/bibliotheques/qt/vue-densemble-larchitecture-modulaire-qt-5-a/" target="_blank">Vous pouvez commenter cet article sur le forum</a>.<br />
Merci à <a href="http://www.developpez.net/forums/u124512/claudeleloup/">ClaudeLELOUP</a> pour sa relecture orthographique.</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>OpenGL dans Qt5</title>
		<link>https://blog.developpez.com/gpu/?p=11</link>
		<comments>https://blog.developpez.com/gpu/?p=11#comments</comments>
		<pubDate>Tue, 29 May 2012 08:55:39 +0000</pubDate>
		<dc:creator><![CDATA[gbdivers]]></dc:creator>
				<category><![CDATA[Facile]]></category>
		<category><![CDATA[OpenGL]]></category>
		<category><![CDATA[Qt5]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Le support d&#8217;OpenGL dans Qt5 a été modifié pour mieux l&#8217;intégrer avec les nouveaux modules de Qt : QtQuick2 et Qt3D. Cet article présente les modifications apportées dans Qt5. OpenGL dans Qt4 Dans Qt4, les fonctionnalités d&#8217;OpenGL sont implémentées dans &#8230; <a href="https://blog.developpez.com/gpu/?p=11">Lire la suite <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Le support d&rsquo;OpenGL dans Qt5 a été modifié pour mieux l&rsquo;intégrer avec les nouveaux modules de Qt : QtQuick2 et Qt3D. Cet article présente les modifications apportées dans Qt5.<br />
<span id="more-11"></span><br />
<strong><em>OpenGL dans Qt4</em></strong></p>
<p>Dans Qt4, les fonctionnalités d&rsquo;OpenGL sont implémentées dans un module spécifique, QtOpenGL. Ce module était utilisé par différentes classes pour bénéficier de l’accélération matérielle. Il existe plusieurs méthodes pour activer l&rsquo;accélération matérielle :</p>
<ul>
<li>pour activer par défaut l&rsquo;utilisation de OpenGL, utiliser la ligne de commande &laquo;&nbsp;-graphicssystem opengl&nbsp;&raquo; ou la fonction QApplication::setGraphicsSystem(&laquo;&nbsp;opengl&nbsp;&raquo;) ;</li>
<li>pour QGraphicsView (QtGraphics) ou QDeclarativeView (QtQuick), utiliser la fonction setViewport(new QGLWidget) ;</li>
<li>on peut également utiliser QPainter directement sur un QGLWidget ;</li>
<li>avec le QML Viewer, utilisez la commande &laquo;&nbsp;-opengl&nbsp;&raquo;.</li>
</ul>
<p><em><strong>L&rsquo;organisation des modules</strong></em><br />
Dans Qt4, on a donc un problème dans l&rsquo;organisation des modules. Beaucoup de classes de QtGui peuvent dépendre des classes appartenant à QtOpenGL alors que ce module dépend normalement de QtGui.<br />
C&rsquo;est pour cela que de nouvelles classes font leur apparition dans Qt5 et que les différents modules ont été réorganisés :</p>
<ul>
<li>les classes QOpenGL appartiennent au module QtGui et fournissent les fonctionnalités de base permettant l’accélération matérielle pour toute les classes de rendu de Qt ;</li>
<li>la classe QWidget n&rsquo;est plus le parent de toutes les classes de rendu. Cette classe et ses dérivées (QGraphicsView) sont transférées dans le module &laquo;&nbsp;widgets&nbsp;&raquo; ;</li>
<li>QtQuick 2 utilise maintenant scenegraph à la place de QWidget et la classe QDeclarativeView devient QQuickView et OpenGL est utilisé par défaut ;</li>
<li>QtOpenGL continue d&rsquo;exister pour fournir la classe QGLWidget et ses dérivés. Le code OpenGL Qt4 est donc compatible avec Qt5 ;</li>
<li>le module Qt3d fait son apparition pour fournir un moteur 3D plus avancé. Ce module est suffisamment important et fera donc l&rsquo;objet d&rsquo;un article spécifique.</li>
</ul>
<p>Remarque : il faut faire attention de ne pas confondre le module QtOpenGL, contenant les classes commençant par QGL, et le module QtGui, contenant les classes commençant par QOpenGL (sans t).</p>
<p><strong><em>Les classes de QtGui dans Qt5</em></strong><br />
Le module QtGui de Qt5 réutilise des classes existantes du module QtOpenGL de Qt4. Les noms sont explicites :</p>
<ol>
<li>QOpenGLBuffer ;</li>
<li>QOpenGLContext ;</li>
<li>QOpenGLFramebufferObject ;</li>
<li>QOpenGLFramebufferObjectFormat ;</li>
<li>QOpenGLShader ;</li>
<li>QOpenGLShaderProgram.</li>
</ol>
<p>Plusieurs nouvelles classes font leur apparition :</p>
<ol>
<li>QOpenGLContextGroup : groupe de contextes OpenGL pouvant partager des ressources. Cette classe est gérée automatiquement par les objets QOpenGLContext ;</li>
<li>QOpenGLFunctions : fournit un accès indépendant de la plateforme aux fonctions d&rsquo;OpenGL ;</li>
<li>QOpenGLPaintDevice : permet de dessiner dans un contexte OpenGL avec QPainter ;</li>
<li>QOpenGLStaticContext : manque de documentation ;</li>
<li>QOpenGLContextData : manque de documentation ;</li>
<li>QWindowsGLContext : manque de documentation.</li>
</ol>
<p><strong><em>Que faut-il modifier pour utiliser OpenGL dans Qt5</em></strong><br />
Tout d&rsquo;abord, il faut Qt5. Le plus simple est d&rsquo;utiliser les dépôts PPA sur Ubuntu : https://launchpad.net/~forumnokia/+archive/fn-ppa. Qt5 sera installé dans le répertoire /opt/qt5. Pour ajouter cette version de Qt dans QtCreator, il faut aller dans le menu &laquo;&nbsp;Outils&nbsp;&raquo; puis &laquo;&nbsp;Options…&nbsp;&raquo;, allez dans &laquo;&nbsp;Compiler et exécuter…&nbsp;&raquo; puis l&rsquo;onglet &laquo;&nbsp;Versions de Qt&nbsp;&raquo;. Cliquer sur &laquo;&nbsp;Ajouter&nbsp;&raquo; et aller chercher le fichier &laquo;&nbsp;/opt/qt5/bin/qmake&nbsp;&raquo;. Voilà, Qt5 est prêt à être utilisé.</p>
<p>Normalement, vous pouvez utiliser vos projets directement, mais il est préférable de prendre l&rsquo;habitude d&rsquo;ajouter le module &laquo;&nbsp;widgets&nbsp;&raquo; (remarque : l&rsquo;ajout des modules core et gui n&rsquo;est pas obligatoire puisqu&rsquo;ils sont inclus par défaut) :</p>
<div class="codecolorer-container text blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">QT += core gui opengl <br />
greaterThan(QT_MAJOR_VERSION, 4) { <br />
&nbsp; &nbsp; QT += widgets <br />
}</div></td></tr></tbody></table></div>
<p>Amusez-vous bien !</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Les signaux et slots dans Qt5</title>
		<link>https://blog.developpez.com/gpu/?p=12</link>
		<comments>https://blog.developpez.com/gpu/?p=12#comments</comments>
		<pubDate>Wed, 25 Apr 2012 15:19:18 +0000</pubDate>
		<dc:creator><![CDATA[gbdivers]]></dc:creator>
				<category><![CDATA[C++]]></category>
		<category><![CDATA[Qt]]></category>
		<category><![CDATA[Qt5]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[La nouvelle version de Qt vient de sortir en version 5 alpha. Cette version améliore la prise en charge de la nouvelle norme du C++, le C++11, et modifie ainsi le fonctionnement des signaux et slots de Qt. Cet article &#8230; <a href="https://blog.developpez.com/gpu/?p=12">Lire la suite <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>La nouvelle version de Qt vient de sortir <a href="http://www.developpez.net/forums/d1209764/c-cpp/bibliotheques/qt/sortie-qt-5-alpha/">en version 5 alpha</a>. Cette version améliore la prise en charge de la nouvelle norme du C++, le C++11, et modifie ainsi le fonctionnement des signaux et slots de Qt. Cet article fait un rappel sur l&rsquo;utilisation des signaux et slots et présente les nouvelles fonctionnalités offertes par Qt5.<br />
<span id="more-12"></span><br />
<strong><em>Couplage entre classes et intérêt des signaux et slots</em></strong></p>
<p>Lorsque l&rsquo;on souhaite faire communiquer des objets entre eux, il nécessaire en général que les objets se connaissent mutuellement. Par exemple</p>
<div class="codecolorer-container text blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">class Receiver { <br />
public: <br />
&nbsp; &nbsp; void slot() { cout &amp;lt;&amp;lt; &amp;quot;slot exécuté&amp;quot; &amp;lt;slot(); } <br />
private: <br />
&nbsp; &nbsp; Receiver* receiver; <br />
}; <br />
&nbsp;<br />
int main() { <br />
&nbsp; &nbsp; // on crée nos objets <br />
&nbsp; &nbsp; Receiver r; <br />
&nbsp; &nbsp; Sender s; <br />
&nbsp;<br />
&nbsp; &nbsp; // on connecte le sender et le receiver <br />
&nbsp; &nbsp; s.connect(&amp;amp;r); <br />
&nbsp;<br />
&nbsp; &nbsp; // on émet le signal <br />
&nbsp; &nbsp; s.signal(); <br />
}</div></td></tr></tbody></table></div>
<p>Ce code présente cependant plusieurs problèmes :</p>
<ul>
<li>il faut que la classe Sender connaisse la classe Receiver et cela implique d&rsquo;ajouter une dépendance (include) entre ces classes ;</li>
<li>il est nécessaire de créer une fonction spécifique dans Sender pour chaque type de classe Receiver et pour chaque slot possible ;</li>
<li>il ne permet pas de gérer des connexions vers plusieurs objets Receiver et il faut modifier le code pour gérer une liste de Receiver.</li>
</ul>
<p>Ces contraintes s&rsquo;accumulent dans un framework complexe comme Qt et cela alourdit fortement le code en ajoutant un nombre important de dépendances inutiles. Le code devient très vite ingérable (*).</p>
<p>Le système des signaux et slots permet de faire de s&rsquo;affranchir de ces contraintes. Il est ainsi possible de faire communiquer des objets entre eux sans qu&rsquo;il soit nécessaire que ces objets se connaissent mutuellement. On peut également choisir lors de la connexion le slot que l&rsquo;on souhaite appeler lorsque le signal est émis. On passe ainsi d&rsquo;un couplage fort (nécessité d&rsquo;avoir une dépendance) à un couplage faible (plus de dépendance nécessaire) et l&rsquo;on parle de découplage des classes.</p>
<p><em>(*) Il est possible d&rsquo;utiliser d&rsquo;autres approches que celle présentée ici. En particulier, on peut utiliser les pointeurs de fonctions ou équivalents (callback). Le lecteur intéressé par la question pourra par exemple étudier l&rsquo;approche utilisée dans <a href="http://www.boost.org/doc/libs/1_49_0/doc/html/signals.html">Boost.Signals</a></em></p>
<p><em><strong>Le système des signaux et slots dans Qt</strong></em></p>
<p>Le système de signaux et slots de Qt est relativement simple. Lorsqu&rsquo;un événement se produit, un signal est émis. Tous les slots qui sont connectés à ce signal sont alors exécutés. La fonction QObject::connect permet de créer une telle connexion. La forme la plus classique de cette fonction prend en paramètres un pointeur vers l&rsquo;objet émetteur, le nom du signal (ainsi que la liste des types des arguments du signal), un pointeur vers l&rsquo;objet recepteur et pour terminer le nom du slot (ainsi que la liste des types des arguments du slot). Il est possible de connecter plusieurs signaux à un même slot, un signal à plusieurs slots ou un signal avec un signal. Le compatibilité entre les classes et les signaux et slots est vérifiés lors de la compilation.</p>
<div class="codecolorer-container text blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">QAction a; <br />
QWidget w; <br />
QObject::connect( <br />
&nbsp; &nbsp; &amp;amp;a, SIGNAL(triggered()), // connecte le signal triggered() de QAction <br />
&nbsp; &nbsp; &nbsp; &amp;amp;w, SLOT(show())); &nbsp; &nbsp; &nbsp; // au slot show() de QWidget <br />
// ce code permet donc d'afficher le QWidget lorsque l'utilisateur active la QAction</div></td></tr></tbody></table></div>
<p><img src="http://doc-snapshot.qt-project.org/5.0/images/abstract-connections.png" alt="Exemple de connexions dans Qt" title="Exemples de connexions dans Qt" /></p>
<p>Les classes de Qt fournissent de nombreux signaux et slots par défaut. Ces signaux et slots seront disponibles dans les classes créées par les utilisateurs et dérivant des classes de Qt. Il est également possible de créer ses propres signaux et slots et de les connecter aux signaux et slots par défaut de Qt :</p>
<div class="codecolorer-container text blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">#include &nbsp;<br />
&nbsp;<br />
class Counter : public QObject // on hérite de QObject pour bénéficier des méta-informations de Qt <br />
{ <br />
&nbsp; &nbsp;Q_OBJECT // cette macro permet de générer les signaux et slots lors de la compilation <br />
&nbsp;<br />
public slots: <br />
&nbsp; &nbsp;void setValue(int value) <br />
&nbsp; &nbsp;{ <br />
&nbsp; &nbsp; &nbsp; if (value != m_value) // lorsque la valeur est changée <br />
&nbsp; &nbsp; &nbsp; { <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;m_value = value; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;emit valueChanged(value); // on émet un signal valueChanged <br />
&nbsp; &nbsp; &nbsp; } <br />
&nbsp; &nbsp;} <br />
&nbsp;<br />
signals: <br />
&nbsp; &nbsp; void valueChanged(int newValue); // signal émis lorsque la valeur est changée <br />
&nbsp;<br />
private: <br />
&nbsp; &nbsp; int m_value; <br />
}; <br />
&nbsp;<br />
Counter a, b; <br />
&nbsp;<br />
// on connecte valueChanged de a à setValue de b <br />
QObject::connect(&amp;amp;a, &amp;amp;Counter::valueChanged, &amp;amp;b, &amp;amp;Counter::setValue); <br />
&nbsp;<br />
a.setValue(12); &nbsp;<br />
// a émet un signal valueChanged qui active le slot setValue de b <br />
// a.value() == 12, b.value() == 12 <br />
&nbsp;<br />
b.setValue(48); &nbsp; &nbsp; &nbsp;<br />
// b émet un signal valueChanged mais ce signal n'est pas connecté à un slot <br />
// a.value() == 12, b.value() == 48</div></td></tr></tbody></table></div>
<p><em><strong>Créer une connexion dans Qt 5</strong></em></p>
<p>Dans Qt 4, il est possible de connecter uniquement les fonctions déclarées comme signaux et<br />
slots dans la classes, comme indiqué dans le code d&rsquo;exemple précédant. Dans Qt 5, il est<br />
maintenant possible de connecter directement des pointeurs de fonctions ou d&rsquo;utiliser des<br />
fonctions lambdas.</p>
<p>La connexion de pointeurs de fonctions est similaire à une connexion classique, en donnant un pointeur sur les objets et sur les fonctions. Les classes émettrices et réceptrices doivent dériver de QObject mais il n&rsquo;est pas nécessaire de déclarer les fonctions slots avec le mot clé &laquo;&nbsp;slots&nbsp;&raquo;.</p>
<div class="codecolorer-container text blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">class Sender : public QObject { <br />
&nbsp; &nbsp; Q_OBJECT <br />
&nbsp;<br />
signals: <br />
&nbsp; &nbsp; void send(int i = 0); <br />
}; <br />
&nbsp;<br />
class Receiver : public QObject { <br />
&nbsp;<br />
public: <br />
&nbsp; &nbsp; void receive(int i = 0) { std::cout &amp;lt;&amp;lt; &amp;quot;receive:&amp;quot; &amp;lt;&amp;lt; i &amp;lt;send(123);</div></td></tr></tbody></table></div>
<p>L&rsquo;avantage de cette écriture est que la compatibilité des paramètres est effectuée lors de la compilation et non lors de l’exécution. </p>
<p>Pour les fonctions lambdas :</p>
<div class="codecolorer-container text blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">// connexion avec les lambdas <br />
QObject::connect(s, &amp;amp;Sender::send, [r](int i = 0){ r-&amp;gt;receive(i); }); <br />
emit s-&amp;gt;send(456);</div></td></tr></tbody></table></div>
<p>Dans ce code, on capture le pointeur vers l&rsquo;objet recepteur et on récupère le paramètre passé par la fonction send() puis on appelle dans le corps de la lambda le fonction receive(). Le résultat obtenu est identique au code précédant, mais il est possible de faire beaucoup d&rsquo;autres choses dans la lambda (par exemple déconnecter tous le signaux ou parcourir tous les enfants de l&rsquo;objet récepteur).</p>
<p>Si le compilateur utilisé ne support pas les variadic template, les signaux et slots doivent avoir moins de 6 paramètres. </p>
<p><em><strong>Remarques</strong></em><br />
Vous pouvez télécharger un projet d&rsquo;exemple montrant ces nouvelles fonctionnalités en action : <a href="http://cpp.developpez.com/telecharger/detail/id/2744/-Qt-5-Les-nouvelles-possibilites-de-connexions-signaux-slots-dans-Qt-5">la page de téléchargement</a>.</p>
<p>Les images et codes d&rsquo;exemple sont issus de la documentation de Qt5 disponible à cette page : <a href="http://qt-project.org/doc/qt-5.0/qtcore/signalsandslots.html#signals-and-slots">Qt 5.0: Signals &amp; Slots</a>.</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Introduction aux geometry shaders</title>
		<link>https://blog.developpez.com/gpu/?p=1</link>
		<comments>https://blog.developpez.com/gpu/?p=1#comments</comments>
		<pubDate>Thu, 12 Apr 2012 08:14:02 +0000</pubDate>
		<dc:creator><![CDATA[gbdivers]]></dc:creator>
				<category><![CDATA[C++]]></category>
		<category><![CDATA[Facile]]></category>
		<category><![CDATA[Geometry shaders]]></category>
		<category><![CDATA[OpenGL]]></category>
		<category><![CDATA[Qt]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[A la demande de LittleWhite, mon premier bloc technique est consacré à l&#8217;utilisation des geometry shader. Il n&#8217;y a rien de tres compliqué donc je présente un exemple simple apres quelques rappels. Pour ceux qui ne connaissent pas du tout &#8230; <a href="https://blog.developpez.com/gpu/?p=1">Lire la suite <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>A la demande de LittleWhite, mon premier bloc technique est consacré à l&rsquo;utilisation des geometry shader. Il n&rsquo;y a rien de tres compliqué donc je présente un exemple simple apres quelques rappels. Pour ceux qui ne connaissent pas du tout les geometry shaders, je ferais un article plus detaille sur ce sujet.<br />
Pour faire au plus simple, j&rsquo;utilise Qt et en particulier QShaderProgram, qui gère les geometry shaders depuis Qt 4.7.<br />
<span id="more-1"></span></p>
<p><em><strong>Quelques rappels</strong></em><br />
Les geometry shaders sont optionnels et s&rsquo;intercalent entre les vertex shaders et les fragment shaders. Ils travaillent sur des primitives (triangle, ligne, points, avec un maximum de 6 vertices) et permettent de générer d&rsquo;autres primitives. Ils sont disponibles dans le Core depuis OpenGL 3.2 / GLSL 1.5 ou avant avec l&rsquo;extension GL_ARB_geometry_shader4 (en ajoutant le code #extension GL_EXT_geometry_shader4 : enable dans le geometry shader).</p>
<div class="codecolorer-container cpp blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; &nbsp; <span style="color: #666666;">// Rechercher la présence de GL_EXT_geometry_shader4 pour &nbsp; </span><br />
&nbsp; &nbsp; <span style="color: #666666;">// tester si les geometry shaderssont pris en charge </span><br />
&nbsp; &nbsp; glGetString<span style="color: #008000;">&#40;</span>GL_EXTENSIONS<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> &nbsp;<br />
&nbsp; &nbsp; glGetStringi<span style="color: #008000;">&#40;</span>GL_EXTENSIONS, i<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #666666;">// GL 3.2 </span><br />
&nbsp; &nbsp; &nbsp;<br />
&nbsp; &nbsp; <span style="color: #666666;">// Créer un geometry shader </span><br />
&nbsp; &nbsp; glCreateShader<span style="color: #008000;">&#40;</span>GL_GEOMETRY_SHADER<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
&nbsp; &nbsp; QGLShader shader<span style="color: #008000;">&#40;</span>QGLShader<span style="color: #008080;">::</span><span style="color: #007788;">Geometry</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #666666;">// Qt 4.7 </span><br />
&nbsp; &nbsp; &nbsp;<br />
&nbsp; &nbsp; <span style="color: #666666;">// Gérer les informations de position </span><br />
&nbsp; &nbsp; gl_PositionIn<span style="color: #008000;">&#91;</span>i<span style="color: #008000;">&#93;</span><span style="color: #008080;">;</span> <span style="color: #666666;">// position du vertex i en entrée </span><br />
&nbsp; &nbsp; gl_Position<span style="color: #008080;">;</span> <span style="color: #666666;">// position du nouveau vertex émis </span><br />
&nbsp; &nbsp; gl_in<span style="color: #008000;">&#91;</span>i<span style="color: #008000;">&#93;</span>.<span style="color: #007788;">gl_Position</span><span style="color: #008080;">;</span> <span style="color: #666666;">// GLSL &gt; 330 </span><br />
&nbsp; &nbsp; gl_in.<span style="color: #007788;">length</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #666666;">// GLSL &gt; 330, nombre de vertices en entrée </span><br />
&nbsp; &nbsp; &nbsp;<br />
&nbsp; &nbsp; <span style="color: #666666;">// Générer des vertices et primitives (GLSL) </span><br />
&nbsp; &nbsp; EmitVertex<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
&nbsp; &nbsp; EndPrimitive<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
&nbsp; &nbsp; &nbsp;<br />
&nbsp; &nbsp; <span style="color: #666666;">// Spécifier le type de primitives en entrée et sortie </span><br />
&nbsp; &nbsp; <span style="color: #666666;">// (GLSL) </span><br />
&nbsp; &nbsp; layout <span style="color: #008000;">&#40;</span>triangles<span style="color: #008000;">&#41;</span> in<span style="color: #008080;">;</span> <span style="color: #666666;">// points, lines, triangles, lines_adjacency ou triangles_adjacency </span><br />
&nbsp; &nbsp; layout <span style="color: #008000;">&#40;</span>triangle_strip<span style="color: #008000;">&#41;</span> out<span style="color: #008080;">;</span> <span style="color: #666666;">// points, line_strip ou triangle_strip </span><br />
&nbsp; &nbsp; layout <span style="color: #008000;">&#40;</span>max_vertices <span style="color: #000080;">=</span> <span style="color: #0000dd;">3</span><span style="color: #008000;">&#41;</span> out<span style="color: #008080;">;</span> <span style="color: #666666;">// maximum = GL_MAX_GEOMETRY_OUTPUT_VERTICES </span><br />
&nbsp;<br />
&nbsp; &nbsp; <span style="color: #666666;">// (Qt) </span><br />
&nbsp; &nbsp; program_shader.<span style="color: #007788;">setGeometryInputType</span><span style="color: #008000;">&#40;</span>GL_TRIANGLES<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
&nbsp; &nbsp; program_shader.<span style="color: #007788;">setGeometryOutputType</span><span style="color: #008000;">&#40;</span>GL_LINE_STRIP<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
&nbsp; &nbsp; program_shader.<span style="color: #007788;">setGeometryOutputVertexCount</span><span style="color: #008000;">&#40;</span><span style="color: #0000dd;">6</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>Lors de l&rsquo;appel à glDrawArray ou glDrawElement, il faut que le type spécifié corresponde au type d&rsquo;entrée du geometry shader. Les correspondances autorisées sont :</p>
<ol>
<li>points : GL_POINTS</li>
<li>lines : GL_LINES, GL_LINE_LOOP ou GL_LINE_STRIP</li>
<li>triangles : GL_TRIANGLES, GL_TRIANGLE_FAN ou GL_TRIANGLE_STRIP</li>
<li>lines_adjacency : GL_LINES_ADJACENCY</li>
<li>triangles_adjacency : GL_TRIANGLES_ADJACENCY</li>
</ol>
<p>Les nouveaux types ADJACENCY (GL_LINES_ADJACENCY, GL_LINE_STRIP_ADJACENCY, GL_TRIANGLES_ADJACENCY et GL_TRIANGLE_STRIP_ADJACENCY) permettent d&rsquo;accéder aux vertices des primitives voisines de la primitive en cours de traitement.</p>
<p><img src="http://gbelz.developpez.com/blog/geometry-shader.png" alt="Exemple d'affichage des vecteurs normaux" title="Exemple d'affichage des vecteurs normaux" /></p>
<p><strong><em>Un exemple simple</em></strong><br />
L&rsquo;exemple choisit est tres tres classique. Il permet d&rsquo;afficher le mailage d&rsquo;un mesh, les vecteurs normaux des faces et de calculer les vecteurs normaux de chaque face (flat mode). Cet exemple me permet également d&rsquo;introduire quelques classes simples, pour lire un fichier .obj (version simplifiee), calculer les vecteurs normaux, initialiser un contexte GL avec Qt.</p>
<p>Pour l&rsquo;affichage des vecteurs normaux et des triangles, on a besoin des positions et des normales, que l&rsquo;on passent donc aux shaders en attributs. </p>
<p>Pour afficher les vecteurs normaux dans le geometry shader, on prend un seul vertex en entree (input = points) et l&rsquo;on retourne une ligne (output = lignes, size = 2), dont le premier point est la position du vertex et le second point est la position du vertex auquel on ajoute le vecteur normal (multiplie par une constante, passee comme uniform, pour modifier la longueur du vecteur)</p>
<p>Pour afficher les triangles, on recupere un triangle en entree (input = triangles) et l&rsquo;on retourne 3 lignes (output = lignes, size = 6). Chaque points correspond a la position d&rsquo;un vertex decale legerement par le vecteur normal (pour que les lignes soient bien visibles et ne soient pas cachees par les triangles).</p>
<p><a href="http://gbelz.developpez.com/blog/geometry-shader.zip">Télécharger le projet d&rsquo;exemple</a></p>
<p><strong><em>A suivre&#8230;</em></strong></p>
<ol>
<li><a href="http://www.google.fr/url?sa=t&amp;rct=j&amp;q=&amp;esrc=s&amp;source=web&amp;cd=4&amp;cts=1331312136494&amp;ved=0CEwQFjAD&amp;url=http%3A%2F%2Fweb.engr.oregonstate.edu%2F~mjb%2Fcs519%2FHandouts%2Fgeometry_shaders.1pp.pdf&amp;ei=ATZaT6zoFIiz8QPy3IXPDg&amp;usg=AFQjCNG9d-4Lpr0TbpuvK0iQrvmRVXKaMw&amp;sig2=zf5Oc9N-aIUMtgqDR-FXqw">Shrink, explosion, subdivision, silhouette, hedgehog</a></li>
<li><a href="http://www.twodee.org/blog/?p=805">Explosion, cheveux</a></li>
<li><a href="http://bat710.univ-lyon1.fr/~jpfarrug/Geometry.pdf">Instanciation et culling</a></li>
<li><a href="http://bat710.univ-lyon1.fr/~jciehl/Public/educ/M2PROIMA/2011/opengl_cm4.pdf">Instanciation et culling</a></li>
</ol>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
