<?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</title>
	<atom:link href="https://blog.developpez.com/gpu/?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>Lambdas T() et std::function&lt;const T&amp;&gt;, un mélange dangereux</title>
		<link>https://blog.developpez.com/gpu/?p=309</link>
		<comments>https://blog.developpez.com/gpu/?p=309#comments</comments>
		<pubDate>Wed, 15 May 2013 00:49:31 +0000</pubDate>
		<dc:creator><![CDATA[germinolegrand]]></dc:creator>
				<category><![CDATA[Avancé]]></category>
		<category><![CDATA[C++]]></category>

		<guid isPermaLink="false">http://blog.developpez.com/gpu/?p=309</guid>
		<description><![CDATA[Le chat de Dvp est le lieu de rendez-vous quotidien des devs C++ et de nombreuses discussions techniques sur le C++ soulèvent des interrogations sur des points particuliers du langage. Il nous est apparu qu&#8217;une faille dangereuse et non détectée &#8230; <a href="https://blog.developpez.com/gpu/?p=309">Lire la suite <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Le chat de Dvp est le lieu de rendez-vous quotidien des devs C++ et de nombreuses discussions techniques sur le C++ soulèvent des interrogations sur des points particuliers du langage.</p>
<p>Il nous est apparu qu&rsquo;une faille dangereuse et non détectée par le compilateur résultait de l&rsquo;utilisation conjointe de la déduction automatique de type retour des lambdas et des std::function&lt;const A&amp;()&gt; qui retournent une référence constante.</p>
<p><span id="more-309"></span></p>
<p>Le code suivant compile parfaitement sans aucun warning sous g++4.8 et clang++3.2 avec les flags <code class="codecolorer text blackboard"><span class="text">-pedantic -Wall -Wextra</span></code>.</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 />19<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;iostream&gt;</span><br />
<span style="color: #339900;">#include &lt;functional&gt;</span><br />
<br />
<span style="color: #0000ff;">struct</span> A<br />
<span style="color: #008000;">&#123;</span> <br />
&nbsp; &nbsp; A<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#123;</span> std<span style="color: #008080;">::</span><span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot;A()&quot;</span> <span style="color: #000080;">&lt;&lt;</span> std<span style="color: #008080;">::</span><span style="color: #007788;">endl</span><span style="color: #008080;">;</span> <span style="color: #008000;">&#125;</span><br />
&nbsp; &nbsp; ~A<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#123;</span> std<span style="color: #008080;">::</span><span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot;~A()&quot;</span> <span style="color: #000080;">&lt;&lt;</span> std<span style="color: #008080;">::</span><span style="color: #007788;">endl</span><span style="color: #008080;">;</span> <span style="color: #008000;">&#125;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #0000ff;">int</span> i <span style="color: #000080;">=</span> <span style="color: #0000dd;">32</span><span style="color: #008080;">;</span><span style="color: #666666;">//variable témoin</span><br />
<span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span><br />
&nbsp;<br />
<span style="color: #0000ff;">int</span> main<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; A a<span style="color: #008080;">;</span><br />
&nbsp; &nbsp; std<span style="color: #008080;">::</span><span style="color: #007788;">function</span><span style="color: #000080;">&lt;</span><span style="color: #0000ff;">const</span> A<span style="color: #000040;">&amp;</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #000080;">&gt;</span> f <span style="color: #000080;">=</span> <span style="color: #008000;">&#91;</span><span style="color: #000040;">&amp;</span>a<span style="color: #008000;">&#93;</span><span style="color: #008000;">&#123;</span><span style="color: #0000ff;">return</span> a<span style="color: #008080;">;</span><span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">const</span> A<span style="color: #000040;">&amp;</span> aref <span style="color: #000080;">=</span> f<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; std<span style="color: #008080;">::</span><span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot;checkpoint_1&quot;</span> <span style="color: #000080;">&lt;&lt;</span> std<span style="color: #008080;">::</span><span style="color: #007788;">endl</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; std<span style="color: #008080;">::</span><span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> aref.<span style="color: #007788;">i</span> <span style="color: #000080;">&lt;&lt;</span> std<span style="color: #008080;">::</span><span style="color: #007788;">endl</span><span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span></div></td></tr></tbody></table></div>
<p>Or le résultat obtenu en commentant cette ligne est :</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">A<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;`<br />
~A<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><br />
checkpoint_1<br />
<span style="color: #0000dd;">1</span><br />
~A<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span></div></td></tr></tbody></table></div>
<p>Pour les rapides, oui aref est totalement corrompue, et son utilisation résulte en un crash sauvage et sans pitié du programme lorsqu&rsquo;on a de la chance. Pour les autres, voici l&rsquo;explication.</p>
<p>Savez-vous quel est le type de retour implicite de la lambda ci-dessous ?</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">A a<span style="color: #008080;">;</span><br />
<span style="color: #0000ff;">auto</span> lm <span style="color: #000080;">=</span> <span style="color: #008000;">&#91;</span><span style="color: #000040;">&amp;</span>a<span style="color: #008000;">&#93;</span><span style="color: #008000;">&#123;</span><span style="color: #0000ff;">return</span> a<span style="color: #008080;">;</span><span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>Si comme moi, à première vue vous répondez A&amp;, vous vous en mordrez les doigts.<br />
La réponse est A.</p>
<p>En effet, comment se déduit automatiquement le type de retour d&#039;une lambda ? Eh bien de la même façon que decltype. C&#039;est à dire tel que la variable a été déclarée. Ici, a étant déclaré comme A, c&#039;est donc A qui est le type du retour de la lambda.</p>
<p>Si l&#039;on capture cette fois une référence vers A :</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">A a<span style="color: #008080;">;</span><br />
A<span style="color: #000040;">&amp;</span> refTo_a<span style="color: #008000;">&#40;</span>a<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<span style="color: #0000ff;">auto</span> lm <span style="color: #000080;">=</span> <span style="color: #008000;">&#91;</span><span style="color: #000040;">&amp;</span>refTo_a<span style="color: #008000;">&#93;</span><span style="color: #008000;">&#123;</span><span style="color: #0000ff;">return</span> refTo_a<span style="color: #008080;">;</span><span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>Ici refTo_a est déclarée comme une A&amp;, c&#039;est donc A&amp; qui sera déduit.</p>
<p>Reprenons notre cas initial. Bon, à priori ce n&#039;est pas une grande perte, on fait une simple copie.</p>
<p>Ainsi, le code suivant est parfaitement sain si on reconnait la légitimité de la copie :</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 /></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;iostream&gt;</span><br />
<span style="color: #339900;">#include &lt;functional&gt;</span><br />
<br />
<span style="color: #0000ff;">static</span> <span style="color: #0000ff;">int</span> ID <span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span><br />
<br />
<span style="color: #0000ff;">struct</span> A<br />
<span style="color: #008000;">&#123;</span> <br />
&nbsp; &nbsp; A<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#123;</span> id <span style="color: #000080;">=</span> ID<span style="color: #000040;">++</span><span style="color: #008080;">;</span> std<span style="color: #008080;">::</span><span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot;A() &quot;</span> <span style="color: #000080;">&lt;&lt;</span> id <span style="color: #000080;">&lt;&lt;</span> std<span style="color: #008080;">::</span><span style="color: #007788;">endl</span><span style="color: #008080;">;</span><span style="color: #008000;">&#125;</span><br />
&nbsp; &nbsp; A<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> A<span style="color: #000040;">&amp;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#123;</span> id <span style="color: #000080;">=</span> ID<span style="color: #000040;">++</span><span style="color: #008080;">;</span> std<span style="color: #008080;">::</span><span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot;A(const A&amp;) &quot;</span> <span style="color: #000080;">&lt;&lt;</span> id <span style="color: #000080;">&lt;&lt;</span> std<span style="color: #008080;">::</span><span style="color: #007788;">endl</span><span style="color: #008080;">;</span> <span style="color: #008000;">&#125;</span><br />
&nbsp; &nbsp; ~A<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#123;</span> std<span style="color: #008080;">::</span><span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot;~A() &quot;</span> <span style="color: #000080;">&lt;&lt;</span> id <span style="color: #000080;">&lt;&lt;</span> std<span style="color: #008080;">::</span><span style="color: #007788;">endl</span><span style="color: #008080;">;</span><span style="color: #008000;">&#125;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #0000ff;">int</span> i <span style="color: #000080;">=</span> <span style="color: #0000dd;">32</span><span style="color: #008080;">;</span><span style="color: #666666;">//variable témoin</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">int</span> id <span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span><br />
&nbsp;<br />
<span style="color: #0000ff;">int</span> main<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; A a<span style="color: #008080;">;</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">auto</span> lm <span style="color: #000080;">=</span> <span style="color: #008000;">&#91;</span><span style="color: #000040;">&amp;</span>a<span style="color: #008000;">&#93;</span><span style="color: #008000;">&#123;</span><span style="color: #0000ff;">return</span> a<span style="color: #008080;">;</span><span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">const</span> A<span style="color: #000040;">&amp;</span> aref <span style="color: #000080;">=</span> lm<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; std<span style="color: #008080;">::</span><span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot;checkpoint_1&quot;</span> <span style="color: #000080;">&lt;&lt;</span> std<span style="color: #008080;">::</span><span style="color: #007788;">endl</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; std<span style="color: #008080;">::</span><span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> aref.<span style="color: #007788;">i</span> <span style="color: #000080;">&lt;&lt;</span> std<span style="color: #008080;">::</span><span style="color: #007788;">endl</span><span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span></div></td></tr></tbody></table></div>
<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">A<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #0000dd;">0</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;`<br />
A<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> A<span style="color: #000040;">&amp;</span><span style="color: #008000;">&#41;</span> <span style="color: #0000dd;">1</span><br />
checkpoint_1<br />
<span style="color: #0000dd;">32</span><br />
~A<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #0000dd;">1</span><br />
~A<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #0000dd;">0</span></div></td></tr></tbody></table></div>
<p>La prise par référence constante allonge bien la durée de vie de la temporaire retournée par la lambda jusqu&#039;à la fin de la vie de la référence, ainsi que la norme le demande.</p>
<p>Oui mais&#8230;</p>
<p>Que se passe-t-il lorsque notre lambda est encapsulée dans une std::function&lt;const A&amp;()&gt; ?</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"><span style="color: #339900;">#include &lt;iostream&gt;</span><br />
<span style="color: #339900;">#include &lt;functional&gt;</span><br />
<br />
<span style="color: #0000ff;">static</span> <span style="color: #0000ff;">int</span> ID <span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span><br />
<br />
<span style="color: #0000ff;">struct</span> A<br />
<span style="color: #008000;">&#123;</span> <br />
&nbsp; &nbsp; A<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#123;</span> id <span style="color: #000080;">=</span> ID<span style="color: #000040;">++</span><span style="color: #008080;">;</span> std<span style="color: #008080;">::</span><span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot;A() &quot;</span> <span style="color: #000080;">&lt;&lt;</span> id <span style="color: #000080;">&lt;&lt;</span> std<span style="color: #008080;">::</span><span style="color: #007788;">endl</span><span style="color: #008080;">;</span><span style="color: #008000;">&#125;</span><br />
&nbsp; &nbsp; A<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> A<span style="color: #000040;">&amp;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#123;</span> id <span style="color: #000080;">=</span> ID<span style="color: #000040;">++</span><span style="color: #008080;">;</span> std<span style="color: #008080;">::</span><span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot;A(const A&amp;) &quot;</span> <span style="color: #000080;">&lt;&lt;</span> id <span style="color: #000080;">&lt;&lt;</span> std<span style="color: #008080;">::</span><span style="color: #007788;">endl</span><span style="color: #008080;">;</span> <span style="color: #008000;">&#125;</span><br />
&nbsp; &nbsp; ~A<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#123;</span> std<span style="color: #008080;">::</span><span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot;~A() &quot;</span> <span style="color: #000080;">&lt;&lt;</span> id <span style="color: #000080;">&lt;&lt;</span> std<span style="color: #008080;">::</span><span style="color: #007788;">endl</span><span style="color: #008080;">;</span><span style="color: #008000;">&#125;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #0000ff;">int</span> i <span style="color: #000080;">=</span> <span style="color: #0000dd;">32</span><span style="color: #008080;">;</span><span style="color: #666666;">//variable témoin</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">int</span> id <span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span><br />
&nbsp;<br />
<span style="color: #0000ff;">int</span> main<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; A a<span style="color: #008080;">;</span><br />
&nbsp; &nbsp; std<span style="color: #008080;">::</span><span style="color: #007788;">function</span><span style="color: #000080;">&lt;</span><span style="color: #0000ff;">const</span> A<span style="color: #000040;">&amp;</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #000080;">&gt;</span> f <span style="color: #000080;">=</span> <span style="color: #008000;">&#91;</span><span style="color: #000040;">&amp;</span>a<span style="color: #008000;">&#93;</span><span style="color: #008000;">&#123;</span><span style="color: #0000ff;">return</span> a<span style="color: #008080;">;</span><span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">const</span> A<span style="color: #000040;">&amp;</span> aref <span style="color: #000080;">=</span> f<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; std<span style="color: #008080;">::</span><span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot;checkpoint_1&quot;</span> <span style="color: #000080;">&lt;&lt;</span> std<span style="color: #008080;">::</span><span style="color: #007788;">endl</span><span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span></div></td></tr></tbody></table></div>
<p>Ainsi que cela a été révélé plus haut, mais en ajoutant l&#039;indication du constructeur de copie et un id aux objets la sortie est :</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">A<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #0000dd;">0</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;`<br />
A<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> A<span style="color: #000040;">&amp;</span><span style="color: #008000;">&#41;</span> <span style="color: #0000dd;">1</span><br />
~A<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #0000dd;">1</span><br />
checkpoint_1<br />
~A<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #0000dd;">0</span></div></td></tr></tbody></table></div>
<p>Lors de l&#039;appel à f(), une copie est donc faite, conformément à ce qu&#039;on a vu précédemment avec la déduction automatique du type de la lambda. Mais elle est détruite immédiatement !</p>
<p>Pourtant on récupère bien une const A&amp;, pourquoi ne fait-elle pas prolonger de la copie temporaire comme précédemment ?</p>
<p>Un petit code montrant le mécanisme du avec std::function&lt;const A&amp;()&gt; en détail :</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 />30<br />31<br />32<br />33<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;">static</span> <span style="color: #0000ff;">int</span> ID <span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span><br />
<br />
<span style="color: #0000ff;">struct</span> A<br />
<span style="color: #008000;">&#123;</span> <br />
&nbsp; &nbsp; A<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#123;</span> id <span style="color: #000080;">=</span> ID<span style="color: #000040;">++</span><span style="color: #008080;">;</span> std<span style="color: #008080;">::</span><span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot;A() &quot;</span> <span style="color: #000080;">&lt;&lt;</span> id <span style="color: #000080;">&lt;&lt;</span> std<span style="color: #008080;">::</span><span style="color: #007788;">endl</span><span style="color: #008080;">;</span><span style="color: #008000;">&#125;</span><br />
&nbsp; &nbsp; A<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> A<span style="color: #000040;">&amp;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#123;</span> id <span style="color: #000080;">=</span> ID<span style="color: #000040;">++</span><span style="color: #008080;">;</span> std<span style="color: #008080;">::</span><span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot;A(const A&amp;) &quot;</span> <span style="color: #000080;">&lt;&lt;</span> id <span style="color: #000080;">&lt;&lt;</span> std<span style="color: #008080;">::</span><span style="color: #007788;">endl</span><span style="color: #008080;">;</span> <span style="color: #008000;">&#125;</span><br />
&nbsp; &nbsp; ~A<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#123;</span> std<span style="color: #008080;">::</span><span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot;~A() &quot;</span> <span style="color: #000080;">&lt;&lt;</span> id <span style="color: #000080;">&lt;&lt;</span> std<span style="color: #008080;">::</span><span style="color: #007788;">endl</span><span style="color: #008080;">;</span><span style="color: #008000;">&#125;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #0000ff;">int</span> i <span style="color: #000080;">=</span> <span style="color: #0000dd;">32</span><span style="color: #008080;">;</span><span style="color: #666666;">//variable témoin</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">int</span> id <span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span><br />
<br />
A lambda<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; A a<span style="color: #008080;">;</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">return</span> a<span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span><br />
<br />
<span style="color: #0000ff;">const</span> A<span style="color: #000040;">&amp;</span> function<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;">const</span> A<span style="color: #000040;">&amp;</span> aret <span style="color: #000080;">=</span> lambda<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<br />
&nbsp; &nbsp; std<span style="color: #008080;">::</span><span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot;checkpoint_1&quot;</span><span style="color: #008080;">;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #0000ff;">return</span> aret<span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span><br />
<br />
<span style="color: #0000ff;">int</span> main<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;">const</span> A <span style="color: #000040;">&amp;</span>aref <span style="color: #000080;">=</span> function<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<br />
&nbsp; &nbsp; std<span style="color: #008080;">::</span><span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot;checkpoint_2&quot;</span><span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span></div></td></tr></tbody></table></div>
<p>On note à nouveau un silence total du compilateur. Le résultat est :</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">A<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #0000dd;">0</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;`<br />
checkpoint_1<br />
~A<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #0000dd;">0</span><br />
checkpoint_2</div></td></tr></tbody></table></div>
<p>Là où ça devient tordu c&#039;est que l&#039;extension de durée de vie d&#039;une temporaire par référence constante est limitée à une seule fois.</p>
<p>En effet, une fois récupérée dans une const A&amp;, la copie temporaire n&#039;a plus du tout le statut de temporaire : aussi on ne peut donc plus étendre sa durée de vie de cette façon !</p>
<p>Voici donc le pourquoi du comment. En conclusion il est donc dangereux soit de jouer avec les std::function&lt;const A&amp;()&gt; soit de laisser faire la déduction automatique du type retour des lambdas. En l&#039;absence d&#039;arguments forts pour pencher la balance, la vigilance est donc de mise lorsque l&#039;on joue avec les deux règles responsables du problème ici :</p>
<ol>
<li>Un type de retour automatiquement déduit est équivalent à un decltype(<em>expression_de_return</em>), soit le type de l&rsquo;expression telle qu&rsquo;elle a été déclarée, la capture par référence n&rsquo;y fait rien, ça reste le type de la variable avant sa capture.</li>
<li>Si une lambda a vocation à être stockée dans une std::function, alors il faut veiller à ce qu&rsquo;elle ne renvoie pas une temporaire et que le type de la std::function corresponde au comportement souhaité.</li>
</ol>
<p>Un grand merci à Flob90 qui a pris le temps de faire beaucoup de tests que vous pouvez consulter ici : <a href="http://pastebin.com/TR7f8rB2" title="lien pastebin" target="_blank">lien pastebin</a>. Merci à gbdivers pour sa relecture attentive.</p>
<p>Vous pouvez commenter ce billet de blog sur le <a href="http://www.developpez.net/forums/d1343028/cpp/billet-lambdas-t-stdfunctionltconst-tampgt-melange-dangereux/">forum</a>.</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Compléments sur l&#8217;article &#171;&#160;implémenter un Voxel Cone Tracing&#160;&#187;</title>
		<link>https://blog.developpez.com/gpu/?p=214</link>
		<comments>https://blog.developpez.com/gpu/?p=214#comments</comments>
		<pubDate>Sun, 12 May 2013 20:45:59 +0000</pubDate>
		<dc:creator><![CDATA[gbdivers]]></dc:creator>
				<category><![CDATA[Intermédiaire]]></category>
		<category><![CDATA[OpenGL]]></category>
		<category><![CDATA[Techniques]]></category>

		<guid isPermaLink="false">http://blog.developpez.com/gpu/?p=214</guid>
		<description><![CDATA[J&#8217;ai récement traduit l&#8217;article Implémenter un Voxel Cone Tracing, qui présente quelques difficultés techniques pour ceux qui ne sont pas habitués avec les concepts présentés dans cet article. Ce billet de blog à pour objectif de présenter ces concepts. Quelques &#8230; <a href="https://blog.developpez.com/gpu/?p=214">Lire la suite <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>J&rsquo;ai récement traduit l&rsquo;article <a href="http://simonstechblog.blogspot.fr/2013/01/implementing-voxel-cone-tracing.html">Implémenter un Voxel Cone Tracing</a>, qui présente quelques difficultés techniques pour ceux qui ne sont pas habitués avec les concepts présentés dans cet article. Ce billet de blog à pour objectif de présenter ces concepts.<br />
<span id="more-214"></span></p>
<h1>Quelques définitions</h1>
<h2>Illumination globale</h2>
<p>Les techniques d&rsquo;illuminations globales (GI) visent à améliorer le rendu d&rsquo;une scène 3D, en prenant en compte aussi bien la lumière directe (les sources de lumières qui éclairent les objets) que la lumière indirecte (réflexion de la lumière sur les objets, qui éclaire d&rsquo;autres objets). Ces techniques permettent d&rsquo;obtenir des rendus réalistes, au prix d&rsquo;un temps de calcul relativement long (parfois trop pour être compatible avec du rendu en temps réel). Un domaine de la recherche actuelle vise à développer de nouveaux algorithmes d&rsquo;illumination globale compatible avec le temps réel (jeux 3D).</p>
<p style="text-align: center"><img src="http://upload.wikimedia.org/wikipedia/commons/0/0d/Global_illumination.JPG" alt="Exemple d'une scène rendu avec l'illumination globale" /></p>
<p style="text-align: center">(source : <a href="http://fr.wikipedia.org/wiki/Illumination_globale">Wikipédia &#8211; Illumination globale</a>)</p>
<h3>Illumination indirecte</h3>
<p>Dans l&rsquo;illumination directe (à gauche sur l&rsquo;illustration suivante), la lumière provenant d&rsquo;une source est directement réfléchie sur une surface, puis renvoyé vers la caméra. C&rsquo;est le modèle classique de calcul de la lumière en 3D, que l&rsquo;on retrouve par exemple dans le <a href="http://cpp.developpez.com/redaction/data/pages/users/gbdivers/qtopengl/?page=opengl#L5-A">modèle de Phong</a>. La lumière est alors décomposée en plusieurs composantes : la lumière ambiante (qui représente une illumination globale constante), la lumière diffuse (qui représente une diffusion de la lumière sur la surface) et la lumière spéculaire (qui représente une réflexion sur la surface).</p>
<p style="text-align: center"><img src="http://www.cgg-journal.com/2010-1/02/files/VPLs.png" alt="Principe de l'illumination indirecte" /></p>
<p style="text-align: center">(Source : <a href="http://www.cgg-journal.com/2010-1/02/index.html">Real-Time Global Illumination for Point Cloud Scenes</a>)</p>
<p>Dans l&rsquo;illumination indirecte, on considère que chaque surface qui reçoit de la lumière va à son tour en renvoyer. Il n&rsquo;y a donc plus qu&rsquo;une seule source de lumière, mais une infinité, correspondant à chaque surface qui renvoie de la lumière. Pour réaliser le rendu d&rsquo;une scène, il faut donc procéder de la façon suivante :</p>
<ol>
<li>pour chaque surface S1 visible par la caméra ;</li>
<li>pour chaque surface S2 visible depuis la surface S1 ;</li>
<li>calculer la lumière reçue par la surface S2 provenant de la source ;</li>
<li>calculer la lumière renvoyée par la surface S2 vers la surface S1 ;</li>
<li>calculer la lumière reçue par la surface S1 provenant de la surface S2 ;</li>
<li>calculer la lumière totale renvoyée par la surface S1 vers la caméra.</li>
</ol>
<p>Chaque étape doit prendre en compte plusieurs paramètres. Pour (3), il faut par exemple prendre en compte la distance entre la source et la surface S2 et l&rsquo;atténuation de la lumière en fonction de la distance. Pour (4), il faut prendre en compte les caractéristiques de la surface et sa capacité à réfléchir la lumière. Pour (5), il faut prendre en compte la distance entre les surfaces S1 et S2 et l&rsquo;angle d&rsquo;incidence. Pour (6), les capacités de réflexion de la surface S1 et la distance entre la surface S1 et la caméra.</p>
<p>Cette première approche simple peut largement être améliorée (et complexifiée), en prenant en compte par exemple que la lumière peut se réfléchir plusieurs fois sur des surfaces avant d&rsquo;atteindre la caméra (particulièrement important lorsque les surfaces sont très réfléchissantes, comme du verre ou du métal poli), de la diffusion de la lumière dans le brouillard ou la poussière (<a href="http://http.developer.nvidia.com/GPUGems3/gpugems3_ch13.html">lumière volumétrique</a>, <a href="http://http.developer.nvidia.com/GPUGems/gpugems_ch21.html">éclat lumineux</a>), la présence de plusieurs sources lumineuses (voir des milliers de sources lumineuses dans le cas de particules incandescentes).</p>
<h3>Lancé de rayons</h3>
<p>Il existe plusieurs techniques de &laquo;&nbsp;lancés&nbsp;&raquo;. Elles reposent sur l&rsquo;idée que la lumière est constituée de rayons qui vont partir de des sources lumineuses, se réfléchir, diffuser et réfracter sur les différentes surfaces (chaque surface pouvant renvoyer plusieurs rayons), puis atteindre la caméra. Dans les techniques de photon mapping, on part des sources lumineuses, on émet des rayons et on les suit jusqu&rsquo;à la caméra (cette technique est décrite dans un autre <a href="http://simonstechblog.blogspot.fr/2012/06/photon-mapping-part-1.html">article du blog de Simon</a> et fera l&rsquo;objet d&rsquo;une traduction). Dans les techniques de lancé de rayons, on part de la caméra, on lance un rayon pour chaque pixel de l&rsquo;image finale et l&rsquo;on remonte jusqu&rsquo;aux sources de lumière (illustration suivante).</p>
<p style="text-align: center"><img src="http://upload.wikimedia.org/wikipedia/commons/thumb/8/83/Ray_trace_diagram.svg/300px-Ray_trace_diagram.svg.png" alt="Principe du lancé de rayons" /></p>
<p style="text-align: center">(Source : <a href="http://en.wikipedia.org/wiki/Ray_tracing_(graphics)">Wikipédia &#8211; Raytracing</a>)</p>
<p>Dans la technique du lancé de cônes (Cone Tracing), présentée dans l&rsquo;article traduit, on remplace simplement les rayons par des cônes pour le calcul de l&rsquo;illumination.</p>
<h3>Occlusion ambiante</h3>
<p>Cette technique fera également l&rsquo;objet de <a href="http://simonstechblog.blogspot.fr/2011/06/ssao-using-line-integrals.html">plusieurs</a> <a href="http://simonstechblog.blogspot.fr/2012/10/angle-based-ssao.html">traductions</a> du blog de Simon, je la détaillerai à ce moment là.</p>
<p>Simplement pour comprendre l&rsquo;idée générale : lorsque deux surfaces sont proches (dans une fissure, un trou), la lumière indirecte diminue fortement et l&rsquo;on observe des ombres douces. Plus les surfaces sont proches et fermées, plus l&rsquo;ombrage sera important. L&rsquo;illustration suivante représente la même scène sans (en haut) et avec l&rsquo;occlusion ambiante (en bas). Remarquez en particulier l&rsquo;ombre dans l&rsquo;angle du mur et du sol et entre la sphère dans l&rsquo;image du bas.</p>
<p style="text-align: center"><img src="http://blog.developpez.com/gpu/files/2013/02/ambient-occlusion-2.png" /></p>
<p>Cette technique améliore fortement la qualité du rendu et commence à être très utilisée dans les jeux. Un de ses points forts est que pour un objet statique (ou peu dynamique), l&rsquo;occlusion ambiante ne varie pas (ou peu) et il est possible de la pré-calculer, le résultat étant mis dans une texture. Il suffit ensuite d&rsquo;appliquer la texture sur l&rsquo;objet lors du rendu, comme n&rsquo;importe quelle autre texture.</p>
<p>Il existe plusieurs algorithmes de calcul de l&rsquo;occlusion ambiante, mais pour comprendre le principe, voyons un exemple simple représenté dans l&rsquo;illustration suivante. Pour chaque point d&rsquo;une surface, on va lancer un nombre fixé de rayons qui vont parcourir une distance fixée aussi dans toutes les directions. On compte ensuite le nombre de rayons qui ne rencontrent pas une autre surface et on calcul le rapport entre le nombre de rayons ayant rencontrés une surface et le nombre de rayons lancés. Ainsi, dans l&rsquo;illustration suivante, pour le point A, sur les six rayons lancés, aucun ne rencontre de surfaces, le rapport est de 0/6 = 0 %. Pour le point B, seul quatre rayons ne rencontrent pas de surfaces sur les six lancés, le rapport est de 4/6 = 66 %. Pour le point C, deux rayons ne rencontrent pas de surfaces, le rapport est de 2/6 = 33 %.</p>
<p style="text-align: center"><img src="http://blog.developpez.com/gpu/files/2013/02/ambient-occlusion.png" /></p>
<p>Il suffit ensuite d&rsquo;atténuer la lumière pour chaque point en fonction du rapport calculé. Plus le rapport est proche de 0 %, plus la surface sera sombre et plus le rapport est proche de 100 %, plus la surface est claire.</p>
<p>Pour obtenir un bon rendu, on pourra augmenter le nombre de point et le nombre de rayons lancés, mais l&rsquo;impact sur les performances sera important.</p>
<h2>Partitionnement de l&rsquo;espace</h2>
<h3>Voxel</h3>
<p>Le principe des voxels est relativement simple : ils sont l&rsquo;équivalent en 3D des pixels pour la 2D. Un exemple bien connu d&rsquo;utilisation des voxels est le jeu Minecraft, dans lequel chaque élément (terrain, objets) sont représentés par des cubes.</p>
<p style="text-align: center"><img src="http://upload.wikimedia.org/wikipedia/en/7/74/Minecraft_city_hall.png" alt="Un exemple d'utilisation des voxels bien connu : Minecraft" /></p>
<p style="text-align: center">(Source : <a href="http://en.wikipedia.org/wiki/Minecraft">Wikiépdia &#8211; Minecraft</a>)</p>
<p>Les voxels sont particulièrement gourmand en termes de performances et sont encore peu utilisés pour les jeux vidéos. Ils sont particulièrement adaptés pour le rendu de volumes transparents (verre, liquide, fumée, nuage) ou de géométries très complexes (pour le rendu d&rsquo;un mesh complexe, une approche utilisant une version <a href="http://en.wikipedia.org/wiki/Low_poly">low poly</a> du mesh et une texture des <a href="http://fr.wikipedia.org/wiki/Displacement_mapping">Displacement</a>/<a href="http://fr.wikipedia.org/wiki/Normal_mapping">Normal</a>/<a href="http://fr.wikipedia.org/wiki/Bump_mapping">Bump</a> mapping).</p>
<h3>Octree</h3>
<p>Un octree est une structure permettant de partitionner l&rsquo;espace dans un arbre, permettant par exemple de faciliter la recherche d&rsquo;un élément par rapport à sa position 3D. La construction d&rsquo;un tel arbre est simple : à chaque itération, le cube représentant une partie de l&rsquo;espace est divisé en 8 cubes.</p>
<p style="text-align: center"><img src="http://http.developer.nvidia.com/GPUGems2/elementLinks/37_octree_03.jpg" alt="Division de l'espace avec un octree" /></p>
<p style="text-align: center">(Source : <a href="http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter37.html">GPU Gems 2 &#8211; Octree Textures on the GPU</a>)</p>
<p>L&rsquo;intérêt des octrees avec les voxels est que l&rsquo;on va pouvoir utiliser une structure &laquo;&nbsp;creuse&nbsp;&raquo; : les zones qui sont vides ne seront pas divisées en cubes plus petits, simplifiant ainsi les algorithmes de recherche et la mémoire.</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>Pourquoi le C++ est un langage plus adapté pour les débutants que le C ?</title>
		<link>https://blog.developpez.com/gpu/?p=155</link>
		<comments>https://blog.developpez.com/gpu/?p=155#comments</comments>
		<pubDate>Mon, 21 Jan 2013 11:15:10 +0000</pubDate>
		<dc:creator><![CDATA[gbdivers]]></dc:creator>
				<category><![CDATA[C++]]></category>
		<category><![CDATA[Facile]]></category>

		<guid isPermaLink="false">http://blog.developpez.com/gpu/?p=155</guid>
		<description><![CDATA[Un adage bien connu dit qu&#8217;enseigner, c&#8217;est répéter. Ceux qui fréquentent depuis quelque temps le forum C++ de Developpez le savent très bien : on revoit les mêmes discussions revenir régulièrement. Ce billet de blog va tenter d&#8217;analyser un peu &#8230; <a href="https://blog.developpez.com/gpu/?p=155">Lire la suite <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Un adage bien connu dit qu&rsquo;enseigner, c&rsquo;est répéter. Ceux qui fréquentent depuis quelque temps le <a href="http://cpp.developpez.com" title="forum C++">forum C++</a> de Developpez le savent très bien : on revoit les mêmes discussions revenir régulièrement. Ce billet de blog va tenter d&rsquo;analyser un peu les arguments concernant l&rsquo;apprentissage du C++,  en se focalisant plus particulièrement sur les difficultés d&rsquo;utilisation. En particulier le raisonnement suivant, que l&rsquo;on entend souvent : &laquo;&nbsp;il est préférable d&rsquo;apprendre le C avec le C++&nbsp;&raquo;, ainsi que l&rsquo;affirmation suivante, souvent pas comprise : &laquo;&nbsp;le C++ est un meilleur langage pour débuter que le C&nbsp;&raquo;.<br />
<span id="more-155"></span></p>
<p><a href="http://www.developpez.net/forums/d1299991/c-cpp/cpp/pourquoi-cpp-langage-plus-adapte-debutants-c/">Vous pouvez commenter cet article sur le forum.</a></p>
<h1>Complexité du langage ou de l&rsquo;apprentissage</h1>
<p><em>Cette partie a été écrite par <a href="http://www.developpez.net/forums/u44106/jolyloic/">JolyLoic</a>.</em></p>
<p>Lorsque l&rsquo;on compare différents langages, il existe plusieurs notions de complexité, dont la confusion est une des causes qui fait que ces comparaisons s&rsquo;enflamment.</p>
<p>Il y a au moins :</p>
<ul>
<li>la complexité intrinsèque d&rsquo;un langage, celle qui correspond à l&rsquo;effort à réaliser pour y devenir un gourou qui connait tous les détails les plus arcanes. Cette complexité peut quasiment se mesurer au nombre de pages d&rsquo;un document décrivant le langage. Sur ce plan, le C++ est beaucoup plus complexe que le C, c&rsquo;est indéniable ;</li>
<li>la complexité au jour le jour d&rsquo;un langage, qui est liée au niveau de discipline mentale nécessaire pour coder, ainsi qu&rsquo;à la puissance des abstractions que l&rsquo;utilisateur peut mettre en œuvre pour l&rsquo;aider. Je suis convaincu que sur ce plan, le C++ est beaucoup plus simple que le C ;</li>
<li>la complexité d&rsquo;apprentissage. Elle correspond à la difficulté du parcours d&rsquo;un étudiant ne connaissant rien et devant apprendre assez du langage pour en devenir professionnel. Je pense là aussi que le C++ et plus simple que le C, mais la réponse est moins tranchée.</li>
</ul>
<p>La complexité intrinsèque et la complexité au jour le jour sont bien évidemment en opposition, puisque si l&rsquo;on complexifie un langage, ce n&rsquo;est pas par pur plaisir masochiste, mais bien pour le rendre plus puissant, donc plus efficace au jour le jour. La complexité d&rsquo;apprentissage est liée aux deux autres, mais aussi à la notion de progressivité. </p>
<p>Cette notion de progressivité de l&rsquo;apprentissage me semble importante. À part à un haut niveau post-bac, où l&rsquo;on suppose les étudiants comme des experts dans l&rsquo;art d&rsquo;ingurgiter des connaissances (et où à mon avis, on se trompe de méthode, mais c&rsquo;est un autre sujet), l&rsquo;ordre d&rsquo;apprentissage n&rsquo;a rien à voir avec un ordre logique, qui irait du plus théorique au plus pratique (ce qui consisterait pour notre langue maternelle à faire de la linguistique, de la grammaire et à apprendre le dictionnaire dans l&rsquo;ordre, avant de dire papa-maman, et dans le programmation à préconiser l&rsquo;apprentissage du théorème du point fixe, du lambda calculus et autres modélisations mathématiques des langages avant de faire un hello world), ou encore, pour parler d&rsquo;informatique du plus proche du matériel au plus éloigné (qui consisterait à faire de l&rsquo;électronique, puis de l&rsquo;assembleur, puis du C puis du C++).</p>
<p>Non, l&rsquo;apprentissage se fait de manière pragmatique, en parcourant le sujet à enseigner de manière en apparence erratique, mais avec pour objectifs :</p>
<ul>
<li>que chaque pas ne soit pas trop gros, afin de ne perdre personne ;</li>
<li>que le parcours soit à chaque étape intéressant, afin de motiver les gens.</li>
</ul>
<p>Un des points de passage de plus haute complexité du C comme du C++ est la notion de pointeurs, avec ses corollaires d&rsquo;allocation dynamique de la mémoire (mais même sans ça, la notion de pointeur et de valeur pointée pose bien des problèmes). Or, en C, impossible d&rsquo;écrire un programme un minimum intéressant sans utiliser explicitement des pointeurs. En C++ (ou des d&rsquo;autres langages comme java ou C#), l&rsquo;utilisation de ces pointeurs peut être cachée pendant assez longtemps et on a donc bien plus de liberté pour choisir un parcours le long duquel la courbe d&rsquo;apprentissage ne présente pas de murs trop importants.</p>
<h1>Apprentissage d&rsquo;un langage ou de la programmation</h1>
<p>Avant d&rsquo;expliquer et critiquer les phrases indiquées dans l&rsquo;introduction, il convient de préciser quel est l&rsquo;objectif recherché dans l&rsquo;apprentissage. Si l&rsquo;on est dans le cadre de l&rsquo;apprentissage d&rsquo;un langage précis, par exemple dans le cadre d&rsquo;un cours scolaire, dans lequel le langage à utiliser est imposé, alors bien évidemment, la question de savoir si le C++ est plus adapté pour les débutants n&rsquo;a pas lieu d&rsquo;être. Nous nous placeront donc dans le cas où la personne qui souhaite apprendre le C ou le C++ est libre de son choix.</p>
<p>Quelle est la différence entre apprendre un langage et apprendre la programmation ? Dans le premier cas, l&rsquo;attention se porte sur l&rsquo;apprentissage de la syntaxe du langage, ce que l&rsquo;on fait de ce langage compte peu finalement. Dans le second cas, l&rsquo;objectif est de savoir concevoir efficacement un programme permettant de répondre à une problématique donnée. Que ce soit dans le cadre amateur ou professionnel, ce dernier objectif est beaucoup plus intéressant et c&rsquo;est dans cette optique que se place ce billet de blog.</p>
<p>Précisons ce que signifie ce que l&rsquo;on entend par &laquo;&nbsp;efficacement&nbsp;&raquo;. Dans la création d&rsquo;un programme, on pense en général à la phase de codage et l&rsquo;on comprend facilement qu&rsquo;entre deux langages, si le premier permet d&rsquo;obtenir le même résultat que le second, mais en utilisant 10 fois moins de lignes de code, alors il sera beaucoup plus efficace d&rsquo;écrire un programme dans ce langage. Cependant, la création d&rsquo;une application ne se limite pas à écrire du code et l&rsquo;expérience montre que l&rsquo;on passe beaucoup de temps sur d&rsquo;autres tâches : la conception du programme, la correction des bugs, la validation du programme (vérifier que le programme donne le résultat correct). Le terme &laquo;&nbsp;efficacement&nbsp;&raquo; doit donc être considéré en analysant le temps global de développement et pas simplement la phase de codage.</p>
<h1>Conception impérative et objet</h1>
<p>La comparaison entre les différents paradigmes de programmation, leurs intérêts et inconvénients respectifs, leurs efficacités, n&rsquo;est pas le propos de cet article, je ne vais donc pas m&rsquo;attarder sur ce point. Signalons simplement que la raison même de la création de la programmation objet est de faciliter la création d&rsquo;application, on peut s&rsquo;attendre à ce que la conception en C++ utilisant des objets (correctement&#8230;) sera plus efficace qu&rsquo;en C.</p>
<h1>Erreurs à la compilation et l&rsquo;exécution</h1>
<h2>Problématique</h2>
<p>Probablement tous les développeurs expérimentés ont déjà eu le problème suivant, d&rsquo;un bug dont l&rsquo;origine était indéterminée et qui a nécessité plusieurs heures de recherche pour le corriger. Partant de ce constat, on peut tirer la règle suivante : plus la détection des erreurs est précoce, plus il sera facile de les corriger. Autrement dit, les erreurs survenant à la compilation seront beaucoup plus simples à corriger que les erreurs survenant lors de l&rsquo;exécution (et l&rsquo;une des forces des templates en C++ est de pouvoir justement réaliser beaucoup de vérifications à la compilation, sans surcoût à l&rsquo;exécution, mais cela sort du sujet de ce blog).</p>
<p>Pour être plus concret, voyons un exemple avec la vérification de la constance des variables (&laquo;&nbsp;const-correctness&nbsp;&raquo;). Le mot-clé const, utilisé pour le passage de paramètres dans les fonctions, est un contrat que passe l&rsquo;utilisateur d&rsquo;une fonction avec le créateur de cette fonction. Il permet de dire : cette variable ne sera pas modifiée dans cette fonction.</p>
<p>En théorie&#8230;</p>
<p>Voyons ce que cela donne en pratique. Imaginons une fonction foo() prenant une chaîne de caractères constante et pouvant modifier cette chaîne. Le respect de cette constance implique donc que la fonction ne doit pas travailler sur la chaîne passée en argument de la fonction (potentiellement non modifiable), mais sur une copie modifiable de cette chaîne.</p>
<h2>Cas du C</h2>
<p>Voyons par exemple le code suivant, qui convertit un simple const char* en char* (donc qui supprime le mot-clé const) :</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 /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">void foo(const char* cstr) {<br />
&nbsp; &nbsp; char* str = cstr;<br />
&nbsp; &nbsp; bar(str); // modifie potentiellement str<br />
}<br />
&nbsp;<br />
int main()<br />
{ &nbsp;<br />
&nbsp; &nbsp;foo(&quot;une chaîne de caractères&quot;);<br />
&nbsp; &nbsp;return 0;<br />
}</div></td></tr></tbody></table></div>
<p>Lorsque l&rsquo;on compile avec un compilateur C, celui-ci ne donne qu&rsquo;un simple avertissement sur le fait que l&rsquo;on modifie une variable constante en non constante. Malheureusement, les warnings sont souvent ignorés par les débutants et le code ne sera pas corrigé. C&rsquo;est une mauvaise pratique largement répandue et c&rsquo;est souvent une bonne chose d&rsquo;activer l&rsquo;option -Werror dans gcc, pour que les warnings deviennent des erreurs). On va pouvoir observer des comportements différents en fonction du code de bar(). Si la fonction bar() ne modifie pas la chaîne, par exemple avec le code suivant, alors il n&rsquo;y aura pas de problème, le programme s&rsquo;exécutera sans erreur :</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">void bar(char* str) {<br />
&nbsp; &nbsp; printf(&quot;%s&quot; , str);<br />
}</div></td></tr></tbody></table></div>
<p>En revanche, si la fonction bar() modifie la chaîne, on va obtenir une erreur à l&rsquo;exécution. Par exemple, le code suivant :</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">void bar(char* str) {<br />
&nbsp; &nbsp; str[0] = 'X'; // on suppose que str existe et contient au moins un caractère<br />
&nbsp; &nbsp; printf(&quot;%s&quot; , str);<br />
}</div></td></tr></tbody></table></div>
<p>Ce code va générer l&rsquo;erreur suivante :</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">result: runtime error &nbsp;time: 0.02s &nbsp;memory: 1676 kB &nbsp;signal: 11 (SIGSEGV)</div></td></tr></tbody></table></div>
<p>Ce message d&rsquo;erreur ne nous apprend pas grand-chose. Il indique simplement qu&rsquo;il y a un problème d&rsquo;accès sur une mémoire invalide, mais n&rsquo;indique pas que l&rsquo;on ne respecte pas le const-correctness et ne précise pas la ligne de code où se situe le problème. On imagine bien alors que dans un programme contenant plusieurs milliers de lignes de code, il sera difficile de trouver l&rsquo;erreur.</p>
<p>Même si le premier code de bar() ne provoque pas d&rsquo;erreur à l&rsquo;exécution, il n&rsquo;en reste pas moins que le code de foo() est la source du problème. Cependant, il n&rsquo;y a pas de validation réalisée par le compilateur et il est facilement possible dans ces conditions d&rsquo;avoir du code potentiellement problématique qui fonctionne&#8230; quelques temps. Et à l&rsquo;occasion d&rsquo;une modification mineure, ce code problématique va déclencher une erreur d&rsquo;exécution et la recherche de l&rsquo;erreur sera fastidieuse. On dit souvent, de façon humoristique, qu&rsquo;un code problématique et qui fonctionne quand même &laquo;&nbsp;que le programme tombe en marche&nbsp;&raquo;.</p>
<p>Sans cette vérification à la compilation, il est facile de se tromper, par exemple en écrivant le nom des fonctions. Supposons que l&rsquo;on a deux fonctions, une version qui ne modifie pas la chaîne et utilise donc directement la chaîne passée en argument ; une version qui modifie la chaîne, par exemple en appelant realloc(). Normalement, il faudrait récupérer le pointeur retourné par la fonction, mais comme on appelle la mauvaise fonction, on oublie de le faire :</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 /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">// version constante<br />
// s'utilise de la façon suivante : c_bar(str);<br />
void c_bar(const char* str) { <br />
&nbsp; &nbsp; do_something(str); <br />
}<br />
<br />
// version non constante<br />
// s'utilise de la façon suivante : str = c_bar(str);<br />
char* bar(char* str) { <br />
&nbsp; &nbsp; char* str2 = realloc(str, strlen(str)*2); <br />
&nbsp; &nbsp; if (str2) { str = str2; } else { printf(&quot;Error de réallocation&quot;); }<br />
&nbsp; &nbsp; do_something(str); <br />
&nbsp; &nbsp; return str; <br />
}<br />
<br />
void foo(const char* cstr) {<br />
&nbsp; &nbsp; // allocation et copie<br />
&nbsp; &nbsp; size_t len = strlen(cstr) + 1;<br />
&nbsp; &nbsp; char* str = malloc(len);<br />
&nbsp; &nbsp; strcpy(str, cstr);<br />
<br />
&nbsp; &nbsp; // appel de bar() au lieu de c_bar()<br />
&nbsp; &nbsp; bar(str); // problème !<br />
<br />
&nbsp; &nbsp; // libération<br />
&nbsp; &nbsp; free(str);<br />
}</div></td></tr></tbody></table></div>
<p>En C, lors de la compilation, il y aura un simple warning, qui est facilement manqué. À l&rsquo;exécution, le message d&rsquo;erreur n&rsquo;indique pas l&rsquo;origine du problème. Plus que le fait que le code à écrire est plus long qu&rsquo;en C++, il y aura une perte de temps très importante, plusieurs heures voir plusieurs jours, pour trouver l&rsquo;origine des erreurs.</p>
<h2>Cas du C++</h2>
<p>En C++, la situation sera beaucoup plus simple : ce code génère une erreur suivante, indiquant que l&rsquo;on essaie de convertir une variable constante en variable non constante :</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 /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">prog.cpp: In function ‘void foo(const char*)’:<br />
prog.cpp:5: error: invalid conversion from ‘const char*’ to ‘char*’</div></td></tr></tbody></table></div>
<p>L&rsquo;erreur est simple (profitons-en, ce n&rsquo;est pas toujours le cas en C++) et parfaitement localisée, la correction du code sera directe et rapide.</p>
<h1>Détection des fuites mémoires</h1>
<h2>Problématique</h2>
<p>Commençons par un rappel : qu&rsquo;est-ce qu&rsquo;une fuite mémoire ? Lorsque l&rsquo;on alloue une variable dynamique sur le Tas, le bloc mémoire alloué doit être détruit à un moment donné, quand on en a plus besoin, pour éviter de saturer la mémoire disponible. L&rsquo;adresse mémoire est sauvegardée dans un pointeur et il suffit d&rsquo;appeler la fonction adéquate pour libérer la mémoire, en fonction de la fonction utilisée pour l&rsquo;allouer : free() avec malloc ou calloc, delete avec new, delete[] avec new[]. Une fuite mémoire survient lorsque cette libération n&rsquo;est pas réalisée, par exemple si on perd le pointeur, si on n&rsquo;appelle pas la fonction de libération adéquate, voir qu&rsquo;on appelle pas du tout cette fonction.</p>
<p>La difficulté avec les fuites mémoires est que c&rsquo;est un problème qui survient exclusivement à l&rsquo;exécution, on retombe sur le souci décrit dans le chapitre précédent : la localisation pourra être complexe et longue. Il existe des outils d&rsquo;analyse des allocations, tel que valgrind, qui permet de rechercher ce type de problème (et il est recommandé de l&rsquo;utiliser régulièrement), mais s&rsquo;il est possible de minimiser les risques lors de la phase de codage, cela pourra améliorer l&rsquo;efficacité.</p>
<h2>Cas du C</h2>
<p>Revenons sur le code précédent de foo() et corrigeons le problème de const-correctness en copiant la chaîne constante dans une nouvelle chaîne non constante. Pour simplifier le code, il est possible d&rsquo;écrire deux fonctions d&rsquo;aide pour gérer la mémoire : createString(), pour allouer la mémoire et copier la chaîne, et destroyString(), pour libérer la mémoire. Une implémentation de ces fonctions peut-être la suivante :</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 /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">char* createString(const char* cstr) {<br />
&nbsp; &nbsp; size_t len = strlen(cstr) + 1;<br />
&nbsp; &nbsp; char* str = malloc(len);<br />
&nbsp; &nbsp; strcpy(str, cstr);<br />
&nbsp; &nbsp; return str;<br />
}<br />
<br />
void destroyString(char* str) {<br />
&nbsp; &nbsp; free(str)<br />
}</div></td></tr></tbody></table></div>
<p>Le code de la fonction foo() est modifié de la façon suivante :</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">void foo(const char* cstr) {<br />
&nbsp; &nbsp; char* str = createString(cstr);<br />
&nbsp; &nbsp; bar(str); // modifie potentiellement str<br />
&nbsp; &nbsp; destroyString(str);<br />
}<br />
<br />
int main()<br />
{ &nbsp;<br />
&nbsp; &nbsp;foo(&quot;une chaîne de caractères&quot;);<br />
&nbsp; &nbsp;return 0;<br />
}</div></td></tr></tbody></table></div>
<p>Dans un code aussi simple, il est peu probable que le développeur oublie de libérer la mémoire à la fin de la fonction foo(). Par contre, dans une situation plus complexe, dans lequel la création de la chaîne est réalisée à un endroit du programme, l&rsquo;utilisation à d&rsquo;autres endroits et la libération encore ailleurs, il peut être difficile de savoir si la mémoire est correctement libérée.</p>
<p>De plus, le code précédent n&rsquo;apporte pas de garanties fortes sur la libération. Par exemple, si le code entre createString() et destroyString() contient des return, la fonction destroy() ne sera pas appelée. Il est de la responsabilité du développeur de penser à appeler destroy() avant chaque return, ce qui peut être facilement oublié. Si la fonction manipule plusieurs objets dynamiques, il faut savoir à tout moment quelles sont les variables allouées et celles qui ne le sont pas.</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">void foo(const char* cstr) {<br />
&nbsp; &nbsp; char* str = createString(cstr);<br />
&nbsp; &nbsp; if (test) <br />
&nbsp; &nbsp; &nbsp; &nbsp; return; // problème !<br />
&nbsp; &nbsp; destroyString(str);<br />
}</div></td></tr></tbody></table></div>
<p>Plus pernicieux, le code peut allouer un nouveau bloc mémoire et attribuer l’adresse dans un pointeur, ce qui invalidera celui-ci et provoquera une fuite.</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">void foo(const char* cstr) {<br />
&nbsp; &nbsp; char* str = createString(cstr);<br />
&nbsp; &nbsp; if (test) <br />
&nbsp; &nbsp; &nbsp; &nbsp; str = createString(&quot;un nouvelle chaîne&quot;); // problème !<br />
&nbsp; &nbsp; destroyString(str);<br />
}</div></td></tr></tbody></table></div>
<p>En général, on trouve deux profils sur le forum : ceux qui croient qui ne feront jamais d&rsquo;erreurs aussi grossières et ceux qui savent qu&rsquo;il peut arriver de faire de telles erreurs. En général aussi, les premiers viennent sur le forum parce qu&rsquo;ils ont des problèmes avec leur code, les seconds viennent pour aider les premiers.<br />
Choisissez votre camp. Et si vous faites partie du premier groupe, posez-vous peut être des questions&#8230;</p>
<h2>Cas du C++</h2>
<p>La situation pourrait sembler plus compliquée en C++. En effet, le C++ ajoute un système de gestion d&rsquo;erreurs, absent du C : les exceptions. Ce système peut briser l&rsquo;ordre séquentiel d&rsquo;exécution du code et il peut être difficile de garantir la robustesse du code.</p>
<p>Cependant, le C++ propose également un système qui permet de transférer la responsabilité de la libération de la mémoire. En effet, grâce au <a href="http://cpp.developpez.com/faq/cpp/?page=pointeurs#POINTEURS_raii">RAII</a> (acquisition de ressources à l&rsquo;initialisation), la libération est sous la responsabilité d&rsquo;une classe au lieu d&rsquo;être sous celle de l&rsquo;utilisateur. Le RAII est un principe qui peut être implémenté par les concepteurs d&rsquo;une classe utilisant des ressources dynamiques, mais pour simplifier le travail, la bibliothèque standard STL fournit déjà de nombreuses classes encapsulant le RAII : std::string pour les chaînes, std::vector pour les tableaux, std::shared_ptr pour les pointeurs, etc. </p>
<p>Voyons par exemple une fonction utilisant une chaîne de caractères en C++ :</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">void foo(const char* cstr) {<br />
&nbsp; &nbsp; std::string str(cstr);<br />
&nbsp; &nbsp; // code quelconque pouvant modifier str<br />
}</div></td></tr></tbody></table></div>
<p>Ce code, en plus du fait d&rsquo;être beaucoup plus simple, nous garantit que quelles que soient les lignes de code contenues dans la fonction, la chaîne de caractères str sera correctement libérée lorsque l&rsquo;on sort de la fonction et quelle que soit la façon dont on sort de cette fonction (par return, par exception). L&rsquo;attention du développeur peut se focaliser sur le problème à résoudre et plus sur les détails de gestion de la mémoire.</p>
<h1>Conclusion</h1>
<p>D&rsquo;autres arguments peuvent être abordés pour justifier l&rsquo;apprentissage du C avant le C++ (on parle de l&rsquo;approche historique de l&rsquo;apprentissage du C++), mais une analyse peut facilement les mettre à mal. Par exemple, l&rsquo;argument selon lequel l&rsquo;apprentissage bas-niveau en C permet de mieux comprendre ensuite la programmation plus haut-niveau en C++. Outre le fait que l&rsquo;apprentissage de la gestion manuelle de la mémoire n&rsquo;est pas un prérequis pour comprendre les notions d&rsquo;allocation dynamique, de Pile et de Tas, la pratique montre que ceux qui abordent l&rsquo;apprentissage par cette approche se perdent dans les détails et le débogage et ont plus de mal à assimiler les concepts plus haut-niveau (conception objet, encapsulation, principes de programmations objet, etc.)</p>
<p>On pourrait croire que mes propos sont exagérés, qu&rsquo;il est rare de faire des erreurs aussi grossières, que cela n&rsquo;empêche pas de comprendre les concepts de programmation objet. En pratique, on voit régulièrement sur le forum les étudiants faire les mêmes erreurs d&rsquo;apprentissage (<a href="http://www.developpez.net/forums/d1298957/c-cpp/cpp/debuter/instanciation-statique-classe/#post7076206">un exemple récent</a>), mais ce n&rsquo;est pas une fatalité et il est possible de corriger notre façon d&rsquo;enseigner la programmation en C++.</p>
<h1>Remerciements</h1>
<p>Merci à <a href="http://www.developpez.net/forums/u44106/jolyloic/">JolyLoic</a> pour la partie qu&rsquo;il a rédigée et ses remarques, à <a href="http://www.developpez.net/forums/u329028/winjerome/">Winjerome</a>, <a href="http://www.developpez.net/forums/u169075/kalith/">Kalith</a> et <a href="http://www.developpez.net/forums/u240267/littlewhite/">LittleWhite</a> pour leur relecture et leurs remarques, à <a href="http://www.developpez.net/forums/u329028/winjerome/">Winjerome</a> pour ses corrections orthographiques.</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</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>
	</channel>
</rss>
