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

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

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

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

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Lorsque l&#8217;on débute l&#8217;apprentissage d&#8217;OpenGL et des shaders (et même ensuite), on est vite confronté au problème du débogage, soit parce que le programme s&#8217;arrête brusquement, soit parce que le résultat obtenu ne correspond pas à ce que l&#8217;on attend. &#8230; <a href="https://blog.developpez.com/gpu/?p=6">Lire la suite <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Lorsque l&rsquo;on débute l&rsquo;apprentissage d&rsquo;OpenGL et des shaders (et même ensuite), on est vite confronté au problème du débogage, soit parce que le programme s&rsquo;arrête brusquement, soit parce que le résultat obtenu ne correspond pas à ce que l&rsquo;on attend. Traditionnellement, on utilise la fonction <em>glGetError</em>, mais elle est encore trop souvent &laquo;&nbsp;oubliée&nbsp;&raquo; par les développeurs et elle donne finalement assez peu d&rsquo;informations.<br />
Heureusement, cette problématique a été prise en compte dans les dernières spécifications d&rsquo;OpenGL avec l&rsquo;ajout de nouvelles extensions pour le débogage. Ce billet de blog aborde les fonctionnalités de débogage introduites dans OpenGL 4.1 avec l&rsquo;extension ARB_debug_output et complétées dans OpenGL 4.3 avec l&rsquo;extension KHR_debug.<br />
Les outils externes de débogage ne sont pas abordés.<br />
<span id="more-6"></span></p>
<p><a href="http://www.developpez.net/forums/d1255099/applications/developpement-2d-3d-jeux/api-graphiques/opengl/deboguer-opengl/">Vous pouvez commenter cet article sur le forum</a></p>
<h1>Les nouvelles extensions</h1>
<h2>L&rsquo;extension ARB_debug_output (GL 4.1)</h2>
<p>Dans la version OpenGL 4.1, a été ajouté l&rsquo;extension ARB_debug_output, qui est une promotion de l&rsquo;extension GL_AMD_debug_output proposée par AMD. Cette extension ajoute la possibilité de créer des contextes avec un mode de débogage. En l&rsquo;activant, un système d&rsquo;événements est activé et permet d&rsquo;obtenir des informations variées, par exemple sur les problèmes rencontrés lors de la compilation des shaders GLSL, des appels de fonction non valides ou des problèmes potentiels de performance. Les messages générés par ce système peuvent être stockés dans une pile (&laquo;&nbsp;message log&nbsp;&raquo;) ou être récupérés par une fonction callback définie par l&rsquo;utilisateur.</p>
<h2>L&rsquo;extension KHR_debug (GL 4.3)</h2>
<p>Dans le but d&rsquo;uniformiser les différentes versions d&rsquo;OpenGL (en particulier avec OpenGL ES), l&rsquo;évolution d&rsquo;OpenGL tend à reprendre des fonctions provenant d&rsquo;OpenGL ES. C&rsquo;est le cas de l&rsquo;extension KHR_debug dans OpenGL 4.3 qui est une promotion de l&rsquo;extension ARB_debug_output d&rsquo;OpenGL 4.1 et des extensions EXT_debug_marker et EXT_debug_label d&rsquo;OpenGL ES. Cette extension ajoute ainsi des fonctions pour annoter les événements ou des groupes de commandes OpenGL.</p>
<h1>Création d&rsquo;un contexte de débogage (GL 4.1)</h1>
<p>La première chose à faire pour utiliser un contexte de débogage est de vérifier que l&rsquo;extension ARB_debug_output est bien prise en charge. Un exemple de code pour vérifier une extension est donné dans le tutoriel <a href="http://alexandre-laurent.developpez.com/tutoriels/OpenGL/OpenGL-Extensions/#L2-B">Les extensions OpenGL</a>.</p>
<p>Pour créer un contexte de débogage, il faut simplement créer un contexte en appelant la fonction <em>CreateContextAttribs</em> avec le paramètre CONTEXT_DEBUG_BIT. En fonction du système d&rsquo;exploitation, on aura donc un code équivalent à celui-ci :</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;">int</span> attribs<span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span> <span style="color: #000080;">=</span> <br />
<span style="color: #008000;">&#123;</span> <br />
<span style="color: #339900;">#ifdefWIN32 </span><br />
&nbsp; &nbsp; WGL_CONTEXT_MAJOR_VERSION_ARB, <span style="color: #0000dd;">4</span>, <br />
&nbsp; &nbsp; WGL_CONTEXT_MINOR_VERSION_ARB, <span style="color: #0000dd;">1</span>, <br />
&nbsp; &nbsp; WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_DEBUG_BIT_ARB, <br />
&nbsp; &nbsp; WGL_CONTEXT_PROFILE_MASK, WGL_CONTEXT_CORE_PROFILE_BIT_ARB, <br />
<span style="color: #339900;">#endif </span><br />
<span style="color: #339900;">#ifdef__linux__ </span><br />
&nbsp; &nbsp; GLX_CONTEXT_MAJOR_VERSION_ARB, <span style="color: #0000dd;">4</span>, <br />
&nbsp; &nbsp; GLX_CONTEXT_MINOR_VERSION_ARB, <span style="color: #0000dd;">1</span>, <br />
&nbsp; &nbsp; GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_DEBUG_BIT_ARB, <br />
&nbsp; &nbsp; GLX_CONTEXT_PROFILE_MASK, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, <br />
<span style="color: #339900;">#endif </span><br />
&nbsp; &nbsp; <span style="color: #0000dd;">0</span> <br />
<span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span> <br />
&nbsp;<br />
<span style="color: #666666;">// intialisation </span><br />
HDC hdc<span style="color: #008080;">;</span> &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #666666;">// Handle to a device context </span><br />
HGLRC hglrc<span style="color: #008080;">;</span> &nbsp; &nbsp;<span style="color: #666666;">// Handle to an OpenGL rendering context </span><br />
hglrc <span style="color: #000080;">=</span> wglCreateContext <span style="color: #008000;">&#40;</span>hdc<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
wglMakeCurrent <span style="color: #008000;">&#40;</span>hdc, hglrc<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
&nbsp;<br />
<span style="color: #666666;">// contexte attribs </span><br />
<span style="color: #0000ff;">int</span> pixelFormat, numFormats<span style="color: #008080;">;</span> <br />
glChoosePixelFormatARB<span style="color: #008000;">&#40;</span>hdc, attribList, <span style="color: #0000ff;">NULL</span>, <span style="color: #0000dd;">1</span>, <span style="color: #000040;">&amp;</span>pixelFormat, <br />
&nbsp; &nbsp; <span style="color: #000040;">&amp;</span>numFormats<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
HGLRC wglCreateContextAttribsARB<span style="color: #008000;">&#40;</span>HDC hDC, HGLRC hshareContext, <br />
&nbsp; &nbsp; <span style="color: #0000ff;">const</span> <span style="color: #0000ff;">int</span> <span style="color: #000040;">*</span>attribList<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> &nbsp;<br />
&nbsp;<br />
<span style="color: #666666;">// après utilisation </span><br />
wglMakeCurrent <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">NULL</span>, <span style="color: #0000ff;">NULL</span><span style="color: #008000;">&#41;</span> <span style="color: #008080;">;</span> &nbsp;<br />
wglDeleteContext <span style="color: #008000;">&#40;</span>hglrc<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>Les fonctionnalités de débogage sont activées en utilisant la constante GL_DEBUG_OUTPUT. Celle-ci peut être activée ou désactivée avec <em>glEnable</em> et <em>glDisable</em>. Par défaut, cette constante est activée dans un contexte de débogage et désactivée dans le cas contraire.</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: #666666;">// active les messages de débogage </span><br />
glEnable<span style="color: #008000;">&#40;</span>GL_DEBUG_OUTPUT<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br />
<br />
<span style="color: #666666;">// désactive les messages de débogage</span><br />
glDisable<span style="color: #008000;">&#40;</span>GL_DEBUG_OUTPUT<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>Plusieurs niveaux de débogage sont possibles en fonction de la création ou non d&rsquo;un contexte de débogage et de si l&rsquo;on active GL_DEBUG_OUTPUT :
<ul>
<li>si on ne crée pas un contexte de débogage et que l&rsquo;on active GL_DEBUG_OUTPUT, les messages envoyés et le contenu sont laissés à l&rsquo;appréciation des implémentations d&rsquo;OpenGL, mais l&rsquo;appel des fonctions de débogage ne produit pas d&rsquo;erreur ;</li>
<li>si on crée un contexte de débogage et que l&rsquo;on n&rsquo;active pas GL_DEBUG_OUTPUT, aucun message de débogage n&rsquo;est lancé ;</li>
<li>si on crée un contexte de débogage et que l&rsquo;on active GL_DEBUG_OUTPUT, toutes les fonctionnalités de débogage sont activées.</li>
</ul>
<h1>Créer des contextes de débogage à partir d&rsquo;une bibliothèque (GL 4.1)</h1>
<p>Il existe plusieurs bibliothèques graphiques qui permettent de travailler sur des contextes OpenGL (SFML, SDL, Qt, etc.). Voyons comment créer un contexte de débogage dans ces cas d&rsquo;utilisation.</p>
<h2>Avec <a href="http://freeglut.sourceforge.net/">FreeGlut</a></h2>
<p>FreeGlut fournit directement une constante pour créer un contexte en mode débogage : GLUT_DEBUG.</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: #666666;">// FreeGlut </span><br />
glutInitContextFlags<span style="color: #008000;">&#40;</span>GLUT_DEBUG<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<h2>Avec <a href="http://qt-project.org/">Qt</a></h2>
<p>La bibliothèque Qt fournit des outils pour créer et manipuler directement des fenêtres contenant un contexte OpenGL avec le module <a href="http://qt-project.org/doc/qt-4.8/qtopengl.html">QtOpenGL</a>. Pour créer un contexte spécifique d&rsquo;une version OpenGL, il suffit simplement d&rsquo;utiliser la fonction <a href="http://qt-project.org/doc/qt-4.8/qglformat.html#setVersion">setVersion</a> de la classe <a href="qt-project.org/doc/qt-4.8/qglformat.html">QGLFormat</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 />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"><span style="color: #339900;">#include QtOpenGL</span><br />
... <br />
<span style="color: #007788;">QGLFormat</span> format<span style="color: #008080;">;</span> <br />
format.<span style="color: #007788;">setVersion</span><span style="color: #008000;">&#40;</span><span style="color: #0000dd;">4</span>, <span style="color: #0000dd;">3</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
format.<span style="color: #007788;">setProfile</span><span style="color: #008000;">&#40;</span> QGLFormat<span style="color: #008080;">::</span><span style="color: #007788;">CoreProfile</span> <span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #666666;">// nécessite Qt &gt;= 4.8 </span><br />
format.<span style="color: #007788;">setSampleBuffers</span><span style="color: #008000;">&#40;</span> <span style="color: #0000ff;">true</span> <span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
GLWidget<span style="color: #000040;">*</span> w <span style="color: #000080;">=</span> <span style="color: #0000dd;">new</span> QGLWidget<span style="color: #008000;">&#40;</span>format<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>Pour plus de détails, voir l&rsquo;article <a href="http://qt-project.org/wiki/How_to_use_OpenGL_Core_Profile_with_Qt">How to use OpenGL Core Profile with Qt</a> sur le wiki de Qt.</p>
<h2>Avec <a href="http://www.sfml-dev.org/index-fr.php">SFML 2.0</a></h2>
<p>La bibliothèque SFML permet de demander lors de la création d&rsquo;une fenêtre la version du contexte OpenGL à utiliser avec la classe <a href="http://www.sfml-dev.org/documentation/2.0/structsf_1_1ContextSettings.php">sf::ContextSettings</a>. S&rsquo;il n&rsquo;est pas possible de créer un contexte avec les paramètres demandés, SFML va créer un contexte le plus proche possible. Il est donc important de vérifier la version de contexte réellement créé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 />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 SFML/OpenGL.hpp</span><br />
... <br />
<span style="color: #007788;">sf</span><span style="color: #008080;">::</span><span style="color: #007788;">ContextSettings</span> settings<span style="color: #008080;">;</span> <br />
settings.<span style="color: #007788;">depthBits</span> <span style="color: #000080;">=</span> <span style="color: #0000dd;">24</span><span style="color: #008080;">;</span> <br />
settings.<span style="color: #007788;">stencilBits</span> <span style="color: #000080;">=</span> <span style="color: #0000dd;">8</span><span style="color: #008080;">;</span> <br />
settings.<span style="color: #007788;">antialiasingLevel</span> <span style="color: #000080;">=</span> <span style="color: #0000dd;">4</span><span style="color: #008080;">;</span> <br />
settings.<span style="color: #007788;">majorVersion</span> <span style="color: #000080;">=</span> <span style="color: #0000dd;">4</span><span style="color: #008080;">;</span> <br />
settings.<span style="color: #007788;">minorVersion</span> <span style="color: #000080;">=</span> <span style="color: #0000dd;">3</span><span style="color: #008080;">;</span> <br />
&nbsp;<br />
sf<span style="color: #008080;">::</span><span style="color: #007788;">Window</span> window<span style="color: #008000;">&#40;</span>sf<span style="color: #008080;">::</span><span style="color: #007788;">VideoMode</span><span style="color: #008000;">&#40;</span><span style="color: #0000dd;">800</span>, <span style="color: #0000dd;">600</span><span style="color: #008000;">&#41;</span>, <span style="color: #FF0000;">&quot;OpenGL&quot;</span>, <br />
&nbsp; &nbsp; sf<span style="color: #008080;">::</span><span style="color: #007788;">Style</span><span style="color: #008080;">::</span><span style="color: #007788;">Default</span>, settings<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
&nbsp;<br />
sf<span style="color: #008080;">::</span><span style="color: #007788;">ContextSettings</span> settings <span style="color: #000080;">=</span> window.<span style="color: #007788;">getSettings</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
std<span style="color: #008080;">::</span><span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot;depth bits:&quot;</span> <span style="color: #000080;">&lt;&lt;</span> settings.<span style="color: #007788;">depthBits</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 />
std<span style="color: #008080;">::</span><span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot;stencil bits:&quot;</span> <span style="color: #000080;">&lt;&lt;</span> settings.<span style="color: #007788;">stencilBits</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 />
std<span style="color: #008080;">::</span><span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot;antialiasing level:&quot;</span> <span style="color: #000080;">&lt;&lt;</span> settings.<span style="color: #007788;">antialiasingLevel</span> <br />
&nbsp; &nbsp; <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 />
std<span style="color: #008080;">::</span><span style="color: #0000dd;">cout</span> <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot;version:&quot;</span> <span style="color: #000080;">&lt;&lt;</span> settings.<span style="color: #007788;">majorVersion</span> <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot;.&quot;</span> <br />
&nbsp; &nbsp; <span style="color: #000080;">&lt;&lt;</span> settings.<span style="color: #007788;">minorVersion</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></div></td></tr></tbody></table></div>
<p>Pour plus de détails, voir l&rsquo;article <a href="http://www.sfml-dev.org/tutorials/2.0/window-opengl.php">Using OpenGL in a SFML window</a> sur le site de SFML.</p>
<h2>Avec <a href="http://www.libsdl.org/">SDL 1.3</a></h2>
<p>La bibliothèque SDL fournit les constantes SDL_GL_CONTEXT_MAJOR_VERSION pour définir la version du contexte que l&rsquo;on souhaite utiliser.</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">SDL_GL_SetAttribute<span style="color: #008000;">&#40;</span>SDL_GL_CONTEXT_MAJOR_VERSION, <span style="color: #0000dd;">4</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
SDL_GL_SetAttribute<span style="color: #008000;">&#40;</span>SDL_GL_CONTEXT_MINOR_VERSION, <span style="color: #0000dd;">3</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
mainwindow <span style="color: #000080;">=</span> SDL_CreateWindow<span style="color: #008000;">&#40;</span>PROGRAM_NAME, SDL_WINDOWPOS_CENTERED, <br />
&nbsp; &nbsp; SDL_WINDOWPOS_CENTERED, <span style="color: #0000dd;">512</span>, <span style="color: #0000dd;">512</span>, <br />
&nbsp; &nbsp; SDL_WINDOW_OPENGL <span style="color: #000040;">|</span> SDL_WINDOW_SHOWN<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
maincontext <span style="color: #000080;">=</span> SDL_GL_CreateContext<span style="color: #008000;">&#40;</span>mainwindow<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>Pour plus de détails, voir l&rsquo;article <a href="http://www.opengl.org/wiki/Tutorial1:_Creating_a_Cross_Platform_OpenGL_3.2_Context_in_SDL_%28C_/_SDL%29">Creating a Cross Platform OpenGL 3.2 Context in SDL</a> sur le site de SFML.</p>
<h1>Les modes de synchronisation (GL 4.1)</h1>
<p>Par défaut, les appels de fonction OpenGL sont asynchrones, ce qui veut dire que les fonctions peuvent simplement envoyer les commandes aux contextes OpenGL puis passent à l&rsquo;instruction suivante dans le code. Par exemple, le code suivant peut poser des problèmes puisque rien ne garantit que l&rsquo;on mesure réellement le temps d’exécution de la commande :</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">boost<span style="color: #008080;">::</span><span style="color: #007788;">timer</span> t<span style="color: #008080;">;</span> <br />
glDrawElement<span style="color: #008000;">&#40;</span>...<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
<span style="color: #0000ff;">double</span> elapsed_time <span style="color: #000080;">=</span> t.<span style="color: #007788;">elapsed</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>Lorsque l&rsquo;on débogue une application utilisant OpenGL, il peut alors y avoir un décalage entre l&rsquo;appel d&rsquo;une fonction et une erreur générée. Pour faciliter le débogage, il est possible de changer le mode de synchronisation pour forcer OpenGL à attendre la fin de la commande avant de passer à l&rsquo;instruction suivante dans le code. Cette fonctionnalité garantit la synchronisation dans un contexte, mais pas la synchronisation entre plusieurs contextes, qui reste sous la responsabilité de l&rsquo;application.</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: #666666;">// active le mode synchrone</span><br />
glEnable<span style="color: #008000;">&#40;</span>GL_DEBUG_OUTPUT_SYNCHRONOUS<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>Il est possible de tester le mode avec <a href="http://www.opengl.org/sdk/docs/man/xhtml/glIsEnabled.xml">glIsEnabled</a> et de le désactiver avec <a href="http://www.opengl.org/sdk/docs/man/xhtml/glEnable.xml">glDisable</a>. Activer cette fonctionnalité peut être très coûteux en termes de performance et doit être utilisée uniquement pour le débogage.</p>
<h1>La pile des évènements (GL 4.1)</h1>
<p>La pile des évènements, appelée &laquo;&nbsp;message log&nbsp;&raquo; contient les messages lancés dans un contexte de débogage. Cette pile est de taille limitée, ce qui signifie que si elle est pleine, les événements les plus anciens seront perdus. Il faut donc la vider régulièrement en lisant les messages. Lorsque l&rsquo;on utilise plusieurs contextes, chaque contexte possède sa propre pile des événements.</p>
<p>La fonction <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGet.xml">glGetIntegerv</a> permet d&rsquo;obtenir des informations sur les capacités et le contenu de la pile.</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 /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">GLint maxMessages, totalMessages, len, maxLen, lens<span style="color: #008000;">&#91;</span><span style="color: #0000dd;">10</span><span style="color: #008000;">&#93;</span><span style="color: #008080;">;</span> <br />
GLenum source, type, id, severity, severities<span style="color: #008000;">&#91;</span><span style="color: #0000dd;">10</span><span style="color: #008000;">&#93;</span><span style="color: #008080;">;</span> <br />
&nbsp;<br />
glGetIntegerv<span style="color: #008000;">&#40;</span>GL_MAX_DEBUG_LOGGED_MESSAGES_ARB, <span style="color: #000040;">&amp;</span>maxMessages<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
<span style="color: #0000dd;">printf</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;Nombre de messages maximum que peut contenir la pile : %d<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span>, <br />
&nbsp; &nbsp; maxMessages<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
&nbsp;<br />
glGetIntegerv<span style="color: #008000;">&#40;</span>GL_DEBUG_LOGGED_MESSAGES_ARB, <span style="color: #000040;">&amp;</span>totalMessages<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
<span style="color: #0000dd;">printf</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;Nombre de messages contenus actuellement dans la pile : %d<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span>, <br />
&nbsp; &nbsp; totalMessages<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
&nbsp;<br />
glGetIntegerv<span style="color: #008000;">&#40;</span>GL_MAX_DEBUG_MESSAGE_LENGTH_ARB, <span style="color: #000040;">&amp;</span>maxLen<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
<span style="color: #0000dd;">printf</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;Taille maximale de message : %d<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span>, maxLen<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
&nbsp;<br />
glGetIntegerv<span style="color: #008000;">&#40;</span>GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_ARB, <span style="color: #000040;">&amp;</span>len<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
<span style="color: #0000dd;">printf</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;Taille du prochain message : %d<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span>, len<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<h1>Les messages contenus dans la pile (GL 4.1)</h1>
<p>Les messages dans la pile contiennent plusieurs informations comme l&rsquo;origine du message, son type et son importance.</p>
<p><em>Origine du message</em> :</p>
<ul>
<li>GL_DEBUG_SOURCE_API : le message est lancé lors d&rsquo;un appel d&rsquo;une fonction OpenGL ;</li>
<li>GL_DEBUG_SOURCE_WINDOW_SYSTEM : le message est lancé par le gestionnaire de fenêtre ;</li>
<li>GL_DEBUG_SOURCE_SHADER_COMPILER : le message est lancé par le compilateur de shader ;</li>
<li>GL_DEBUG_SOURCE_THIRD_PARTY : le message est lancé par une bibliothèque externe ;</li>
<li>GL_DEBUG_SOURCE_APPLICATION : le message est lancé par l&rsquo;application (voir la partie &laquo;&nbsp;Envoyer un message personnalisé&nbsp;&raquo;) ;</li>
<li>GL_DEBUG_SOURCE_OTHER : le message ne provient pas d&rsquo;une des sources précédentes.</li>
</ul>
<p><em>Type de message</em> (l&rsquo;utilisation des constantes spécifiques d&rsquo;OpenGL 4.3 sera décrite dans la partie &laquo;&nbsp;L&rsquo;extension KHR_debug&nbsp;&raquo; de ce billet) :</p>
<ul>
<li>GL_DEBUG_TYPE_ERROR : message d&rsquo;erreur récupérable avec glEvent ;</li>
<li>GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR : utilisation fonction dépréciée ;</li>
<li>GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR : appel qui provoque un comportement indéfini ;</li>
<li>GL_DEBUG_TYPE_PORTABILITY : problèmes de portabilité ;</li>
<li>GL_DEBUG_TYPE_PERFORMANCE : notifications de performance ;</li>
<li>GL_DEBUG_TYPE_OTHER : ne correspond pas aux types précédents ;</li>
<li>GL_DEBUG_TYPE_MARKER : annotation (GL 4.3) ;</li>
<li>GL_DEBUG_TYPE_PUSH_GROUP : entrée dans un groupe (GL 4.3) ;</li>
<li>GL_DEBUG_TYPE_POP_GROUP : sortie d&rsquo;un groupe (GL 4.3).</li>
</ul>
<p><em>Importance du message</em> :</p>
<ul>
<li>GL_DEBUG_SEVERITY_NOTIFICATION : les messages qui ne concernent pas les performances et les erreurs ;</li>
<li>GL_DEBUG_SEVERITY_LOW : les alertes de performance concernant les changements redondants de contextes, les comportements indéfinis triviaux ;</li>
<li>GL_DEBUG_SEVERITY_MEDIUM : les alertes de performance sévères, les alertes de compilation ou de linkage GLSL, utilisation d&rsquo;un comportement déprécié ;</li>
<li>GL_DEBUG_SEVERITY_HIGH  : les erreurs OpenGL, les comportements indéfinis dangereux, les erreurs de compilation ou de link GLSL.</li>
</ul>
<p>Les messages sont identifiés de façon unique grâce à la combinaison de leur type, leur source et un numéro d&rsquo;identification.</p>
<p>Le dernier élément composant un message est une chaîne de caractères terminée par le caractère NULL (chaîne de caractères, style C) et donnant des informations plus détaillées sur le message.</p>
<h1>Lire les messages dans la pile (GL 4.1)</h1>
<p>La fonction <a href="http://www.opengl.org/sdk/docs/man4/xhtml/glGetDebugMessageLog.xml">glGetDebugMessageLog</a> permet de lire un ou plusieurs messages contenus dans la pile.</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">GLuint glGetDebugMessageLog<span style="color: #008000;">&#40;</span> &nbsp;<br />
&nbsp; &nbsp; GLuint count, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666;">// nombre de messages que l'on souhaite </span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666;">// récupérer </span><br />
&nbsp; &nbsp; GLsizei bufSize, &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #666666;">// taille du tampon de caractères </span><br />
&nbsp; &nbsp; GLenum <span style="color: #000040;">*</span> sources, &nbsp; &nbsp; &nbsp; <span style="color: #666666;">// récupère les sources </span><br />
&nbsp; &nbsp; Glenum <span style="color: #000040;">*</span> types, &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666;">// récupère les types </span><br />
&nbsp; &nbsp; GLuint <span style="color: #000040;">*</span> ids, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666;">// récupère les identifiants </span><br />
&nbsp; &nbsp; GLenum <span style="color: #000040;">*</span> severities, &nbsp; &nbsp;<span style="color: #666666;">// récupère l'importance des messages </span><br />
&nbsp; &nbsp; GLsizei <span style="color: #000040;">*</span> lengths, &nbsp; &nbsp; &nbsp;<span style="color: #666666;">// tableau contenant la taille des chaînes </span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666;">// pour chaque message </span><br />
&nbsp; &nbsp; GLchar <span style="color: #000040;">*</span> messageLog<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> &nbsp; <span style="color: #666666;">// récupère les chaînes de caractères des </span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #666666;">// messages</span></div></td></tr></tbody></table></div>
<p>Pour récupérer un message :</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;">char</span><span style="color: #000040;">*</span> message <span style="color: #000080;">=</span> <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">char</span><span style="color: #000040;">*</span><span style="color: #008000;">&#41;</span> <span style="color: #0000dd;">malloc</span><span style="color: #008000;">&#40;</span><span style="color: #0000dd;">sizeof</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">char</span><span style="color: #008000;">&#41;</span> <span style="color: #000040;">*</span> len<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
glGetDebugMessageLog<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">1</span>, len, <span style="color: #000040;">&amp;</span>source, <span style="color: #000040;">&amp;</span>type, <span style="color: #000040;">&amp;</span>id, <span style="color: #000040;">&amp;</span>severity, <span style="color: #0000ff;">NULL</span>, <br />
&nbsp; &nbsp; message<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>Pour récupérer les dix premiers messages :</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;">char</span><span style="color: #000040;">*</span> messages <span style="color: #000080;">=</span> <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">char</span><span style="color: #000040;">*</span><span style="color: #008000;">&#41;</span> <span style="color: #0000dd;">malloc</span><span style="color: #008000;">&#40;</span><span style="color: #0000dd;">sizeof</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">char</span><span style="color: #008000;">&#41;</span> <span style="color: #000040;">*</span> maxLen <span style="color: #000040;">*</span> <span style="color: #0000dd;">10</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
glGetDebugMessageLog<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">10</span>, maxLen<span style="color: #000040;">*</span><span style="color: #0000dd;">10</span>, <span style="color: #0000ff;">NULL</span>, <span style="color: #0000ff;">NULL</span>, <span style="color: #0000ff;">NULL</span>, severities, lens, <br />
&nbsp; &nbsp; messages<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
<span style="color: #666666;">// retourne une chaîne séparée par NULL </span><br />
<span style="color: #666666;">// lens retourne la taille de chaque message</span></div></td></tr></tbody></table></div>
<p>Pour effacer tous les messages dans la pile :</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">glGetIntegerv<span style="color: #008000;">&#40;</span>GL_DEBUG_LOGGED_MESSAGES_ARB, <span style="color: #000040;">&amp;</span>totalMessages<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
glGetDebugMessageLog<span style="color: #008000;">&#40;</span>totalMessages, <span style="color: #0000dd;">0</span>, <span style="color: #0000ff;">NULL</span>, <span style="color: #0000ff;">NULL</span>, <span style="color: #0000ff;">NULL</span>, <span style="color: #0000ff;">NULL</span>, <span style="color: #0000ff;">NULL</span>, <br />
&nbsp; &nbsp; <span style="color: #0000ff;">NULL</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>Une erreur GL_INVALID_VALUE est lancée si le paramètre <em>bufSize</em> est négatif.</p>
<h1>Envoyer un message personnalisé (GL 4.1)</h1>
<p>Il est possible d&rsquo;envoyer un message personnalisé avec la fonction <a href="http://www.opengl.org/sdk/docs/man4/xhtml/glDebugMessageInsert.xml">glDebugMessageInsert</a>. Cela permet d&rsquo;écrire des bibliothèques graphiques ou de transmettre des erreurs entre différentes parties d&rsquo;une application.</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> glDebugMessageInsert<span style="color: #008000;">&#40;</span>GLenum source, GLenum type, GLuint id, &nbsp;<br />
&nbsp; &nbsp; GLenum severity, GLsizei length, <span style="color: #0000ff;">const</span> <span style="color: #0000ff;">char</span> <span style="color: #000040;">*</span> message<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>Les paramètres sont équivalents aux autres fonctions. Si <em>length</em> est négatif, alors <em>message</em> est une chaîne de caractères terminée par NULL.</p>
<p>Par exemple :</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">glDebugMessageInsert<span style="color: #008000;">&#40;</span>GL_DEBUG_SOURCE_APPLICATION_ARB, <br />
&nbsp; &nbsp; GL_DEBUG_TYPE_ERROR_ARB, <span style="color: #0000dd;">1234</span>, GL_DEBUG_SEVERITY_LOW_ARB, <span style="color: #000040;">-</span><span style="color: #0000dd;">1</span>, <br />
&nbsp; &nbsp; <span style="color: #FF0000;">&quot;Un exemple de message personnalise&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>La fonction glDebugMessageInsert peut générer les erreurs suivantes :</p>
<ul>
<li>INVALID_ENUM : <em>type</em> n&rsquo;est pas une valeur valide ou <em>source</em> ne vaut pas DEBUG_SOURCE_APPLICATION ou DEBUG_-<br />
SOURCE_THIRD_PARTY ;</li>
<li>INVALID_VALUE : <em>severity</em> n&rsquo;est pas une valeur valide ;</li>
<li>INVALID_VALUE : le nombre de caractères de <em>message</em> est supérieur à MAX_DEBUG_MESSAGE_LENGTH.</li>
</ul>
<h1>Les filtres de messages (GL 4.1)</h1>
<p>Dans de nombreux cas, il est souhaitable de pouvoir limiter les messages, pour éviter de perdre des messages s&rsquo;ils sont trop nombreux et éviter de devoir gérer un trop grand nombre de messages. Il est alors possible d&rsquo;ajouter un ou plusieurs filtres, pour supprimer certains types de messages ou au contraire n&rsquo;en garder que certains. Les filtres appliqués ne seront actifs que sur les nouveaux messages et non sur ceux qui sont déjà sur la pile.</p>
<p>La fonction <a href="http://www.opengl.org/sdk/docs/man4/xhtml/glDebugMessageControl.xml">glDebugMessageControl</a> permet d&rsquo;ajouter un filtre :</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;">void</span> glDebugMessageControl<span style="color: #008000;">&#40;</span>GLenum source, GLenum type, <br />
&nbsp; &nbsp; GLenum severity, GLsizei count, <span style="color: #0000ff;">const</span> GLuint <span style="color: #000040;">*</span> ids, <br />
&nbsp; &nbsp; GLboolean enabled<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>Les paramètres <em>source</em>, <em>type</em> et <em>severity</em> prennent l&rsquo;une des valeurs décrites au-dessus (GL_DEBUG_SOURCE_API, GL_DEBUG_SOURCE_WINDOW_SYSTEM, GL_DEBUG_SOURCE_SHADER_COMPILER, GL_DEBUG_SOURCE_THIRD_PARTY, GL_DEBUG_SOURCE_APPLICATION ou GL_DEBUG_SOURCE_OTHER pour <em>source</em>, GL_DEBUG_TYPE_ERROR, GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR, GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR, GL_DEBUG_TYPE_PORTABILITY, GL_DEBUG_TYPE_PERFORMANCE ou GL_DEBUG_TYPE_OTHER pour <em>type</em> et GL_DEBUG_SEVERITY_LOW, GL_DEBUG_SEVERITY_MEDIUM ou GL_DEBUG_SEVERITY_HIGH pour <em>severity</em>) ou GL_DONT_CARE pour ne pas prendre en compte le paramètre.</p>
<p>Le paramètre <em>ids</em> permet de donner un tableau d&rsquo;identifiants de taille <em>count</em>. Si le paramètre <em>count</em> est supérieur à 0, alors le filtre s&rsquo;applique aux messages dont les identifiants correspondent aux valeurs données dans le tableau <em>ids</em>. Dans ce cas, les paramètres <em>source</em> et <em>type</em> ne doivent pas être GL_DONT_CARE et <em>severity</em> doit être GL_DONT_CARE.</p>
<p>Le paramètre <em>enabled</em> permet de préciser si le filtre supprime les messages correspondant aux critères (GL_FALSE) ou les garde (GL_TRUE).</p>
<p>Par exemple, pour garder tous les messages :</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">glDebugMessageControl<span style="color: #008000;">&#40;</span>GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, <span style="color: #0000dd;">0</span>, <span style="color: #0000ff;">NULL</span>, GL_TRUE<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>Par exemple, pour ne garder que les messages importants :</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">glDebugMessageControl<span style="color: #008000;">&#40;</span>GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_LOW, <span style="color: #0000dd;">0</span>, <span style="color: #0000ff;">NULL</span>, GL_TRUE<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>Pour désactiver les messages correspondant à l&rsquo;appel de fonctions déprécié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">glDebugMessageControlARB<span style="color: #008000;">&#40;</span>GL_DONT_CARE, &nbsp;<br />
&nbsp; &nbsp; GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB, GL_DONT_CARE, <span style="color: #0000dd;">0</span>, <span style="color: #0000ff;">NULL</span>, <br />
&nbsp; &nbsp; GL_FALSE<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>Pour ne garder que les messages correspondant à une liste d&rsquo;identifiants donné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 />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: #666666;">// on supprime tous les messages </span><br />
glDebugMessageControlARB<span style="color: #008000;">&#40;</span>GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, <br />
&nbsp; &nbsp; <span style="color: #0000dd;">0</span>, <span style="color: #0000dd;">0</span>, FALSE<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
&nbsp;<br />
<span style="color: #666666;">// on ne garde ensuite que les messages possédant les identifiants 1280 ou 1282 </span><br />
GLuintid<span style="color: #008000;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #008000;">&#93;</span> <span style="color: #000080;">=</span> <span style="color: #008000;">&#123;</span> <span style="color: #0000dd;">1280</span>, <span style="color: #0000dd;">1282</span> <span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span> <br />
glDebugMessageControlARB<span style="color: #008000;">&#40;</span>GL_DEBUG_SOURCE_API_ARB, &nbsp;<br />
&nbsp; &nbsp; GL_DEBUG_TYPE_ERROR_ARB, GL_DONT_CARE, <span style="color: #0000dd;">2</span>, id, GL_TRUE<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>La fonction GLDebugMessageControl peut générer les erreurs suivantes :</p>
<ul>
<li>INVALID_ENUM : utilisation d&rsquo;une valeur incorrecte pour <em>source</em>, <em>type</em> ou <em>severity</em> ;</li>
<li>INVALID_VALUE : <em>count</em> est négatif ;</li>
<li>INVALID_OPERATION : <em>count</em> est positif, mais <em>source</em> ou <em>type</em> valent DONT_CARE ou severity ne vaut pas DONT_CARE.</li>
</ul>
<p>Pour éviter d&rsquo;avoir à écrire deux codes, pour les versions debug et release, il est possible de créer une macro définissant ou non une fonction appelant les filtres :</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: #339900;">#ifdef OPENGL_DEBUG </span><br />
&nbsp; &nbsp; <span style="color: #339900;">#define GLDebugMessageControl(source, type, sev, num, id, enabled) \\</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; glDebugMessageControlARB<span style="color: #008000;">&#40;</span>source, type, sev, num, id, enabled<span style="color: #008000;">&#41;</span> <br />
<span style="color: #339900;">#else </span><br />
&nbsp; &nbsp; <span style="color: #339900;">#define GLDebugMessageControl(source, type, sev, num, id, enabled) </span><br />
<span style="color: #339900;">#endif</span></div></td></tr></tbody></table></div>
<h1>Les fonctions callback (GL 4.1)</h1>
<p>Une autre possibilité pour récupérer les messages est de créer une fonction callback qui sera appelée dès qu&rsquo;un message est lancé. Les messages ne sont alors plus mis dans la pile et ne peuvent être lus avec <em>glGetDebugMessageLog</em>. Par contre, les filtres ajoutés avec <em>GLDebugMessageControl</em> continuent de fonctionner.</p>
<p>Une fonction callback doit avoir la signature suivante :</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;">typedef</span> <span style="color: #0000ff;">void</span> <span style="color: #008000;">&#40;</span>APIENTRY <span style="color: #000040;">*</span>DEBUGPROC<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#40;</span>GLenum source, GLenum type, GLuint id, GLenum severity, &nbsp;<br />
&nbsp; &nbsp; GLsizei length, <span style="color: #0000ff;">const</span> GLchar<span style="color: #000040;">*</span> message, <span style="color: #0000ff;">void</span><span style="color: #000040;">*</span> userParam<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>Les paramètres <em>source</em>, <em>type</em>, <em>id</em>, <em>severity</em> et <em>message</em> correspondent aux paramètres des messages comme décrit au-dessus. Le paramètre <em>length</em> est la taille de la chaîne de caractères <em>message</em>. La mémoire allouée pour le paramètre <em>message</em> est gérée directement par OpenGL. Sa portée correspond à la fonction callback, donc il est nécessaire de copier le message si on souhaite l&rsquo;utiliser en dehors de la fonction. Le paramètre <em>userParam</em> est un pointeur vers des données pouvant être utilisées dans le corps de la fonction et passées lorsque l&rsquo;on attache la fonction callback à un contexte.</p>
<p>Elle ne doit pas appeler de fonction OpenGL ou du système de fenêtrage. Cette fonction est appelée par un thread différent du thread appelant la fonction GL, il faut donc faire particulièrement attention au respect du thread-safe.<br />
Lorsque l&rsquo;on travaille avec plusieurs contextes OpenGL, il faut fournir une fonction callback pour chaque contexte pour lesquels on souhaite capturer les messages. Dans une application multithread, il est possible d&rsquo;avoir une fonction callback sur un contexte appelé par plusieurs threads différents, mais l&rsquo;application est responsable du respect du thread-safe.</p>
<p>Par exemple, la fonction suivante permet d&rsquo;afficher dans la console les informations des messages reçus.</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 /></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> DebugLog<span style="color: #008000;">&#40;</span>GLenumsource, GLenumtype, GLuintid, GLenumseverity, &nbsp;<br />
&nbsp; &nbsp; GLsizeilength, constGLchar<span style="color: #000040;">*</span>message, GLvoid<span style="color: #000040;">*</span>userParam<span style="color: #008000;">&#41;</span> <br />
<span style="color: #008000;">&#123;</span> <br />
&nbsp; &nbsp; <span style="color: #0000dd;">printf</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;Message reçu :<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
&nbsp; &nbsp; <span style="color: #0000ff;">switch</span> <span style="color: #008000;">&#40;</span>source<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">case</span> GL_DEBUG_SOURCE_API <span style="color: #008080;">:</span> <span style="color: #0000dd;">printf</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot; &nbsp; &nbsp;Source : GL_DEBUG_SOURCE_API<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #0000ff;">break</span><span style="color: #008080;">;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">case</span> GL_DEBUG_SOURCE_WINDOW_SYSTEM <span style="color: #008080;">:</span> <span style="color: #0000dd;">printf</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot; &nbsp; &nbsp;Source : GL_DEBUG_SOURCE_WINDOW_SYSTEM<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #0000ff;">break</span><span style="color: #008080;">;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">case</span> GL_DEBUG_SOURCE_SHADER_COMPILER <span style="color: #008080;">:</span> <span style="color: #0000dd;">printf</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot; &nbsp; &nbsp;Source : GL_DEBUG_SOURCE_SHADER_COMPILER<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #0000ff;">break</span><span style="color: #008080;">;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">case</span> GL_DEBUG_SOURCE_THIRD_PARTY <span style="color: #008080;">:</span> <span style="color: #0000dd;">printf</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot; &nbsp; &nbsp;Source : GL_DEBUG_SOURCE_THIRD_PARTY<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #0000ff;">break</span><span style="color: #008080;">;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">case</span> GL_DEBUG_SOURCE_APPLICATION <span style="color: #008080;">:</span> <span style="color: #0000dd;">printf</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot; &nbsp; &nbsp;Source : GL_DEBUG_SOURCE_APPLICATION<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #0000ff;">break</span><span style="color: #008080;">;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">case</span> GL_DEBUG_SOURCE_OTHER <span style="color: #008080;">:</span> <span style="color: #0000dd;">printf</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot; &nbsp; &nbsp;Source : GL_DEBUG_SOURCE_OTHER<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #0000ff;">break</span><span style="color: #008080;">;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">default</span><span style="color: #008080;">:</span> <span style="color: #0000dd;">printf</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot; &nbsp; &nbsp;Source inconnue<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> &nbsp;<br />
&nbsp; &nbsp; <span style="color: #008000;">&#125;</span> <br />
&nbsp; &nbsp; <span style="color: #0000ff;">switch</span> <span style="color: #008000;">&#40;</span>type<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">case</span> GL_DEBUG_TYPE_ERROR <span style="color: #008080;">:</span> <span style="color: #0000dd;">printf</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot; &nbsp; &nbsp;Type : GL_DEBUG_TYPE_ERROR<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #0000ff;">break</span><span style="color: #008080;">;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">case</span> GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR <span style="color: #008080;">:</span> <span style="color: #0000dd;">printf</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot; &nbsp; &nbsp;Type : GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #0000ff;">break</span><span style="color: #008080;">;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">case</span> GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR <span style="color: #008080;">:</span> <span style="color: #0000dd;">printf</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot; &nbsp; &nbsp;Type : GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #0000ff;">break</span><span style="color: #008080;">;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">case</span> GL_DEBUG_TYPE_PORTABILITY <span style="color: #008080;">:</span> <span style="color: #0000dd;">printf</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot; &nbsp; &nbsp;Type : GL_DEBUG_TYPE_PORTABILITY<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #0000ff;">break</span><span style="color: #008080;">;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">case</span> GL_DEBUG_TYPE_PERFORMANCE <span style="color: #008080;">:</span> <span style="color: #0000dd;">printf</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot; &nbsp; &nbsp;Type : GL_DEBUG_TYPE_PERFORMANCE<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #0000ff;">break</span><span style="color: #008080;">;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">case</span> GL_DEBUG_TYPE_OTHER <span style="color: #008080;">:</span> <span style="color: #0000dd;">printf</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot; &nbsp; &nbsp;Type : GL_DEBUG_TYPE_OTHER<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #0000ff;">break</span><span style="color: #008080;">;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">default</span><span style="color: #008080;">:</span> <span style="color: #0000dd;">printf</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot; &nbsp; &nbsp;Type inconnu<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> &nbsp;<br />
&nbsp; &nbsp; <span style="color: #008000;">&#125;</span> <br />
&nbsp; &nbsp; <span style="color: #0000ff;">switch</span> <span style="color: #008000;">&#40;</span>severity<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">case</span> GL_DEBUG_SEVERITY_LOW <span style="color: #008080;">:</span> <span style="color: #0000dd;">printf</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot; &nbsp; &nbsp;Type : GL_DEBUG_SEVERITY_LOW<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #0000ff;">break</span><span style="color: #008080;">;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">case</span> GL_DEBUG_SEVERITY_MEDIUM <span style="color: #008080;">:</span> <span style="color: #0000dd;">printf</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot; &nbsp; &nbsp;Type : GL_DEBUG_SEVERITY_MEDIUM<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #0000ff;">break</span><span style="color: #008080;">;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">case</span> GL_DEBUG_SEVERITY_HIGH <span style="color: #008080;">:</span> <span style="color: #0000dd;">printf</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot; &nbsp; &nbsp;Type : GL_DEBUG_SEVERITY_HIGH<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #0000ff;">break</span><span style="color: #008080;">;</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">default</span><span style="color: #008080;">:</span> <span style="color: #0000dd;">printf</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot; &nbsp; &nbsp;Type inconnu<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> &nbsp;<br />
&nbsp; &nbsp; <span style="color: #008000;">&#125;</span> <br />
&nbsp; &nbsp; <span style="color: #0000dd;">printf</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot; &nbsp; &nbsp;Message : %s<span style="color: #000099; font-weight: bold;">\n</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span>, message<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>La fonction <a href="http://www.opengl.org/sdk/docs/man4/xhtml/glDebugMessageCallback.xml">glDebugMessageCallback</a> permet d&rsquo;attacher une fonction callback à un contexte. Elle prend en paramètre la fonction callback et un pointeur vers des données utilisateurs. Sa signature est la suivante :</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;">void</span> glDebugMessageCallback<span style="color: #008000;">&#40;</span>DEBUGPROC callback, <span style="color: #0000ff;">void</span><span style="color: #000040;">*</span> userParam<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>Le code d&rsquo;exemple suivant présente comment attacher une fonction callback et modifier les données utilisateurs entre deux messages.</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;">int</span> myData<span style="color: #008080;">;</span> <br />
glDebugMessageCallbackARB<span style="color: #008000;">&#40;</span>DebugLog, <span style="color: #000040;">&amp;</span>myData<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
&nbsp;<br />
myData <span style="color: #000080;">=</span> <span style="color: #0000dd;">2</span> <br />
glEnable<span style="color: #008000;">&#40;</span>GL_UNIFORM_BUFFER<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #666666;">// erreur </span><br />
&nbsp;<br />
myData<span style="color: #000080;">=</span><span style="color: #0000dd;">3</span><span style="color: #008080;">;</span> <br />
glPolygonMode<span style="color: #008000;">&#40;</span>GL_FRONT, GL_LINE<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #666666;">// erreur</span></div></td></tr></tbody></table></div>
<p>Pour supprimer une fonction callback, il suffit d&rsquo;appeler <em>glDebugMessageCallback</em> avec des valeurs nulles ;</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">glDebugMessageCallback<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">0</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>La fonction <a href="http://www.opengl.org/sdk/docs/man/xhtml/glGetPointerv.xml">glGetPointerv</a> permet de récupérer la fonction callback en utilisant le paramètre GL_DEBUG_CALLBACK_FUNCTION et les données <em>userParam</em> avec GL_DEBUG_CALLBACK_USER_PARAM :</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> <span style="color: #008000;">&#40;</span><span style="color: #000040;">*</span>callback<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#40;</span>GLenum, GLenum, GLuint, GLenum, GLsizei, <span style="color: #0000ff;">const</span> GLchar<span style="color: #000040;">*</span>, <span style="color: #0000ff;">void</span><span style="color: #000040;">*</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
glGetPointerv<span style="color: #008000;">&#40;</span>GL_DEBUG_CALLBACK_FUNCTION, <span style="color: #008000;">&#40;</span>GLvoid <span style="color: #000040;">**</span><span style="color: #008000;">&#41;</span> <span style="color: #000040;">&amp;</span>callback<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
&nbsp;<br />
<span style="color: #0000ff;">void</span><span style="color: #000040;">*</span> userParam<span style="color: #008080;">;</span> <br />
glGetPointerv<span style="color: #008000;">&#40;</span>GL_DEBUG_CALLBACK_USER_PARAM, <span style="color: #008000;">&#40;</span>GLvoid <span style="color: #000040;">**</span><span style="color: #008000;">&#41;</span> <span style="color: #000040;">&amp;</span>userParam<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<h1>Les annotations de débogage (GL 4.3)</h1>
<p>Un des problèmes que l&rsquo;on peut rencontrer lorsque l&rsquo;on débogue une application est de savoir quels objets provoquent une erreur. Il est nécessaire alors de garder une table contenant les identifiants des objets. Dans OpenGL 4.3 a été ajouté les annotations de débogage (debug label), qui permettent d&rsquo;attacher une chaîne de caractères à n&rsquo;importe quel objet OpenGL grâce à la fonction <a href="http://www.opengl.org/sdk/docs/man4/xhtml/glObjectLabel.xml">glObjectLabel</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 /></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> glObjectLabel<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">enum</span> identifier, uint name, sizei length, <span style="color: #0000ff;">const</span> <span style="color: #0000ff;">char</span> <span style="color: #000040;">*</span>label<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>Le paramètre <em>name</em> correspond au numéro retourné par les fonctions create. Le paramètre identifier indique le type d&rsquo;objet correspondant à name. Il peut prendre les valeurs suivantes :</p>
<ul>
<li>BUFFER</li>
<li>FRAMEBUFFER</li>
<li>PROGRAM_PIPELINE</li>
<li>PROGRAM</li>
<li>QUERY</li>
<li>RENDERBUFFER</li>
<li>SAMPLER</li>
<li>SHADER</li>
<li>TEXTURE</li>
<li>TRANSFORM_FEEDBACK</li>
<li>VERTEX_ARRAY</li>
</ul>
<p>La fonction <em>glObjectLabel</em> peut générer les erreurs suivantes :</p>
<ul>
<li>INVALID_ENUM : si <em>identifier</em> n&rsquo;est pas une valeur valide ;</li>
<li>INVALID_VALUE : si <em>name</em> ne correspond pas à un objet valide de type <em>identifier</em> ;</li>
<li>INVALID_VALUE : si la taille de la chaîne de caractères <em>label</em> est plus grande que MAX_LABEL_LENGTH.</li>
</ul>
<p>La fonction <a href="http://www.opengl.org/sdk/docs/man4/xhtml/glGetObjectLabel.xml">glGetObjectLabel</a> permet de récupérer l&rsquo;annotation associée avec un objet identifié par <em>identifier</em> et <em>name</em> :</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;">void</span> glGetObjectLabel<span style="color: #008000;">&#40;</span> <span style="color: #0000ff;">enum</span> identifier, uint name, sizei bufSize, sizei <span style="color: #000040;">*</span>length, <span style="color: #0000ff;">char</span> <span style="color: #000040;">*</span>label <span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>Cette fonction peut retourner les erreurs suivantes :</p>
<ul>
<li>INVALID_ENUM : si <em>identifier</em> ne correspond pas à un type d&rsquo;objet valide ou si name ne correspond pas à un objet valide de type donné ;</li>
<li>INVALID_VALUE : si <em>bufSize</em> est négatif.</li>
</ul>
<p>En plus de la fonction <em>glObjectLabel</em>, la fonction <a href="http://www.opengl.org/sdk/docs/man4/xhtml/glObjectPtrLabel.xml">glObjectPtrLabel</a> permet d&rsquo;annoter un objet de synchronisation (un objet de synchronisation permet de tester si des commandes OpenGL sont en cours ou terminées ; voir le chapitre 4 &#8211; Event model des spécifications d&rsquo;OpenGL 4.3 pour plus de détails).</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;">void</span> glObjectPtrLabel<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">void</span> <span style="color: #000040;">*</span>ptr, sizei length, <span style="color: #0000ff;">const</span> <span style="color: #0000ff;">char</span> <span style="color: #000040;">*</span>label<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>La fonction glObjectPtrLabel peut générer les erreurs suivantes :</p>
<ul>
<li>INVALID_VALUE : si <em>ptr</em> ne correspond pas à un objet de synchronisation valide ;</li>
<li>INVALID_VALUE : si la taille de la chaîne de caractères <em>label</em> est plus grande que MAX_LABEL_LENGTH.</li>
</ul>
<p>La fonction <a href="http://www.opengl.org/sdk/docs/man4/xhtml/glGetObjectPtrLabel.xml">glGetObjectPtrLabel</a> permet de récupérer le label d&rsquo;un objet de synchronisation :</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;">void</span> glGetObjectPtrLabel<span style="color: #008000;">&#40;</span> <span style="color: #0000ff;">void</span> <span style="color: #000040;">*</span>ptr, sizei bufSize, size <span style="color: #000040;">*</span>length, <span style="color: #0000ff;">char</span> <span style="color: #000040;">*</span>label <span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<h1>Les groupes de débogage (GL 4.3)</h1>
<p>Les groupes permettent d&rsquo;annoter un ensemble de fonctions OpenGL. Un message GL_DEBUG_TYPE_PUSH_GROUP est envoyé lorsque l&rsquo;on entre dans le groupe puis GL_DEBUG_TYPE_POP_GROUP lorsque l&rsquo;on sort. Il est également possible d&rsquo;utiliser plusieurs groupes, qui seront alors hiérarchisés dans une pile de groupes. Les filtres appliqués sont actifs sur le groupe courant et les groupes qui seront inclus dans ce groupe. Au démarrage, la pile contient un groupe par défaut. Ce système permet ainsi de retrouver plus facilement l&rsquo;origine des messages. </p>
<p>Les fonctions <a href="http://www.opengl.org/sdk/docs/man4/xhtml/glPushDebugGroup.xml">glPushDebugGroup</a> et <a href="http://www.opengl.org/sdk/docs/man4/xhtml/glPopDebugGroup.xml">glPopDebugGroup</a> permettent de débuter et finir un groupe.</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> glPushDebugGroup<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">enum</span> source, uint id, sizei length, <span style="color: #0000ff;">const</span> <span style="color: #0000ff;">char</span> <span style="color: #000040;">*</span>message<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
<span style="color: #0000ff;">void</span> glPopDebugGroup<span style="color: #008000;">&#40;</span> <span style="color: #0000ff;">void</span> <span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>Le message généré contient la chaîne de caractères <em>message</em>, l&rsquo;identifiant <em>id</em>, le type sera DEBUG_TYPE_PUSH_GROUP ou DEBUG_TYPE_POP_GROUP, la source devra être GL_DEBUG_SOURCE_APPLICATION ou GL_DEBUG_SOURCE_THIRD_PARTY et <em>severity</em> sera GL_DEBUG_SEVERITY_NOTIFICATION.</p>
<p>La fonction <em>glPushDebugGroup</em> peut générer les erreurs suivantes :</p>
<ul>
<li>INVALID_ENUM : si la source ne correspond pas à DEBUG_SOURCE_APPLICATION ou DEBUG_SOURCE_THIRD_PARTY ;</li>
<li>INVALID_VALUE : si la taille de <em>message</em> est supérieure à MAX_DEBUG_MESSAGE_LENGTH ;</li>
<li>STACK_OVERFLOW : si le nombre de groupes dépasse MAX_DEBUG_GROUP_STACK_DEPTH &#8211; 1.</li>
</ul>
<p>La fonction <em>glPopDebugGroup</em> peut générer une erreur STACK_UNDERFLOW si la pile de groupes ne contient que le groupe par défaut.</p>
<h1>Notes sur les implémentations</h1>
<p>Les situations pouvant générer des messages et le contenu de ces messages sont laissés à l&rsquo;appréciation des implémentations. On observe donc des différences de comportement entre les différentes implémentations.<br />
Pour le moment, la taille de la pile semble être de 128 messages et la taille des messages au maximum de 1024 octets chez AMD et NVIDIA.</p>
<p><em>Exemples de situations et de message générés</em></p>
<p>Lorsque l&rsquo;on attache un tampon mémoire sur un objet ne correspondant pas à un tampon, NVIDIA ne donne aucun message alors que AMD retourne un message signalant une fonction dépréciée :</p>
<blockquote><p>glBindBuffer in a Core context performing invalid operation<br />
with parameter &laquo;&nbsp;name&nbsp;&raquo; set to &lsquo;0x5&prime; which was removed<br />
from Core OpenGL (GL_INVALID_OPERATION)</p></blockquote>
<p>Lorsque l&rsquo;on appelle une fonction dépréciée ou avec une combinaison dépréciée de paramètres, par exemple <em>glPolygonMode(GL_FRONT, GL_LINE)</em>, NVIDIA et AMD retournent une erreur GL_INVALID_ENUM :</p>
<blockquote><p>// NVIDIA<br />
GL_INVALID_ENUM error generated. Polygonmodes for &laquo;&nbsp;face&nbsp;&raquo; are<br />
disabled in the current profile.<br />
// AMD<br />
Using glPolygonMode in a Core context with parameter<br />
&laquo;&nbsp;face&nbsp;&raquo; and enum &lsquo;0x404&prime; which was removed from<br />
Core OpenGL (GL_INVALID_ENUM)     </p></blockquote>
<p>Les messages peuvent également servir lorsqu&rsquo;il n&rsquo;y a pas d&rsquo;erreur, par exemple pour faire le suivi des appels de fonction. Par exemple, lorsque l&rsquo;on attache un tampon mémoire et que les données sont correctement envoyées, NVIDIA lance le message suivant en GL_DEBUG_SEVERITY_LOW alors que AMD ne lance rien.</p>
<blockquote><p>Buffer detailed info: Buffer object 3 (bound to<br />
GL_ELEMENT_ARRAY_BUFFER_ARB, usage hint<br />
is GL_ENUM_88e4) will use VIDEO memory as<br />
the source for buffer object operations.</p></blockquote>
<p>Lorsqu&rsquo;on appelle la fonction glDrawElement pour lancer un rendu alors que la mémoire graphique est pleine, NVIDIA va générer le message suivant :</p>
<blockquote><p>Unknown internal debug message . The NVIDIA<br />
OpenGL driver has encountered an out of memory<br />
error. This application might behave inconsistently and fail.</p></blockquote>
<p>Pour terminer, une situation posant des problèmes de performance. Lorsque l&rsquo;on utilise un nombre important de Vertex Array Object de petites tailles, NVIDIA lancera un message signalant une perte de performance alors que AMD ne donne aucun message.</p>
<h1>Sources et remerciements</h1>
<p>Certains exemples (en particulier les messages d&rsquo;erreurs générés dans certaines situations) proviennent du livre <a href="http://openglinsights.com/">OpenGL Insight</a> de Patrick Cozzi et Christophe Riccio, dont certains chapitres sont accessibles gratuitement sur le site du livre. Merci également à Christophe Riccio pour ses revues des spécifications d&rsquo;OpenGL qu&rsquo;il publie sur <a href="http://www.g-truc.net/">g-truc</a>. Vous pouvez également consulter les <a href="http://www.opengl.org/registry/doc/glspec43.core.20120806.pdf">spécifications d&rsquo;OpenGL 4.3</a>, en particulier le chapitre consacré au débogage : &laquo;&nbsp;Chapter 20 &#8211; Debug Output&nbsp;&raquo;.<br />
Merci à <a href="http://www.developpez.net/forums/u283256/f-leb/">f-leb</a> pour sa relecture orthographique.</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Les accesseurs et les détails d&#8217;implémentation</title>
		<link>https://blog.developpez.com/gpu/?p=7</link>
		<comments>https://blog.developpez.com/gpu/?p=7#comments</comments>
		<pubDate>Thu, 21 Jun 2012 08:40:13 +0000</pubDate>
		<dc:creator><![CDATA[gbdivers]]></dc:creator>
				<category><![CDATA[C++]]></category>
		<category><![CDATA[Facile]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[C&#8217;est une discussion qui revient régulièrement sur le chat de Developpez.com. Une personne demande comment fait-on pour accéder aux variables membres privées d&#8217;une classe et on lui répond de créer des getter et setter. Viens alors un C++ien moyen (c&#8217;est-à-dire &#8230; <a href="https://blog.developpez.com/gpu/?p=7">Lire la suite <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>C&rsquo;est une discussion qui revient régulièrement sur le <a href="http://chat.developpez.com/">chat de Developpez.com</a>. Une personne demande comment fait-on pour accéder aux variables membres privées d&rsquo;une classe et on lui répond de créer des getter et setter. Viens alors un C++ien moyen (c&rsquo;est-à-dire un casse-pied, en général moi) qui hurle au scandale et sort l&rsquo;adage bien connu : &laquo;&nbsp;les accesseurs, c&rsquo;est le mal&nbsp;&raquo;. S&rsquo;en suit une discussion sur pourquoi les accesseurs sont à éviter, quand j&rsquo;ai le temps et l&rsquo;humeur. <img src="https://blog.developpez.com/gpu/wp-includes/images/smilies/icon_smile.gif" alt=":)" class="wp-smiley" /><br />
Dans cet article, je vais présenter les problèmes que posent les accesseurs concernant l&rsquo;exposition des détails d&rsquo;implémentation.<br />
<span id="more-7"></span><br />
<strong><em>Un exemple simple</em></strong></p>
<p>Imaginons que l&rsquo;on souhaite créer une classe représentant un point en 3D. On écrit alors le code suivant :</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: #0000ff;">class</span> Point3D <span style="color: #008000;">&#123;</span> &nbsp;<br />
&nbsp; &nbsp; <span style="color: #0000ff;">float</span> x, y, z<span style="color: #008080;">;</span> &nbsp;<br />
<span style="color: #0000ff;">public</span><span style="color: #008080;">:</span> <br />
&nbsp; &nbsp; <span style="color: #0000ff;">inline</span> <span style="color: #0000ff;">float</span> x<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> x<span style="color: #008080;">;</span> <span style="color: #008000;">&#125;</span> <br />
&nbsp; &nbsp; <span style="color: #0000ff;">inline</span> <span style="color: #0000ff;">float</span> y<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> y<span style="color: #008080;">;</span> <span style="color: #008000;">&#125;</span> <br />
&nbsp; &nbsp; <span style="color: #0000ff;">inline</span> <span style="color: #0000ff;">float</span> z<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> z<span style="color: #008080;">;</span> <span style="color: #008000;">&#125;</span> <br />
&nbsp;<br />
&nbsp; &nbsp; <span style="color: #0000ff;">inline</span> <span style="color: #0000ff;">void</span> setX<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">float</span> v<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> x <span style="color: #000080;">=</span> v<span style="color: #008080;">;</span> <span style="color: #008000;">&#125;</span> <br />
&nbsp; &nbsp; <span style="color: #0000ff;">inline</span> <span style="color: #0000ff;">void</span> setY<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">float</span> v<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> y <span style="color: #000080;">=</span> v<span style="color: #008080;">;</span> <span style="color: #008000;">&#125;</span> <br />
&nbsp; &nbsp; <span style="color: #0000ff;">inline</span> <span style="color: #0000ff;">void</span> setZ<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">float</span> v<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> z <span style="color: #000080;">=</span> v<span style="color: #008080;">;</span> <span style="color: #008000;">&#125;</span> <br />
<span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>On utilise ensuite cette classe à plusieurs endroits dans notre code, par exemple dans une fonction <a href="http://www.opengl.org/sdk/docs/man/xhtml/glVertex.xml">glVertex</a> (remarque : pour ceux, qui comme <a href="http://www.developpez.net/forums/member.php?u=240267">LittleWhite</a> bloquent sur l&rsquo;utilisation de glVertex, je précise que ce n&rsquo;est qu&rsquo;un code d&rsquo;exemple ; glVertex est une fonction dépréciée et ne doit plus être utilisée) :</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">Point3D p { 1.0f, 1.0f, 1.0f }; <br />
glVertex3f(p.x(), p.y(), p.z());</div></td></tr></tbody></table></div>
<p>Jusque là, tout va bien. </p>
<p>(Ou presque. Si on modifie les coordonnées d&rsquo;un point, on obtient un nouveau point, bien distinct du premier. Les setters sont donc contraire au respect de la <a href="http://cpp.developpez.com/faq/cpp/?page=classes#CLASS_valeur">sémantique de valeur</a> et doivent être évités.)</p>
<p><strong><em>Là où les choses se gâtent</em></strong></p>
<p>Nos besoins évoluent. Au lieu de simplement vouloir faire de la représentation 3D sur nos points, on doit également faire des calculs pour de la simulation physique. On a la chance d&rsquo;avoir une carte graphique prenant en charge l&rsquo;extension <a href="http://www.opengl.org/registry/specs/ARB/gpu_shader_fp64.txt">fp64</a> et on décide donc d&rsquo;utiliser <em>double</em> au lieu de <em>float</em> :</p>
<div class="codecolorer-container text blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">class Point3D { &nbsp;<br />
&nbsp; &nbsp; double x, y, z; &nbsp;<br />
public: <br />
&nbsp; &nbsp; inline double x() const { return x; } <br />
&nbsp; &nbsp; inline double y() const { return y; } <br />
&nbsp; &nbsp; inline double z() const { return z; } <br />
&nbsp;<br />
&nbsp; &nbsp; inline void setX(double v) { x = v; } <br />
&nbsp; &nbsp; inline void setY(double v) { y = v; } <br />
&nbsp; &nbsp; inline void setZ(double v) { z = v; } <br />
};</div></td></tr></tbody></table></div>
<p>Malheureusement, le code qui utilise cette classe <em>Point3D</em> doit également être modifié pour pouvoir compiler. En effet, <em>glVertex3<strong>f</strong></em> prend comme paramètres des <em>float</em>, il faut maintenant utiliser <em>glVertex3<strong>d</strong></em> qui prend comme paramètres des <em>double</em> :</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">Point3D p { 1.0, 1.0, 1.0 }; <br />
glVertex3d(p.x(), p.y(), p.z());</div></td></tr></tbody></table></div>
<p>La modification est relativement facile. Maintenant imaginons que cette classe Point3D est utilisée dans des centaines de ligne de code. Imaginons aussi que toutes vos classes présentent le même problème d&rsquo;exposer des détails d&rsquo;implémentation interne. À chaque fois que l&rsquo;on doit modifier une classe, on se retrouve avec plein de bugs à la compilation et on doit perdre du temps à corriger toutes les lignes de code utilisant notre classe. C&rsquo;est un problème que connaissent beaucoup de débutants (et d&rsquo;autres développeurs plus anciens&#8230; mais aiment faire des erreurs de débutants). Quelle perte de temps ! On parle de couplage fort entre deux classes quand la modification de l&rsquo;une de classe implique la modification de l&rsquo;autre classe. Sinon, on parle de couplage faible.</p>
<p>En utilisant les templates, on améliore un peu la situation. On laisse la responsabilité de choisir le type utilisé en interne à l&rsquo;utilisateur de notre classe. Il sait donc quelle fonction appeler selon le contexte :</p>
<div class="codecolorer-container text blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">template&lt;class T = float&gt; <br />
class Point3D { &nbsp;<br />
&nbsp; &nbsp; T x, y, z; &nbsp;<br />
public: <br />
&nbsp; &nbsp; inline T x() const { return x; } <br />
&nbsp; &nbsp; inline T y() const { return y; } <br />
&nbsp; &nbsp; inline T z() const { return z; } <br />
&nbsp;<br />
&nbsp; &nbsp; inline void setX(T v) { x = v; } <br />
&nbsp; &nbsp; inline void setY(T v) { y = v; } <br />
&nbsp; &nbsp; inline void setZ(T v) { z = v; } <br />
}; <br />
&nbsp;<br />
Point3D p { 1.0, 1.0, 1.0 }; <br />
glVertex3f(p.x(), p.y(), p.z()); <br />
Point3D&lt;double&gt; p2 { 1.0, 1.0, 1.0 }; <br />
glVertex3d(p2.x(), p2.y(), p2.z());</div></td></tr></tbody></table></div>
<p>Même si le code est meilleur que le précédent, il est encore améliorable. L&rsquo;idéal serait de ne plus avoir à choisir manuellement la fonction à appeler et laisser le compilateur faire le travail pour nous.</p>
<p><strong><em>Comment corriger ce problème ?</em></strong></p>
<p>Le premier principe qui n&rsquo;est pas respecté dans ce cas est le principe de ségrégation des interfaces. Ce principe dit &laquo;&nbsp;Une classe ou une fonction cliente ne doit pas dépendre d’interfaces dont elle n’a pas l’utilité&nbsp;&raquo; (<a href="http://blog.emmanueldeloget.com/index.php?post/2006/10/19/24-le-principe-de-segregation-des-interfaces">source</a>). Dit autrement, cela veut dire que si une classe A utilise une classe B et que cette classe B utilise une classe C, A n&rsquo;a pas à connaître C. Dans notre exemple, il faudrait que le code qui utilise la classe <em>Point3D</em> n&rsquo;a pas à connaître le type utilisé en interne (<em>float</em> ou <em>double</em>).</p>
<p>Mais le problème est plus profond (et critique) que cela. Le problème vient en fait d&rsquo;une mauvaise compréhension de ce qu&rsquo;est l&rsquo;encapsulation. La règle est la suivante : &laquo;&nbsp;On encapsule un comportement, pas des propriétés&nbsp;&raquo; (<a href="http://blog.emmanueldeloget.com/index.php?post/2006/08/30/11-le-principe-d-encapsulation">source</a>). Voyons ce que cela implique en pratique pour notre classe représentant un point en 3D. Si on pense en termes de propriétés, comme on l&rsquo;a fait au début, un point dans un espace 3D est effectivement un objet représenté par ses trois composantes réelles x, y et z. Si on pense en terme de comportement, l&rsquo;implémentation sera différente. Quels sont les comportements attendus pour notre point ? En suivant notre code d&rsquo;exemple précédant, le seul comportement que l&rsquo;on souhaite implémenter est de pouvoir l&rsquo;afficher. On écrit donc simplement 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 />5<br />6<br />7<br />8<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">class Point3D { &nbsp;<br />
&nbsp; &nbsp; float x, y, z; &nbsp;<br />
public: <br />
&nbsp; &nbsp; void draw() const { glVertex3f(x, y, z); } <br />
}; <br />
&nbsp;<br />
Point3D p { 1.0f, 1.0f, 1.0f }; <br />
p.draw();</div></td></tr></tbody></table></div>
<p>La différence par rapport au code précédant est ridicule en terme de travail à fournir pour l&rsquo;implémentation. On a simplement refactorisé l&rsquo;appel à glVertex dans une fonction membre de Point3D. Par contre, en terme de sémantique, la différence est énorme : le code client n&rsquo;a plus besoin de connaître les détails d&rsquo;implémentation, notre code est plus facilement évolutif et donc efficace. Les modifications à apporter à notre code en cas de changement est localisé : on sait que si l&rsquo;on modifie une variable membre d&rsquo;une classe, on n&rsquo;a que les fonctions membres de la classe à modifier et rien d&rsquo;autre. </p>
<p>Si on est paresseux (et donc intelligent), on va utiliser la version template pour plus de souplesse, par exemple avec des spécialisations :</p>
<div class="codecolorer-container text blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">template&lt;class T = float&gt; <br />
class Point3D { &nbsp;<br />
&nbsp; &nbsp; T x, y, z; &nbsp;<br />
public: <br />
&nbsp; &nbsp; void draw() const; <br />
}; <br />
&nbsp;<br />
template&lt;&gt; &nbsp;<br />
void Point3D&lt;float&gt;::draw() const { glVertex3f(x, y, z); } <br />
&nbsp;<br />
template&lt;&gt; &nbsp;<br />
void Point3D&lt;double&gt;::draw() const { glVertex3d(x, y, z); } <br />
&nbsp;<br />
Point3D p { 1.0, 1.0, 1.0 }; <br />
p.draw(); <br />
Point3D&lt;double&gt; p2 { 1.0, 1.0, 1.0 }; <br />
p2.draw();</div></td></tr></tbody></table></div>
<p>La version template demande un peu plus de ligne de code que la version non template et peu donc demander un peu plus de travail pour le développeur. Pour autant, elle est préférable puisqu&rsquo;il ne sera plus nécessaire de modifier le code en fonction des besoins du code client (respect du principe ouvert-fermé). Si on a plusieurs fonctions qui dépendent du type utilisé en interne, on peut également utiliser une classe de traits et polices :</p>
<div class="codecolorer-container text blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">template&lt;class T = float&gt; <br />
struct gl_trait { <br />
&nbsp; &nbsp; typdef T internal; <br />
&nbsp; &nbsp; // static inline glVertex &nbsp;(internal x, internal y, internal z) const {} <br />
&nbsp; &nbsp; // static inline glNormal &nbsp;(internal x, internal y, internal z) const {} <br />
&nbsp; &nbsp; // static inline glTexCoord(internal x, internal y, internal z) const {} <br />
}; <br />
&nbsp;<br />
&lt;code&gt;template&lt;&gt; <br />
struct gl_trait&lt;float&gt; { <br />
&nbsp; &nbsp; static inline glVertex &nbsp;(internal x, internal y, internal z) const { glVertex3f(x, y, z); } <br />
&nbsp; &nbsp; static inline glNormal &nbsp;(internal x, internal y, internal z) const { glNormal3f(x, y, z); } <br />
&nbsp; &nbsp; static inline glTexCoord(internal x, internal y, internal z) const { glTexCoord3f(x, y, z); } <br />
}; <br />
&nbsp;<br />
&lt;code&gt;template&lt;&gt; <br />
struct gl_trait&lt;double&gt; { <br />
&nbsp; &nbsp; static inline glVertex &nbsp;(internal x, internal y, internal z) const { glVertex3d(x, y, z); } <br />
&nbsp; &nbsp; static inline glNormal &nbsp;(internal x, internal y, internal z) const { glNormal3d(x, y, z); } <br />
&nbsp; &nbsp; static inline glTexCoord(internal x, internal y, internal z) const { glTexCoord3d(x, y, z); } <br />
}; <br />
&nbsp;<br />
template&lt;class T&gt; <br />
class Point3D { &nbsp;<br />
&nbsp; &nbsp; gl_trait&lt;T&gt;::internal x, y, z; &nbsp;<br />
public: <br />
&nbsp; &nbsp; void draw() const { gl_trait&lt;T&gt;::glVertex(x, y, z); } <br />
}; <br />
&nbsp;<br />
Point3D p { 1.0, 1.0, 1.0 }; <br />
p.draw(); <br />
Point3D&lt;double&gt; p2 { 1.0, 1.0, 1.0 }; <br />
p2.draw();</div></td></tr></tbody></table></div>
<p>Avec ce code, la liste des fonctions à appeler en fonction du type utilisé en interne est localisé dans une même classe de traits. Et si on souhaite ajouter un nouveau type, il suffit d&rsquo;ajouter une nouvelle spécialisation pour la classe de traits, <em>sans rien modifier au code existant</em>.</p>
<p><em><strong>Pour terminer, un peu de lecture</strong></em><br />
Le respect de ces principes est une méthode pour éviter les couplages trop forts entre les classes. Il existe d&rsquo;autres méthodes pour découpler des classes (ie diminuer la force du couplage). Tout le monde connait par exemple la séparation du code des classes dans un fichier d&rsquo;en-tête (partie la moins susceptible d&rsquo;être modifiée) et un fichier d&rsquo;implémentation (partie plus facilement modifiable). On peut également citer l&rsquo;idiome Pimpl (Pointer To Implementation) ou l&rsquo;utilisation des signaux et slots, deux techniques très utilisée dans Qt.</p>
<p>En complément, Emmanuel Deloget a publié quelques articles intéressants sur les principes de programmation objet :</p>
<ul>
<li>valider et corriger une architecture objet <a href="http://blog.emmanueldeloget.com/index.php?post/2008/02/01/112-valider-et-corriger-une-architecture-objet-premiere-partie">première partie</a> et <a href="http://blog.emmanueldeloget.com/index.php?post/2008/02/29/114-valider-et-corriger-une-architecture-objet-seconde-partie">seconde partie</a> par Emmanuel Deloget ;</li>
<li><a href="http://blog.emmanueldeloget.com/index.php?post/2006/08/30/11-le-principe-d-encapsulation">le principe d&rsquo;encapsulation</a>, <a href="http://blog.emmanueldeloget.com/index.php?post/2006/10/19/24-le-principe-de-segregation-des-interfaces">le principe de ségrégation des interfaces</a> et <a href="http://blog.emmanueldeloget.com/index.php?post/2006/09/21/15-le-principe-ouvert-ferme">le principe ouvert-fermé</a> par Emmanuel Deloget ;</li>
<li><a href="http://blog.emmanueldeloget.com/index.php?post/2006/09/14/12-la-guerre-des-accesseurs">la guerre des accesseurs</a> par Emmanuel Deloget ;</li>
<li><a href="http://alp.developpez.com/tutoriels/traitspolicies/">présentation des classes de Traits et de Politiques en C++</a> par Alp Mestan ;</li>
<li><a href="http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Handle_Body#Pointer_To_Implementation_.28pImpl.29">l&rsquo;idome pImpl</a> (WikiBooks) ;</li>
<li><a href="http://www.boost.org/doc/libs/1_49_0/doc/html/signals.html">Boost.Signals</a> (documentation de Boost) ;</li>
<li><a href="http://qt-project.org/doc/qt-4.8/signalsandslots.html">les signaux et slots dans Qt</a> (documentation de Qt 4.8).</li>
</ul>
<p><em><strong>Commentaires</strong></em><br />
Vous pouvez réagir à ce billet sur le forum dans cette <a href="http://www.developpez.net/forums/d1234432/c-cpp/cpp/accesseurs-details-dimplementation/">discussion</a>. Merci.</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>OpenGL dans Qt5</title>
		<link>https://blog.developpez.com/gpu/?p=11</link>
		<comments>https://blog.developpez.com/gpu/?p=11#comments</comments>
		<pubDate>Tue, 29 May 2012 08:55:39 +0000</pubDate>
		<dc:creator><![CDATA[gbdivers]]></dc:creator>
				<category><![CDATA[Facile]]></category>
		<category><![CDATA[OpenGL]]></category>
		<category><![CDATA[Qt5]]></category>

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