Vous êtes sur la page 1sur 260

Ac ure

tu Ba
P

al si
is c
é V
po 4.
ur 5x
Traduction Française

PureBasic
Une Introduction à la Progammation Informatique
Beta Version fr
Informations de la Version German:
http://www.purebasic.fr/german/viewtopic.php?f=1&t=23627
Version Française: Juillet 2019

Gary Willoughby
2
PureBasic
Une introduction à la programmation informatique

Gary Willoughby
PureBasic - Une Introduction à la Programmation Informatique
par Gary Willoughby

Copyright © 2006 Gary Willoughby


Ce livre et tous les documents qu'il contient, tels que les tableaux, les photos et le code source de PureBasic, sont
soumis à l'approbation de la Creative Commons Paternité Paternité Partage des Conditions Initiales à l'Identique Non-
Commercial. Pour de plus amples informations, veuillez consulter le site suivant :
http://creativecommons.org/about/licenses/.

PureBasic est une marque déposée de Fantaisie Software. PureBasic et tous les composants inclus dans le
pack PureBasic sont Copyright © 2006 Fantaisie Software.

Fantaisie Software
10, rue de Lausanne
67640 Fegersheim France
www.purebasic.com

Editeur 2006, Aardvark Global Publishing.

Auteur
Gary Willoughby

Impréssion
Disponible 1 Juli 2006

Traduction en allemand et adaptation à la version actuelle de PureBasic


Andreas Schweitzer (Juli 2010 - Dezember 2010)
Disponible 1 X 2011

Etabli: 01.06.2011

Traduction en Français depuis la Traduction German actualisée pour PB4.51 d' Andreas Schweitzer
et de la version Originale de Gary Willoughby
par: "kernadec" Forum Français Période de traduction de Janvier à Juillet 2019

Dégagement de responsabilité
Bien que toutes les précautions aient été prises dans la préparation de ce livre pour assurer l'exactitude du contenu et
des programmes qu'il contient, l'auteur et l'éditeur n'acceptent aucune responsabilité pour les erreurs, omissions ou
dommages résultant de l'utilisation des informations et programmes qu'il contient. L'auteur ou l'éditeur n'est pas
responsable des dommages, des dommages consécutifs ou des pertes financières découlant de la fourniture, de
l'exécution ou de l'utilisation des programmes ou d'une partie de ceux-ci. Toutes les informations contenues dans ce livre
se réfèrent à la date de publication. Puisque PureBasic est dans une phase constante d'amélioration et de
développement, il peut arriver que certaines parties du livre soient dépassées avec le temps. Vous trouverez des
informations actuelles sur les changements et les innovations concernant PureBasic sous: www.purebasic.com.

Noms de Marque
Les noms de marque sont utilisés partout dans ce livre. Au lieu d'énumérer les noms et les entités juridiques des
propriétaires de marques ou d'identifier chaque mention d'une marque par un symbole, l'éditeur déclare qu'il utilise les
noms de marque uniquement à des fins d'édition. La mention des noms de marque est faite à l'intention du propriétaire
de la marque et ne constitue pas une intention d'interférer avec cette marque.
5

Consécration
Je dédie ce livre à mon amie Sara Jane Gostick et à son chien 'Stella' pour leurs nombreuses nuits solitaires
pendant que j'écrivais ce livre et pour les encouragements (et les dîners au poulet) qu'elle me préparer

Dédicace du traducteur
Je dédie ce livre à mon épouse Constanze et à nos trois enfants Tabea, Johanna et Manuel pour leur
grand soutien dans la création de l'espace pour travailler sur cet ouvrage.

Remerciements
Merci à Fred et à l'équipe PureBasic pour le langage de programmation PureBasic, continuez votre beau travail !

Merci à Paul Dixon d'avoir clarifié quelques détails sur le codage binaire de Valeurs en virgule flottante.

Merci à Timo Harter de m'avoir aidé à sélectionner les types de données PureBasic appropriés pour remplacer
les types de données Win32 API, pour me montrer comment utiliser les différents pointeurs de chaînes
de caractères de l'API Win32 dans la mémoire

"Une grande puissance suit une grande responsabilité !"


--Ben Parker (Spiderman's Onkel)

Les exemples de codes contenus dans ce livre peuvent être téléchargés gratuitement à partir de la page suivante
www.pb-beginners.co.uk (englisch)
asw.gmxhome.de (deutsch)

Ce livre a été créé avec "TextMaker 2008".


www.softmaker.de

ISBN 1-4276-0428-2 19/7/2006 (Edition originale Anglaise)


6
7

Table de Matières

Avant-Propos................................................................................................................................................... 9

I. Les bases du langage .................................................................................................................................. 12

1. Nous Commençons................................................................................................................................12
L'histoire de PureBasic..................................................................................................................... .......12
La Philosophie de Développement de PureBasic.................................................................................. ...13
Un Premier Regard sur l'Environnement de Développement........................................................ ............14
Comment Démarrer les Programmes PureBasic.............................. .............. ................................ ....15
Le Débogueur........................................................................................... ..............................................16
Notes sur la Structure du Programme.......................................................................................................16
Introduction à l'Aide PureBasic ................................................................. ...............................................16

2. Types de Données .................................................................................................................................. 18


Types de données intégrés ......................................................................................................................18
Données Chiffrées ................................................ ................................................................................. 18
Chaines................. ................................................................................................................................. 19
Variables et Constantes ................................................................................................................. ......... 19

3. Operateurs............................................................................................................................................... 24
Introduction aux Opérateurs .................................................................................................................... 24
Priorités des Opérateurs .............................. ........................................................................................... 35
Règles de Calcul pour les Expressions ..................................................................................................... 36

4. Conditions et Boucles................................ ............................................................................................ 38


Logique Booléenne............................................................................................................................... .. 38
La Déclaration « if »................................................................................................................................... 38
La Déclaration «Select »........................................................................................................................... 40
Boucles ......................................................................................................................... .......................... 42

5. Autres structures de données ...................................................... ................................ ........................ 47


Structure............................................................. ............ ........................................................................ 47
Arrays....................................................................................................................................................... 49
Listes............................................................................................ ......... .................................................. 57
Tri des Tableaux (Arrays) ..s Listes ........................................................................................................... 60

6. Procédures et Sous-Programmes ......................................................................................................... 64


Pourquoi Utiliser des Procédures et des Sous-Routines ?................. ........................................................ 64
Sous-Routines ................................................................................................................... ..................... 64
Procédures de Base ....................................................................................................... ........................ 66
Champ d'Application du Programme......................................................................................................... 67
Mot-clé « Global » ................. .......... ........... ........ ...................................................... .............................. 69
Mot-clé « Protected »............................................................................................ .................................. 70
Mot-clé « Shared »................................................................................................................................... 71
Mot-clé « Static » ............................................................................................................. ....................... 72
Passage des Variables aux Procédures .............. .............................. .......... ....... ......... ........ ............. ....73
Passage des Tableaux (Arrays) aux Procédures.............................................. ........................ .............. 74
Transfert des Listes aux Procédures................... ................. ........................................................ ............ 77
Retourner une Valeur à Partir des Procédures........................................................................................... 78

7. Utilisation des Commandes Intégrées ......... ......................................................................................... 81


Utilisation de l'Aide PureBasic ........................................................ ............ .............................. ...... ....... 81
Numéros PureBasic et Identificateurs de Système d'Exploitation ............. ................. ....... ......... ...... .... 82
Exemples de Commandes Courantes....................................................... .................................... ........... 84
Travailler avec des Fichiers........................................................................... ............................................ 89
Lecture de l'Aide ....................................... ................. ................................. ........................................... 94
8

8. Bon Style de Programmation................................................................................................................95


Pourquoi devrais-je faire un Formatage Propre du Code ?........... .......................................... .............95
L'importance des Commentaires............................................................................................................95
Ma Conception de Code.........................................................................................................................96
Règles d'Or pour Ecrire un Bon Code Lisible.........................................................................................99
Minimiser les Erreurs et leur Traitement......................... ........................... ...........................................99

II. Interfaces Utilisateur Graphiques ...........................................................................................................108

9. Création d'Interfaces Utilisateur ........................................................................................................108


Console Programme.............................................................................................................................108
Création d'Interfaces Utilisateur Communes au Système d'Exploitation.................................................113
Comprendre les Evénements..............................................................................................................114
Ajouter des Gadgets.............................................................................................................................115
Ajout d'un Menu ................................... .............................. ................................................... ............120
Menu Raccourcis Clavier......................................................................................................................124
Intégration de Graphiques dans votre Programme ..................... ................................. ......................127
Un premier Regard sur le Nouveau« Visual Designer ».........................................................................131

III. Graphismes et Sons.................................................................................................................................134

10. Graphiques 2D..................................................................................................................................134


Commandes de Dessin 2D....................................................................................................................134
Enregistrement d'Images......................................................................................................................143
Introduction aux Ecrans...............................................................................................................145
Sprites................................................................................................................................................153

11. Graphiques 3D....................................................................................................................................161


Vue d'Ensemble du Moteur OGRE ........................................................................................... ............161
Un Démarrage en Douceur......................................................................................................... ..........163
Une Simple Caméra au Premièr Plan...................................................................................... .............170
Un peu plus Avancé.................................................................................................................. ............174
Quelle est la Prochaine Etape ?............................................. .......................................... ...... .............178

12. Sons ................................................................................................................................ ....................179


Fichier Wave............................ ............................ .............................. ..................................................179
Fichier Module......................................................... ................... ........................ ..................................182
MP3 ........................................................................ ............................... ...............................................184
CD Audio ................................................................. .............................. .......... .......................... .........186

IV. Sujets Avancés............................................................ ........................................................... ..................190

13. Au-Delà de l'Essentiel ................................................................................. .................................... ..190


Directives et Fonctions du Compilateur ............................................................... .................................190
Options de Compilation Avancées. ............................................................... ........................................195
Evaluation des Paramètres de la Ligne de Commande .............................................................. ..........201
Un Examen plus Approfondi des Types de Données Numériques ....................................... .................203
Pointers........................................................................................................................ ..........................209
Threads (Processus)..............................................................................................................................217
Bibliothèques de Liens Dynamiques .......................................................................................................222
Das Windows Application Programming Interface...................................................................... ...........227

V. Appendix.............................................................................................................................................. .......234

A. Adresse Internet Utiles ............................................................................................................ ............234

B. Tables Utiles............................................................................................................................... ...........236

C. Index des Termes .......................................................................................................................... ........243

Index ........................................................................................................................................................ ........255

A propos de l'auteur .......................................................................................................................................259


Préface 9

Préface
A propos de ce Livre
Ce livre est une introduction rapide au langage de programmation PureBasic, dont la popularité a beaucoup augmenté
ces dernières années. Il est utilisé à diverses fins, comme le développement rapide de logiciels, la création d'applications
et de jeux commerciaux et d'applications de CGI sur Internet. Beaucoup l'utilisent simplement pour créer de petits outils.
Ce livre a été écrit avec le débutant complet à l'esprit. Tout le monde doit bien commencer quelque part et je pense que
PureBasic est un premier pas fantastique dans le monde de la programmation. Avec la diffusion de PureBasic, il est de
plus en plus fréquent que les gens aient besoin d'une "poussée dans la bonne direction" ou d'une explication pour une
fonction particulière. Ce livre est un guide pour les débutants. Pour les programmeurs plus avancés, le livre donne un
aperçu rapide du langage.

Le Sujet de ce Livre
Bien que ce livre couvre les éléments essentiels de PureBasic, j'ai gardé le sujet très étroit afin de ne pas surcharger les
nouveaux utilisateurs avec trop d'informations. Parfois, le texte fait référence à des concepts et à une syntaxe des plus
simples, qui peuvent être compris comme une étape intermédiaire vers des sujets plus avancés ou une référence croisée
vers l'aide PureBasic.

Par exemple, je ne vous dirai pas grand-chose sur la facilité d'utiliser DirectX ou OpenGL directement dans PureBasic,
sinon ce livre serait trois fois plus épais, et même si des sujets comme les pointeurs et l'API Win32 sont abordés plus loin
dans ce livre, ne vous attendez pas à trop d'exemples spéciaux, car je ne fais que donner un aperçu des sujets avancés.

PureBasic place la barre plus haut non seulement pour les dialectes Basic, mais aussi pour les langages de
programmation en général : syntaxe propre, pas surchargée, petits exécutables et une communauté de programmation
active fantastique. J'espère que ce livre vous donnera une compréhension claire des fonctionnalités de base de
PureBasic et des objectifs et de la philosophie de conception sous-jacents, et j'espère que vous souhaitez en savoir plus.

Indépendamment du domaine limité du sujet, je pense que vous avez ici un bon premier livre sur PureBasic qui constitue
une bonne base pour la programmation, même si vous passez plus tard à d'autres langages de programmation. Vous
apprendrez tout ce dont vous avez besoin pour écrire des programmes utiles et autonomes. Une fois que vous aurez
parcouru ce livre, non seulement vous comprendrez les bases du langage, mais vous serez en mesure de transférer les
connaissances que vous avez acquises dans votre vie quotidienne de programmation. Vous serez bien équipé pour vous
aventurer dans des sujets plus avancés qui se mettront en travers de votre chemin.

La Structure de ce Livre
Beaucoup de choses dans ce livre sont conçues pour vous donner une introduction à PureBasic le plus rapidement
possible. Les principaux éléments linguistiques sont divisés en sections. Chaque chapitre est en grande partie autonome,
mais les chapitres suivants, en particulier les chapitres avancés, renvoient aux informations des chapitres précédents.
Par exemple, lorsque nous couvrons les interfaces utilisateur graphiques et la programmation graphique, je suppose que
vous avez compris les procédures et les structures.

Partie I : Les bases de ce Langage


Cette partie du livre est une explication simple et complètement guidée des éléments essentiels du langage, tels que les
types, les procédures, les structures, etc. La plupart des exemples donnés ne sont pas très utiles en tant que
programmes autonomes, mais ils démontrent et expliquent le sujet actuel.

Chapitre 1, Nous Commençons


Nous commençons ici par une brève introduction à PureBasic et à l'histoire de la langue. Vous obtiendrez un aperçu de
la façon dont les programmes PureBasic sont lancés à partir de l'IDE et à quoi sert le débogueur.
10 Préface

Chapitre 2, Types de Données


Dans ce chapitre, j' énumère et explique tous les types de données intégrés, tels que les chaînes de caractères, les
types numériques et les constantes. Je vous donnerai des directives d' utilisation, ainsi que des i nformations sur les
limites numériques et l'utilisation de la mémoire.

Chapitre 3, Opérateurs
Je décris ici comment assigner des valeurs aux variables et quels opérateurs sont nécessaires pour calculer
les données. Une explication complète de tous les opérateurs avec tableaux et exemples est disponible. La
commande « Debug » est également présentée dans ce chapitre car c'est l' une des commandes les plus
utiles de PureBasic et devrait être apprise très tôt.

Chapitre 4, Conditions et Boucles


Dans ce chapitre, j'explique comment PureBasic gère les valeurs booléennes. Les énoncés et les boucles « If » et «
Sélectionner » sont présentés et expliqués en détail à l'aide d'exemples.

Chapitre 5, Autres Structures de Données


Ce chapitre présente d'autres méthodes de stockage et d'organisation des données, telles que les structures,
tableaux et listes définis par l'utilisateur. Tout cela est expliqué en détail et illustré par des exemples.

Chapitre 6, Procédures et Sous-Programmes


Les procédures et sous-routines sont un élément essentiel de tout langage de programmation, car elles permettent
d'appeler certaines sections de code (dans le cas de procédures même avec le passage de variables comme
paramètres) partout dans le programme. Cela rend la programmation beaucoup plus facile, car le programme réel peut
être divisé en sous-problèmes plus faciles à gérer. Cette conception modulaire facilite également la réutilisation du code
déjà créé pour d'autres projets.

Chapitre 7, Utilisation des Commandes Intégrées


Ce chapitre présente quelques-unes des commandes les plus couramment utilisées. Il ne s'agit pas d'une référence
complète ou d'un guide pour chaque commande ou bibliothèque de commandes, mais elle fournit une bonne base sur la
manière et le moment d'utiliser les commandes intégrées. Il y a aussi une explication des poignées et des identificateurs,
qui sont tous deux assez faciles à comprendre, mais qui causent parfois une certaine confusion.

Chapitre 8, Bon Style de Programmationl


Ce chapitre est un guide des bonnes pratiques de programmation qui vous guidera à travers l'utilisation de ce livre et
fournit un aperçu des techniques simples de dépannage. Si vous programmez dans n'importe quelle langue, les erreurs
sont toujours un problème, que ce soit une simple faute de frappe ou une erreur dans la langue elle-même. Ce chapitre
montre comment vous pouvez consciemment éviter les erreurs, comment et pourquoi vérifier les erreurs dans votre
programme et comment traiter les erreurs trouvées.

Partie II : Interfaces Utilisateur Graphiques


Presque tous les programmes ont aujourd'hui une interface utilisateur descriptive, et ici je vais vous montrer comment en
créer une. En vous basant sur des idées et des exemples d'applications pour consoles, vous apprendrez à construire des
applications Windows avec des commandes standard (gadgets), y compris des menus, des boutons et des graphiques.

Chapitre 9, Création d'Interfaces Utilisateur


Ici je vous montre comment créer vos propres interfaces utilisateur. Nous commencerons par expliquer et démontrer les
programmes de la console, puis nous passerons aux interfaces basées sur les fenêtres. Les événements sont également
décrits, et il existe de nombreux exemples de la manière dont vous devez réagir lorsqu'un événement se produit dans
votre interface utilisateur. Le concepteur visuel inclus est également brièvement discuté.

Partie III : Graphiques et Son


Le graphisme et le son ont aujourd' hui une importance énorme dans presque tous les systèmes informatiques. Cette
section montre comment jouer des sons, afficher et manipuler des graphiques à l'écran, le tout en 2D ou 3D.
Préface 11

Chapitre 10, Graphiques 2D


Ce chapitre vous présente le monde des graphiques bidimensionnels, tels que les lignes et les formes, et comment ils
sont dessinés à l' écran. De plus, les « Sprites » (images qui peuvent être affichées et manipulées), « Ecrans » et «
Double Buffering » seront abordés.

Chapitre 11, Graphiques 3D


Les graphiques tridimensionnels sont créés dans PureBasic par le « Moteur OGRE ». Dans ce chapitre, vous
trouverez une vue d' ensemble et quelques exemples démontrant ce qu' il est possible de faire avec ce
moteur graphique. d' « OGRE Engine » est en constante évolution et est entièrement intégré dans
PureBasic. Cela rend déjà de belles choses possibles.

Chapitre 12, Son


Ce chapitre montre comment utiliser les sons avec PureBasic et comment charger et lire les formats de
fichiers sonores connus.

Partie IV : Sujets Avancés


La dernière partie du livre traite de sujets qu'un débutant considère comme très avancés. Les sujets de cette partie n'ont
pas besoin d'être compris pour écrire des programmes complets, mais avec eux certaines choses sont possibles qui ne
peuvent pas être réalisées avec des commandes normales. Cette partie a pour but de vous mettre l'eau à la bouche, de
vous faire connaître et comprendre PureBasic, et la programmation en général, en constante évolution.

Chapitre 13, Au-delà de l'Essentiel


Ce chapitre traite de la gestion avancée de la mémoire à l' aide de pointeurs. Les directives du compilateur sont
expliquées et vous obtenez un guide pour créer des DLLs. Une autre partie couvre l' interface de programmation
d'applications Windows.

Partie V : Annexe
C'est la dernière section de ce livre, et elle se termine par des liens utiles vers des sites Web, des diagrammes utiles et
un glossaire expliquant les termes importants.

Résumé.
J'espère que vous savez vous servir d'un ordinateur. Ce livre ne parle pas de l'utilisation d'une souris ou de ce qu'est
une'icône', mais en ce qui concerne la programmation, je suppose que c'est un débutant absolu (pas seulement avec
PureBasic, mais la programmation en général).

Tout ce dont vous avez besoin pour commencer, c'est d'un peu de temps et d'une copie de PureBasic, que vous pouvez
obtenir à www.purebasic.com .
12 Nous Commençons

I. Les Bases du Language


Dans cette section, nous examinerons le PureBasic langage de programmation. Je l'ai appelé cette partie de « Les
bases de la langue » parce que nous mettons l'accent sur les éléments essentiels du langage: le haut-types, déclarations
et expressions. Si vous avez lu cette section et suivi les exemples, vous serez en mesure de créer leurs propres
programmes.

Le terme « fondamentaux » dans le titre afin de préciser que cette section n'est pas un traité exhaustif sur tous les détails
de PureBasic. Je vais sauter quelques points pour sûr, mais le savant ici formeront une base solide pour la résolution des
problèmes inconnus.

L'histoire de PureBasic et son cours de philosophie de développement je vais pas non plus priver le lecteur intéressé.

1. Nous Commençons
Ce premier chapitre commence par un bref historique de PureBasic, nous verrons bientôt comment les programmes de
travail PureBasic. L'objectif principal est d'installer PureBasic pour permettre de compiler des programmes et de
commencer les programmes sur votre ordinateur. Ensuite, vous devez travailler dans une position à l'aide des
instructions et des exemples dans le livre. Aller de l'avant, nous allons apprendre à connaître différentes façons de
compiler des programmes PureBasic - bref, vous obtenez toutes les informations nécessaires pour commencer. Nous
allons continuer à jeter un oeil à l'environnement de développement inclus (IDE). Elle affecte les nouveaux utilisateurs un
peu intimidant, mais après une brève introduction de cette alerte initiale est terminée rapidement.

L'histoire de PureBasic
L'histoire de PureBasic a commencé en 1995 comme une extension de commande pour BlitzBasic après l'auteur
Frédéric Laboureur de PureBasic avait rencontré de nombreuses limites dans BlitzBasic pour aider à la programmation
d'une application nommée « TheBoss » (Un lance-programme puissant pour la Commodore Amiga) désactivé.
L'extension du nom « NCS » (NewCommandSet) a été entièrement programmé en langage assembleur 68000, parce
qu'à ce moment-là a dû être programmé en langage assembleur, toutes les nouvelles commandes pour Flash Basic. les
progrès de Fred était très lent, car il était difficile de trouver une bonne documentation assembleur et forums en ligne pour
le développement du plugin BlitzBasic n'existait pas.

Après le développement de « NCS » déjà couru un an, il a obtenu des commentaires très positifs sur son travail, ce qui
lui avait fait très familier avec la programmation Assembleur et le débogage. Il a également été très surpris par ce que les
choses fantastiques pourraient être réalisées avec un vieux processeur 68000 quand tout est programmé correctement.

A cette époque, est apparu pour les cartes de processeur PowerPC IBM Amiga, ce qui représente une alternative très
puissante pour les processeurs Motorola 68000. Ils étaient très rapides et ont été comparés aux processeurs haut de
gamme 68060, vendus à un prix relativement modéré. Avec ces nouvelles puces arrivent voulaient les programmeurs
une version native de Blitz Basic pour ces processeurs, car il était une langue très populaire à cette époque, mais tout le
monde savait que le développement de la plate-forme Amiga, en faveur d'Intel PC x86 gelé, était , Une occasion de créer
un nouveau langage de programmation lui-même présenté. Cela devrait être une reconstruction logique et une extension
de Blitz de base, offert un support complet pour les 680x0 et les processeurs PowerPC.

Faites place à PureBasic!


Le début de la conception et la première version de PureBasic a commencé en 1998. La principale différence entre les
compilateurs Pure Basic et « normal » a été l'installation d'un « processeur virtuel » (en fait les mnémoniques assembleur
680x0 utilisés) directement au début de ce que les différents types de sortie de l'assembleur (ou toute autre langue)
autorisée sans modifier le noyau du compilateur. Après la conception initiale a été achevée et a commencé la
programmation, le projet se déplaçait rapidement. Fred a consacré tout son temps à la programmation du compilateur et
beaucoup appris à ce sujet à intégrer le langage C dans son projet d'avoir la possibilité de créer un compilateur
entièrement portable.

La première version de PureBasic n'a été publié pour l'Amiga, et avait un (quoique très défectueuse) complètement
éditeur multi-plateforme, un débogueur intégré et de nombreuses commandes intégrées (vous l'avez déjà deviné)
directement au « NCS » précédent Package Blitz
Nous Commençons 13

ont été retirés. Au cours de l'amélioration et le dépannage Fred langages de programmation supplémentaires étudiés par
plus de sécurité dans d'autres domaines pour gagner et obtenir une bonne base pour la planification de conception
interne et comment Pure Basic se développer dans l'avenir et prospérer.

Au cours de la quatrième année des études commerciales de Fred, l'ordinateur Amiga était en train de devenir une
plate-forme morte et plusieurs de ses camarades lui a demandé pourquoi il ne fonctionnerait pas sur une version
Windows. Fred s'est défendu en disant qu'il serait facile de porter PureBasic vers d'autres systèmes, mais il a dû le
prouver.

Un Langage Assembleur d'Information en Bref

Le langage assembleur ou assembleur court, est une forme lisible par l'homme du langage machine qui utilise une
architecture informatique particulière. Le langage machine, qui se compose de modèles binaires instructions
machine codées est mis sous une forme lisible par le Rohbefehle être remplacés par des symboles. Ces symboles
sont appelés mnémoniques.

Programmation en code machine par des puissances les numéros d'ordinateur des commandes est un grand
fardeau, car regardé le nombre correspondant à chaque commande ou doit être notée. Par conséquent, a été mis
au point un ensemble de moyens mnémotechniques pour. Chaque numéro a été donné un code alphabétique est
attribué. Au lieu de cela, par exemple, entrez le numéro correspondant de l'addition, d'ajouter deux numéros, était
désormais seul « ADD » nécessaire. Assembleur code source est compilé avec un assembleur.

Une plus Grande Audience


Fred a commencé Microsoft DirectX et la programmation API Win32 (voir le chapitre 13) pour apprendre - complètement
en langage assembleur - un énorme succès! Intel x86 à la programmation était pour lui, avec son fond Motorola 680x0,
un cauchemar, comme les deux puces ont un style complètement différent. Même le stockage interne des numéros a été
inversée. Après trois mois de développement et la fondation de sa nouvelle société « Fantaisie Software », il a publié un
nouveau site Web - Pure Basic pour Windows a été terminée. Le nombre de PureBasic a augmenté les utilisateurs et les
testeurs et Fred a demandé de développer la meilleure langue possible très nombreux mails utiles et enthousiastes que
d'autres l'ont inspiré.

Après plusieurs années de développement prudent, une équipe dirigée par Fred qui l'a soutenu dans le développement
et le test de nouvelles versions faites. Cette équipe est composée de programmeurs expérimentés, web designers et
rédacteurs de documentation qui ont partagé ensemble tous la vision de Fred de la langue.

Après l'énorme succès de la version Windows, la prochaine étape logique était de soutenir d'autres systèmes
d'exploitation. Ainsi, ont ensuite été présentées à un public de plus en plus et enthousiaste, propres versions Linux et
Mac OS de PureBasic. Toutes les versions prennent en charge l'interface de programmation d'applications respectives
(Application Programming Interface [API]) de ce système d'exploitation particulier et l'interface utilisateur graphique
correspondant aux programmes pour donner un aspect du système d'exploitation typique et se sentir.

Le développement de la version Commodore Amiga a été arrêté en 2002 après qu'il est devenu clair que de plus en plus
umstiegen utilisateurs de l'Amiga à PC parce qu'ils ont accepté (par les utilisateurs inconditionnels de côté) qu'il est une
plate-forme morte. Windows, Linux et Mac OS versions sont développées sans relâche jusqu'à aujourd'hui et le soutien!

La version 4 est le dernier niveau dans la branche de développement de Pure Basic. Pour cette version, presque tout a
été écrit à partir de zéro. Cela était nécessaire afin d'intégrer l'expansion future plus facile, ainsi que la « Croix-plateforme
de développement pour simplifier. PureBasic 4 a également apporté une énorme quantité d'améliorations linguistiques
qui sont presque tous couverts ici dans le livre.

La Philosophie de Développement de PureBasic


La philosophie de développement de PureBasic diffère à certains égards, un peu d'autres langages de programmation.
Voici une liste des objectifs de développement et la politique commerciale de PureBasic.

Après l'achat d'une licence PureBasic toutes les mises à jour ultérieures sont gratuites (pour la vie).Tous les programmes
développés avec PureBasic peuvent, sans frais de licence supplémentaires, sont distribués gratuitement ou commercial.
14 Nous Commençons

Tous les programmes sont compilés à une taille de fichier minimale et ne contiennent pas de code gonflé. Les
programmes créés ne dépendent pas du tout de bibliothèque d'exécution car ils sont capables de fonctionner
indépendamment.

Les points ci-dessus sont de bons points de vente et sont en contraste avec une certaine philosophie de développement
des entreprises concurrentes. Pouvez-vous convaincre Microsoft de vous fournir des mises à jour gratuites à vie pour
VB.NET disponibles? Je ne sais pas.

La philosophie de développement de PureBasic est de fournir un environnement de programmation qui est amusant et
fonctionnel. Il donne à l'utilisateur un outil puissant à portée de main avec laquelle il les programmes dont il a besoin,
peut créer de la façon la plus simple possible. Avec chaque mise à jour qui passe beaucoup de bugs ont été corrigés, a
ajouté de nouvelles fonctionnalités et un nouveau IDE et concepteur visuel intégré. Les deux derniers sont discutés dans
les chapitres suivants dans le livre. mettre à jour, non seulement consister en des corrections de bugs, mais contiennent
également des extensions de commande du langage et des outils utiles pour l'environnement de développement.

Un Premier Regard sur l'Environnement de Développement


L'environnement de développement intégré Pure Basic se compose de l'éditeur de code, ainsi que le concepteur visuel
et le compilateur. Le concepteur visuel est discuté dans le chapitre 9, ici, nous traiterons d'abord seulement avec
l'éditeur et le compilateur. Dans la communauté PureBasic le code source est généralement abrégé Editor avec « IDE »
et le concepteur visuel avec « VD », de sorte que sur le forum les recherches avec mots de trois lettres sont vaines ou
bien alors 3 lettres plus un astérisque « * », donc la convention pour la recherche doit se faire avec un nom complet.

Barre de menu
Barre d'outils

Fenêtre Editeur Fenêtre de


Rapports
Permutable

Journal des erreurs

Position de l' Erreur

Windows IDE Fig. 1

L'IDE (Fig. 1) lui-même a été entièrement programmée dans Pure Basic. Il est l'outil principal pour créer des
programmes PureBasic. Dans ce qui suit, nous allons jeter un oeil à l'interface utilisateur. En haut se trouve la barre de
menu qui permet d'accéder aux différentes fonctions de l'IDE. On voit que la barre d'outils, qui peut être équipée
individuellement avec des fonctions de la barre de menu. Ci-dessous la barre d'outils il y a la fenêtre de l'éditeur dans
lequel on saisi tout le code source, Côté droit de l'éditeur une fenêtre d'édition permutable pour les différents outils, tels
que la liste de procédure, liste de variables, File Explorer, peut être affiché ainsi de suite. Par défaut, la fenêtre inférieure
et utilisée pour le rapport d'erreur de l'éditeur. Elle peut être commutée via la commande de menu ou désactivée (Menu:
→ rapport d'erreur → Afficher le rapport d'erreur). Au bas de l'EDI, se trouve la barre d'état. Ici, les coordonnées
actuelles du curseur dans la fenêtre de l'éditeur et, si possible, une aide rapide de commande actuellement sélectionné
est affiché.

L'IDE est l'interface utilisateur au compilateur PureBasic réelle. Après avoir entré un code dans l'éditeur et en appuyant
sur la barre d'outils bouton « Compile / Run » (raccourci: F5), le code est transmis au compilateur qui à partir du code
source crée un programme exécutable.
Nous Commençons 15

En principe, un éditeur peut être utilisé pour modifier le code source. Cependant, je vous recommande d'utiliser l'éditeur
officiel, comme il a été conçu dès le départ justement conçu pour le support du compilateur Pure Basic. D'autres
éditeurs ont souvent besoin d'être reconfiguré afin qu'ils fournissent le code source dans le format correct pour le
compilateur, il accablait la plupart des débutants.

L'aide Rapide de l' IDE

Si vous tapez dans l'éditeur d'une commande des bibliothèques fournies, c'est rempli d’ exemples visuels de tous
les paramètres requis dans la barre d'état. En affichant ces informations, regardez bien à l'aide peut être sauvé,
comme on le verra un coup d'oeil quels paramètres nécessite une commande. commandes fournies sont discutés
dans le chapitre 7

Comment Lancer des Programmes PureBasic


Maintenant, nous allons apprendre comment démarrer des programmes. Avant que les programmes PureBasic soit
compilés se sont des fichiers texte (standard avec l'extension de fichier « * .pb ») qui contiennent le code source. Pour
créer un exécutable à partir de ce fichier il doit être transmis pour le traitement au compilateur. et Il y a plusieurs façons
d'opérer :

Dans l'IDE:

Appuyez sur la touche F5 raccourci clavier pour « Compile / Run ».


Appuyez sur le bouton « Compile / Run » dans la barre d'outils.
Sélectionnez la commande de menu: Menu: « Compiler → Compiler/ Exécuter ».
Sélectionnez la commande de menu: Menu: « Compiler → Créer Executable ... ».

Utiliser la Ligne de Commande:

Entrez la commande: « PBCompiler fichier » où « fichier » est le nom du fichier texte..

Il semble qu'il y a beaucoup de façons différentes pour obtenir le même résultat. Cependant, certains résultats sont
légèrement différents et doivent être expliquées en détail ici.

Les trois méthodes IDE premières conduisent tous au même résultat et peut être utilisé tester le programme en écrivant
à (peu importe la méthode que vous utilisez). Le but des trois méthodes est de compiler le programme et le lancer.

Après avoir sélectionné la méthode, le fichier texte est compilé sans délai, et il est dans le dossier « / Pure Basic /
compilateur » un fichier exécutable temporaire nommé « PureBasic0.exe » créé qui est démarré. Cette approche est
utile lorsque vous voulez voir instantanément comment votre programme fonctionne, sans avoir à attribuer un nom à
votre programme. Si un programme est en cours d'exécution avec ce nom, un nouvel exécutable avec le chiffre suivant
est créé (dans ce cas « PureBasic1.exe »). Pendant ce temps, si les programmes actuels sont déjà fermés, les chiffres
correspondants sont à nouveau disponibles et seront pris en considération au prochain démarrage du programme. De
cette façon, on peut éviter des noms de programmes incrémentés avec des chiffres très élevés.

Compilateur » La dernière méthode IDE → Créer Executable ... « est généralement utilisé lorsque le processus de
développement est terminé et que le programme sera utilisé. Si vous utilisez cette méthode pour la première fois, une
boîte de dialogue dans laquelle vous devez entrer le nom du programme apparaît.

La méthode de ligne de commande est plus appropriée pour les utilisateurs avancés. elle permet de transmettre le code
source directement en tant que paramètre au compilateur. En passant d'autres paramètres vous donne la possibilité de
contrôler le processus de compilation individuellement. Ces autres paramètres sont décrits dans le chapitre 13

Maintenant, vous savez tout ce que vous devez savoir pour commencer votre premier programme Après avoir
entré des instructions à l'éditeur, appuyez simplement sur la touche F5 et votre programme est éxécuté
16 Nous Commençons

Le Débogueur
Le débogueur PureBasic est un outil très précieux. Il surveille l'exécution de votre programme actuel et conserve le
contrôle de toutes les variables, les paramètres de procédure et beaucoup plus loin. Si une erreur se produit lors de
l'exécution du programme, il marque la ligne appropriée dans votre code de programme et sont également un
commentaire sur l'erreur qui a eu lieu à partir. Une autre force est d'éviter les accidents potentiels du programme comme
la division par zéro, l'accès non valide par les limites de tableau ou d'une erreur de débordement de données. De plus,
vous pouvez votre programme pour arrêter à tout moment et observer les valeurs actuelles des variables. Ensuite, vous
pouvez continuer votre programme en mode pas à pas pour localiser les erreurs ou la source de comportements
inhabituels.

Le débogueur peut être activé et désactivé à tout moment en cliquant sur le bouton « Activer le débogueur » de la barre
d'outils.ou en sélectionnant la commande de menu (Menu: Débogueur-> Activer le débogueur). Attention lors du
développement d'un programme avec le débogueur éteint, vous pouvez planter votre ordinateur si un problème n’est pas
reconnu et est sera résolu autorisé à s'exécuter.

Notes sur la Structure du Programme


La structure d'un programme PureBasic est facile à comprendre. Le compilateur fonctionne le code de haut en bas. Les
principales commandes sont traitées sur le sous-jacent. En principe, le compilateur traite le texte que vous lisez.
Reconnaît le débogueur un problème, il arrête la compilation et affiche un message d'erreur. Prenez ce pseudo-code
comme exemple :

1 PRINT "THIS LINE IS EXECUTED FIRST"


2 PRINT "THIS LINE IS EXECUTED SECOND"
3 PRINT "THIS LINE IS EXECUTED THIRD"

Le résultat de cet exemple de pseudo-code serait trois lignes de texte affichées dans l'ordre dans lequel elles ont été
écrites (1-3). C'est exactement ainsi que le compilateur traite le fichier texte. Il est important de le comprendre et de s'en
souvenir, car vous rencontrerez des erreurs si, par exemple, vous essayez d'accéder à un fichier qui n'a pas encore été
ouvert. Tout cela semble assez simple, mais il se peut que vous rencontriez ce problème à un moment donné, surtout
lorsque vous commencez à utiliser des procédures (celles-ci seront expliquées en détail au chapitre 6). La structure d'un
programme ne se limite pas à ce petit bout de texte, mais cela deviendra évident à mesure que votre cheminement se
poursuivra et que je m'étendrai davantage sur l'utilisation des énoncés et des procédures.

Présentation du fichier d'aide PureBasic


Avec chaque installation de PureBasic, un fichier d'aide complet est installé à côté. Ce fichier d'aide est une référence
fantastique pour tout le langage PureBasic mais peut être un peu intimidant pour les nouveaux utilisateurs car parfois les
choses ne sont pas complètement expliquées. Si c'était le cas, ce serait un document très volumineux et pas très facile à
imprimer. En l'état cependant, c'est une ressource inestimable pour rechercher des mots-clés, vérifier la syntaxe et il
s'intègre bien avec l'IDE. En fait, chaque fois que je crée personnellement un programme en utilisant l'IDE PureBasic,
j'aime garder le fichier d'aide ouvert à tout moment pour naviguer rapidement entre les deux. Cette simple habitude
pourrait faire gagner des heures de temps précieux.

L'intégration dans l'IDE


A tout moment lorsque vous utilisez l'IDE pour créer votre programme, vous pouvez appuyer sur la touche « F1 » de
votre clavier pour lancer le fichier d'aide PureBasic. De plus, si vous avez votre curseur dans l'IDE sur un mot-clé
PureBasic en appuyant sur « F1 », alors le fichier d'aide est affiché en premier plan et ce mot-clé sera mis en évidence
dans le fichier d'aide, vous donnant une explication de cette commande. Cette intégration entre l'IDE et le fichier d'aide
est inestimable une fois que vous commencez à gagner en vitesse pendant la programmation.

Essayons un petit exemple pour montrer ceci en action, tapez ceci (exactement) dans l'IDE :

OpenConsole()
Print("Appuyez sur enter pour sortir")
Input()
End
Nous Commençons 17

Après le lancement de ce petit programme, une console ouvre la fenêtre où une ligne de texte informe l'utilisateur qu'il
doit quitter le programme, appuyez sur la touche « Entrée ». Tant que cela est fait, le programme attend l'entrée. Après
la touche « Entrée », le programme est fermé.

Si vous déplacez le curseur clignotant dans l'IDE sur un mot-clé et appuyez sur la touche « F1 » ouvre au premier plan
l'aide et saute à la page qui décrit cette commande. Placez le curseur, par exemple, n' importe où avec le mot-clé
« Console Open() » et appuyez sur « F1 ». Comme par magie, la page d'aide de l'instruction « Console Open() »
apparaît.

Pour en savoir plus sur l'utilisation du fichier d'aide intégrée de PureBasic, reportez-vous au Chapitre 7
18 Types de Données

2. Types de Données
Après les présentations sont maintenant à travers, nous allons maintenant tourner notre attention vers un chapitre avec
plus de poids, à savoir les types de données. Vous devez savoir que vous manipuler des données de processus de
programmes informatiques. Les types de données sont les descriptions pour le conteneur de ces données. Dans ce
chapitre, je vais vous présenter à tous les types de données disponibles et vous dire exactement comment et quand ils
sont utilisés.

Pour vous donner l'occasion d'une introduction rapide, j'ai ajouté beaucoup d'exemples et je vais tout expliquer dans un
langage simple.

Intégré Types de Données


Les types de données (ou simplement connu sous le nom des « types ») peuvent être considérées comme une façon de
décrire les données stockées. affecter les données de l'idée initiale de certains types de collecte de chiffres binaires était
de donner un sens. Que ce soit du texte ou des chiffres, la description de ces types de données, il est plus facile de les
comprendre, de manipuler ou récupérer. Les données sont conservées dans la mémoire vive de l'ordinateur jusqu'à ce
qu'ils soient nécessaires par le programme. La quantité de mémoire requise pour chaque type de données dépend du
type utilisé..

Nombres
Les premiers types de données que je cite sont les types numériques. Les chiffres peuvent être utilisés pour quoi que ce
soit. tout est possible à partir de la date de longueurs jusqu'à le résultat d'un calcul à long. Tout ce pour quoi vous utilisez
des nombres dans le monde réel,vous pouvez également utiliser les types numériques de PureBasic pour stocker ces
données.

Les nombres sont disponibles en deux versions : PureBasic, nombres entiers et nombres à virgule flottante. Les nombres
entiers sont des nombres qui n'ont pas de point décimal et peuvent être positifs ou négatifs. Voici quelques exemples
d'entiers :

16543 -1951434 100 -1066 0

Nombres à virgule flottante (ou « flottant ») d'autre part sont des nombres qui contiennent un point décimal et
peuvent également être positifs ou négatifs. Voici quelques exemples de nombres en virgule flottante :

52.887 -11.0005 1668468.1 -0.000004 0.0

PureBasic fournit dix types de données numériques disponibles que vous pouvez utiliser dans votre programmation,
chacun utilisant une quantité différente de RAM et ayant des limites numériques différentes. Les types numériques sont
décrits dans la Fig.2.

Les Types Numériques de Pure Basic

Nom suffixe utilisation de la mémoire zone


Byte .b 1 Byte (8 Bit) -128 bis +127
Ascii .a 1 Byte (8 Bit) 0 bis +255
Character .c 1 Byte (8 Bit) (Ascii) 0 bis +255
Word .w 2 Byte (16 Bit) -32768 bis +32767
Unicode .u 2 Byte (16 Bit) 0 bis +65535
Character .c 2 Byte (16 Bit) (Unicode) 0 bis +65535
Long .l 4 Byte (32 Bit) -2147483648 bis +2147483647
Integer .i 4 Byte (32 Bit)* -2147483648 bis +2147483647
Integer .i 8 Byte (64 Bit)* -9223372036854775808 bis +9223372036854775807
Quad .q 8 Byte (64 Bit) -9223372036854775808 bis +9223372036854775807
Float .f 4 Byte (32 Bit) unlimitiert**
Double .d 8 Byte (64 Bit) unlimitiert**

* La taille dépend du système d'exploitation (32/64 bit) * Déclaration à l'article 13 (types de données numériques) Fig. 2
Types de Données 19

Dans la Fig.2 vous pouvez voir que beaucoup de types ont une limite numérique, ceci est directement lié à la quantité de
RAM que ce type particulier est alloué. La quantité de RAM allouée et les noms des types numériques sont plus ou
moins les mêmes que ceux du langage C. Note en C, vous trouverez qu'il y a beaucoup plus de types que ceux listés ici,
mais PureBasic est de garder les choses simples, et non de plier votre tête avec des centaines de types avancés. Pour
les débutants, il suffit de se rappeler les limites numériques de chaque type et de comprendre qu'elles ne peuvent être
dépassées. Pour expliquer pourquoi la mémoire allouée à chaque type affecte la limite numérique, j'ai besoin d'expliquer
comment les nombres sont stockés en RAM à l'aide de binaire, ce que vous pouvez trouver au chapitre 13 (Un regard
plus attentif aux types de données numériques).

Si un type de données numériques est dépassé numériquement, cette valeur numérique s'enroule autour du niveau
numérique inférieur. Par exemple, si vous avez assigné la valeur de « 129 » à une variable octet, alors cette valeur a
dépassé la limite numérique pour un octet et sera renvoyée à « -127 ».

Chaines
Le dernier type de données PureBasic standard est une chaîne de caractères. Les chaînes de caractères sont un type
de données tellement important et utile qu'elles sont implémentées dans presque tous les langages de programmation
disponibles. Comme leur nom l'indique, les chaînes de caractères sont simplement des chaînes de caractères.
Contrairement à un nombre, il y a une certaine façon d'écrire une chaîne de caractères pour s'assurer qu'elle est
reconnue comme telle. Cette méthode consiste à utiliser des guillemets doubles pour encapsuler la chaîne. Voici
quelques exemples de cette syntaxe :

"abcdefghijklmnopqrstuvwxyz" "Tous mes petits canards" "123456789"

Notez que la dernière chaîne est une chaîne de chiffres. Ceci est reconnu comme une chaîne de caractères plutôt qu'un
nombre à cause des guillemets doubles qui l'entourent. Les chaînes de caractères ainsi définies sont également
appelées chaînes littérales. Les chaînes de caractères sont probablement le type de données le plus simple à
comprendre car elles sont très faciles à utiliser. Tant que vous vous souvenez des guillemets doubles autour des
caractères, vous avez une chaîne de caractères.

Les Types de Chaîne de Pure Basic

Nom suffixe utilisation de la mémoire zone


chaîne .s Longueur de la chaîne + 1 octet illimité
chaîne $ Longueur de la chaîne + 1 octet illimité

Chaîne fixes .s {longueur} Longueur de la chaîne personnalisé *


Chaîne fixes $ {longueur} Longueur de la chaîne personnalisé *

* le paramètre de longueur définit la longueur maximale de la chaîne Fig. 3

Les chaînes peuvent être composées à partir de n'importe quel caractère du jeu de caractères ASCII, y compris les
caractères de contrôle (voir l'annexe B (Graphiques utiles) pour une liste complète des caractères ASCII) sauf le
caractère nul qui est utilisé pour indiquer la fin d'une chaîne. Les chaînes de caractères qui utilisent le caractère « NUL »
pour définir sa fin sont appelées « chaînes terminées par zéro ».

Variables et Constantes
Pour stocker et manipuler des données dans n'importe quel programme, vous devez utiliser le bon type de données pour
le stockage, mais vous devez également trouver facilement ces données en mémoire. Les variables et constantes
fournissent une réponse simple à ce problème en attribuant un nom descriptif clair à une donnée particulière pour qu'elle
puisse être facilement accessible ultérieurement. En termes simples, les variables font référence à des données qui
peuvent changer leur valeur, tandis que les constantes font référence à des données qui ne changeront jamais.

Les Variables
Typiquement, le nom d'une variable est lié à une zone et une quantité particulières de RAM (définies par son type de
données), et toute opération sur une variable manipulera cette zone associée de mémoire. Les noms de variables
peuvent être nommés comme bon vous semble, mais beaucoup de gens aiment les garder aussi descriptifs que possible
pour indiquer quelle est la valeur réelle de la variable. Les variables sont les éléments constitutifs de tout programme
informatique, car elles contiennent des données qui peuvent être manipulées, référencées et finalement affichées. Les
variables sont essentielles pour l'organisation et le stockage de vos données.

D'accord, nous allons jouer un peu avec PureBasic. Ouvrez l'IDE PureBasic et nous allons créer une variable
distincte. La syntaxe pour créer une variable est très simple.
20 Types de Données

Vous entrez une variable suivie d'un type (suffixe) pour définir le type de variable à suivre, suivi d'une opération que
vous souhaitez effectuer elle. Cette opération est avant tout une définition de valeur

Dans la déclaration suivante nous attribuons la valeur « 1 » au nom « NumberOfLinesOfCode » au moyen de


l'opérateur directe « = » et en utilisant un octet comme type de données.

NumberOfLinesOfCode.b = 1

Regardez cette déclaration d'un peu plus près. Vous verrez que le nom de la variable n'a pas d'espace, c'est très
important. Aucune variable n'a jamais d'espace ! Si vous avez besoin de séparer les mots d'une variable pour la rendre
plus facile à lire, vous pouvez utiliser des tirets de soulignement comme ceci :

Number_Of_Lines_Of_Code.b = 1

Vous pouvez utiliser n'importe quel nom pour une variable mais il y a peu de règles. Les noms de variables ne
doivent pas commencer par un nombre et ne doivent contenir aucun opérateur (voir Fig.15 pour la liste
complète des opérateurs). De même, aucun caractère spécial comme les caractères accentués (ß, ä, ä, ö, ü) n'
est autorisé. Le « .B » ajouté à la fin du nom de la variable est un suffixe pour indiquer au compilateur que cette
variable doit être un octet et en tant que tel utilisera la quantité de mémoire associée et imposera la limite
numérique associée. La Fig.2. montre tous les suffixes que vous devez utiliser pour les types de nombres, tandis
que la Fig.3. montre les suffixes nécessaires pour les types de chaînes. Si un suffixe de type n'est pas utilisé comme
ceci :

NumberOfLinesOfCode = 1

la variable est automatiquement déclarée comme un entier - qui est le type standard PureBasic. Il est important de
comprendre parce que si vous oubliez le suffixe à une variable, créer une variable de type entier, ce qui peut
éventuellement provoquer des erreurs. PureBasic offre la possibilité type par défaut pour les nouvelles variables en
utilisant le mot-clé « Define » pour changer:

Define.b
NumberOfLinesOfCode = 1
TodaysDate = 11

Le mot-clé « Define » reçoit un suffixe qui lui est propre et toutes les variables qui doivent être déclarés après ce
nouveau type. Les deux variables dans l'exemple ci-dessus sont à la fois l'octet de type, en raison du suffixe «.B » après
le mot-clé « define ». Si ce mot-clé n'est pas utilisé dans un programme PureBasic, le type par défaut est entier.

Lorsque vous créez quelques variables pour une utilisation ultérieure, mais souhaitez tout de même attribuer une valeur,
vous pouvez utiliser la syntaxe suivante.

Define.w Day, Month, Year

Ce code bascule le type par défaut sur « Word » et déclare trois variables de type « Word » (Day, Month, Year). Année).
Comme aucune valeur n’a été attribuée aux variables, la valeur zéro « 0 » leur est automatiquement attribuée. ici un
exemple de création de tous les types de variables à l'aide de code PureBasic:

ByteVariable.b = 123
AsciiVariable.a = 255
CharVariable.c = 222
WordVariable.w = 4567
UnicodeVariable.u = 1973
LongVariable.l = 891011
IntegerVariable.i = 78936
QuadVariable.q = 9223372036854775807
FloatVariable.f = 3.1415927
DoubleVariable.d = 12.53456776674545 =
StringVariableEins.s "Test String One" =
StringVariableZwei$ "Test String Two"
StringVariableDrei.s{6} = "abcdef"
StringVariableVier${3} = "abc"

Vous remarquerez que les quatre dernières variables sont des chaînes de caractères mais sont toutes définies par des
suffixes légèrement différents. les deux premières sont des chaînes de longueur illimitée tandis que les deux dernières
sont définies comme des chaînes de longueur fixe. Chacun d'entre eux de ces types peuvent être définis en utilisant
deux suffixes. Ces deux suffixes différents sont «. s »et « $ ». Les deux sont identiques en tous points, c'est juste que le
suffixe « $ » est un vieux style,
Types de Données 21

conservé pour apaiser les puristes de base.qui aiment utiliser l'ancien suffixe String. Les deux peuvent être utilisés dans
le même programme mais les deux suffixes ne sont pas interchangeables. Par exemple, ces deux variables sont
différentes :

StringVariable.s = "Test String One"


StringVariable$ = "Test String Two"

Même s'il semble que les deux ont le même nom, différent suffixe les rend deux variables différentes. Si vous ne
me croyez pas? Eh bien, cela peut être vérifié avec mot-clé « Debug ».

StringVariable.s = "Test String One"


StringVariable$ = "Test String Two"
Debug StringVariable.s
Debug StringVariable$

Dans cet exemple, le mot-clé « Debug » est utilisé pour faire écho aux valeurs des deux variables dans la fenêtre
« Debug » Output. Tapez cet exemple dans l'IDE et cliquez sur le bouton « Compile/Run » (F5). Vous verrez apparaître
deux lignes dans la fenêtre « Debug » montrant les valeurs des deux variables avec lesquelles nous avons utilisé
« Debug ». Ce mot-clé est probablement le mot-clé le plus utilisé dans tout le langage PureBasic car il est utilisé pour
tester les valeurs et faire écho à d'autres textes utiles dans la fenêtre « Debug » pendant le développement du
programme. Lorsqu'un exécutable final est créé, toutes les commandes « Debug » sont supprimées du programme final,
laissant une petite taille d'exécutable.

La Commande « Debug »
La commande de débogage est très utile en matière de textes à déboguer rapidement pour les afficher la
fenêtre « Debug ». Étant donné que chaque type de données peut être utilisé avec cette commande, il est
indispensable quand il vient de montrer rapidement quelques chiffres utiles, les adresses mémoire des chaînes
retournées et / ou les résultats des calculs. Si vous désactivez le débogueur ou leur programme fini « Menu:
Compilateur → Créer Executable »... « Commande Debug » lors de la creation tous sont ignorés et non compilé
avec le programme.

Vous devez également savoir encore les variables ne sont pas « sensibles à la Case ». Ce qui signifie que toute
capitalisation est ignorée. ce qui est le comportement standard du langage de base. Regardez cet exemple :

TestVariable.s = "Test String One"


TestVariable = "Test String Two"
TestVariable = "Test String Three"
Debug TestVariable

Ici, il semble que j'assigne des valeurs à trois variables différentes, mais en vérité, je réassigne une valeur à la même
variable, c'est juste que chaque fois que je le fais, j'utilise une capitalisation différente pour le nom de variable. Comme
vous pouvez le voir, la casse de lettre ne signifie rien pour une variable car cet exemple affiche le texte "Test String
Three". Cet exemple démontre également une autre caractéristique des variables de PureBasic, en ce sens qu'une fois
qu'une variable a été déclarée en utilisant un type de données donné, ce type de données reste assigné à cette variable
pendant toute la durée de vie du programme. Par exemple, une fois qu'une variable a été déclarée en tant que chaîne,
vous ne pouvez plus jamais stocker un nombre entier ou un nombre en virgule flottante dans cette variable. Laissez-moi
vous montrer un mauvais exemple :

StringVariable.s = "Test String One"


StringVariable = 100

Cet exemple ne peut pas être compilé, et si vous essayez de toute façon, vous obtiendrez un message poli de l'IDE
qui vous dit que vous ne pouvez pas écrire une valeur numérique dans une variable de chaîne. L'exemple suivant
fonctionne:

StringVariable.s = "Test String One"


StringVariable = "100"

Puisque la variable « StringVariable » a été déclarée à l'origine comme une chaîne de caractères, seules les chaînes de
caractères peuvent être données comme valeurs à cette variable à partir de ce moment. Quand nous changeons sa
valeur à « Cent », cela fonctionne bien parce que nous changeons une corde pour une corde. Récapitulons donc les
principales règles des variables.
22 Types de Données

1). Les variables ne peuvent pas contenir des espaces


2). Les noms de variables ne peuvent pas commencer par un nombre, mais ceux-ci peuvent inclure
3). Les noms de variables aucun opérateur inclus (voir la figure. 15)
4). Les noms de variables ne peuvent pas contenir des caractères spéciaux (ß, ä, ö, ü)
5). Si aucun suffixe est spécifié, la variable de type entier
6). Lorsqu'une variable est déclarée une fois, son type ne peut pas être modifié
7). Lorsqu'une variable est déclarée, vous pouvez l'utiliser librement sans suffixe, le compilateur se souvient de son type.

Constantes
Les constantes sont similaires aux variables en ce sens qu'elles fournissent un moyen facile de référencer les données
et peuvent être appelées comme vous voulez, mais c'est là que la similarité s'arrête. Les constantes sont utilisées
lorsque vous voulez donner un nom à une donnée particulière tout en sachant que la valeur ne changera jamais.
Regardez cet exemple :

#DAYS_IN_THE_YEAR = "365"

Nous savons que le nombre de jours d'une année normale ne changera jamais, alors nous pouvons utiliser une
constante pour exprimer cela. Si nous essayons de changer sa valeur comme une variable, nous obtenons une erreur.
L'IDE se plaindra en vous disant qu'une constante avec ce nom a déjà été déclarée et arrêtera la compilation.

L'avantage des constantes est qu'elles n'utilisent pas de mémoire, car elles ne sont jamais compilées comme telles,
elles sont remplacées dans votre code par leurs valeurs initiales avant compilation. Regardez cet exemple :

#DAYS_IN_THE_YEAR = "365"
Debug "Il y a " + #DAYS_IN_THE_YEAR + " jours dans l'année."

Avant que cet exemple ne soit compilé dans votre programme, il ressemble vraiment à ceci pour le compilateur :

Debug "Il y a 365 jours dans l'année."

parce que la constante est remplacée par la valeur qui lui a été affectée, en l'occurrence « 365 », puis compilée. Toutes
les constantes suivent exactement les mêmes règles de nommage que les variables à l'exception des suffixes, les
constantes ne les utilisent pas quel que soit le type de données que vous affectez à une constante, car aucune
allocation mémoire n'est nécessaire. Toutes les constantes sont déclarées en utilisant un préfixe plutôt qu'un suffixe. Le
préfixe est un caractère de hachage (#).

« Enumeration » de Constantes (Liste)


Si vous avez besoin d'un bloc de constantes avec des numéros consécutifs, vous pouvez utiliser le mot-clé «
énumération ».

Enumeration
#ZERO
#ONE
#TWO
#THREE
EndEnumeration

Debug #ZERO
Debug #ONE
Debug #TWO
Debug #THREE

Dans la fenêtre Debug, vous pouvez voir que chaque constante a une valeur supérieure à la précédente, en
commençant par « 0 ». Si vous voulez commencer leurs départ avec un autre numéro que « 0 », vous pouvez joindre
un paramètre numérique en option au mot-clé « Enumération », comme ceci:
Types de Données 23

Enumeration 10
#TEN
#ELEVEN
#TWELVE
EndEnumeration

Debug #TEN
Debug #ELEVEN
Debug #TWELVE

Maintenant vous pouvez voir que la constante « #TEN » a la valeur « 10 » et que le reste est incrémenté à partir de là.
Vous pouvez même utiliser le mot-clé « Step » après le paramètre numérique pour changer la valeur d'incrément dans
un bloc d'énumération. Regardez cet exemple :

Enumeration 10 Step 5
#TEN
#FIFTEEN
#TWENTY
EndEnumeration

Debug #TEN
Debug #FIFTEEN
Debug #TWENTY

Maintenant, les constantes sont augmentées de « 5 », à partir de « 10 ».

Si vous attribuez à tout moment dans l'énumération d'une valeur constante que l'énumération de cette valeur continuera.

Enumeration 5
#FIVE
#ONE_HUNDRED = 100
#ONE_HUNDRED_AND_ONE
#ONE_HUNDRED_AND_TWO
EndEnumeration

Debug #FIVE
Debug #ONE_HUNDRED
Debug #ONE_HUNDRED_AND_ONE
Debug #ONE_HUNDRED_AND_TWO

Dans cet exemple, vous pouvez voir qu'il passe après la ligne « #ONE_HUNDRED = 100 » toutes les constantes
sont alors énumérées à partir de « 100 ».

Les constantes énumérées sont surtout utilisées dans la programmation de l'interface utilisateur graphique (voir chapitre
9) où chaque fenêtre ou gadget a besoin de son propre ID, les constantes énumérées sont un excellent moyen de
fournir ces ID et les blocs énumérés éliminent tous les problèmes liés à l'attribution de valeurs incrémentées à de
nombreuses constantes.
24 Opérateurs

3. Les Opérateurs
Les opérateurs sont utilisés pour assigner des valeurs aux variables et pour manipuler les données qu'elles contiennent.
Dans ce chapitre, je vous présenterai tous les opérateurs supportés par PureBasic et pour chacun d'entre eux, je vous
donnerai un bref exemple décrivant sa fonction et son utilisation. Il existe également de nombreux diagrammes montrant
comment les opérateurs les plus avancés manipulent les données à un niveau binaire. La priorité de l'opérateur (ou la
priorité de l'opérateur si vous préférez) est également expliquée et des notes sur l'évaluation des expressions de
PureBasic sont portées à votre attention.

Introduction aux Opérateurs


Les opérateurs sont un ensemble de fonctions qui peuvent effectuer des opérations arithmétiques sur des données
numériques, des opérations booléennes sur des valeurs de vérité et des opérations de chaîne pour manipuler des
chaînes de texte. Certains opérateurs sont connus sous le nom d'opérateurs surchargés, ce qui signifie qu'ils peuvent
être utilisés sur plus d' un type de données et peuvent exécuter différentes fonctions. Par exemple, l' opérateur égal
« = » peut être utilisé pour assigner une valeur à une variable ainsi que comme opérateur d'égalité pour tester que deux
variables sont de valeurs égales.

« = » ( Egals )
C'est probablement l'opérateur le plus facile à expliquer même s'il peut être utilisé de deux façons. Tout d'abord, il peut
être utilisé pour assigner une valeur à une variable comme celle-ci :

LongVariable.l = 1

Deuxièmement, il peut être utilisé pour faire une comparaison d'égalité entre deux expressions, variables ou valeurs,
comme celle-ci :

LongVariable.l = 1
If LongVariable = 1
Debug "Oui, LongVariable est égal 1"
EndIf

C'est la première fois que vous voyez le mot-clé « If » , mais ne vous inquiétez pas. Ce mot-clé permet à vos
programmes d'exécuter du code en fonction du respect d'une certaine condition. Dans ce cas, si la « Variable Long »
égal à « 1 », affichera un texte dans la fenêtre Debug.

« + » ( Plus )
L'opérateur plus est un autre opérateur couramment utilisé et est utilisé pour concaténer des chaînes de caractères ainsi
que pour l'ajout de nombres. Tout d'abord, voici un exemple d'addition de chiffres

NumberOne.l = 50
NumberTwo.l = 25
NumberThree.l = NumberOne + NumberTwo
Debug NumberThree

Le nombre affiché dans la fenêtre Debug devrait être « 75 » parce que nous avons ajouté la valeur de « NumberOne » à
« NumberTwo » (50+25) et stocké la valeur résultante « 75 » dans la variable « NumberThree », nous répétons ensuite
cette valeur dans la fenêtre Debug. Une autre façon de le montrer pourrait être :

NumberOne.l = 50 + 25
Debug NumberOne

Vous pouvez également utiliser un raccourci lorsque vous utilisez l'opérateur plus avec des nombres, si vous avez juste
besoin d'incrémenter une variable numérique d'une autre valeur ou expression :

NumberOne.l = 50
NumberOne + 25
Debug NumberOne

Une fois qu'une valeur initiale est assignée à « NumberOne », nous pouvons utiliser l'opérateur plus pour lui ajouter une
autre valeur, donc maintenant le nombre qui apparaît dans la fenêtre Debug est « 75 ».
Opérateurs 25

Voici un exemple de concaténation de chaînes de caractères à l'aide de l'opérateur plus :

StringOne.s = "Marie a eu un"


StringTwo.s = " petit agneau"
StringThree.s = StringOne + StringTwo
Debug StringThree

Le mot concaténation signifie essentiellement enchaîner ou joindre ensemble et c'est exactement ce que nous faisons
avec ces deux cordes. Nous concaténons « StringOne » et « StringTwo » et stockons la chaîne résultante dans «
StringThree », puis nous faisons écho à cette valeur dans la fenêtre Debug Output. C'est une autre façon :

StringOne.s = "Marie a eu un" + " petit agneau


Debug StringOne

Vous pouvez également utiliser le raccourci lorsque vous utilisez l'opérateur plus avec des chaînes de caractères, si
vous avez juste besoin de concaténer du texte sur une variable existante :

StringOne.s = "Marie a eu un"


StringOne.s + " petit agneau"
Debug StringOne

Cela fonctionne un peu comme le raccourci numérique, mais au lieu d'ajouter la valeur numériquement, la deuxième
chaîne de caractères est jointe à la variable Chaîne existante.
« - » ( Moins )
L'opérateur moins travaille exactement à l'inverse de l'opérateur d'addition, en ce sens qu'il soustrait plutôt qu'il ajoute.
Contrairement à l'opérateur d'addition, l'opérateur moins ne peut pas travailler avec les chaînes de caractères. Voici un
exemple de l'opérateur moins en action :

NumberOne.l = 50
NumberTwo.l = 25
NumberThree.l = NumberOne - NumberTwo
Debug NumberThree

Le texte affiché dans la fenêtre de débogage doit être « 25 », c'est à dire « Numéro Deux » soustrait de « Numéro Un ».
Encore une fois, un raccourci peut être utilisé si vous avez besoin de décrémenter une variable d'un montant
spécifique :

NumberOne.l = 50
NumberOne - 10
Debug NumberOne

Ici, « NumberOne » reçoit la valeur « 50 » puis « NumberOne » est décrémenté de « 10 ». en utilisant l'opérateur
moins. La nouvelle valeur de « NumberOne » « 40 » est alors affiché dans la fenêtre Debug.

« * » (Multiplication)
L'opérateur de multiplication est utilisé pour multiplier deux valeurs ensemble et comme l'opérateur moins ne peut pas
travailler avec des chaînes. Pour montrer comment cet opérateur est utilisé, voici un exemple :

NumberOne.l = 5
NumberTwo.l = 25
NumberThree.l = NumberOne * NumberTwo
Debug NumberThree

La sortie de débogage doit être « 125 », car dans cet exemple nous avons multiplié « NumberOne » avec «
NumberTwo » (5 * 25 = 125). Encore une fois, un raccourci peut être utilisé pour multiplier une variable par un nombre
spécifié.

NumberOne.l = 50
NumberOne * 3
Debug NumberOne

Ici, « NumberOne » reçoit la valeur « 50 » puis « NumberOne » est multiplié par « 3 »,en utilisant l'opérateur de
multiplication. La nouvelle valeur de « NumberOne » (150) est ensuite affichée dans la fenêtre Debug.
26 Opérateurs

« / » (Division)
L'opérateur de division est un autre opérateur mathématique qui fonctionne uniquement avec des chiffres et non des
chaînes de caractères.. À la lecture des autres exemples peuvent être sans doute deviné comment il est utilisé, mais de
toute façon est ici un autre exemple d'utilisation:

NumberOne.l = 100
NumberTwo.l = 2
NumberThree.l = NumberOne / NumberTwo
Debug NumberThree

Ici, « NumberOne » reçoit la valeur « 100 » et « NumberTwo » reçoit la valeur « 2 » Nous divisons ensuite « NumberOne
» «100» par « NumberTwo » (2) et mémoriser le résultat (50) dans « NumberThree ». Nous affichons alors la valeur de «
NumberThree » dans la fenêtre Debug. Comme précédemment, un raccourci peut être utilisé pour diviser une variable
par un nombre spécifié :

NumberOne.l = 50
NumberOne / 5
Debug NumberOne

Ici, la valeur « 50 », est attribuée à « NumberOne », puis nous utilisons l'opérateur de division pour diviser
cette valeur par « 5 » Ensuite, nous répercutons le résultat stocké dans « NumberOne » « 10 » et affiché dans la
fenêtre Debug

« & » ( AND ) (ET)


Les opérateurs binaires sont un groupe d'opérateurs qui manipulent les nombres à un niveau binaire. Si vous n'êtes pas
familier avec le binaire et la façon dont PureBasic stocke les nombres en binaire, vous pouvez vous référer au chapitre
13 (Un examen plus approfondi des types de données numériques) où une explication complète est donnée. Les
opérateurs par bit ne peuvent pas être utilisés avec les Flottants ou les Chaînes.

L'opérateur « & » teste deux valeurs pour voir si elles sont toutes les deux vraies bit par bit, si deux bits sont comparés
et sont tous les deux vrais (1) alors l'opérateur retourne vrai (1) sinon il retourne faux (0). Ceci s'applique à tous les bits
à l'intérieur des deux nombres qui doivent être comparés. Voici un diagramme pour essayer d'expliquer un peu mieux.

L'Opérateur ‘&’ (AND) (ET)


False

False
False
False

False
True

True

True

1
Valeur Binaire 77 0 0 0 1 1 0 1
&
Valeur Binaire 117 0 1 1 1 0 1 0 1

Resultat 69 0 1 0 0 0 1 0 1

8 bit number
(1 byte)
Fig. 4

Sur la figure 4 vous pouvez voir que les deux nombres à évaluer en utilisant l'opérateur « & » - « 77 » et « 117 ». Après
le calcul complet on obtient un résultat de « 69 » un. Pour comprendre comment fonctionne cette valeur, vous devez
regarder chaque colonne de bits de haut en bas. Si vous regardez la colonne la plus à droite (qui est la colonne
associée à la valeur de « 1 » en binaire), donc la valeur retournée par l'opérateur « & » ,est « 1 », (ce qui dans
PureBasic est vrai). Si nous déplaçons une colonne vers la gauche, nous pouvons voir que les deux bits des deux
nombres sont tous les deux « 0 », donc l'opérateur « & » renvoie « 0 » (Faux). Rappelez-vous, si vous utilisez
l'opérateur « & », les deux bits doivent être « 1 » avant que l'opérateur ne retourne « 1 ». sinon il retourne « 0 ».

Cet opérateur est appliqué à toutes les colonnes de bits à partir de la droite vers la gauche et une fois terminé, le
nombre résultant est renvoyé. Dans ce cas, la valeur obtenue par ce calcul est « 69 ». Voici un exemple dans la Fig.4
traduit en code :
Opérateurs 27

NumberOne.b = 77
NumberTwo.b = 117
NumberThree.b = NumberOne & NumberTwo
Debug NumberThree

Dans ce petit exemple, deux variables se voient attribuer des numéros qui doivent être évalués à l'aide de l'opérateur «
& ». La variable « NumberThree » contient le résultat de ce calcul. La valeur de « NumberThree » sera affiché dans la
fenêtre Debug ce qui dans ce cas devrait être « 69 ». Tout comme les autres opérateurs, l'opérateur « And » a
un raccourci si vous avez juste besoin de « & » un nombre à une seule variable :

NumberOne.b = 77
NumberOne & 117
Debug NumberOne

Ici, « NumberOne » reçoit la valeur « 77 ». Dans la ligne suivante, nous associons la valeur « 117 » en utilisant
l'opérateur « & » avec « NumberOne ». Cette valeur est alors affichée dans la fenêtre Debug. Fig. 5 montre la
comparaison des deux bits à l'aide de l'opérateur « & » et le résultat correspondant.

Comparateur de Bits ‘&’ (AND) (ET)

Coté Gauche Coté Droit Resultat

0 0 0
0 1 0
1 0 0
1 1 1
Fig. 5
« | » ( OR ) ( OU )
L'opérateur « | » teste deux valeurs pour voir si une ou plusieurs est vraie bit par bit, si deux bits sont comparés et si
l'un ou les deux sont vrais (1) alors l'opérateur retourne true (1) sinon il retourne faux (0). Ceci s'applique à tous les bits
à l'intérieur des deux nombres qui doivent être comparés.

Dans la Fig.6, vous pouvez voir que les deux nombres à évaluer en utilisant l'opérateur « | » sont « 54 » et « 102 ».
Une fois le calcul terminé, on obtient un résultat final de « 118 ». Pour expliquer comment cette valeur est obtenue,
vous devez regarder chaque colonne de bits de haut en bas. Si vous regardez la colonne la plus à droite (qui est la
colonne associée à la valeur de « 1 » en binaire), les deux bits des deux nombres dans cette colonne sont mis à « 0 »,
donc la valeur retournée par l'opérateur « | » est « 0 » (false). Si nous déplaçons une colonne vers la gauche, nous
pouvons voir que les deux bits des deux nombres sont tous les deux « 1 », donc l'opérateur « | » retourne « 1 » (vrai).
Si nous regardons la cinquième colonne à partir de la droite, vous verrez que le premier nombre a un bit qui est fixé à
« 1 » et le deuxième nombre a un bit qui est fixé à « 0 ». Dans ce cas, l'opérateur « | » retourne toujours « 1 » (vrai)
parce que tant que l'un ou l'autre bit est vrai, l'opérateur retourne vrai. L'opérateur « | » retournera toujours vrai, sauf si
les deux bits sont « 0 ».

L'Opérateur « | » (OR) (OU)


False

False

False
True
True
True

True
True

Valeure Binaire 54 0 0 1 1 0 1 1 0

Valeur Binaire 102 0 1 1 0 0 1 1 0

Résultat 118 0 1 1 1 0 1 1 0

Nombre 8 bits
(1 Octet)
Fig. 6
28 Opérateurs

Cet opérateur est appliqué à toutes les colonnes de bits de la Fig.6 en partant de la droite vers la gauche et une fois
terminé, le nombre obtenu est renvoyé. Dans ce cas, la valeur obtenue par ce calcul est « 118 ». Voici un exemple pour
traduit en code Fig.6 :

NumberOne.b = 54
NumberTwo.b = 102
NumberThree.b = NumberOne & NumberTwo
Debug NumberThree

Dans ce petit exemple, deux variables se voient attribuer des numéros qui doivent être évalués à l'aide de l'opérateur
« | » et la variable « NumberThree » contient le résultat de ce calcul. La valeur de « NumberThree » est alors répercutée
dans la fenêtre Debug qui dans ce cas devrait être «118 ». Tout comme les autres opérateurs, l'opérateur binaire « | »
peut être utilisé comme un raccourci si vous avez juste besoin de « | » un nombre vers une seule variable :

NumberOne.b = 54
NumberTwo | 102
Debug NumberOne

Ici, « NumberOne » reçoit la valeur « 54 » et dans la ligne suivante, nous « | » attribuons la valeur « 102 » à
« NumberOne ». Cette valeur est alors affichée dans la fenêtre Debug.

La figure 7 montre la comparaison entre deux bits et le résultat donné par l'opérateur « | »

Comparateur de bits « | » (OR) (OU)

Coté Gauche Coté Droit Resultat

0 0 0
0 1 1
1 0 1
1 1 1
Fig. 7

« ! » (OU EXCLUSIF au niveau binaire [XOR])


L'opérateur « bit par bit » teste deux valeurs pour voir si l'une d'elles est vraie bit par bit, si les deux bits sont comparés
et si l'un des deux est vrai (1) alors l'opérateur retourne vrai (1) sinon il retourne faux (0). Ceci s'applique à tous les bits à
l'intérieur des deux nombres qui doivent être comparés. Voici un diagramme pour essayer d'expliquer un peu mieux :

L'Opérateur « ! » (XOR)
False

False

False
False
True
True

True
True

Valeure Binaire 38 0 0 1 0 0 1 1 0
!
Valeure Binaire 74 0 1 0 0 1 0 1 0

Resultat 108 0 1 1 0 1 1 0 0

8 bit number
(1 byte)
Fig. 8
Dans la Fig.8, vous pouvez voir que les deux nombres à évaluer à l'aide de l'opérateur « ! » sont « 38 » et « 74 ». Une
fois le calcul terminé, le résultat final est « 108 ». Pour expliquer comment cette valeur est obtenue, vous devez regarder
chaque colonne de bits de haut en bas à nouveau. Si vous regardez la colonne la plus à droite (qui est la colonne
associée à la valeur de « 1 » en binaire), les deux bits des deux nombres de cette colonne sont mis à « 0 », la valeur
retournée par l'opérateur « ! » est « 0 » (false). Si nous déplaçons une colonne vers la gauche, nous pouvons voir que
les deux bits des deux nombres sont tous les deux « 1 », donc l'opérateur « ! » renvoie toujours « 0 ». (false). En effet,
lorsque deux bits sont comparés, l'opérateur « ! » ne retournera « 1 » (true) que si un seul bit est mis à « 1 ». Si les
deux bits sont réglés sur « 1 » ou « 0 », l'opérateur « ! » renvoie « 0 » (false).
Opérateurs 29

Cet opérateur est appliqué à toutes les colonnes de bits de la Fig.8 en partant de la droite vers la gauche et une fois
terminé, le nombre obtenu est renvoyé. Dans ce cas, la valeur obtenue par ce calcul est « 108 ». .Voici un exemple
traduit en code Fig.8 :

NumberOne.b = 38
NumberTwo.b = 74
NumberThree.b = NumberOne ! NumberTwo
Debug NumberThree

Dans ce petit exemple, deux variables se voient attribuer des numéros qui doivent être évalués à l'aide de l'opérateur
« ! ». et la variable « NumberThree » contient le résultat de ce calcul. La valeur de « NumberThree » est alors afichée
dans la fenêtre Debug, qui dans ce cas devrait être « 108 ». Tout comme les autres opérateurs, « ! » est un raccourci
si vous avez juste besoin d'un nombre vers une seule variable :

NumberOne.b = 38
NumberOne ! 74
Debug NumberOne

Ici, « NumberOne » reçoit la valeur « 38 », et dans la ligne suivante, nous avons« 74 » à « NumberOne ». Cette valeur
est ensuite affichée dans la fenêtre Debug.

La figure 9 montre la comparaison faite entre deux bits et le résultat donné par l'opérateur « ! »:

Le Comparateur de Bits « ! » ( XOR)


Coté Gauche Coté Droit Resultat

0 0 0
0 1 1
1 0 1
1 1 0
Fig. 9

« ~ » ( NOT ) ( Non )
L'opérateur « ~ » est un opérateur plus facile à expliquer dans la mesure où il retourne simplement un nombre dont
les bits ont été inversés en utilisant un numéro d'entrée ou une expression comme source.

L'opérateur binaire « ~ » est connu comme un opérateur unaire, ce qui signifie qu'il utilise une valeur ou une
expression pour renvoyer une valeur. Cela peut être démontré par ce code:

NumberOne.b = 43
NumberTwo.b = ~NumberOne
Debug NumberTwo

Ici la variable « NumberOne » se voit attribuer la valeur « 43 », puis on crée une variable « NumberTwo » et on lui
attribue la valeur « NumberOne » qui est inversée au niveau binaire avec l'opérateur « ~ ». Cette valeur (qui doit être
-44 ») est ensuite affichée à la fenêtre Debug.
30 Opérateurs

L'Opérateur ‘~’ (NOT) (Non)

Inversé
Inversé
Inversé
Inversé
Inversé
Inversé
Inversé
Inversé
Valeur Binaire 43 0 0 1 0 1 0 1 1
~
Résultat -44 1 1 0 1 0 1 0 0

Nombre 8 bits
(1 Octet)
Fig. 10
Dans la Fig.10 vous pouvez voir que l'opérateur « ~ » inverse simplement les bits du numéro de la source puis retourne
cette nouvelle valeur. Pour mieux comprendre comment les nombres sont représentés en binaire dans PureBasic, en
particulier les nombres négatifs (signés), voir le chapitre 13 (Un examen plus approfondi des types de données
numériques).

<< (Décalage de Bits vers la Gauche)


Les opérateurs de décalage de bit sont semblables aux opérateurs de bit en ce sens qu'ils manipulent des nombres à un
niveau binaire. Comme leur nom l'indique, ils déplacent tous les bits vers la gauche ou la droite selon l'opérateur utilisé.
Voici quelques codes démontrant l'utilisation de l'opérateur « << »:

NumberOne.b = 50
NumberTwo.b = NumberOne << 1
Debug NumberTwo

Dans cet exemple, nous attribuons à « NumberOne » la valeur « 50 ». Ensuite, nous créons une variable appelée «
NumberTwo » et lui attribuons la valeur de « NumberOne » qui a été décalée d'un bit vers la gauche d'un endroit. Cette
valeur résultante (qui devrait être « 100 ») est alors répercutée dans la fenêtre Debug. Vous pouvez comprendre plus
clairement la fonction de cet opérateur en regardant la Fig.11.

L'Opérateur ‘<<’ (Décalage Vers la Gauche)

Valeur Binaire 50 0 0 1 1 0 0 1 0

Résultat 100 0 1 1 0 0 1 0 0 Décale le Bits d' une place à gauche

Nombre 8 bits
(1 Octet)
Fig. 11
Comme vous pouvez le voir, la valeur résultante a simplement ses chiffres binaires (bits) décalés vers la gauche de leur
position d'origine, dans ce cas-ci d'un endroit. En déplaçant les bits vers la gauche comme ceci, des zéros sont créés et
décalés pour combler le vide à droite, tandis que les bits à gauche seront décalés « hors de l'extrémité » du nombre
(dans ce cas un octet) et seront perdus à jamais.

>> (Décalage de Bits vers la droite)


L'opérateur « >> » est exactement le même que l'opérateur « << » , ne fonctionnent que dans l' autre sens. Voici un
exemple de code qui montre l'opérateur « >> »:

NumberOne.b = 50
NumberTwo.b = NumberOne >> 1
Debug NumberTwo

Dans cet exemple, nous attribuons à « NumberOne » la valeur « 50 ». Ensuite, nous créons une variable appelée «
NumberTwo » et lui attribuons la valeur de « NumberOne » qui a été décalée d'un bit vers la droite d'un endroit. Cette
valeur résultante (qui devrait être « 25 ») est alors répercutée dans la fenêtre Debug. Vous pouvez comprendre plus
clairement la fonction de cet opérateur à La figure 12.
Opérateurs 31

L'Opérateur ‘>>’ (Décalage Vers la Droite)

Valeur Binaire 50 0 0 1 1 0 0 1 0

Résultat 25 0 0 0 1 1 0 0 1 Décale le Bits d' une place à droite

Nombre 8 bits
(1 Octet) Fig. 12

Comme vous pouvez le voir, la valeur résultante a simplement ses chiffres binaires (bits) décalés vers la droite par
rapport à leur position d'origine, dans ce cas par un endroit. En déplaçant les bits vers la droite comme ceci, il est
important de comprendre quels bits sont utilisés pour combler l'espace qui est créé sur le côté gauche du nombre
binaire. Si le nombre est positif, le bit le plus à gauche (parfois appelé bit le plus significatif) est mis à zéro. Dans ce cas,
le vide sera comblé par des bits mis à zéro. Si le numéro de la source est un numéro négatif (signé), le bit le plus à
gauche sera un. Dans ce cas, l'espace sera comblé avec des bits mis à un. Les bits à droite seront décalés « hors de la
fin » du nombre (dans ce cas un octet) et seront perdus à jamais.

< (Inférieur à)
L'opérateur « < » est utilisé pour comparer deux variables ou expressions. Si la valeur du côté gauche de cet
opérateur est inférieure à la valeur du côté droit, cet opérateur retournera true « 1 » sinon il retournera false « 0 ». Voici
un extrait de code démontrant son utilisation :

NumberOne.l = 1
NumberTwo.l = 2

If NumberOne < NumberTwo


Debug "1: NumberOne est inférieur à NumberTwo"
Else
Debug "2: NumberTwo est inférieur à NumberOne"
EndIf

Ici, dans l'instruction « If», nous testons pour voir si « NumberOne » est inférieur à « NumberTwo », ce qui bien sûr est
le cas, présent, donc la première instruction de débogage est exécutée. Si nous changeons la valeur de « NumberOne »
en « 3 », comme ceci :

NumberOne.l = 3
NumberTwo.l = 2

If NumberOne < NumberTwo


Debug "1: NumberOne est inférieur à NumberTwo"
Else
Debug "2: NumberTwo est inférieur à NumberOne"
EndIf

Nous voyons maintenant dans la fenêtre Debug que la deuxième instruction de débogage a été exécutée parce que
maintenant « NumberOne » n'est plus inférieur à « NumberTwo ».

> (Supérieur à)
L'opérateur « > » est utilisé pour comparer deux variables ou expressions. Si la valeur du côté gauche de cet opérateur
est supérieure à la valeur du côté droit, cet opérateur retournera true. « 1 » sinon il retournera false « 0 ». Voici un
extrait de code démontrant son utilisation :

NumberOne.l = 2
NumberTwo.l = 1

If NumberOne > NumberTwo


Debug "1: NumberOne est supérieur à NumberTwo"
Else
Debug "2: NumberTwo est supérieur à NumberOne"
EndIf

Ici, dans l'instruction « If », nous testons pour voir si « NumberOne » est plus que « NumberTwo », ce qui est bien sûr le
cas, présent, donc la première instruction de débogage est exécutée. Si nous changeons la valeur de « NumberOne »
en « 0 », comme ceci :
32 Opérateurs

NumberOne.l = 0
NumberTwo.l = 1

If NumberOne > NumberTwo


Debug "1: NumberOne est inférieur à NumberTwo"
Else
Debug "2: NumberTwo est inférieur à NumberOne"
EndIf

Nous voyons maintenant dans la fenêtre Debug que la deuxième instruction de débogage a été exécutée parce que
maintenant « NumberOne » n'est plus supérieur à « NumberTwo ».

<= (Inférieur ou égal à)


L'opérateur « <= » est utilisé pour comparer deux variables ou expressions. Si la valeur du côté gauche de
cet opérateur est inférieure ou égale à la valeur du côté droit, cet opérateur retournera true « 1 » sinon il retournera false
« 0 ». Voici un extrait de code démontrant son utilisation :

NumberOne.l = 0
NumberTwo.l = 1

If NumberOne <= NumberTwo


Debug "1: NumberOne est inférieur ou égal à NumberTwo"
Else
Debug "2: NumberOne n'est pas inférieur ou égal à NumberTwo"
EndIf

Ici, dans l'instruction « If », nous testons pour voir si « NumberOne » est inférieur ou égal à « NumberTwo », ce qui bien
sûr est le cas présent, donc la première instruction de débogage est exécutée. Si nous changeons la valeur de «
NumberOne » à « 1 » alors l'instruction « If » retournera toujours vrai « 1 » parce que « NumberOne » est toujours
inférieur ou égal à « NumberTwo ».. Pour démontrer que la deuxième instruction de débogage est exécutée, nous
devons nous assurer que l'opérateur « <= » donne un faux résultat à l'instruction « If ». Ceci est réalisé facilement en
s'assurant que la valeur de « NumberOne » n'est PAS inférieure ou égale à la valeur de « NumberTwo », comme ceci :

NumberOne.l = 2
NumberTwo.l = 1
If NumberOne <= NumberTwo
Debug "1: NumberOne est inférieur ou égal à NumberTwo"
Else
Debug "2: NumberOne n'est pas inférieur ou égal à NumberTwo"
EndIf

> = (Supérieur ou égal)


L'opérateur « > = » est utilisé pour comparer deux variables ou expressions. Si la valeur du côté gauche de cet
opérateur est supérieure ou égale à la valeur du côté droit, cet opérateur doit retourne true « 1 » sinon elle retourne false
« 0 ». Voici un extrait de code démontrant son utilisation :

NumberOne.l = 2
NumberTwo.l = 1

If NumberOne <= NumberTwo


Debug "1: NumberOne est supérieur ou égal à NumberTwo"
Else
Debug "2: NumberOne n'est pas supérieur ou égal à NumberTwo"
EndIf

Ici, dans l'instruction « If », nous testons pour voir si « NumberOne » est supérieur ou égal à « NumberTwo », ce qui
bien sûr est le cas, donc la première instruction de débogage est exécutée. Si nous changeons la valeur de «NumberOne
» à « 1 » alors l'instruction « If » retournera toujours vrai « 1 » parce que « NumberOne » est toujours supérieur ou
égal à « NumberTwo ».. Pour démontrer que la deuxième instruction de débogage est exécutée, nous devons nous
assurer que l'instruction « If » reçoit un faux résultat de l'opérateur « >= ». Ceci est réalisé facilement en s'assurant
que la valeur de « NumberOne » n'est PAS supérieure ou égale à la valeur de « NumberTwo », comme ceci :
Opérateurs 33

NumberOne.l = 0
NumberTwo.l = 1

If NumberOne >= NumberTwo


Debug "1: NumberOne est supérieur ou égal à NumberTwo"
Else
Debug "2: NumberOne n'est pas supérieur ou égal à NumberTwo"
EndIf

<> (Différent)
L'opérateur « <> » est utilisé dans les comparaisons de deux variables ou expressions qui fonctionnent exactement à
l'opposé de la fonction de comparaison (et non d'affectation) de l'opérateur « = ». Si la valeur du côté gauche de cet
opérateur n'est pas égale à la valeur du côté droit, cet opérateur retournera true « 1 » sinon il retournera false « 0 ».
Voici un extrait de code démontrant son utilisation :

NumberOne.l = 0
NumberTwo.l = 1

If NumberOne <> NumberTwo


Debug "1: NumberOne est différent du NumberTwo"
Else
Debug "2: NumberOne est égal au NumberTwo"
EndIf

Ici, dans l'instruction « If », nous testons pour voir si « NumberOne » n'est pas égal à « NumberTwo », ce qui n'est bien
sûr pas le cas présent, donc la première instruction de débogage est exécutée. Si nous changeons la valeur de «
NumberOne » en « 1 », comme ceci :

NumberOne.l = 1
NumberTwo.l = 1

If NumberOne <> NumberTwo


Debug "1: NumberOne est différent du NumberTwo"
Else
Debug "2: NumberOne est égal à NumberTwo"
EndIf

Nous voyons maintenant dans la fenêtre Debug que la deuxième instruction de débogage a été exécutée parce que
« NumberOne » est maintenant égal à « NumberTwo » et l'opérateur « <> » renvoie false « 0 ».

And (logique) Et
Les opérateurs logiques sont utilisés pour combiner les résultats logiques vrais ou faux des opérateurs de
comparaison afin de fournir une solution plus robuste pour comparer les valeurs de plusieurs expressions.

L'Opérateur « And » est utilisé pour vérifier deux expressions afin de s'assurer qu'elles sont vraies. Regardez ce code:

StringOne.s = "Le renard brun rapide"


NumberOne.l = 105

If StringOne = "Le renard brun rapide" And NumberOne = 105


Debug "1: Les deux expressions évaluent à true(1)"
Else
Debug "2: Une ou les deux expressions évaluée comme false (0)"
EndIf

Nous pouvons voir que l'instruction « If » teste pour s'assurer que la variable String, « StringOne » égale "Le renard
brun rapide" et que la variable Longue « NumberOne » égale « 105 ». Parce que les deux le font, l'opérateur « And »
retourne vrai et la première instruction de débogage est exécutée. Si l'une des deux expressions à droite et à gauche de
l'opérateur « And » renvoie un résultat faux, l'opérateur « And » renvoie lui-même un résultat faux. Cet opérateur est
optimisé de telle sorte que si la première des expressions retourne un résultat faux, l'opérateu r« And » retourne
immédiatement faux et ne se donne pas la peine d'évaluer l'expression suivante. C'est pratique lorsque vous voulez
écrire du code qui s'exécute très rapidement.
34 Opérateurs

NOT (NON logique)


L'opérateur « Not » est utilisé pour effectuer une négation logique sur une expression ou une valeur booléenne. En
d'autres termes, tout ce qui est évalué comme vrai du côté droit de cet opérateur est retourné comme faux et vice
versa. Voir cet exemple :

One.l = 1
Two.l = 2

If Not One = 5
Debug "1: One = 5 est evalué True(1)"
Else
Debug "2: One = 5 est évalué False(0)"
EndIf

If Not Two = 2
Debug "1: Two = 2 est evalué true (1)"
Else
Debug "2: Two = 2 est évalué false (0)"
EndIf

Nous pouvons voir ici que la première instruction « If » teste pour s'assurer que la variable Longue, « One » égale « 5 »
ce qui n'est pas le cas et l'expression retourne false. Parce que nous avons l'opérateur « Not » devant « Un » = « 5 » ce
qui permet d'inverser la valeur de retour fausse à une valeur vraie. Les valeurs contraires sont indiquées dans la
deuxième instruction « If ». L'expression retourne ici true « 1 » mais à cause de l'opérateur « Not » elle l'inverse à une
valeur fausse.

OR (OU logique)
L'opérateur « OR » est de vérifier deux expressions. afin de s'assurer que l'une ou l'autre évalue comme vraie. Regarde
ce morceau de code :

StringOne.s = "Le renard brun rapide"


NumberOne.l = 105

If StringOne = " Le renard brun rapide " Or NumberOne = 100


Debug "1: Une ou plusieurs expressions évaluées à True (1)"
Else
Debug "2: Les deux expressions évaluées comme False(0)"
EndIf

Ici nous pouvons voir que l'instruction « if » teste pour s'assurer que la variable String, « StringOne » égale "Le renard
brun rapide" ou que la variable Long « NumberOne » égale « 100 ». Vous remarquerez que la deuxième expression de
l'instruction « if » retourne false parce que « NumberOne » ne correspond pas à «100 ». Parce qu'une des expressions
retourne un résultat vrai, l'opérateur « Or » retourne vrai et la première instruction de débogage est exécutée.
L'opérateur « Or » ne retournera un résultat faux que si les deux expressions à droite et à gauche retournent elles-
mêmes un résultat faux. Cet opérateur est également optimisé de telle sorte que si la première expression retourne un
résultat vrai, alors l'opérateur « Or » retourne immédiatement vrai et ne prend pas la peine d'évaluer l'expression
suivante. C'est pratique lorsque vous voulez écrire du code qui s'exécute très rapidement.

XOR Exclusif (OU logique)


L'opérateur « XOR » est utilisé pour vérifier deux expressions afin de s' assurer qu' une seule est évaluée comme vraie.
Regarde ce morceau de code :

StringOne.s = "Le renard brun rapide"


NumberOne.l = 105
If StringOne = "Le renard brun rapide" XOr NumberOne = 105
Debug "1: une seule expression renvoie true(1)"
Else
Debug "2: Les deux expressions sont true(1) ou les deux sont false(0)"
EndIf

L'Instruction « If » teste les deux expressions en utilisant l'opérateur « XOr » pour s'assurer qu'une seule expression est
évaluée comme vraie. Si les deux évaluent comme vrai ou faux alors l'instruction'If' elle-même retournera false et
exécutera la deuxième instruction de débogage, ce qui est le cas ici. Si cet exemple a été modifié pour s'assurer qu'une
seule expression retourne une valeur vraie, alors le « If » retourne true et exécute la première instruction de débogage.
Opérateurs 35

% (Modulo)
L'opérateur « % » divise le nombre sur le côté gauche par le nombre sur le côté droit et retourne le reste de cette
division. En voici un exemple :

NumberOne.l = 20 % 8
Debug NumberOne

on divise ici le nombre « 20 » à « 8 » au moyen de l'opérateur « % ». Etant donné que le « 8 » correspond à deux fois
dans le « 20 », est un reste de « 4 ». Ce reste est attribué à la variable « NumberOne ». nous affichons la valeur dans
la fenêtre Debug.

() (Entre Parenthèses)
Les parenthèses ne sont pas vraiment un opérateur en soi parce qu'elles ne retournent jamais aucun résultat. Ils sont
utilisés pour déterminer l'ordre d'exécution des expressions imbriquées. La règle générale est que l'expression entre
parenthèses est évaluée en premier. Dans le cas des parenthèses imbriquées, l'ensemble le plus intérieur est évalué en
premier, puis l'ensemble suivant et ainsi de suite jusqu'à ce que l'ensemble final soit atteint. En voici un exemple :

NumberOne.l = 2 * 5 + 3
Debug NumberOne
Ici, la valeur de « NumberOne » « 13 » étant donné que l'ordre de traitement des « 2 * 5 » puis « + 3 » applique. Si
l'on ajoute entre parenthèses qui va changer:
NumberOne.l = 2 * (5 + 3)
Debug NumberOne
Ensuite, l'ordre d'évaluation est modifié à « 5 + 3 » puis « * 2 », dont les résultats « 16 » qui à son tour est assignée à
« NumberOne » et affichée dans la fenêtre Debug.

Les Priorités des Opérateurs


La priorité de l'opérateur est un terme qui signifie l'ordre dans lequel les opérateurs sont évalués pendant le temps de
compilation. Si vous regardez la Fig.13, vous pouvez voir l'ordre dans lequel les opérateurs sont évalués en fonction de
leur priorité individuelle. Cette priorité est indiquée dans la colonne de gauche, le nombre le plus bas « 1 » signifie que
ces opérateurs sont évalués en premier, tandis que le nombre le plus élevé signifie que ces opérateurs seront évalués
plus tard.

Priorité des Operateurs


Priorité* Operateurs

1 ( )
2 ~
3 << >> % !

4 | &

5 * /
6 + -
7 > >= < <= = <>
8 A
And Or Not XOr
* Les opérateurs en haut de cette liste sont évalués en premier. Fig. 13
Voici un exemple:

Debug 3 + 10 * 2
la multiplication est effectuée avant l'addition, comme cet opérateur a une priorité plus élevée, même si elle
apparaît dans le code seulement après l'addition. Le résultat dans la fenêtre Debug doit être « 23 ».

Pour définir la priorité des opérateurs, vous pouvez utiliser des parenthèses qui vous permettent d'encapsuler les parties
du code. Ces parties ont alors une priorité plus élevée. Si nous voulons exécuter, par exemple, l' addition d'abord, nous
devons réécrire l'expression comme ceci:
Debug (3 + 10) * 2
Maintenant, la valeur dans la fenêtre Debug est « 26 ».
36 Opérateurs

Règles de Calcul des Expressions


Si PureBasic calculé les expressions avec des nombres entiers et à virgule flottante, certains éléments d'expression
changements appropriés à leur type. Si l'expression contient une valeur flottante, toutes les parties de l'expression sont
converties en flottant avant que le calcul soit effectué et le résultat renvoyé. Fig. 14 montre, comme de pures
expressions de base sont calculées sous certaines conditions.

Si vous avez l'impression que le résultat du calcul a une valeur étrange ou d' un type non attendu, une bonne idée de
serait vérifier vos expressions alors que le compilateur ne respecte que les règles suivantes:

Règles de Calcul d' Expression

Exemple de Régles de Calcul d' Expression


« b » et « c » restent tous les deux en tant que Long avant et pendant l'évaluation, un Long est
a.l = b.l + c.l alors retourné et assigné « a » .

a.l = b.l + c.f Comme cette expression contient un flottant, « b » est convertie en flottant avant l'évaluation. « b
» est ensuite ajouté à « c » et le Flottant résultant est alors converti en un Long et assigné « a »

« b » et « c » restent tous les deux en tant que « b » et « c » bien avant et pendant l'évaluation. Le
a.f = b.l + c.l
Long résultant renvoyé par l'opérateur d'addition est ensuite converti en Flottant et assigné à « a »

« b » et « c » Restent tous les deux comme un Flottant avant et pendant l'évaluation. Le flottant
a.l = b.f + c.f
renvoyé par l'opérateur d'addition est alors converti en un long et assigné à « a ».

Figure 14.
Opérateurs 37

Opérateurs de Référence Rapide

Opérateurs Descriptions
= DC. Cela a deux utilisations. La première consiste à affecter la valeur de l'expression de la variable RVO OVM. La deuxième possibilité est
l'utilisation du résultat de l'opérateur dans une expression est identique à vérifier si la valeur de l'expression LVO et RVO (si elles sont
identiques, le même opérateur retourne vrai, sinon il retourne faux).

+ Plus. Ajoute la valeur de l'expression RVO à la valeur des OVM d'expression et renvoie le résultat. Si le résultat de cet opérateur n'est pas
utilisé et il y a un OVM variable, la valeur de l'expression RVO est ajoutée directement aux OVM variables.

- Moins. Soustrait la valeur de l'expression RVO par la valeur des OVM d'expression. Si OVM n'est pas une expression, la valeur de
l'expression RVO donné un signe négatif. Si le résultat de cet opérateur n'est pas utilisé et il y a un OVM variable, la valeur de l'expression
RVO directement des OVM variables est retranchée. (Cet opérateur ne peut pas être utilisé avec des stings).

* Multiplication. Multiplie la valeur des OVM d'expression avec la valeur de l'expression RVO. Si le résultat de cet opérateur ne sert pas et il
y a un OVM variable, la valeur de l'expression RVO est directement multipliait dans OVM variables. (Cet opérateur ne peut pas être utilisé
avec des stings).

/ Division. Divise la valeur des OVM d'expression par la valeur de l'expression RVO. Si le résultat de cet opérateur n'est pas utilisé et il est
une variable LVO, la valeur de la variable LVO est divisée directement à partir de la valeur de l'expression RVO. (Cet opérateur ne peut
pas être utilisé avec des stings).

& ET Bitwise. Vous devez être familier avec les nombres binaires en utilisant cet opérateur. Le résultat de cet opérateur est la valeur de
l'expression LVO et liée à la valeur de l'expression RVO. Ce lien est peu à peu. Si le résultat de l'opérateur ne sert pas et il y a un OVM
variable, le résultat est stocké directement dans cette variable. (Cet opérateur ne peut pas être utilisé avec des stings).

| Bitwise OU. Vous devez être familier avec les nombres binaires en utilisant cet opérateur. Le résultat de cet opérateur est la valeur de
l'expression LVO ORed avec la valeur de l'expression RVO. Ce lien est peu à peu. Si le résultat de l'opérateur ne sert pas et il y a un OVM
variable, le résultat est stocké directement dans cette variable. (Cet opérateur ne peut pas être utilisé avec des stings).

! XOR. Vous devez être familier avec les nombres binaires en utilisant cet opérateur. Le résultat de cet opérateur est la valeur de
l'expression LVO EXCLUSIF ORed avec la valeur de l'expression RVO. Ce lien est peu à peu. Si le résultat de l'opérateur ne sert pas et il
y a un OVM variable, le résultat est stocké directement dans cette variable. (Cet opérateur ne peut pas être utilisé avec des stings).

~ Bitwise PAS. Vous devez être familier avec les nombres binaires en utilisant cet opérateur. Le résultat de cet opérateur est la valeur de
l'expression RVO dissociées, soit les bits du résultat sont inversées par rapport à la valeur de l'expression. (Cet opérateur ne peut pas être
utilisé avec des stings).

< Moins. Comparer utilisé pour les valeurs des expressions OVM et RVO. Si la valeur des OVM d'expression est inférieure à la valeur de la
RVO d'expression, l'opérateur retourne vrai, sinon il retourne faux.

> Plus de. Comparer utilisé pour les valeurs des expressions OVM et RVO. Si la valeur des OVM d'expression est supérieure à la valeur du
RVO d'expression, l'opérateur retourne vrai, sinon il retourne faux.

<= Inférieur ou égal. Comparer utilisé pour les valeurs des expressions OVM et RVO. Si la valeur de l'expression LVO inférieure ou égale à la
valeur du RVO d'expression, l'opérateur retourne vrai, sinon il retourne faux.

>= Supérieure ou égale. Comparer utilisé pour les valeurs des expressions OVM et RVO. Si la valeur de l'expression LVO est supérieure ou
égale à la valeur du RVO d'expression, l'opérateur retourne vrai, sinon il retourne faux.

<> Inégalitaire. Comparer utilisé pour les valeurs des expressions OVM et RVO. Si la valeur des OVM d'expression est égale à la valeur de
l'expression RVO, l'opérateur renvoie false, sinon il retourne vrai.

And ET logique. Comparer utilisé pour les valeurs des expressions OVM et RVO. Si la valeur des OVM d'expression et la valeur du RVO
d'expression sont vraies, l'opérateur retourne vrai, sinon il retourne faux.

Or OU logique. Comparer utilisé pour les valeurs des expressions OVM et RVO. Si la valeur des OVM d'expression ou la valeur de
l'expression RVO est vrai, l'opérateur retourne vrai, sinon il retourne faux.

Not NOTlogique. Il est utilisé pour annuler une valeur booléenne. En d'autres termes, lorsqu'une expression renvoie True, cela est converti par
l'opérateur d'urgence sur False. A l'inverse, si l'expression renvoie False RVO, est-ce converti en vrai.

XOr XOR logique. Comparer utilisé pour les valeurs des expressions OVM et RVO. Si seulement l'un des OVM expressions ou RVO retourne
vrai, alors le résultat est vrai. Si les deux expressions sont soit Vrai ou faux, l'opérateur XOR retourne Faux.

<< diapositive Arithmétique vers la gauche. Décaler chaque bit dans la valeur de l'expression LVO au nombre défini par la valeur de
l'expression des positions de RVO vers la gauche. Si le résultat de cet opérateur n'est pas utilisé et il y a un OVM variable, la valeur de la
variable est poussé au nombre de RVO chiffres. Il est utile que vous comprenez les nombres binaires lorsque vous utilisez cet opérateur.
Chaque lieu décalé ressemble à une multiplication par un facteur 2.

>> décalage à droite arithmétique. Décale chaque bit de la valeur des OVM d'expression au nombre de défini par la valeur des lieux
d'expression RVO à droite. Si le résultat de cet opérateur n'est pas utilisé et il y a un OVM variable, la valeur de la variable est poussé au
nombre de RVO chiffres. Il est utile que vous comprenez les nombres binaires lorsque vous utilisez cet opérateur. Chaque décalé points
agit comme une division par un facteur de seconde

% Modulo. Renvoie le reste du terme OVM Division retournée par l'expression RVO.

( ) Supports. Vous pouvez utiliser une partie entre parenthèses d'une expression préférée ou modifier dans un ordre précis. Les expressions
entre parenthèses sont traitées avant toute autre partie de l'expression. Dans les parenthèses sont imbriquées, le plus à l'intérieur d'abord
dissous puis continuer à aller à l'extérieur.

RVO = droite de l'opérateur OVM = gauche de l'opérateur Figure 15.


38 Conditions et les Boucles

4. Conditions et les Boucles


Dans ce chapitre, je vais introduire des énoncés conditionnels et des boucles. Il s'agit d'éléments majeurs de tout
programme et qui aident à définir le déroulement du programme. Je commence par expliquer ce que sont les valeurs
booléennes et comment PureBasic les gère. Je passe ensuite aux énoncés conditionnels tels que « If » et « Sélect » qui
sont utilisés pour indiquer au programme comment procéder lorsqu'une condition particulière est remplie. Je termine
ensuite le chapitre avec des explications et des exemples des différentes boucles disponibles dans PureBasic. Comme
toujours, des explications complètes sont données avec de nombreux exemples.

Logique Booléenne
D'abord, fouillons dans les livres d'histoire. George Boole était un mathématicien et philosophe qui a inventé une forme
d'algèbre maintenant appelée algèbre booléenne. La logique derrière cette forme d'algèbre a été nommée logique
booléenne en l'honneur de George Boole. Cette forme est devenue la base de toute l'arithmétique informatique
moderne. Ce qui est étonnant, c'est que George Boole a inventé cette forme environ soixante-dix ans avant la création
du premier ordinateur qui l'a utilisée !

En un mot, tout le système s'articule autour de deux valeurs, Vrai et Faux. Ces deux valeurs (ou états) sont testés à
l'aide d'opérations logiques pour déterminer un résultat. C'est aussi simple que cela. Les trois opérations logiques les
plus fondamentales étaient (et sont toujours) AND, OR et NOT. Ce sont ces trois opérateurs qui ont formé la base de
l'algèbre de Boole forme, et ont été les seules opérations nécessaires pour effectuer des comparaisons ou des
mathématiques de base. (Vous pouvez voir ces opérateurs logiques implémentés dans PureBasic et lire comment les
utiliser dans le chapitre 3).

PureBasic n'a pas de type de données booléennes (comme vous pouvez le voir sur les Fig.2 et Fig.3), contrairement à
certains langages tels que C++. Ainsi, dans PureBasic, pour exprimer une valeur vraie ou fausse, nous utilisons des
nombres. « 1 » égal à Vrai et « 0 » égal à Faux, gardez ceci à l'esprit lorsque vous testez pour un résultat vrai ou faux.
Si vous utilisez ces valeurs numériques pour représenter le vrai et le faux, alors ce serait une bonne idée d'utiliser
PureBasic construit en constantes à la place, pour rendre votre code de programme plus facile à lire et à comprendre
plus tard.

Voici les deux constantes:

#True
#False

« #True » à la valeur « 1 » et « #False » à la valeur « 0 ».


Presque toutes les commandes PureBasic renvoient une valeur. parfois c'est le résultat d'une fonction mathématique,
une autre fois c'est l'état d'une fenêtre que vous avez créé. Ces valeurs sont retournées après vérification. En fonction
du résultat du test, il est possible de commencer à différentes actions. Regardez ce morceau de pseudo-code:

Si création d'une fenêtre est égal True(1)


dessiner des graphiques et des boutons sur la fenêtre
Alors
prévenir l utilisateur qu'il y a eu un problème
Terminez le programme

Ce n'est pas un vrai code compilable, mais vous voyez l'idée. Ici, je teste pour m'assurer que ma fenêtre a été créé. Une
fois que j'ai testé si elle a été créé, je peux dessiner mon contenu dessus. Si elle n’a pas été créé, je termine le
programme après avoir informé l’utilisateur que quelque chose s’est mal passé. Si je ne le fais pas tester la création de
la fenêtre, je risquerais un crash logiciel si j'essayais de dessiner des boutons et graphiques sur quelque chose qui
n'existe pas.

Ce fut un premier aperçu du test de « True(1)» et «False(0) ». Cela nous amène à la section suivante, où le « If »
déclaration est expliquée en détail.

« If » Déclaration
Le mot-clé « If » est utilisé pour contrôler le flux de programme pour la construction d'instructions. Il affecte le
déroulement ultérieur du programme si une certaine condition se pose ou est remplie. Parfois, lorsque les programmes
sont en cours d'exécution vous pouvez provoquer des erreurs ou des entrées inhabituelles. Dans de tels cas, il est utile
dans ces situations de contrôler directement le flux programme et en conséquence de pouvoir détecter les erreurs.
Conditions et les Boucles 39

La Déclaration « if »
Une instruction « If » est utilisée pour rechercher une valeur vraie. Si elle reçoit cette valeur vraie, elle exécute
immédiatement le morceau de code situé après la première ligne de l’instruction « If ». S'il ne reçoit pas cette valeur
vraie, il exécutera un autre morceau de code séparé immédiatement après le mot clé « Else » plus loin dans l'instruction.
Regardons un exemple.

a.i = 5

If a = 5
Debug "une valeur à été trouvée True(1)"
Else
Debug "Aucune valeur à été trouvée False(0)"
EndIf

Ici, l’opérateur « If » teste que la variable « a » est égale à « 5 ». Si, et renvoie une valeur vraie, la première ligne après
le mot-clé « If » est exécutée. Si cette comparaison donnait la valeur false, le code situé après le mot clé « Else » aurait
été exécuté. Pour terminer l’instruction « If », vous devez utiliser le mot-clé « EndIf », car il définit la fin de l’ instruction
« If ».

Tout est Vrai?


Comme vous l'avez lu plus tôt, et généralement dans PureBasic, « 1 » = Vrai et « 0 » = Faux. Bien que cela soit
correct, les déclarations « If » constituent un cas particulier en ce qui concerne ce qu’elles ont reconnu comme
étant vraies. Dans les instructions « If », tout est égal, sauf si la valeur renvoyée est « 0 » (zéro), puis false (sauf si
vous effectuez des comparaisons spécifiques). Cette option est pratique lorsque vous utilisez une instruction « If »
pour tester si une variable, une commande ou expression renvoie une valeur autre que « 0 »

La première chose à prendre en compte lors de l’apprentissage des instructions « If » est l’expression qui suit
directement le mot-clé « If ». Cette expression est testée pour voir si elle est évaluée comme étant vraie. Cette
expression pourrait être une simple variable ou une très longue expression. Le mot clé « Else » est également
complètement optionnel et n’est utilisé ici que pour présenter un exemple complet. Nous pourrions l'omettre
complètement et retaper l'exemple ci-dessus comme ceci:

a.l = 5

If a = 5
Debug "une valeur à été trouvée True(1)"
EndIf

Le seul inconvénient de cet petit exemple est qu’il ne fournit aucun retour lorsqu'un résultat faux est rencontré. Aucune
règle ne stipule que vous devez utiliser le mot clé « Else » dans une instruction « If » mais il est parfois agréable de
fournir un moyen de gérer un résultat faux pour des raisons d' achèvement.

Regardez l'exemple suivant où nous testons une variable à une valeur:

perles.l = 5

If perles
Debug "la variable a une valeur"
Else
Debug "variable n'a pas de valeur "
EndIf

Ici, après le mot-clé « If » j’ai utilisé une seule variable comme expression à tester. Cette variable est testée pour voir si
elle retourne une valeur, ce qui est le cas dans ce cas. La valeur n’est pas « 0 », elle est donc considérée comme vraie
(voir la boîte d’information « Tout est vrai? ») Et le morceau de code correspondant est exécuté. Essayez de changer la
valeur de « Perles » en « 0 » et exécutez à nouveau pour voir un résultat faux.

Jetons un coup d’œil à un exemple plus compliqué d’expression dans une instruction « If ». Re-lisez le Chapitre 3 si
vous avez besoin de comprendre parfaitement tous les opérateurs utilisés dans cette expression.
40 Conditions et les Boucles

Value1.l = 10
Value2.l = 5
Value3.l = 1

If Value1 >= 10 And (Value2 / 5) = Value3


Debug "l'expression est évaluée à True(1)"
Else
Debug " l'expression est évaluée à False(0)"
EndIf

Cette instruction « If » teste pour voir si « Valeur1 » est supérieur ou égal à « 10 » et si « Valeur2 » divisé par « 5 » est
égal à « Valeur3 ». Comme vous pouvez le constater, les expressions pouvant être testées peuvent être assez
compliquées et très spécifiques quant aux valeurs que vous testez.

Mot-Clé « ElseIf »
Un autre mot clé qui peut être utilisé dans une instruction « If » est le mot-clé « ElseIf ». Le mot-clé « ElseIf », comme
son nom l'indique, est une combinaison de « Else » et « If ». Comme « Else », il étend une instruction « If » pour
exécuter un morceau de code différent si l'expression « If » d'origine est évaluée comme fausse. Toutefois,
contrairement au mot clé « Else », il n' exécutera un morceau de code alternatif que si l' expression conditionnelle
« ElseIf » est évaluée à true. Si cela est confus? Voici un exemple:

Nombredeperles.l = 10

If Nombredeperles < 5
Debug "la variable a une valeur inférieur à 5"
ElseIf Nombredeperles > 5
Debug " la variable a une valeur supérieur à 5"
Else
Debug " la variable a une valeur de 5"
EndIf

Ici, nous testons la valeur de la variable « Nombredeperles ». Le premier « If » teste pour voir si cette valeur est
inférieure à « 5 ». Comme cela retourne false, le programme passe ensuite à la partie « ElseIf ». Ici, la ligne « ElseIf »
devient vraie car « Nombredeperles » est supérieur à « 5 ».

L’instruction « ElseIf » est un excellent moyen d’étendre un « If » pour rechercher plusieurs valeurs et il existe un
nombre illimité de vérifications « ElseIf » que vous pouvez effectuer dans une instruction « If ». Le seul inconvénient est
que, lorsqu'un grand nombre de ces déclarations sont utilisées, les choses peuvent devenir un peu compliquées lors du
choix de l'ordre dans lequel elles sont saisies. Lorsque de nombreuses vérifications sont nécessaires, il est parfois
préférable d'utiliser une déclaration « Select ».

Passer des Instructions


À tout moment pendant l'exécution d'une instruction « If », si une partie de l’instruction renvoie true, la plus grande partie
de l’instruction « If » est ignorée et non exécutée. En raison de ce comportement, il est nécessaire de prendre des
précautions lors de la conception d’une déclaration « If ».

Le dernier exemple est cette page déjà démontré. La section « Else » a été complètement ignoré que la partie « ElseIf »
est revenu vrai.

La Déclaration « Select »
La déclaration « Select » est un complément directe à la déclaration « If » et de telle manière qu'il offre une autre façon
de faire plus de tests sur une variable ou une expression dans un bloc de déclaration. Bien que la déclaration « If » est
très puissante, il faut parfois choisir la commande « Sélect » dans les cas compliqués qui ont un grand nombre de sous
instructions de test. Permettez-moi de vous montrer un exemple dans la syntaxe correcte et la déclaration d'utilisation.
Conditions et les Boucles 41

Days.l = 2

Select Days
Case 0
Debug "0 Days"
Case 1
Debug "1 Day"
Case 2
Debug "2 Days"
Default
Debug "Sur 2 Days"
EndSelect

L’instruction « Sélect » commence par le mot-clé « Sélect », qui sélectionne essentiellement une expression ou une
variable à tester, dans le cas présent il s’agit de la variable « Days ». Les mots-clés « Case » suivants sont des
branches qui pourraient éventuellement être exécutées si la valeur de « Days » est égale à la variable ou à l'expression
qui suit cette instruction « Case » particulière. Dans notre exemple ici, si la variable « Days » a la valeur « 0 », le code
suivant immédiatement la case « 0 » est exécuté, si la variable « Days » a la valeur « 1 », le code qui suit
immédiatement la « case 1 » est exécutée etc.

Vous remarquerez que dans le dernier endroit où il y aurait normalement une instruction « Case », il existe un autre mot-
clé nommé « Default ». Il s’agit de la partie de code qui s’exécute si tous les autres « Case » retournent faux, un peu
comme l’option « Else » dans une instruction « If ».

Vérifiez les Valeurs Multiples


Les instructions « Sélect » peuvent rechercher de nombreuses valeurs différentes et peuvent être présentées avec
précision pour produire un code de concision clair. Pour faciliter cette approche agréable et propre consistant à tester de
nombreuses valeurs, une instruction « Sélect » peut utiliser quelques raccourcis lors de la définition des instructions
« Case ». Voici un exemple:
Poids.l = 12

Select Poids
Case 0
Debug "No Poids"
Case 1, 2, 3
Debug "Leger"
Case 4 To 15
Debug "Moyen"
Case 16 To 30
Debug "Lourd"
Default
Debug "Massive"
EndSelect

Vous pouvez voir ici des raccourcis pouvant être utilisés pour spécifier une plage de cas. Utilisez le mot-clé « To » pour
spécifier une plage ou spécifier plusieurs nombres dans une instruction « Case » à l'aide de virgules. Lorsque vous
spécifiez des gammes à l’aide du mot clé « To », le deuxième nombre doit toujours être plus grand que le premier. Dans
cet exemple, j’ai utilisé des nombres, mais ceux-ci peuvent être remplacés par des expressions ou des variables pour un
traitement plus précis des valeurs potentielles que la variable ou l’expression sélectionnée pourrait avoir.

Voici un autre exemple en utilisant « Select » dans un programme de la console:

If OpenConsole()
PrintN("1. Official PureBasic Home")
PrintN("2. Official PureBasic Forums")
PrintN("3. PureArea.net")
PrintN("")
PrintN("Enter un nombre de 1 à 3 et appuyer sur Return:")
Destination.s = Input()
Select Destination
Case "1"
RunProgram("http://www.purebasic.com")
Case "2"
RunProgram("http://forums.purebasic.com")
Case "3"
RunProgram("http://www.purearea.net")
EndSelect
EndIf
End
42 Conditions et les Boucles

Dans cet exemple, j’ai utilisé quelques nouvelles commandes avec lesquelles qui ne vous sont pas familiière, mais je
pense que ce programme simple illustre parfaitement une utilisation de l’instruction « Sélect ». Ces nouvelles
commandes seront expliquées un peu plus tard, mais je pense que vous pouvez comprendre ce qui se passe par leurs
noms descriptifs.

La principale chose à noter à propos de cet exemple est que l’instruction « Sélect » teste la variable « Destination ».
Une valeur Chaine est attribuée à cette variable. Elle est renvoyée à partir de la commande « Input() » après que la
touche « Entrée » ai été appuyée. Les instructions « Case » sont également définies à l’aide de chaînes pour faire
correspondre correctement la valeur de la variable. Tout type PureBasic ou tout type résultant d’une expression peut
être testé à l’aide d’une instruction « Sélect » ou « Case ».

Notez également que, dans ce dernier exemple, j’ai utilisé une instruction « If » pour tester que « OpenConsole() »
renvoie true et ouvre correctement une fenêtre de console.

Boucle (Loops)
Pour être en mesure de recevoir des données en continu et à traiter, vous avez besoin de ponçage. Tous les
programmes avec des interfaces utilisateur graphiques utilisent des boucles pour la gestion de leur surface et la
surveillance continue des entrées utilisateur. L'IDE PureBasic utilise autant de boucles pour les frappes et clics de souris
pour surveiller et mettre à jour la surface. Les boucles sont toujours un excellent moyen pour de grandes quantités de
données dans des tableaux ou des listes de passer par tous les éléments un par un.

Boucles « For »
La première boucle dont je veux parler est probablement la plus connue et peut-être la plus largement utilisée de toutes
les boucles - c'est la boucle « For ». appelé ces boucles, des boucles parfois « For / Next » sont particulièrement bien si
vous avez besoin d'une variable de plus en plus automatiquement un compteur ou index sur un élément particulier dans
un tableau. Voici un petit exemple pour vous aider à démarrer:

For x.i = 1 To 10
Debug x
Next x

Dans cet exemple, nous avons construit une boucle qui utilise le mot-clé « For ». Immédiatement après le mot-clé une
variable numérique définie par l'utilisateur doit être, dans notre exemple « x ». Le « x » valeur affectée est la valeur de
départ de la boucle, ici I ont la valeur « 1 » spécifiée. Après l'attribution, la variable « To » mot-clé est utilisé pour définir
une plage. Ici, j'ai entré « 10 » en haut, réalisable pour la limite « x ». Ainsi, toute la tête de la boucle est définie,
maintenant, nous devons définir une seule extrémité de la boucle. Cela se fait avec la ligne « Next x ». Cette dernière
ligne indique au compilateur qu'il doit « x » augmentation après chaque itération par un et puis sautez en arrière au
début de la boucle.

Le code entre les deux lignes est généré en fonction du nombre de pas entre les lignes de début et de fin. Valeur finale,
constamment répétée. Lorsque « x » a atteint la limite supérieure (valeur après « To »), la boucle se termine et le
programme continue en dessous de la boucle.

si vous démarrez l 'exemple ci-dessus, vous remarquerez que dans la fenêtre Debug, toutes les valeurs qui sont « x »
pendant la passe de boucle. Vous verrez la boucle dix fois a été parcouru. augmenté de « x » de « 1 » à chaque
passe.

Voici une autre boucle par exemple pour lire facilement l'ensemble d'un tableau:
Conditions et les Boucles 43

Dim Names.s(4)
Names(0) = "Gary"
Names(1) = "Sara"
Names(2) = "Stella"
Names(3) = "MiniMunch"

For x.l = 0 To 4
Debug Names(x)
Next x

Comme vous pouvez accéder à toutes les valeurs de tableau d'index, et commencer à ces indices toujours à zéro,
boucles « For » parfaitement adapté aux opérations sur tous les éléments d'un tableau peut être réalisé avec peu
d'effort de programmation. Comme vous pouvez le voir dans le dernier exemple, seulement trois lignes de code pour
représenter la fenêtre de sortie nécessaire à tous les éléments d'un tableau en debug, peu importe la taille du tableau
est. Un éventail plus large ne nécessite qu'une plus grande surface, qui est définie dans la première ligne de la boucle
« For ».

Les boucles « For» peuvent également être créés avec des expressions:

StartVar.l = 5
StopVar.l = 10

For x = StartVar - 4 To Stop Var / 2


Debug x
Next x

et bien sûr les boucles peuvent être imbriquées pour traiter des tableaux multidimensionnels:

Dim Numbers.l(2, 2)

Numbers(0, 0) = 1
Numbers(0, 1) = 2
Numbers(0, 2) = 3
Numbers(1, 0) = 4
Numbers(1, 1) = 5
Numbers(1, 2) = 6
Numbers(2, 0) = 7
Numbers(2, 1) = 8
Numbers(2, 2) = 9

For x = 0 To 2
For y = 0 To 2
Debug Numbers(x, y)
Next y
Next x

Tant que les variables de compteur ont des noms différents, vous pouvez imbriquer autant de boucles « For »
ensemble. La configurabilité unique de la boucle Pour vous fait une boucle puissante et extrêmement utile pour un
nombre défini par l'utilisateur de fois.

Jusqu'à présent, vous avez vu comment les boucles « For » ont augmenté le compteur à chaque passage par « 1 ».
Cependant, ce comptage peut être configuré manuellement avec le mot-clé « Step ».

For x.i = 0 To 10 Step 2


Debug x
Next x

Comme vous pouvez le voir, le mot-clé « Step » apparaît dans la première ligne de la boucle « For » Ce mot-clé peut
être utilisé que dans la boucle « For », ce qui est le seul point d'utilisation dans la boucle. Immédiatement après le mot-
clé « Step » définir la valeur par laquelle la variable est incrémentée après chaque pas. Dans ce cas, la valeur « 2 », ce
qui augmente la variable « x » après chaque étape par la valeur « 2 ». Lorsque vous démarrez cet exemple, vous verrez
que toutes les valeurs multiples de la fenêtre Debug de « 2 ».
44 Conditions et les Boucles

Boucles « Foreach »
Ce type de boucles est diffèrente elle ne fonctionne qu'avec des listes d'autres boucles. La syntaxe est très similaire à
la boucle « For », sauf qu'elle ne nécessite pas une variable compteur. Voici un exemple simple:

NewList Shopping.s()

AddElement(Shopping())
Shopping() = "Lot de Bananes"
AddElement(Shopping())
Shopping() = "Sachet de Thé"
AddElement(Shopping())
Shopping() = "Fromage"

ForEach Shopping()
Debug Shopping()
Next

Dans cet exemple, je crée une liste et l'ajouter quelques éléments. Après que j'utilise une boucle « Foreach » autour de
tous les éléments de la liste dans l'affichage de la fenêtre Debug. Comme vous pouvez le voir, la syntaxe est claire et
facile à comprendre. La boucle commence par le mot-clé « Foreach » suivi du nom de la liste. La fin de la boucle est
définie par le mot-clé suivant:« Next ». Le code entre ces deux lignes est répétée en fonction du nombre d'éléments de
la liste. Lorsque la fin de la liste est atteinte, la boucle est sortie. La boucle « Foreach » fonctionne avec toutes sortes de
listes, listes structurées. Dans le chapitre 5, je parlerai des listes en détail.

Boucles « While »
Ce type particulier de boucles utilisé une expression pour déterminer si elle doit commencer et combien de temps
il devrait répéter. Si cette expression renvoie True, la boucle est lancée. Après chaque boucle, l'expression est
vérifiée à nouveau. S'il retourne vrai à nouveau, la boucle continue. Si l' expression renvoie false, la boucle est sorti.
Regardez cet exemple:

Singes.l = 0

While Singes < 10


Debug Singes
Singes + 1
Wend

Cette boucle est très simple à construire. Il commence par la « While » mot-clé, l'expression suivante le contrôle de la
boucle, ici « Singe » 10 ». La boucle est complétée par le mot-clé « Wend ». L'expression initiale est vérifié pour voir si
la variable « Singe » est inférieure à « 10 ». Si tel est le cas, la boucle commence. Le code intérieur de la boucle est
répétée jusqu'à ce que le terme « Singe » 10 « retourne False(0). Quand vous regardez la fenêtre Debug, vous
remarquerez que l'expression renvoie false(0) si « Singe » est égal« 10 » (à partir de là est l'expression d'au moins «
10 ») devient l' extrémité de la boucle.

Il faut noter que les « While » boucles résultats dans leur expression initiale False(0), n'a jamais commencé. Ce fait est
montré dans l'exemple suivant:

Singes.l = 20

While Singes < 10


Debug "le code n'est jamais executé"
Wend

Boucles « Repeat »
Ce type de boucles est à peu près à l'opposé de « While ». ces boucles commencent par le mot-clé « Repeat » et
se terminent par une des deux façons. Le premier est le mot-clé « Until » dans le cadre d' une expression. La
deuxième possibilité est l'utilisation du mot-clé pour toujours: « Forever ». Je vais expliquer en détail les possibilités et
commencer par le mot-clé.« Until »
Conditions et les Boucles 45

Regardez cet exemple:

Bananes.l = 0

Repeat
Debug Bananes
Bananes + 1
Until Bananes > 10

Contrairement à « While » boucle, l'expression de contrôle est à la fin de la boucle, ce qui est de vérifier si elle
retourne False(0). Si tel est le cas, la boucle continue. Est-ce l'expression renvoie True(0), la boucle est terminée.

Vous devez également noter que la boucle « Repeat », par opposition à « While » fait une boucle toujours au moins une
fois jusqu'à ce que l'expression soit vérifiée. Ceci est démontré ici:

Bananes.l = 20

Repeat
Debug Bananes
Until Bananes > 10

Vous pouvez voir qui est exécuté à travers la boucle une fois, bien que « banane » est supérieur à « 10 ». Tel est le cas,
parce que l'expression est vérifiée après la première itération de la boucle. Ayant imprimé testé, cela retourne vrai parce
que « banane » est supérieur à « 10 », et la boucle se termine.

Les boucles « Repeat » offre une alternative. Avec un autre mot-clé, ils peuvent être transformés en boucles
infinies. Pour construire une boucle infinie, utilisez le mot-clé « ForEver » au lieu de l' expression , « Until » comme ceci:

Compteur.l = 0

Repeat
Debug compteur
Compteur +
1 ForEver

Ceci est pratique si vous voulez exécuter une boucle sans fin, ou vous n'êtes pas sûr de ce que condition doit être
remplie pour compléter la boucle, ou si vous avez plusieurs conditions qui doivent être remplies pour sauter hors de la
boucle. commande « End » Utilisation (Menu: Débogueur → Fin du programme) pour fermer cet exemple.

Manuel de Fin de Boucles sans Fin


Si vous utilisez des boucles dans votre programme, il peut parfois arriver que vous avez créé, par inadvertance,
une boucle infinie. Cela peut être un problème pour notre programme, parce que ces boucles bloquent tout le
programme jusqu'à ce qu'ils soient terminés. Le plus grand mal de tête prépare la fin d'un programme dans lequel
l'exécution d'une boucle continue.

L'IDE PureBasic le fait facilement pour vous. Si vous voulez arrêter un programme manuellement, appuyez sur le
bouton « Quitter le programme » sur la barre d'outils ou utilisez la commande de menu « Menu: Débogueur → Exit
Program ». Cette commande se termine non seulement la boucle, mais l'ensemble du programme.

Boucles de Régulation avec « Break » et « Continue »


Toutes ces boucles peuvent être contrôlées par deux mots-clés à tout moment. Ces deux mots clés sont « Break » et
« Continue ». Tout d'abord, je vais vous expliquer « Break ». Si la touche « Break » agit à tout moment dans une
boucle, et la boucle est immédiatement quittée pour atteindre le mot clé. Pour boucles imbriquées, il y a un
paramètre optionnel derrière le mot-clé « Break ». Avec elle, le nombre de boucles peut être définie. Regardons un
exemple avec mot-clé le « Break »:
46 Conditions et les Boucles

For x = 1 To 10
If x = 5
Break
EndIf
Debug x
Next x

Dans cette boucle « For » sortie de la boucle prématurée avec mot-clé le « Break » (si « x » « 5 » est la même chose).
Vous remarquerez qu'il annule la boucle avant d'écrire dans la fenêtre débug « 5 ». Voici un exemple de finition de
boucles imbriquées avec les paramètres optionnels pour le mot clé le « Break »:

For x.i = 1 To 10
Compteur.i = 0
Repeat
If x = 5
Break 2
EndIf
Compteur + 1
Until Compteur > 1
Debug x
Next

Dans cet exemple, les deux boucles sont quittées quand « x » « 5 » est déclenchée par l'instruction « Break 2 ».

Ensuite, le mot-clé « Continue ». Cela permet à tout moment pour eux d'interrompre le courant à travers la boucle,
et d'initier la passe suivante dans la boucle courante pour commencer. Cela est plus facile qu'il n'y paraît:

For x.i = 1 To 10
If x = 5
Continue
EndIf
Debug x
Next

Si « x » est égal à « 5 » (la cinquième passe), dans cet exemple, le mot-clé « Continue » est utilisé. À ce stade, le
cinquième cycle est interrompu et la boucle recommence au début de la sixième piste, puis a participé à la « x » la
valeur « 6 ». En raison de ce saut et la poursuite de la boucle, la valeur « 5 » ne sera pas libéré dans la fenêtre Debug
« x » commande du saut au début de la boucle se produit avant.

Les boucles peuvent être utilisées dans la programmation informatique pour beaucoup de choses, principalement pour
réduire le temps de travail du code et de parcourir rapidement de grandes quantités de données. J'espère que vous
avez une bonne idée de la façon dont ils sont utilisés.
Autres Structures de Données 47

5. Autres Structures de Données


Dans ce chapitre, nous expliquerons comment créer et utiliser d’autres méthodes de stockage et d’organisation des
données, telles que les structures définies par l’utilisateur, les tableaux et les listes chaînées. De telles structures de
données sont essentielles pour la programmation d'applications et de jeux, car elles permettent un accès plus facile et
plus rapide à de multiples valeurs de données liées et non liées. Comme toujours, des explications complètes et de
nombreux exemples sont donnés.

Structures
Dans le chapitre 2, je vous ai expliqué les types intégrés (octet, caractère, Word, Long, Entier, quad, float, double et
string). Avec le mot-clé « Structure » vous donne la possibilité de concevoir votre propre type de données structurées et
attribuer ensuite une variable. Pour créer votre propre variable structurée est assez simple, puisque vous résumez
seulement un ensemble de nom de la variable commune sous le nom d'une structure. Toto? Alors regardons un exemple
de structure avec plusieurs champs:

Structure Coordonnées
Prénom.s
Nom.s
Maison.s
EndStructure

Me. Coordonnées
Me\Prénom = "Gary"
Me\Nom = "Willoughby"
Me\Maison = "Appart"
Debug "Prénom: " + Me\ Prénom
Debug "Nom: " + Me\Nom
Debug "Maison: " + Me\Maison

Ici, la structure « Coordonnées » créé avec le mot-clé « structure » . Ensuite, les éléments de structure ont été définis
avec précision pour définir les variables normales. Le mot-clé « EndStructure » marque la fin de la nouvelle structure.
Après que la structure a été déclarée, elle est prête à l'emploi. Nous avons une variable de ce type structuré comme la
façon dont nous rejetons tout autre type. Comme ceci:

Me. Coordonnées

Voici le nom de la variable « Me » et vous tapez « Coordonnées ». Pour les variables individuelles (parfois appelées
champs), à attribuer dans la structure « Me » des valeurs variables, nous utilisons le caractère « \ ». Si vous regardez le
grand exemple ci-dessus, vous voyez que le caractère « \ » est également utilisé pour lire les données des champs
individuels. Comme ceci:

Pere.Coordonnées
Pere\Prénom = "Pierre"
Debug Pere\Prénom

Dans ce petit exemple, nous crérons une nouvelle variable structurée nommée « Père » avec le type structuré défini par
l'utilisateur « Coordonnées ». Nous avons le « Prénom » champ dans la variable « Père » à la valeur « Pierre ». Ensuite,
nous entrons dans cette valeur dans la fenêtre débug.

Cela ne vous frappe peut-être pas encore, mais les structures sont des choses incroyablement utiles. Dans les
applications, ils peuvent aider à définir n'importe quoi, des enregistrements personnels aux coordonnées de la fenêtre.
Dans les jeux, ils peuvent être utilisés pour définir des puces, des vaisseaux spatiaux ainsi que toutes les valeurs
associées.
Considérations Relatives à la Mémoire
La taille d'une variable structurée dans la mémoire est définie à l'intérieur de la structure initiale en fonction des
grandeurs de champ. Dans la structure « Coordonnées » trois variables sur le terrain ont été définies par type chaîne,
chacun occupant 4 octets dans la mémoire (voir Fig. 3 dans le chapitre 2 de l'attribution de types de chaînes). Par
conséquent, la variable « Me » 12 octets occupés (3 x 4 octets) dans la mémoire. nous pouvons vérifier si nous
montrons « SizeOf » la valeur de retour de la commande l'ensemble.
48 Autres Structures de Données
Structure Coordonnées
Prénom.s
Nom.s
Maison.s
EndStructure

Debug SizeOf(Coordonnées)

Voici « Sizeof() » retourne la valeur « 12 », ce qui correspond à la valeur en octets, à la structure en mémoire occupée.

La Commande « sizeof() »

Cette commande retourne la taille de chaque structure ou variable définie en octets. Il ne fonctionne pas avec des
tableaux, des listes ou des interfaces. Cette commande est d'une valeur inestimable pour la programmation
Windows, comme certaines fonctions API Win32 nécessitent la taille d'une structure ou d'une variable particulière
en tant que paramètre. Dans le chapitre 13, vous apprendrez plus sur l'API Windows (API Win32).

Hériter d'Autres Structures


champs Structures d'autres structures au moyen du « extends » mot-clé Hériter.

Structure Coordonnées
Prénom.s
Nom.s
Maison.s
EndStructure

Structure Détails Extends Coordonnées


Address.s
Pays.s
CodePostal.s
EndStructure

Utilisateur.Détails
Utilisateur\Prénom = "John"
Utilisateur\Nom = "Smith"
Utilisateur\lieu = "Caen"
Utilisateur\Adresse = "Rue de Liberté"
Utilisateur\Pays = "FR"
Utilisateur\CodePostal = "14000"

Debug "Utilisateur Prénom: " + Utilisateur\Prénom


Debug "Utilisateur Nom: " + Utilisateur\Nom
Debug "Utilisateur Lieu: " + Utilisateur\lieu
Debug "Utilisateur Adresse: " + Utilisateur\Adresse
Debug "Utilisateur Pays: " + Utilisateur\Pays
Debug "Utilisateur CodePostal: " + Utilisateur\CodePostal

Dans cet exemple, étend la structure « Détails » la structure « Coordonnées ». Lors de la création de la structure
hérite de tous les champs de la structure « Détails ». Ces champs apparaissent en haut de la nouvelle structure.
Ce type structuré nouvellement créé, nous avons la variable « Utilisateur » Ensuite, nous avons tous les champs à des
valeurs « Utilisateur » et vérifier ceux-ci, où nous passons les valeurs dans la fenêtre Debug

Structure des Associations (Union Structure)


associations structurelles doivent enregistrer un stockage d'opportunité en intégrant plusieurs variables dans une
structure qui utilisent la même zone de mémoire. Le sujet est susceptible de progresser un peu à l'heure actuelle,
comme vous le comprenez, mais pour être complet je l'ai ajouté à ce stade. Si vous lisez le chapitre 13 (pointeur), vous
comprendrez mieux comment structurer le travail des organisations. Voici un exemple simple:
Autres Structures de Données 49

Structure UNIONSTRUCTURE
StructureUnion
un.l
deux.l
trois.l
EndStructureUnion

Debug SizeOf(UNIONSTRUCTURE)

UnionVariable.UNIONSTRUCTURE

UnionVariable\un = 123
Debug UnionVariable\un

UnionVariable\Trois = 456
Debug UnionVariable\un

Après la déclaration de la structure « UnionStructure » nous avons utilisé les mots-clés « StructureUnion » et
« EndStructureUnion » utilisés pour encapsuler les variables à utiliser la même zone de mémoire. Si nous executons ce
code en retour, la première instruction de débug «4» (octets). Cela résulte du fait que les trois variables partagent le
même emplacement de mémoire au sein de la structure, et donc que la taille d'une variable longue est retournée.

De plus dans le programme, nous créons la variable « UnionVariable » type « UnionStructure » et ont la « UnionVariable
\Un » champ réglé sur « 123 » et puis donner le contenu de ce champ de la fenêtre Debug. Ensuite, nous avons une
valeur tout à fait nouvelle dans le champ de la variable « UnionVariable\Trois », mais parce qu'il a le même espace que
les autres domaines, nous pouvons accéder avec les noms de champs différents à cette valeur. Dans ce cas, nous
rentrons dans la valeur de « UnionVariable\One » dans la fenêtre Debug, et comme on pouvait s'y attendre, la valeur
commune de « UnionVariable\Trois.

Les structures peuvent également contenir ce qui est connu comme un tableau statique, mais je dois d'abord déclarer le
tableau avant de pouvoir appliquer ces connaissances aux structures. Les tableaux et les tableaux statiques sont
expliqués en détail dans le chapitre suivant.

Arrays (Tableaux)
Dans PureBasic une matrice peut contenir une quantité définie par l'utilisateur de variables du même type. variables
individuelles dans le réseau sont traités par l'intermédiaire d'un index qui se compose d'une gamme croissante de
nombres entiers. Les tableaux peuvent (non seulement Pure Basic types standard) sont construits avec des types
structurés. Ce chapitre vous montre tout ce que vous devez savoir sur les tableaux de PureBasic.

Mot-Clé « Dim »
Les tableaux dans PureBasic sont créés à l’aide du mot clé « Dim », comme dans cet exemple:

Dim LongArray.l(2)

Permettez-moi de vous expliquer cette ligne de code plus en détail. Tout d'abord, nous utilisons le mot-clé « Dim » pour
dire au compilateur que nous voulons mettre un tableau. Ensuite, nous donnons un nom au tableau, je nomme
l'imagination « LongArray » sélectionné ici. Après le nom que nous avons le tableau, comme des variables normales, en
utilisant un suffixe de type « .l » pour définir qu’il s’agit d’un tableau de type Long. Une fois le type défini, nous devons
définir le nombre d'indices que ce tableau doit contenir. Nous utilisons des parenthèses pour définir le dernier numéro
d’index. Dans l’exemple ci-dessus, nous avons utilisé un « 2 » pour définir le dernier index. Cela donne donc trois
indices à notre nouveau tableau, car les index de tableau commencent toujours à zéro. Une fois que le tableau a été
créé, chaque index contient une variable Long.

Ce simple tableau est aussi appelé un tableau à une dimension, car il ne nécessite qu'un index à chaque élément
contenu dans celui-ci d'attribuer une valeur ou récupérer. Dans cet exemple étendu, nous créons un tableau et
assignont les valeurs des indices individuels:

Dim LongArray.l(2)

LongArray(0) = 10
LongArray(1) = 25
LongArray(2) = 30
50 Autres Structures de Données

Debug LongArray(0) + LongArray(1)


Debug LongArray(1) * LongArray(2)
Debug LongArray(2) - LongArray(0)

Après nous avons attribué les valeurs que nous donnons quelques tests avec les données stockées dans les valeurs
des indices dans la fenêtre Debug. Le premier résultat de sortie est, par exemple, le calcul de « + 10 25 », dont les
valeurs stockées dans les indices de s correspond à « 0 » et « 1 ». Ensuite, les résultats de « 25 * 30 » et « 30 - 10 »
sont affichés. Les indices de tableau peuvent également être représentés par des variables ou des expressions.

DernierIndex.l = 2
PremierIndex.l = 0
Dim StringArray.s(DernierIndex)

StringArray(PremierIndex) = "on est un et tout seul"


StringArray(PremierIndex + 1) = "Deux, deux, garcon Sympa"
StringArray(PremierIndex + 2) = "Trois, Trois, Rivaux"

Debug StringArray(PremierIndex)
Debug StringArray(PremierIndex + 1)
Debug StringArray(PremierIndex + 2)

Ici, nous avons défini un tableau avec trois indices et chacun contient une variable de chaîne (note ci-joint le suffixe
» .S sur le nom du tableau en ligne avec la commande « Dim »). Nous avons utilisé la variable « DernierIndex » au
dernier index du tableau à définir. Ensuite, nous avons la variable « PremierIndex » utilisé pour assigner une chaîne au
premier index du tableau. Dans les assignations ultérieures, nous avons alors utilisé des expressions à l'aide de
l'opérateur plus. La même technique (expression comme index utilisé) a été utilisée pour déterminer les valeurs de
chaque index du tableau dans l'affichage de la fenêtre Debug. Voir la Fig. 16 pour une représentation graphique des
tableaux ci-dessus.

Tableau de Chaînes Une Dimension

index valeur
0 L'un est pas

1 Deux extrémités a la saucisse

2 Trois sont toutes les bonnes choses

La figure 16.

Parce que les tableaux sont bien rangés au moyen d'indices, il est très facile de passer à travers et très rapidement par
boucles. Pour vous mettre en appétit, voici un tableau exemple de milliers d'indices, dont chacun se voit attribuer une
valeur au moyen de la boucle. nous donnons ensuite une seconde boucle « For »pour tous les index dans la fenêtre
Debug.

Dim TestArray.i(999)

For x = 0 To 999
TestArray(x) = x
Next x

For x = 0 To 999
Debug TestArray(x)
Next x

Commencez cet exemple et voir la fenêtre Debug. Comme vous pouvez le constater, avec les tableaux, il est très
rapide de définir et d’obtenir même mille valeurs.

Tableaux Multidimensionnels
La meilleure façon de décrire un tableau multidimensionnel, est comparée à une table qui contient des colonnes et
des lignes. Pour créer un tableau multidimensionnel, il vous s uffit de définir le nombre de colonnes et de lignes que
vous avez besoin. Dans l'exemple suivant, nous allons créer un tableau « animaux », qui a trois indices, et chacun
de ces trois indices a trois autres indices.
Autres Structures de Données 51

Dim Animaux.s(2, 2)

Animaux (0, 0) = "Mouton"


Animaux (0, 1) = "4 Pattes"
Animaux (0, 2) = "Beee"
Animaux (1, 0) = "Chat"
Animaux (1, 1) = "4 Pattes"
Animaux (1, 2) = "Miaou"
Animaux (2, 0) = "Perroquet"
Animaux (2, 1) = "2 Pattes"
Animaux (2, 2) = "Hurler"

Debug Animaux (0, 0) + " a " + Animaux (0, 1) + " et dit " + Animaux (0, 2)
Debug Animaux (1, 0) + " a " + Animaux (1, 1) + " et dit " + Animaux (1, 2)
Debug Animaux (2, 0) + " a " + Animaux (2, 1) + " et dit " + Animaux (2, 2)

Après avoir défini le tableau, nous indiquons les valeurs de l'indice. Depuis le tableau « animaux » de deux indices par
lesquels les données sont assignées et la lecture fait référence à ce type de tableaux sous forme de tableaux en deux
dimensions. tableau à deux dimensions peut facilement être comprise si une correspondance dans une table de
colonnes et de lignes. Fig. 17 montre le tableau « animaux » d'une manière similaire à celle de la Fig. 16 qui montre la
matrice à une dimension. Il montre les colonnes et les lignes, qui permettent l'accès aux champs individuels du tableau à
deux dimensions en utilisant les indices.

Tableau à Deux Dimensions de Chaînes

index 0 1 2

0 mouton 4 pattes Beee

1 chat 4 pattes miaou

2 perroquet 2 pattes hurle

La figure 17.

Si nous utilisons la figure. 17 comme référence, nous pouvons voir combien il est facile d'accéder aux valeurs des
différents indices. Si vous z. B. fenêtre Debug affiche la valeur de l'indice de numéro d'index « 1 » et la colonne « 2 »
dans le débogage, il suffit de taper:

Debug Animaux(1, 2)

Cette sortie devrait le texte « Miaou ». Si vous souhaitez remplacer un numéro, vous pouvez le faire:

Animaux(0, 0) = "2 pieds"


Animaux(0, 1) = "3 pattes"
Animaux(0, 2) = "hurle"

Ceci remplace les chaînes "Mouton", "4 pattes" et "Beee" par "Trois pattes", "3 pattes" et "Oo-la" dans l'index des lignes.
"0" dans le tableau "Animaux". La figure 17 ressemble maintenant à la figure 18, remarquez la première ligne modifiée.

Tableau à Deux Dimensions de Chaînes (Modifié)

index 0 1 2

0 3 pieds 3 pattes hurle

1 chat 4 pattes miaou

2 perroquet 2 pattes Beee

La figure 18.

Une autre façon de tableaux multidimensionnels est de décrire de considérer cela comme des tableaux dans des
tableaux. Imaginez que chaque index de tableau contient un autre tableau et vous avez un tableau multidimensionnel.
Combien de tableaux inclus dans chaque indices, dépend de la façon dont le tableau a été défini au début.
52 Autres Structures de Données

Dans l'exemple suivant, je vais vous montrer comment un, deux, trois, quatre et tableaux à cinq dimensions définies.

Dim Animaux.s(5)
Dim Animaux.s(5, 4)
Dim Animaux.s(2, 5, 3)
Dim Animaux.s(1, 5, 4, 5)
Dim Animaux.s(2, 3, 6, 2, 3)

Après deux dimensions, les choses commencent à devenir un peu difficiles à comprendre, mais si vous gardez à l'esprit,
le tableau dans une explication de tableau, vous devriez être capable de résoudre le problème. Même si le nombre
maximal de dimensions pouvant être affectées à un tableau est de deux cent cinquante cinq « 255 », l'utilisation de
tableaux sur deux ou trois dimensions est inhabituelle dans les pratiques de programmation quotidiennes.

Les Tableaux avec des Types Structurés


Jusqu'à présent, nous avons vu comment créer différents tableaux avec les types standard Pure Basic, mais nous
pouvons aussi créer des tableaux avec des types structurés définis par l'utilisateur. Regardez cet exemple simple d'un
tableau à une dimension:

Structure Poissons
Gentil.s
Poids.s
Couleur.s
EndStructure

Dim Aquarium.Poissons(2)

Aquarium(0)\Gentil = "Poisson Clown"


Aquarium(0)\Poids = "125gr"
Aquarium(0)\Couleur = "Rouge, Blanc et Noir"
Aquarium(1)\Gentil = ""poisson Boite""
Aquarium(1)\Poids= "35gr""
Aquarium(1)\Couleur = "Jaune"
Aquarium(2)\Gentil = "Hippocampe"
Aquarium(2)\Poids = "65gr"
Aquarium(2)\Couleur = "Vert"

Debug Aquarium(0)\Gentil+" "+ Aquarium(0)\Poids+" "+ Aquarium(0)\Couleur


Debug Aquarium(1)\Gentil+" "+ Aquarium(1)\Poids+" "+ Aquarium(1)\Couleur
Debug Aquarium(2)\Gentil+" "+ Aquarium(2)\Poids+" "+ Aquarium(2)\Couleur

Ici, nous créons après que nous avons défini la structure « poissons » et utiliser « poissons » comme un type en
utilisant le mot-clé « Dim » et un tableau. Cela se fait de la même manière que nous avons assignés un Tableau (string)
comme type de « Poissons ». j'ai uilisé « 2 » comme dernier index de tableau. attribuer des valeurs à chaque index est
incroyablement facile. Nous associons simplement la syntaxe de l'affectation de tableaux et structures, comme celle-ci:

Aquarium(0)\Gentil = "Poisson Clown"

Décomposons cela en morceaux faciles à comprendre. Le premier est le nom du tableau, dans ce cas-ci il s’agit de, «
Aquarium.Poissons ». Vient ensuite l’index actuel contenu entre parenthèses dans ce cas, l'index « 0 ». Ensuite, nous
utilisons le caractère « \ » pour accéder au champ « Gentil » dans la structure « Poissons ». qui a été attribué au tableau
« Aquarium.Poissons ». Nous utilisons ensuite l’opérateur « = » pour attribuer une valeur de chaîne à ce champ, c'est
très Simple! Pour récupérer la valeur que nous venons d’attribuer, nous utilisons simplement la même syntaxe, mais
sans la partie affectation, comme ceci:

Debug Aquarium(0)\Gentil

Si nous voulons assigner ou lire une valeur d'un autre index, nous le faisons comme dans un tableau:

Debug Aquarium(0)\Gentil
Debug Aquarium(1)\Gentil
Debug Aquarium(2)\Gentil

Dans cette liste de champs « Structure Poissons » avec tous les index des tableaux « Aquarium.Poissons ». Pour
affecter les autres champs ou pour les lires, nous utilisons leurs noms:
Autres Structures de Données 53

Debug Aquarium(1)\Gentil
Debug Aquarium(1)\Poids
Debug Aquarium(1)\Couleur

Ici, nous donnons tous les champs avec l'index « 1 » dans la fenêtre Debug. ce que représente graphiquement le
tableau des « Aquarium.Poissons » et pour mieux comprendre les choses voir la figure Fig 19,

Tableau de Types Structuré à Une Dimension

index Structure «Poissons »

0 Type: PoissonClown poids: 120 gr couleur: Rouge, blanc et noir

1 Type: poisson boîte poids: 30 gr couleur: jaune

2 Type: hippocampe poids: 60 gr couleur: vert

Figure 19.

Comme les tableaux de type standard, vous pouvez également définir des tableaux multidimensionnels avec des types
structurés. Vous avez accès à chaque structure unique dans chaque index de champs de tableaux multidimensionnels.
tableaux structurés multidimensionnels sont créés de la même manière que des tableaux structurés unidimensionnels.
Nous ajoutons simplement plus de dimensions.

Voici un exemple de la façon dont un réseau structuré en deux dimensions est défini: Structure Poissons

Structure Poissons
Gentil.s
Poids.s
Couleur.s
EndStructure

Dim Aquarium.Poissons (2, 2)


...

Je vais ajouter maintenant aucun autre code de plus à ce tableau à deux dimensions, car cela dépasse le
cadre. Ils regardent plutôt à la figure. 20 dans un tableau structuré en deux dimensions fictive est montré.

Tableau Structuré à Deux Dimensions

index 0 1 2

Type: PoissonClown Type: poisson boîte Type: hippocampe


0 poids: 120 g poids: 30 gr poids: 60 g
couleur: Rouge, blanc et noir couleur: j aune couleur: vert
Type: poisson perroquet Type: scalaire Type: crevette
1 poids: 150 g poids: 120 gr poids: 30 g
couleur: rouge couleur: orange couleur: rose

Type: poisson rouge Type: poisson lion Type: requin


2 poids: 60 g poids: 240 gr poids: 2 kg
couleur: orange couleur: Noir et blanc couleur: gris

Figure 20

Pour obtenir une valeur de ce tableau de type, nous avons besoin de deux index et un nom de domaine:

Debug Aquarium(1,1)\Gentil

Ceci afficherait le texte « PoissonGentil » dans la fenêtre Debug.. Si nous voulons changer cela ou d'autres valeurs,
nous utilisons la même méthode que lors de la lecture de cette zone du tableau:

Aquarium(1,1)\Gentil = “Poisson Filou”


Aquarium(1,1)\Poids = “125gr ”
Aquarium(1,1)\Couleur = “Rouge Foncé”
54 Autres Structures de Données

Cela change tous les champs de « Poissons » structure dans la zone centrale du tableau, avec l'index de position exacte
« 1, 1 ». Le résultat est représenté sur la figure 21. ,.

Tableau Structuré en Deux Simensions (Modifié)


index 0 1 2

Type: Poisson clown Type: poisson Type: hippocampe


0 poids: 120 gr boîte poids: 30 gr poids: 60 gr
couleur: Rouge, blanc et noir couleur: Jaune couleur: vert

Type: poisson Type: poisson Type: crevette


1 perroquet poids: 150 gr Filou poids: 180 gr poids: 30 gr
couleur: rouge couleur: pourpre couleur: rose
Type: poisson Type: poisson lion Type: requin
2 rouge poids: 60 gr poids: 240 gr poids: 2 kg
couleur: orange couleur: Noir et blanc couleur: gris
Figure 21.

Comme vous pouvez le constater, ces types de tableaux sont très pratiques, c'est un peu compliqué (surtout si vous
commencez à travailler avec des tableaux en trois dimensions), mais la connaissance de leur fonction est très utile
pour votre programmation future.

Vous n'utiliserez probablement pour l'instant que des tableaux de types structurés unidimensionnels dans vos
programmes, mais pour savoir comment les tableaux de types structurés multidimensionnels fonctionnent, vous aurez
une bonne compréhension de code plus avancé.

Redimensionnement des Tableaux déjà Créés


tableaux standard dans PureBasic ne sont pas complètement statique, à savoir, ils peuvent être redéfinies de deux
façons différentes. La première est à nouveau d'utiliser le mot-clé « Dim », de sorte que le tableau est redéfinie.
Cependant, vous perdrez toutes les données déjà attribués. La deuxième option est d'utiliser le mot-clé « ReDim », qui a
redéfini le tableau sans détruire les données qu'il contient. montrant les deux comportements Voici deux exemples. Tout
d'abord, nous examinons la redéfinition de la commande « Dim »:

Dim Dogs.s(2)

Dogs(0) = "Jack Russell"


Dogs(1) = "Alaskan Husky"
Dogs(2) = "Border Collie"

Debug Dogs(0)
Debug Dogs(1)
Debug Dogs(2)

Dim Dogs.s(2)
Debug Dogs(0)
Debug Dogs(1)
Debug Dogs(2)

Après la création initiale du tableau et l’affectation des données, j’ai utilisé la commande « Dim » pour définir à nouveau
le tableau avec le même nombre d’indices que précédemment. Après la deuxième définition, vous remarquerez que la
commande « Debug » ne renvoient rien du tableau nouvellement défini. En effet, toutes les données ont été détruites
lors de la redéfinition. Cette destruction de données peut toutefois être utile. Par exemple, si je devais libérer la mémoire
utilisée par un tableau, je pourrais simplement le redéfinir avec zéro « 0 » comme index maximal qui libérerait toute la
mémoire qui lui est associée. Lorsque vous redéfinissez des tableaux de ce type, vous devez toujours les redéfinir en
utilisant le même type, sinon une erreur sera générée.

Voici un exemple dans lequel les données restent intactes, alors nous vous commandons de redéfinir le tableau
avec le mot-clé « ReDim »:
Autres Structures de Données 55

Dim Dogs.s(2)

Dogs(0) = "Jack Russell"


Dogs(1) = "Alaskan Husky"
Dogs(2) = "Border Collie"

For x.l = 0 To 2
Debug Dogs(x)
Next x

Debug ""

ReDim Dogs.s(4)

Dogs(3) = "Yorkshire Terrier"


Dogs(4) = "Greyhound"

For x.l = 0 To 4
Debug Dogs(x)
Next x

Ici, je l'ai utilisé la commande « ReDim » pour redéfinir le tableau, mais cette fois je l'ai ajouté au tableau dans la
redéfinition deux indices supplémentaires. Après que je les deux nouveaux indices ( « 3 » et « 4 »), les valeurs affectées
et sortir le contenu de l'ensemble du réseau dans la fenêtre débug. Assurez-vous que les données de la première
génération ne sont pas perdus. mais elle doit faire attention. Si vous utilisez la commande « ReDim » avec un plus petit
nombre d'indices, puis marcher les données perdues dans les indices excédentaires. Si vous souhaitez modifier un
tableau multidimensionnel avec la commande « ReDim », vous ne pouvez changer la dernière dimension. Ceci est une
commande de base comme ce comportement par défaut.

Règles pour l'Utilisation des Tableaux


Même si les tableaux sont très flexibles, ils ont quelques règles à prendre en compte lors de leur utilisation. Vous
devez respecter ces règles lorsque vous utilisez des tableaux dans vos programmes.

1). Lorsqu'un tableau est redéfini / redéfini avec la commande « Dim », toutes les données contenues seront perdues.
2). Si un tableau est redéfini / défini avec la commande « ReDim », les données contenues sont préservées..
3). Les tableaux ne peuvent être créés qu'à partir d'un type de variable (type standard ou type structuré).
4). Les tableaux peuvent être globaux, protégés, statiques et partagés. Voir le chapitre 6 (Portées dans Programme)..
5). La taille d'un tableau n'est limitée que par la quantité de RAM installée.
6). Les tableaux multidimensionnels peuvent avoir jusqu'à 255 dimensions.
7). Les tableaux peuvent être définis dynamiquement, par variable ou par expression.
8). Lors de la définition de la taille d’une dimension, entrez uniquement le dernier numéro d’index (tous les index).commencez par « 0 »).
9). Les dimensions dans des tableaux multidimensionnels peuvent varier en taille.

Tableaux Statiques dans les Structures


Les tableaux statiques au sein des structures sont un peu différents des tableaux normaux décrits précédemment. Les
tableaux statiques dans leur nature même sont statiques et ne peuvent donc pas être modifiés tant qu'ils ont été définis.
Ces types de tableaux n'existent également qu'au sein de structures.

Les tableaux statiques ont également un ensemble de règles différent à prendre en compte lors de leur utilisation:

1). Quand un tableau statique a été définie dans une structure, il ne peut pas être changé.
2). tableaux statiques ne peuvent pas être redéfinis (comme des structures).
3). Ils ne peuvent être créés à partir d'un type de variable (type standard ou type structuré).
4). La taille d'un tableau est uniquement limité par la mémoire RAM.
5). les tableaux statiques ne peuvent avoir qu'une seule dimension.
6). La taille dimensionnelle peut être dynamiquement définie au moyen d'une variable ou une expression.
7). En tant que la taille de la dimension que vous définissez le nombre d'éléments, et non le dernier index.
8). tableaux statiques peuvent être traitées que par la variable de structure dans laquelle elles sont définies.

Donc, maintenant que je vous dois les principales règles, et il est un exemple de ce qu'ils sont utilisés:
56 Autres Structures de Données

Structure FAMILLE
Pere.s
Mere.s
enfant.s[2]
Surnom.s
EndStructure

Family.FAMILLE
Family\pere = "Peter"
Family\Mere = "Sarah"
Family\ enfant[0] = "John"
Family\ enfant[1] = "Jane"
Family\Surnom = "Smith"

Debug "Famille Membres:"


Debug Famille\Pare + " " + Famille\Surnom
Debug Famille\Mere + " " + Famille\Surnom
Debug Famille\enfant[0] + " " + Famille\Surnom
Debug Famille\enfant[1] + " " + Famille\Surnom

Ici dans cet exemple, la structure « FAMILLE » a un champ appelé « Enfant » qui est un tableau de chaînes statique.
Lorsque nous avons défini ce tableau, nous avons utilisé le nombre « 2 ». Ceci définit que ce tableau statique contiendra
deux index. Ce comportement est complètement différent des tableaux standard, avec lesquels vous définissez le
dernier index lors de la création. Dans notre nouveau tableau statique, nous avons maintenant deux index, « 0 » et « 1
», plus loin dans l'exemple, j'assigne des valeurs à tous les champs de la variable structurée « FAMILLE », y compris les
deux index du tableau statique « Enfant ». Vous remarquerez que les tableaux statiques ont une syntaxe légèrement
différente pour assigner et récupérer les données, ils utilisent des crochets au lieu des paranthèses habituelles.

Affectation de données à un tableau de chaîne statique (à l'aide de crochets):

Famille\enfant[0] = "John"

Affectation de données à un tableau de chaîne statique (à l'aide de paranthèses):

LongArray(0) = 10

Vous remarquerez également que vous n'avez pas besoin d'utiliser un mot-clé tel que « Dim » lorsque vous définissez
un tableau statique. Vous ajoutez simplement des crochets à la fin à la fin du nom du champ, vous définissez le nombre
d'index que vous souhaitez donner à ce tableau statique nouvellement créé. Dans la structure « FAMILLE » ci-dessus,
nous utilisons le type chaine pour créer un tableau statique mais vous pouvez utiliser n'importe quel type intégré de
PureBasic ou même utiliser une autre structure !

Regardons un autre exemple simple:

Structure EMPLOYEES
EmployeNom.s
EmployeNombreheure.l
EmployeAdresse.s
EmployeNuméroTel.l[2]
EndStructure

Dim Compagnie.EMPLOYEES(9)

Compagnie(0)\EmployeNom = "Bruce Dickinson"


Compagnie(0)\EmployeNombreHeure = 555
Compagnie(0)\EmployeAdresse = "22 Acacia Avenue"
Compagnie(0)\EmployeNuméroTel[0] = 0776032666
Compagnie(0)\EmployeNuméroMob[1] = 0205467746
Compagnie(1)\EmployeNom = "Adrian Smith"
Compagnie(1)\EmployeNombreHeure = 1158, , ,
Autres Structures de Données 57

Ici, je crée une structure définie par l'utilisateur appelée « EMPLOYEES » pour décrire un enregistrement d'employé
d'une petite entreprise, puis je crée un tableau standard pour contenir dix de ces enregistrements (souvenez-vous que
dans un tableau standard, vous définissez le dernier index et ces index commencent à « 0 »). A l'intérieur de la structure
« EMPLOYEES », j'ai utilisé un tableau statique long pour stocker deux numéros de téléphone de contact. J'ai alors
commencé à définir les enregistrements individuels d'employés commençant par « Company(0)\...» et puis sur «
Company(1)\...», etc. Je ne complète pas vraiment cet exemple parce que je ne veux pas m'attarder, mais vous pouvez
voir où je veux en venir et comment tout fonctionne.

NewList
Les Listes Liées sont similaires aux tableaux en ce sens qu'elles sont capables de se référer à un grand nombre de
données en utilisant un seul nom. Ils sont cependant différents des tableaux en ce sens qu'ils n'utilisent pas d'index pour
assigner et récupérer des données.

Ces listes sont comme un livre où vous pouvez feuilleter les données du début à la fin ou simplement tourner une page à
l'intérieur et lire les données à partir de là. Les listes liées sont également totalement dynamiques, ce qui signifie qu'elles
peuvent croître ou diminuer en fonction de la quantité de données que vous avez besoin qu'elles contiennent. Lorsque
vous augmentez la taille d'une NewList, vous n'endommagerez ni ne modifierez aucune des autres données qu'elle
contient et vous pouvez ajouter des éléments à la liste en toute sécurité dans n'importe quelle position nécessaire.

Les listes liées sont un excellent moyen de stocker et d'organiser des données d'une longueur inconnue et peuvent être
triées de plusieurs façons. Il y a aussi une bibliothèque intégrée de'Linked List' qui fournit des fonctions pour effectuer
des ajouts, des suppressions et des permutations d'éléments. A l'intérieur de la bibliothèque'Sort' intégrée, il y a aussi
deux fonctions qui sont utilisées uniquement pour trier les listes liées, je les mentionnerai plus tard. Un aperçu général et
une introduction aux commandes intégrées de PureBasic sont donnés plus loin dans le chapitre 7.

Mot Clé « NewList »


Listes liées à PureBasic sont créés en utilisant le mot-clé « NewList » comme dans cet exemple:

NewList Fruit.s()

Définir une NewList est très similaire à définir un tableau en utilisant la commande « Dim ». Tout d'abord, nous utilisons
le mot-clé « NewList » pour indiquer au compilateur que nous sommes sur le point de définir une NewList. Ensuite, nous
définissons un nom pour la nouvelle liste, dans ce cas nous l'avons appelé « Fruit ». Après qu'un nom a été donné, nous
définissons ensuite son type, qui dans ce cas encore est le type de chaîne. Les parenthèses sont ensuite utilisées pour
terminer la définition de la liste. Vous remarquerez dans ce petit exemple qu'il n'y a pas d'indices définis entre
parenthèses. C'est parce que les listes liées n'en ont pas besoin, elles sont dynamiques et vont grandir au fur et à
mesure que vous ajoutez des éléments. Voyons comment nous ajoutons des éléments à notre nouvelle liste, voici un
exemple plus complet :

NewList Fruit.s()

AddElement(Fruit())
Fruit() = "Banane"
AddElement(Fruit())
Fruit() = "Pomme"

Parce que les listes liées n'ont pas d'index, il peut sembler un peu étrange au premier abord de les utiliser parce que
vous ne savez peut-être pas où vous êtes dans la liste. Dans l'exemple ci-dessus, j'ai ajouté deux nouveaux éléments à
la liste « Fruits() ». Pour ce faire, j'ai utilisé la fonction « AddElement() » de la bibliothèque NewList intégrée. Lorsque
vous ajoutez un nouvel élément à l'aide de cette fonction, non seulement il définit automatiquement un nouvel élément,
mais il fait également pointer le nom de la NewList vers cet élément vide nouvellement créé. Donc nous utilisons juste
son nom pour assigner une donnée à la liste, remarquez que nous utilisons toujours les parenthèses :

Fruit() = "Banane"

Quand nous ajoutons un autre élément en utilisant la fonction « AddElement() » alors exactement le même processus a
lieu. Le nouvel élément est d'abord créé, puis le nom de la NewList pointe à nouveau vers l'élément vide nouvellement
créé. Nous ajoutons donc les données au nouvel élément exactement de la même manière :

Fruit() = "Pomme"
58 Autres Structures de Données

Note sur l'Utilisation du Terme « Point »

Dans cette introduction et explication de NewList, j'ai beaucoup utilisé le mot « point ». Quand je l'utilise ici, il ne
faut pas le confondre avec le terme informatique « point » ou « pointeurs ». Le terme informatique signifie pointer
vers une zone particulière de la mémoire ou, dans le cas d'un « pointeur », une variable qui contient une adresse
mémoire. Quand je l'utilise ici, surtout quand je dis que le nom de la NewList pointe vers l'élément courant, je
l'utilise dans un sens descriptif et non pas littéralement en pointant vers la zone en mémoire que cet élément
utilise. Pour plus d'explications sur les pointeurs (au sens informatique), voir le chapitre 13 (Pointeurs).

On pourrait penser que ce n'est pas correct parce que nous attribuons le texte « Pomme » au même nom que nous
avons attribué le texte « Banane », Parce que nous avons ajouté un nouvel élément, le nom de liste lié « Fruit() »
pointera vers le nouvel élément dans la liste. Nous pouvons également vérifier le nombre d'éléments de notre liste à tout
moment en utilisant la fonction « ListSize() » intégrée, comme ceci :

Debug ListSize(Fruit())

Si nous exécutons le code ci-dessus, le nombre d’éléments contenus dans la liste « Fruit() » sera affiché dans
la fenêtre Debug.. Dans ce cas, il s'agirait de « 2 ».

Ajoutons quelques éléments supplémentaires à cette liste et faisons ensuite l'affichage à toutes les valeurs des
éléments dans la fenêtre Debug.. Ici encore un exemple complet:

NewList Fruit.s()

AddElement(Fruit())
Fruit() = "Banana"

AddElement(Fruit())
Fruit() = "Apple"

AddElement(Fruit())
Fruit() = "Pear"

AddElement(Fruit())
Fruit() = "Orange"

ForEach Fruit()
Debug Fruit()
Next

Dans cet exemple plus large, nous créons une nouvelle NewList appelée « Fruit() » et nous y créons quatre éléments et
leur attribuons des valeurs individuelles. Nous bouclons ensuite cette liste à l'aide d'une boucle « Foreach » et faisons
affiché à toutes les valeurs de l'élément dans la fenêtre Debug. Le mot-clé « Foreach » est utilisé pour définir une
boucle qui n'est utilisée que pour les listes liées.

La Fig.22 donne un bref aperçu des commandes de liste liées disponibles dans la bibliothèque « NewList » intégrée. Ce
diagramme n'est pas une référence complète, mais il est inclus ici comme un bref guide pour voir quelle commande
utiliser lorsque le besoin s'en fait sentir. Les commandes les plus avancées se trouvent dans le fichier d'aide de
PureBasic.
Autres Structures de Données 59

Bibliothèque de la Liste Chaînée Intégrée


Fonctions Descriptions
AddElement (Liste()) Ajoute à la liste un élément.

ClearList (Liste()) Supprime tous les éléments de la liste.

ListSize (Liste()) Compter les éléments de la liste.

DeleteElement (Liste()) Supprime l'élément en cours dans la liste.

Firstélément (Liste()) Aller au premier élément de la liste.


InsertElement(Liste()) Ajoute un autre élément avant l'élément en cours ou au début
de la liste quand il est vide, a.

LastElement(Liste()) Passe au dernier élément de la liste.

Liste Index (Liste ()) Spécifie la position de l'élément courant de la liste avant
(positions d'élément de départ est de « 0 »).

NextElement(Liste()) Permet de passer à l'élément suivant dans la liste.

PreviousElement(Liste()) Déplacer à l'élément précédent dans la liste.

ResetList(Liste()) Définit la position de la liste à « 0 » et rend le premier élément


à l'élément courant.

SelectElement(List(), Position) Faire de l’élément actuel celui spécifié par le Paramètre « Position »..

Figure 22.

Listes Structurées
Maintenant que j'ai expliqué les listes de liens standard, passons aux listes de liens structurées. Ceux-ci sont très
similaires aux tableaux de types structurés en ce sens qu'ils sont définis avec une structure au lieu d'un type de variable
intégré. Vous pouvez alors avoir une liste de liens redimensionnés dynamiquement en se faisant passer pour un tableau
de types structuré qui se développe et se réduit en fonction des informations que vous avez à stocker. Jetons un coup
d'oeil à un exemple précédent, mais cette fois-ci, recodez-le pour utiliser une liste de liens structurés.

Structure Poissons
Gentil.s
Poids.s
Couleur.s
EndStructure

NewList Aquarium.Poissons()

AddElement(Aquarium())
Aquarium()\Gentil = "Poisson Clown"
Aquarium()\Poids = "125gr"
Aquarium()\Couleur = "Rouge, Blanc et Noir"

AddElement(Aquarium())
Aquarium()\Gentil = "poisson Boite"
Aquarium()\Poids= "35gr""
Aquarium()\Couleur = "Jaune"

AddElement(Aquarium())
Aquarium()\Gentil = "Hippocampe"
Aquarium()\Poids = "65gr"
Aquarium()\Couleur = "Vert"

ForEach Aquarium())
Debug Aquarium(0)\Gentil+" "+ Aquarium(0\Poids+" "+ Aquarium(0\Couleur
Next

Vous pouvez voir dans cet exemple qu'après avoir créé une liste, il est alors très similaire à un tableau de type structuré
pour affecter et récupérer des données. La principale différence ici est que les index de style des tableaux ne sont pas
utilisés. Rappelez-vous que lorsque vous utilisez la commande « AddElement(Aquarium()) » vous créez un nouvel
élément en utilisant la structure de la définition initiale. Cette commande déplace ensuite la position actuelle de la liste
vers cet élément nouvellement créé. Il est alors sûr d'affecter des données au nouvel élément structuré comme ceci :
60 Autres Structures de Données

Aquarium()\Gentil = "Poisson Clown"


Aquarium()\Poids = "125gr"
Aquarium()\Couleur = "Rouge, Blanc et Noir"

Puisque le nom « Aquarium() » pointe maintenant vers votre nouvel élément, il n'est pas nécessaire d'utiliser un index.
Pour accéder aux champs à l'intérieur de cet élément structuré, vous utilisez à nouveau le caractère « \ », A la fin de
l'exemple, une autre boucle « Foreach » est utilisée pour transmettre rapidement et efficacement les données à la fenêtre
Debug

Avantages et Inconvénients des Listes


Les listes liées sont idéales pour stocker des données lorsque vous ne savez pas combien il y en a. Par exemple, dans
le passé, j'ai écrit un programme de suivi des dépenses du ménage et j'ai utilisé une liste de liens structurée pour
conserver les détails de ces dépenses. L'utilisation d'une NewList plutôt que d'un tableau facilite l'ajout, la suppression et
le tri des données.

En écrivant ce programme, j'ai pensé que je devais rendre ce programme flexible pour gérer les nouvelles dépenses
lorsqu'elles surviennent et pour pouvoir supprimer les anciennes, juste au cas où j'achèterais une nouvelle voiture et/ou
rembourserais un prêt, etc. Ceci est très bien géré par les listes liées. Quand j'ai besoin d'ajouter une entrée, j'utilise la
fonction'AddElement()' et quand j'ai besoin de supprimer une entrée, j'utilise la fonction'DeleteElement()'. Une fois l'ajout
et la suppression effectués dans la liste, je transfère toutes ces données dans une interface utilisateur graphique (GUI)
avec laquelle l'utilisateur peut voir et interagir. Je parlerai plus en détail des interfaces graphiques au chapitre 9.

Les listes liées sont plus flexibles que les tableaux en ce sens qu'elles peuvent se développer et se réduire plus
facilement en taille, mais les tableaux utiliseront toujours moins de RAM pour stocker la même quantité de données que
les listes liées. C'est parce que les tableaux sont des zones de mémoire continues qui n'utilisent que la quantité standard
de RAM par type pour chaque index. Les listes liées sont différentes dans la mesure où chaque élément utilise environ
trois fois la quantité de RAM pour son type particulier. C'est parce que les listes liées ne sont pas dans le même morceau
continu de mémoire et ont besoin de stocker des informations sur où trouver les autres éléments dans la RAM. C'est
quelque chose à garder à l'esprit lorsque vous traitez d'énormes quantités de données car vos besoins en mémoire
pourraient être triplés si vous utilisez des listes liées.

Tri des Tableaux et des Listes


Les tableaux et les listes liées sont parfaits pour stocker toutes sortes de données et ces structures de données peuvent
être facilement parcourues pour récupérer rapidement ces données. Parfois, bien que vous ayez besoin de réorganiser
les données contenues dans un tableau ou une NewList, il est donc trié par ordre alphabétique ou numérique. Voici
quelques exemples d' utilisation des commandes de la bibliothèque « Sort » ((Fichier d'aide: Guide de référence →
bibliothèques générales - > Sort ) pour trier les tableaux et listes liées.

Tri d'un Tableau Standart


Le tri d'un tableau standard est extrêmement simple. Tout d' abord vous avez besoin d'un tableau pré-rempli de valeurs
puis utilisez la commande « SortArray() » pour obtenir son tri. Voici un exemple de syntaxe:

SortArray(Array(), Options [, Start, End])

Le premier paramètre est le tableau à trier, notez les parenthèses courbes après le nom du tableau, elles sont
nécessaires pour passer correctement un tableau en paramètre. Le deuxième paramètre est une option, pour spécifier
comment vous voulez que le tableau soit trié. Voici les options pour le deuxième paramètre :

« 0 »: Trier le tableau dans une direction ascendante et est le cas / minuscules (a <> A)
« 1 »: Trier le tableau dans le sens descendant et qui est le cas / minuscules (a <> A)
« 2 »: Trier la matrice dans une direction ascendante et n'a pas de cas / minuscules (a = a)
« 3 »: Trier le tableau dans le sens descendant et n'a pas de cas / minuscules (a = a)
Autres Structures de Données 61

Les crochets autour des deux derniers paramètres indiquent qu'ils sont facultatifs et n'ont pas besoin d'être spécifiés lors
de l'utilisation de cette commande. Ces deux derniers paramètres sont utilisés pour spécifier une plage de position de
tableau pour effectuer le tri à l'intérieur.

En utilisant les informations ci-dessus, nous pouvons trier un tableau complet dans l'ordre croissant et en tenant compte
de la case, en utilisant la commande comme ceci :

Dim Fruit.s(3)
Fruit(0) = "Banane"
Fruit(1) = "Pomme"
Fruit(2) = "Poire"
Fruit(3) = "Orange"

SortArray(Fruit(), 0)

For x.l = 0 To 3
Debug Fruit(x)
Next x

Tri de Tableaux Structurés


Ce processus est un peu plus compliqué et nécessite une commande de tri plus complexe: « SortStructuredArray() ».
Voici un exemple de syntaxe:

SortStructuredArray(Array(), Options, Offset, Type [, Start, End])

Le premier paramètre est le nom du tableau complet avec des parenthèses. La seconde est celle des options de tri, qui
sont exactement les mêmes que la commande « SortArray() ». Le troisième paramètre est un décalage (une position
dans la structure d'origine) de la zone que vous souhaitez trier. Ceci est récupéré en utilisant la commande « (OffsetOf)
». celle-ci retourne le nombre d'octets qu'un champ variable particulier a partir du début d'une structure. Le quatrième
paramètre définit quel type de variable se trouve à l'offset passé précédemment. Vous pouvez utiliser des constantes
intégrées pour le quatrième paramètre afin de décrire le type de variable que vous triez :

# PB_Sort_Byte Le champ de structure est à trier avec des octet (.b)


# PB_Sort_Word Le champ de la structure est à trier avec des nombres Word (.w)
# PB_Sort_Long Le champ de structure est à trier avec des nombres long (.l)
# PB_Sort_String Le champ de la structure est à trier avec des types chaîne ( .s ou $)
# PB_Sort_Float Le champ de la structure est à trier vec des nombres flottant (.F)
# PB_Sort_Double # Le champ de la structure est à trier avec des nombres double (.d)
PB_Sort_Quad Le champ de la structure est à trier avec des nombres quad (.q)
# PB_Sort_Character # Le champ de la structure à trier sont des Character (.c)
PB_Sort_Integer # Le champ de structure à trier est avec des nombres entier (.i)
PB_Sort_Ascii Le champ de la structure à trier sont des caractère ASCII (.u)
# PB_Sort_Unicode Le champ de la structure à trier sont des caractère Unicode (.u)

Les deux derniers paramètres de cette commande sont facultatifs et n'ont pas besoin d'être spécifiés lors de l'utilisation
de cette commande. Ceux-ci sont utilisés pour spécifier une plage de position de tableau pour effectuer le tri. En
utilisant les informations ci-dessus, nous pouvons trier un tableau structuré complet par ordre croissant et le trier par le
champ « Portee », comme ceci :

Structure ARME
Nom.s
Portée.l
EndStructure

Dim ARMES.ARME(2)

ARME(0)\Nom = " Fusil à plasma Phased "


ARME(0)\Portée = 40
ARME(1)\Nom = " Fusil de tireur d'élite SVD-Dragunov "
ARME(1)\Portée = 3800
ARME(2)\Nom = " Pistolet mitrailleur HK-MP5"
ARME(2)\Portée = 300
62 Autres Structures de Données

SortStructuredArray(ARMES(), 0, OffsetOf(ARME\Portée), #PB_Sort_Long)

For x.l = 0 To 2
Debug ARMES(x)\Nom + " : " + Str(ARMES(x)\Portée)
1H[W[

Dans cet exemple, j'ai choisi le champ « Portee » pour trier le tableau structuré par, donc dans la commande de tri j'ai
défini ceci en utilisant le décalage « OffsetOf (ARME \ Portée) » et en disant à la commande de tri que c'est un long
champ variable en utilisant la constante « #PB_Sort_Long ».

Trier une Liste Standard


Le tri d'une liste de liens standard est extrêmement simple. Tout d' abord vous avez besoin d'une NewList pré-remplie
de valeurs puis utilisez la commande « SortList() » pour la trier. Voici l'exemple syntaxique :

SortList(ListName(), Options [, Start, End])

Le premier paramètre est la NewList à trier, notez les crochets courbes après le nom de la liste, ceux-ci sont
nécessaires pour passer correctement la NewList en paramètre. La seconde est celle des options de tri, qui sont
exactement les mêmes que la commande « SortArray() ». Les deux derniers paramètres sont utilisés pour spécifier une
plage de position de NewList pour effectuer le tri.

En utilisant les informations ci-dessus, nous pouvons trier une liste complète de liens dans l'ordre croissant et en tenant
compte de la casse, en utilisant la commande de tri comme ceci :

NewList Fruit.s()

AddElement(Fruit())
Fruit() = "Banane"

AddElement(Fruit())
Fruit() = "Pomme"

AddElement(Fruit())
Fruit() = "Orange"
SortList(Fruit(), 0)

ForEach Fruit()
Debug Fruit()
Next

Trier d'une Liste Structurée


Trier une NewList structurée est légèrement plus compliqué car elle utilise une commande de tri légèrement plus
compliquée « SortStructuredList() ». Voici un exemple de syntaxe de cette commande :

SortStructuredList(List(), Options, Offset, Type [, Start, End])

Le premier paramètre est le nom de la NewList avec des parenthèses. La deuxième est celle des options de tri, qui sont
exactement les mêmes que la commande « SortArray() ». Le troisième paramètre est un décalage (une position dans la
structure d'origine) de la zone que vous souhaitez trier. Ceci est récupéré en utilisant la commande « (OffsetOf) ». Le
quatrième paramètre définit quel type de variable se trouve à l'offset passé précédemment. Vous pouvez utiliser des
constantes intégrées pour le quatrième paramètre pour décrire le type de variable que vous triez, elles sont exactement
les mêmes que la commande « SortStructuredArray() ». Les deux derniers paramètres sont utilisés pour spécifier une
plage de position de NewList pour effectuer le tri.

En utilisant les informations ci-dessus, nous pouvons trier une liste de liens structurée complète dans l'ordre
croissant, trier en respectant les majuscules et minuscules, comme ceci:

Structure FILLE
Nom.s
Poids.s
EndStructure

NewList MANNEQUIN.FILLE()
Autres Structures de Données 63

AddElement(FILLE())
MANNEQUIN()\Nom = "Mia"
MANNEQUIN()\Poids = "55 kilos"

AddElement(FILLE())
MANNEQUIN()\Nom = "Big Rosie"
MANNEQUIN()\poids = "60 kilos"

AddElement(FILLE())
MANNEQUIN()\Nom = "Sara"
MANNEQUIN()\poids = "52 Kilos"

SortStructuredList(MANNEQUIN(), 0, OffsetOf(FILLE\Nom), #PB_Sort_String)

ForEach MANNEQUIN()
Debug MANNEQUIN()\Nom + " : " + MANNEQUIN ()\Poids
Next

Dans cet exemple, je choisi le champ « Nom » pour trier cette liste de liens structurés, Je l’ai défini en utilisant le
décalage « OffsetOf (FILLE\ Name) » et en indicant à la commande qu’ il s’agit d’une Chaîne en utilisant la constante
« #PB_Sort_String ».

Trier Facilement
Tous les exemples de tri précédents peuvent être utilisés de la même manière pour trier tous les champs numériques
ainsi que les chaînes de caractères, il s'agit simplement de choisir la bonne option de tri en utilisant les différentes
commandes de tri. Le tri des tableaux et des listes liées, qu'ils soient créés à l'aide d'une structure ou non, n'est qu'un
cas d'utilisation des bonnes options et des bons décalages. Essayez vous-même quelques exemples pour vous
entraîner au tri à l'aide de ces commandes.
64 Procédures et sous-routines

6. Les Procédures et les Sous-Routines


Dans ce chapitre, je parlerai des procédures et des sous-programmes. Les procédures sont une partie essentielle de
tout langage de programmation et fournissent un moyen de structurer proprement le code et de permettre sa
réutilisation. PureBasic est considéré comme un langage de programmation structuré et les procédures fournissent les
moyens de créer la structure d'un programme. Je mentionnerai également les sous-routines dans ce chapitre mais elles
ne sont pas une caractéristique majeure dans de nombreux langages de programmation. Parce qu'ils jouent un rôle dans
PureBasic, ils sont mentionnés ici par souci d'exhaustivité.

Pourquoi Utiliser des Procédures et des Sous-Routines?


En théorie, je suppose qu'on n'a jamais besoin de procédures ou de sous-programmes. Vous pourriez simplement écrire
un très gros morceau de code, mais cela deviendrait très confus, très rapidement et je pense que vous vous répéteriez
plusieurs fois dans ce code mélangé. Les procédures et les sous-routines permettent d'appeler des morceaux de code
séparés à tout moment pendant votre code principal. Ces morceaux de code séparés peuvent être écrits pour faire
n'importe quoi. Par exemple, vous pouvez appeler une procédure pour jouer un son ou mettre à jour un affichage ou
même appeler une procédure qui contient un programme entièrement fonctionnel.

L'utilisation de procédures et de sous-programmes est un bon moyen de garder votre code propre et en ordre et de lui
donner une structure claire. Un code bien structuré est toujours préférable à lire plus tard, surtout si vous revisitez votre
code pour le peaufiner, ou si vous travaillez en équipe et que plusieurs personnes sont susceptibles de travailler sur le
même fichier.

Sous-Routines
Les sous-routines ne sont pas utilisées très souvent dans PureBasic et cerAutatirnse ls stesr cuocntsiudrèerens dt ec
omme un mauvais style de codage mais parfois elles peuvent être utiles si vous voulez ap peler rapidement du code.
Les sous-routines permettent de sauter à un autre morceau de code plus bas dans votre code source et de revenir au
point de saut après l'avoir exécuté. Pour sauter à un morceau de code séparé à l'aide de cette méthode, vous devez
spécifier un point vers lequel sauter. Cette destination de saut dans votre code est spécifiée à l'aide d'une étiquette de
sous-routine.

Pour spécifier une étiquette de sous-routine dans votre code, vous pouvez utiliser n'importe quel nom, mais vous devez
respecter les mêmes directives de nommage que pour les variables, sauf qu'au lieu d'utiliser un suffixe pour définir une
étiquette, vous utilisez un deux-points, comme ceci :

Label:

Ces sous-routines peuvent aller a l'étiquette de tout point dans votre code avec la commande « Gosub »:

Gosub Label

Notez dans la commande « Gosub » que nous n'utilisons pas de deux-points lorsque nous spécifions vers quelle
étiquette de sous-routine sauter. Après l'étiquette de destination, vous entrez le code PureBasic normal que vous
souhaitez que cette sous-routine exécute. Après ce code, vous devez ensuite spécifier que vous voulez revenir au code
principal en utilisant cette commande :

Return

Voici un petit exemple qui illustre l'utilisation d'un sous-programme:

a.l = 10

Debug a
Gosub Calcul
Debug a
End

Calcul:
a = a * 5 + 5
Return
Procédures et sous-routines 65

Dans cet exemple, nous donnons à la variable « a » la valeur « 10 » et nous l' affichons dans la fenêtre Debug. Nous
utilisons ensuite le mot-clé « Gosub » pour sauter au titre « Calcul: ». Vous pouvez dire que c'est un label par les deux
points après son nom et vous remarquerez probablement que l'IDE colore les étiquettes de saut différemment aussi.
Après avoir sauté à cette étiquette, un petit calcul est effectué sur la variable « a » et nous retournons au code principal
en utilisant le mot clé « Return ». Lorsque nous revenons au code principal, nous retournons à la ligne suivante juste
après la commande « Gosub » originale. Dans ce cas, nous retournons à la ligne « Debug a », qui fait affiché à la valeur
de « a » dans la fenêtre Debug. Cette valeur a maintenant changé en fonction du calcul effectué dans la sous-routine.

Note sur la Position de Sous-Routines dans votre Code


Une chose importante que je dois souligner ici est que si vous incluez des sous-routines à utiliser dans votre
programme, elles doivent toujours être après un mot-clé « End ». Celui-ci n'arrête pas seulement un programme
immédiatement lorsqu'il est exécuté, mais définit également le point final d'un programme pendant la compilation.
Toutes les sous-routines doivent apparaître après ce point pour que votre programme puisse fonctionner correctement.

Saut à Partir d'une Sous-Routine


Ceci est généralement considéré comme une très mauvaise pratique de codage, mais comme je parle de sous-
programmes, je peux aussi bien suivre le style du reste de ce livre et les décrire dans leur intégralité, ainsi que
mentionner la bonne syntaxe pour pouvoir le faire.

Comme toutes les sous-routines doivent contenir un mot-clé « Return » pour revenir au code principal, une sous-routine
doit être retournée prématurément afin de pouvoir la quitter correctement si vous devez sauter à tout moment. Ceci est
réalisé avec le mot-clé mal utilisé « Return » et « Goto ». En voici un exemple :

a.l = 10

Debug a
Gosub Calcul
Debug a
End

Recommence:
a.l = 20
Debug a
Gosub Calcul
Debug a
End

Calcul:
If a = 10
;FakeReturn
Goto Recommence
Else
a = a * 5 + 5
EndIf
Return

Comme vous pouvez le voir dans ce petit exemple, les choses ont commencé à se compliquer et le code saute partout,
comme je l'ai déjà dit, c'est un mauvais style de codage et fait du code très laid.

Cet exemple est assez simple si vous le suivez attentivement. Vous pouvez voir dans la sous-routine « Calcul » que
lorsque nous devons sauter en utilisant la commande « Goto », nous devons utiliser mal utilisé « Return » avant elle.
Nous sautons à une autre étiquette (sous-routine) appelée « Recommence » qui fait référence à un autre programme
presque autonome avec un autre mot-clé « End », ce qui n'est pas vraiment idéal.

J'espère que ces exemples vous donneront un aperçu des sous-programmes et de la façon de contourner les
programmes, mais j'espère que vous n'abuserez pas de ces pratiques et que vous ne les adopterez pas comme une
façon régulière de coder. Je pense que vous pouvez mieux structurer le code à l'aide de procédures.
66 Procédures et sous-routines

Comprendre les procédures


Le terme « programmation structurée » est un terme qui définit clairement PureBasic et les sentiments qui ont conduit à
sa création et son développement, qui défini très clairement PureBasic comme un langage de programmation «
procédurale » et « structurée ». L'architecture de la programmation structurée est fournie par des procédures. elles
forment littéralement la structure de la programmation structurée.

Les procédures (parfois appelées « Fonctions » dans d'autres langages) sont les fonctionnalités les plus importantes
fournies par PureBasic. Dans leur forme la plus élémentaire, ils ne sont qu'un support pour un morceau de code qui peut
être appelé (exécuté) à tout moment dans votre programme, très similaire aux sous-programmes. Ils peuvent être
appelés autant de fois que vous le souhaitez comme des sous-routines et ils peuvent contenir n'importe quel code
PureBasic que vous souhaitez. Contrairement aux sous-programmes cependant, les procédures peuvent recevoir
plusieurs paramètres de démarrage et peuvent même retourner une valeur de n'importe quel type intégré.

Commençons par un exemple simple de procédure:

Procedure Contine()
Debug "Marie avait un petit agneau, sa toison était blanche comme neige."
Débug "Et partout où Mary allait, cet agneau allait sûrement partir."
EndProcedure

Contine()

Pour utiliser une procédure dans votre code, vous devez d'abord la définir. Ici j'ai défini une procédure appelée «
Contine() » en utilisant le mot-clé « Procédure ». Le code est ensuite saisi après cette ligne que la procédure doit
contenir. La fin de la procédure est ensuite définie à l'aide du mot-clé « EndProcedure ». Nous pouvons appeler ce
morceau de code contenu dans cette procédure à tout moment en utilisant simplement son nom, comme ceci :

Contine()

Avant de poursuivre, j'aimerais souligner quelques éléments de cet exemple qui méritent d'être expliqués plus en détail.
Tout d'abord, vous avez peut-être remarqué qu'il y a un mystérieux ensemble de paranthèses après le nom de la
procédure. Ceux-ci sont utilisés pour contenir tous les paramètres qui doivent être transmis à la procédure. Même si vous
ne passez aucun paramètre, comme dans cet exemple, vous devez quand même inclure les parenthèses. De plus,
lorsque vous appelez la procédure, vous devez toujours inclure les parenthèses dans l'appel de procédure, les
paramètres ou aucun paramètre. J'expliquerai plus loin dans ce chapitre le passage des paramètres à une procédure.

Un autre point à souligner est que le nom de la procédure, par exemple « Contine() » ne doit pas contenir
d' espaces et doit respecter les mêmes directives de dénomination que pour les variables.

Si vous exécutez l'exemple ci-dessus, vous devriez voir dans la fenêtre Debug la contine comme codée dans la
procédure « Contine() ». Si vous voulez répéter ce code de procédure à n'importe quel moment dans ce petit exemple, il
suffit de l'appeler encore et encore en utilisant son nom.

Procedure Contine()
Debug "Marie avait un petit agneau, sa toison était blanche comme neige."
Débogage "Et partout où Mary allait, cet agneau allait sûrement partir."
EndProcedure

For x.l = 1 To 5
Contine()
Next x

Les procédures peuvent être appelées de n'importe où dans les programmes, comme dans l'exemple ci-dessus, où j'ai
appelé la procédure « Contine() » depuis une boucle. Les procédures peuvent également être appelées à partir d'autres
procédures.

Procedure Contine2()

Débogage "Et partout où Mary allait, cet agneau allait sûrement partir."
EndProcedure
Procédures et sous-routines 67

Procedure Contine1()
Debug "Marie avait un petit agneau, sa toison était blanche comme neige."
Contine2()
EndProcedure

Contine1()

Ici vous pouvez voir « Contine1() » appeler le contienu de. « Contine2() »

Note Concernant la Position des Procédures dans vos Codes


L'exemple ci-dessus montre clairement pourquoi la position des procédures dans votre code est importante. Vous
remarquerez que j'ai d'abord codé « Contine2() », puis « Contine1() ». C'était intentionnel et nécessaire parce qu'il faut
toujours définir une procédure avant de l'appeler. Parce que « Contine1() » appelle « Contine2() », ce dernier devait
d'abord être défini. Le compilateur PureBasic est connu sous le nom de compilateur « une seule passe », qui lit le code
source de haut en bas. Une erreur se produira s'il rencontre un appel de procédure et qu'aucune procédure n'a encore
été définie. Cet exemple simple montre aussi pourquoi les procédures sont définies en haut de la plupart des codes
sources. Comme pour la plupart des choses dans la vie, il y a cependant une exception à cette règle. Vous pouvez
utiliser le mot-clé « Déclare » pour modifier la position des définitions de procédure dans votre code. Le mot-clé «
Déclare » ne définit pas une procédure, il permet simplement au compilateur de savoir quelles procédures il sera invité à
appeler. Ceci permet de définir ultérieurement les procédures éventuelles dans le code source. En voici un exemple :

Declare Contine1()
Declare Contine2()

Contine1()

Procedure Contiane2()
Debug "Et partout où Mary allait, cet agneau allait sûrement partir."
EndProcedure

Procedure Contine1()
Debug "Marie avait un petit agneau, sa toison était blanche comme neige."
Contine2()
EndProcedure

Lorsque vous utilisez le mot-clé « Declare », vous définissez simplement la première ligne de la procédure, de la même
manière que lorsque vous utilisez le mot-clé « Procédure ». Vous êtes alors libre d'appeler cette procédure à tout
moment après cette déclaration. Comme il s'agit d'une simple déclaration et non d'une définition, vous devez également
définir la procédure comme normale ailleurs dans votre code. La procédure peut être définie n'importe où maintenant,
même à la fin de votre code source, au lieu du haut.

Si vous regardez l' exemple ci-dessus, vous pouvez voir que j'ai utilisé deux déclarations en utilisant le mot-clé
« Declare ». Après cela, je suis alors libre d'appeler la procédure « Contine1 ». Les définitions de la procédure se
trouvent à la fin du code.

Champs d'Application d'un Programme


Lorsque vous utilisez des procédures, il est également très important de comprendre les différentes portées
qu'un programme peut contenir. Ce terme fait référence à la portée dans laquelle une variable, un tableau ou
une NewList donnée est disponible pour être utilisée. Permettez-moi de commencer par expliquer cela à
l'aide d'un exemple simple à l'aide d'une variable.

a.l = 10

Procedure AfficheValeur()
Debug a
EndProcedure

AfficheValeur()

Ici, j'ai défini une variable de type long appelée « a » et lui ai assigné la valeur numérique'10'. J'ai également défini une
procédure appelée « AfficheValeur() » et dans cette procédure j' ai écrit une ligne de code pour faire affiché la valeur
« a ». La dernière ligne de cet exemple appelle la procédure. Maintenant, si vous exécutez cet exemple, vous vous
attendriez à ce que la valeur de « a » (qui est « 10 ») soit répercutée dans la fenêtre Debug mais ce n'est pas le cas.
Vous remarquerez que la valeur « 0 » est répétée à la place. Cela est dû à la portée du programme.
68 Procédures et sous-routines

Permettez-moi d'analyser cet exemple encore plus en détail et d'expliquer exactement ce qui se passe. La première
chose à retenir lors de l'utilisation des variables dans PureBasic est qu'elles sont par défaut de portée locale. Cela
signifie que dans l'exemple ci-dessus, lorsque la première définition de variable est « a.l = 10 », cette variable est locale
à la portée dans laquelle elle est définie, dans ce cas, locale au code source principal. Si cette variable n'est pas rendue
globale, aucune procédure ne pourra la voir ou l'utiliser.

Dans la procédure « AfficheValeur() » nous affichons la valeur de « a », mais cette variable « a » qui n'est pas la même
que celle qui est en dehors de la procédure. Ils portent le même nom mais ne sont pas la même variable. Celle à
l'intérieur de la procédure est locale à la procédure de sorte qu'aucune variable n'est accessible à l'autre.

Cela peut être très déroutant, surtout quand les deux variables locales, comme dans cet exemple, ont le même
nom, mais je pense que j'ai bien expliqué la situation locale d'une variable.

Comme je l'ai déjà dit, si la variable originale a été conçue pour être une variable globale, alors toutes les procédures
peuvent la voir et l'utiliser, laissez-moi vous montrer comment cela se fait.

Global a.l = 10

Procedure AfficheValeur()
Debug a
EndProcedure

AfficheValeur()

Ici, vous remarquerez que le seul changement que j'ai fait est que j'ai utilisé le mot-clé « Global » avant la définition de la
variable. Ceci définit maintenant la variable « a » comme globale et toutes les procédures peuvent maintenant voir et
utiliser cette variable. Dans la fenêtre Debug, vous verrez maintenant la valeur correcte est affichée « 10 ».

Inversement, si nous définissons des variables à l'intérieur d'une procédure, elles sont également considérées
comme locales à cette procédure. Regardez cet exemple:

Procedure AfficheValeur()
a.l = 10
EndProcedure

AfficheValeur()

Debug a

Comme prévu, la dernière ligne « Debug a » affiche la valeur « 0 » dans la fenêtre Debug. Si nous voulons voir et utiliser
la variable « a » en dehors de la procédure de définition, nous devons la rendre globale. Comme ceci :

Procedure AfficheValeur()
Global a.l = 10
EndProcedure

AfficheValeur()
Debug a

En lisant ces derniers exemples, vous vous demandez peut-être pourquoi ne pas rendre toutes les variables globales ?
Cela peut sembler logique pour certaines personnes, mais lorsque les programmes atteignent une plus grande échelle,
les choses peuvent devenir confuses et se mêler si toutes les variables sont globales. Vous pouvez également constater
que vous commencerez à manquer de noms de variables utiles. L'utilisation de différents champs distincts dans votre
programme vous permet également d'utiliser des noms de variables temporaires dans les procédures pour les calculs ou
les boucles, en sachant qu'elles n'affecteront aucune variable à l'extérieur. Certains programmeurs s'efforcent d'utiliser
aussi peu de variables globales que possible car cela rend le débogage d'un programme beaucoup moins difficile. Les
valeurs et les variables suspectes peuvent être réduites plus rapidement à une portée particulière si moins de variables
globales sont utilisées.
Procédures et sous-routines 69

Lorsque vous utilisez des tableaux et des listes liées avec des procédures, elles aussi peuvent avoir des portées
différentes dans votre programme exactement comme des variables. Jusqu'à PureBasic v4, tous les tableaux et listes
liées étaient globaux par défaut, ce qui garantissait qu'ils pouvaient toujours être manipulés par des procédures. Avec
l'arrivée de PureBasic v4, les tableaux et les listes liées peuvent être locaux, globaux, protégés et statiques exactement
de la même manière que les variables. Ils utilisent même les mêmes mots-clés de portée.

Dans la section suivante, j'ai énuméré tous les mots-clés de la portée et donné une explication complète pour chacun
d'entre eux ainsi que de nombreux exemples pour démontrer leur utilisation pour les variables, tableaux et listes liées.

Mot-Clé « Global »
Les Variables « Globales »
Je vous ai déjà donné un exemple du mot-clé « Global », mais comme je vous ai dit dans le champs d'application, mais
le voici encore pour compléter cette liste.

Global a.l = 10

Procedure AfficheValeur()
Debug a
EndProcedure

AfficheValeur()

Le mot-clé « Global » est utilisé avant une définition de variable pour rendre le champ d'application de cette variable
global. Une fois qu'une variable a été définie comme globale, cette variable peut être vue et modifiée dans toutes les
procédures que votre code source peut contenir. La syntaxe est très simple comme vous pouvez le voir dans l'exemple
ci-dessus.

« Global » avec « Arrays » (Tableaux)


Global Dim Nombres.l(1)

Procedure ChangeValeur()
Nombres(0) = 3
Nombres(1) = 4
EndProcedure

ChangeValeur()

Debug Nombres(0)
Debug Nombres(1)

Dans cet exemple, comme pour les variables globales, j'ai utilisé le mot-clé « Global » devant la définition du tableau
pour pouvoir y accéder dans la procédure. Sans le mot-clé « Global » devant le tableau, la procédure ne pourrait pas le
voir ou l'utiliser.

« Global » avec « NewLists »

Global Newlist Nombres.l()

AddElement(Nombres())
Nombres())= 1

Procedure ChangeValeur()
SelectElement(Nombres())1)
Nombres())= 100
EndProcedure

ChangeValeur()

SelectElement(Nombres, 1)
Debug Nombres()
70 Procédures et sous-routines

Dans cet exemple, similaire aux variables globales, j'ai utilisé le mot clé « Global » devant le tableau définition afin que je
puisse y accéder dans le cadre de la procédure. Sans le mot-clé « Global » devant le tableau, la procédure ne serait pas
en mesure de le voir ou de l’utiliser.

Mot-Clé « Protected »
Variables « Protected » (Protégées)
Le mot-clé « Protected » force une variable à être locale dans une procédure même si la même variable a été déclarée
comme globale dans le code source principal. Ceci est très utile pour définir des noms de variables temporaires dans
les procédures ou juste pour s'assurer que les variables de procédure n'interfèrent jamais avec aucune variable globale
dans le code principal.

Global a.i = 10

Procedure ChangeValeur()
Protected a.i = 20
EndProcedure

ChangeValeur()
Debug a

Vous pouvez voir que même si la variable protégée à l'intérieur de la procédure porte le même nom que la variable
globale, elles sont considérées comme des variables séparées dans deux domaines différents. Si vous exécutez
l'exemple ci-dessus, le résultat répercuté dans la fenêtre Debug sera « 10 » car même si nous appelons la procédure
« ChangeValeur() », la variable protégée ne modifie pas la variable globale. Ce mot-clé est essentiel pour écrire des
procédures génériques que vous avez l'intention d'utiliser dans une variété de codes sources différents afin de ne rien
interférer dans le code principal.

« Protected » avec « Arrays » (Tableaux)


Global Dim Zahlen.l(1)

Procedure AendereWert()
Protected Dim Zahlen.l(1)
Zahlen(0) = 3
Zahlen(1) = 4
EndProcedure

AendereWert()

Debug Zahlen(0)
Debug Zahlen(1)
Dans cet exemple, nous utilisons le mot-clé « Protected » exactement de la même manière que l'exemple de la variable
protégée. Si vous exécutez l'exemple ci-dessus, les résultats répercutés dans la fenêtre Debug seront « 0 » car même si
nous appelons la procédure « ChangeValeur() », le tableau protégé ne modifie en rien le tableau global. Ce mot-clé est
idéal pour protéger les tableaux au sein des procédures afin qu'ils n'interfèrent jamais avec le code principal même s'ils
portent le même nom que les tableaux globaux.

« Protected » avec « NewLists »


Global Newlist Nombres.l()
AddElement(Nombres())
Nombres = 1

Procedure ChangeValeur()
Protected Newlist Nombres.l()
AddElement(Nombres(
Nombres() = 100
EndProcedure

ChangeValeur()
SelectElement(Nombres(),1)
Debug Nombres()
Procédures et sous-routines 71

Encore une fois, si vous exécutez l'exemple ci-dessus, le résultat répercuté dans la fenêtre Debug sera « 1 » car même
si nous appelons la procédure « ChangeValeur() », la NewList protégée ne modifie pas la liste globale. Ce mot-clé est
idéal pour protéger les listes liées dans les procédures afin qu'elles n'interfèrent jamais avec le code principal même si
elles ont le même nom que les listes liées globales.

Mot-Clé « Shared »
Variables « Shared » (Partagées)
Parfois, dans votre code, vous pouvez avoir besoin d 'accéder à une variable de l'intérieur d'une procédure qui n' a pas
été définie comme globale. C'est à ce moment que le mot-clé « Shared » est utilisé. En voici un exemple :

a.i = 10

Procedure ChangeValeur()
Shared a
a = 50
EndProcedure

ChangeValeur()
Debug a

Ici, même si à l'origine « a » n'est pas défini comme global, vous pouvez toujours y accéder depuis l'intérieur d'une
procédure en utilisant le mot-clé « Shared ». Lorsque l'exemple ci-dessus est exécuté, la procédure « ChangeValeur() »
change la valeur de « a » même si ce n'est pas une variable globale.

« Shared » avec « Arrays » (Tableaux )


Dim Nombres.i(1)

Procedure ChangeValeur()
Shared Nombres ()
Nombres(0) = 3
Nombres(1) = 4
EndProcedure

ChangeValeur()

Debug Nombres(0)
Debug Nombres(1)

Dans cet exemple, même si le tableau « Nombres() » n'est pas défini comme global, je peux toujours y accéder depuis
la procédure « ChangeValeur() » en utilisant le mot clé « Shared ». Lorsque vous spécifiez quel tableau vous voulez
partager, vous n'avez qu'à spécifier le nom du tableau avec des paranthèses à la fin, comme ceci : « Nombres() », il
n'est pas nécessaire de spécifier le suffixe de type, les indices ou les dimensions.

« Shared » avec « NewLists

Newlist Nombres.i()

Procedure ChangeValeur()
Shared Nombres()
AddElement(Nombres())
Nombres() = 100
EndProcedure

ChangeValeur()

SelectElement(Nombres(), 1)
Debug Nombres()

Dans cet exemple, même si la NewList « Nombres() » n'est pas définie comme globale, je peux toujours y accéder depuis
la procédure « ChangeValue() » en utilisant le mot clé « Shared », très similaire à l'exemple du tableau partagé. Lorsque
vous spécifiez quelle NewList à partager, il vous suffit de spécifier le nom de la NewList avec des parenthèses à la fin,
comme ce « Nombres() », il n'est pas nécessaire de spécifier le suffixe de type.
72 Procédures et sous-routines

Mot-Clé « Static »
Variables « Static »
Chaque fois qu'une procédure se termine, toutes les valeurs de variables qui y sont définies sont perdues. Si vous
souhaitez qu' une procédure mémorise la valeur d' une variable après chaque appel, vous devez utiliser le mot-clé
« Static ». Voir cet exemple :

Procedure ChangeValeur()
Static a.i
a + i
Debug a
EndProcedure

For x.i = 1 To 5
ChangeValeur()
Next x

Ici, dans la procédure « ChangeValue() », j'ai défini la variable « a » pour être statique en utilisant le mot clé « Static ».
Après cela, j'augmente la valeur de « a » de « 1 », puis je fais écho à cette valeur dans la fenêtre Debug. J'appelle
ensuite cette procédure cinq fois en utilisant une boucle « For » standard. Si vous regardez les valeurs échangées, elles
sont toutes différentes et incrémentées de « 1 ». C'est parce que la valeur de « a » est mémorisée entre les appels de
procédure.

« Static » avec « Arrays » (Tableaux )


Vous pouvez également conserver intactes les valeurs du tableau entre les appels de procédure en utilisant le mot-clé
« Static ».
Procedure ChangeValeur()

Static Dim Nombres.l(1)


Nombres(0) + 1
Nombres(1) + 1

Debug Nombres(0)
Debug Nombres(1)
EndProcedure

For x.l = 1 To 5
ChangeValeur()
Next x

Dans l'exemple ci-dessus, j'ai utilisé le mot-clé « Static » pour préserver les valeurs du tableau entre les appels de
procédure dans exactement les mêmes que les variables statiques. Si vous regardez les valeurs échangées, elles sont
toutes différentes et incrémentées de « 1 ». C'est parce que les valeurs du tableau statique ont toutes été préservées
entre les appels.

« Static » avec « NewLists

Procedure ChangeValeur()
Static NewList Nombres.l()
If CountList(Nombres()) = 0
AddElement(Nombres())
EndIf
SelectElement(Nombres(), 1)
Nombres() + 1
Debug Nombres()
EndProcedure

For x.l = 1 To 5
ChangeValeur()
Next x

Dans cet exemple, j'utilise le mot-clé « Static » pour préserver les valeurs d'une liste liée entre les appels de procédure
exactement de la même manière que les tableaux statiques. Si vous regardez les valeurs échangées, elles sont toutes
différentes et incrémentées de « 1 ».
Procédures et sous-routines 73

Parce que cette NewList est statique et que je ne voulais ajouter qu'un seul élément pour les besoins de cet exemple, j'ai
utilisé une instruction « If » dans la procédure pour tester le nombre d'éléments dans la liste. Si la liste n'a pas
d'éléments alors j'en ajoute un, sinon je change juste la valeur de l'élément existant dans la liste liée statique. Si je ne
faisais pas ce genre de choses, je continuerais à ajouter des éléments à chaque appel de procédure, ce qui n'est pas ce
que je voulais.

Passer des Variables aux Procédures


Comme je l'ai déjà mentionné, l'une des capacités les plus utiles des procédures est qu'elles peuvent accepter les
paramètres initiaux de démarrage. Ces paramètres peuvent être des variables de n'importe quel type intégré, des
tableaux ou même des listes liées. Les paramètres sont utilisés comme un moyen de passer des valeurs du programme
principal dans n'importe quelle procédure de traitement. Les procédures peuvent ensuite être définies et utilisées à
plusieurs reprises tout au long du programme avec des valeurs de départ différentes. C'est ainsi que vous définissez une
procédure pour accepter les paramètres :

Procedure AddEnsemble(a.l, b.l)


Debug a + b
EndProcedure

AddEnsemble(10, 5)
AddEnsemble(7, 7)
AddEnsemble(50, 50)

Tous les paramètres qui doivent être passés à une procédure doivent être entre parenthèses et si plusieurs paramètres
sont nécessaires, ils doivent être séparés par des virgules. Lorsque des paramètres sont inclus dans la définition comme
ceci, ils doivent tous avoir leur type défini aussi. Ici, j'ai défini deux paramètres, « a » et « b », qui sont tous deux des
variables de type long.

Une fois qu'une procédure est définie comme celle-ci, vous devez vous rappeler d'inclure les valeurs que vous souhaitez
passer comme paramètres lorsque vous l'appelez, comme ceci :

AddEnsemble(10, 5)

Après cet appel particulier, la valeur « 10 » est passée dans la variable « a » et la valeur « a » dans la variable « b ». La
procédure additionne ensuite ces variables et affiche le résultat dans la fenêtre Debug. Ceci s'applique également à tous
les autres appels, la première valeur de paramètre de l'appel est passée en « a » et la seconde en « b ».

Voici un autre exemple qui utilise des chaînes:

Procedure JoinString(a.s, b.s)


Debug a + b
EndProcedure

JoinString("Mary avait un petit agneau, ", " sa toison était blanche comme neige.")
JoinString("Et partout où Mary est allée, ", " cet agneau allait sûrement partir.")
JoinString("..", "..")

Ici nous utilisons le rôle secondaire de l'opérateur « + », en l'utilisant pour la concaténation de chaînes au lieu de
l'addition. J'ai fondamentalement modifié la procédure « AddEnsemble (a.i, b.i) » et remplacé les paramètres de type
Long par des types String et renommé en « JoinString (a.s, b.s) ». Je peux maintenant appeler cette procédure de
n'importe où dans mon programme en passant Strings pour correspondre aux paramètres définis.

Un autre point à retenir en ce qui concerne les procédures est que leurs paramètres n'ont pas besoin d'être tous du même
type, vous pouvez mélanger et assortir autant que vous le souhaitez.

Procedure LotsOfTypes(a.b, b.w, c.l, d.f, e.s)


Debug "Byte: " + Str(a)
Debug "Word: " + Str(b)
Debug "Long: " + Str(c)
Debug "Float: " + StrF(d)
Debug "String: " + e
EndProcedure

LotsOfTypes(104, 21674, 97987897, 3.141590, "Marie avait un petit agneau")


74 Procédures et sous-routines

Ici, j'ai utilisé quelques types de variables différents comme paramètres dans ma procédure « LotsOfTypes() » pour
démontrer que les paramètres ne doivent pas tous être du même type. Les valeurs qui sont transmises dans l'appel de
procédure sont affectées aux paramètres de procédure définis « a », « b », « c », « d » et « e » respectivement. Vous
remarquerez également que toutes les valeurs transmises doivent correspondre à leurs types de paramètres respectifs,
faute de quoi une erreur de syntaxe peut se produire.

Vous avez aussi probablement remarqué que j'ai utilisé deux fonctions intégrées que vous ne connaissez peut-être pas.
Ces deux fonctions, « Str() » et « StrF() » seront expliquées plus en détail dans le chapitre 7 (Exemples de commandes
communes), mais pour expliquer simplement, elles convertissent les types numériques en chaînes.

Passage strict des valeurs aux procédures


Lors de l'appel d'une procédure, vous devez vous assurer que tous les paramètres définis sont appelés en
utilisant les types corrects, sinon vous risquez de provoquer une erreur de syntaxe lors de la compilation. Par
exemple, si une procédure est définie ainsi :

AddEnsemble(a.i, b.i)

alors seules les variables longues doivent être passées comme paramètres. Si les variables de type chaîne de
caractères sont définies comme paramètres vous devez alors appeler la procédure en utilisant Chaînes de
caractères comme valeurs pour ces paramètres. Procédures utilisant des tableaux et des les listes liées en tant
que paramètres doivent également être appelées correctement et tous les paramètres doivent être dans l'ordre
correct.en utilisant le bon type. Je sais que cela semble évident, mais je pense qu'il vaut la peine de le souligner...

Même à partir de ces exemples simples, le pouvoir des procédures devrait commencer à devenir évident. Non
seulement ils permettent aux programmeurs de gagner du temps en matière de saisie de code, mais ils leur permettent
également d'étendre les fonctionnalités de PureBasic et d'utiliser librement cette fonctionnalité dans n'importe quel code
source à partir de ce moment. Cela permet une grande réutilisabilité du code, surtout si vous avez écrit des procédures
génériques très utiles.

Paramètres Optionnels
Une nouvelle fonctionnalité de PureBasic v4 était l'inclusion de paramètres de procédure optionnels. Ils sont très faciles
à expliquer et à démontrer et sont extrêmement utiles.

En principe, vous pouvez définir une valeur initiale pour n'importe quel paramètre au cas où il ne serait pas utilisé lors de
l'appel de procédure. En voici un exemple :
Procedure AfficheParametres(a.l, b.l, c.l = 3)
Debug a
Debug b
Debug c
EndProcedure

AfficheParametres(1, 2)

Si vous regardez la définition de la procédure dans l'exemple ci-dessus, vous verrez que le dernier paramètre a été
défini différemment des autres et a reçu la valeur initiale de « 3 ». Si le dernier paramètre n'est pas spécifié dans un
appel de procédure, il aura cette valeur par défaut. Quand j' appelle la procédure dans l'exemple ci-dessus en utilisant
« AfficheParametres(1, 2) », en oubliant le dernier paramètre, alors vous pouvez voir cette valeur par défaut reconnue et
utilisée et affichée dans la fenêtre Debug

N'importe quel nombre de paramètres peut être optionnel et défini de cette façon. Vous devez cependant comprendre
que tous les paramètres optionnels doivent toujours apparaître à droite des paramètres standard non optionnels. En
effet, toutes les valeurs passées lors d'un appel de procédure sont affectées de gauche à droite aux paramètres et les
valeurs optionnelles ne peuvent pas être ignorées.

Passage des Tableaux aux Procédures


En accompagnement des variables, vous pouvez également passer des tableaux et des NewLists à des procédures en
tant que paramètres. Leur utilisation est simple et très facile à démontrer.
Procédures et sous-routines 75

Pour passer un tableau en paramètre, vous devez d'abord définir un tableau en utilisant le mot-clé standard « Dim ».
Voici un simple tableau de chaine unidimensionnel défini avec quatre index (rappelez-vous que les index commencent à
« 0 ») que j'ai appelé «Pays »:

Dim Pays.s(3)

Pays(0) = "Angleterre"
Pays(1) = "Irelande du Nord"
Pays(2) = "Ecosse"
Pays(3) = "Pays de Galles"

Puisque nous avons maintenant le tableau défini, nous allons définir une procédure que nous transmettons:

Procedure VoirArray(Array Pays.s(1))


For x.l = 0 To 3
Debug Pays(x)
Next x
EndProcedure

VoirArray(Pays())

Pour définir une procédure permettant d'accepter un tableau comme paramètre, vous devez le faire de manière très
stricte. Pour commencer, vous définissez un paramètre de tableau dans les mêmes parenthèses de procédure que tout
autre paramètre standard. Le paramètre de tableau lui-même est composé de quatre parties

Tout d'abord, un nom est utilisé pour agir en tant que nom de tableau dans la procédure. Ensuite, un suffixe du type de
tableau attendu est ajouté à ce nom et des parenthèses sont ajoutées à la fin. Ces parenthèses contiennent
généralement un nombre qui exprime un index de tableau. Mais ici, ce nombre devrait être le nombre de dimensions
contenues dans le tableau qui doit être passé. Dans l'exemple ci-dessus, j'ai utilisé un tableau unidimensionnel, donc le
paramètre tableau complet ressemble à ceci :

Array Pays.s(1)

Afficher le nom d'un paramètre de tableau, le suffixe du type de tableau, puis entre parenthèses, le nombre de
dimensions définies dans le tableau attendu.

Vous remarquerez que j'ai utilisé « Pays.s(3) » comme nom de paramètre du tableau, ce n'est pas essentiel et vous
pouvez appeler vos paramètres comme vous voulez. Cependant, vous devez toujours respecter les mêmes directives de
dénomination que pour les variables, c'est-à-dire pas d'espaces, pas de noms de mots-clés, etc.

A l'intérieur de cette procédure, vous pouvez maintenant utiliser « Pays() » comme n'importe quel autre tableau normal,
en obtenant et en réglant les valeurs vers et depuis celui-ci en utilisant des index standard. Dans l'exemple ci-dessus, j'ai
utilisé une simple boucle « For » pour itérer à travers ce tableau et faire afficher à ses valeurs dans la fenêtre Debug.
Vous pouvez cependant être aussi créatif que vous le souhaitez, en trouvant des moyens de traiter les tableaux.

Si la procédure est correctement définie, vous pouvez appeler et lui donner le tableau « Pays() », comme ceci:

VoirArray(pays())

Remarquez que lorsque nous passons notre tableau « Pays() », nous n'utilisons son nom qu'avec des crochets à la fin,
un peu comme un appel de procédure lui-même. Aucun type, index ou dimension n'est nécessaire lors du passage d'un
tableau dans un appel de procédure.

Lorsque vous démarrez cet exemple, vous devriez obtenir affiché dans la fenêtre Debug les cinq pays du monde.

Transfers Tableaux Multidimensionnels


Vous pouvez également passer des tableaux multidimensionnels comme paramètres, comme le montre cet exemple :

Dim Pays.s(3, 1)

Pays(0,0) = "Angleterre"
Pays(0,1) = "57,000,000"
76 Procédures et sous-routines

Pays(1, 0) = "Ireland du Nord"


Pays(1,1) = "2,000,000"

Pays(2, 0) = "Ecosse"
Pays(2,1) = "5,200,000"

Pays(3, 0) = "Pays de Galles"


Pays(3,1) = "3,100,000"

Procedure VoirArray(Array Pays.s(2))


For x.l = 0 To 3
Debug Pays(x,0) + " - " + "Population: " + Pays(x,1)
Next x
EndProcedure

VoirArray(Pays())

Même s'il s'agit d'un tableau bidimensionnel, nous utilisons toujours les mêmes règles qu'auparavant lorsque nous
définissons une procédure pour traiter ce tableau comme paramètre. Vous remarquerez que dans cette définition de
paramètre de tableau, nous utilisons « 2 » entre parenthèses pour spécifier que le tableau attendu sera un tableau
bidimensionnel, comme ceci :

Array Pays.s(2)

Même si ce paramètre est défini pour un tableau bidimensionnel, nous appelons toujours la procédure, en passant le
tableau comme avant, sans types, indices ou dimensions :

VoirArray(Pays())

Transfers des Tableaux Structurés


Les tableaux de types structurés peuvent également être passés à une procédure très facilement. Pour ce faire, il vous
suffit de changer le type de paramètre du tableau pour qu'il corresponde à la structure utilisée dans la définition du
tableau. Regardez cet exemple :

Structure Pays
Nom.s
Population.s
EndStructure

Dim Europe.Pays(3)
Europe(0)\Nom = "Angleterre"
Europe(0)\Population = "57,000,000"
Europe(1)\Nom = " Ireland du Nord"
Europe(1)\Population = "2,000,000"
Europe(2)\Nom = "Ecosse"
Europe(2)\Population = "5,200,000"
Europe(3)\Nom = "Pays de Galles"
Europe(3)\Population = "3,100,000"

Procedure VoirArray(Array Europe.pays(1))


For x.i = 0 To 3
Debug Europe(x)\Nom + " - " + "Population: " + Europe(x)\Population
Next x
EndProcedure

VoirArray(Europe())

Debug "Population Mondiale, d'Août 2009"


Procédures et sous-routines 77

Ici, j'ai utilisé un tableau structuré, défini à l'aide de la structure « Pays ». Pour que ce type de tableau soit transmis à
une procédure, vous devez vous assurer que vous définissez le paramètre du tableau pour utiliser la même structure
que celle utilisée lors de la définition du tableau attendu, dans ce cas c'était la structure « Pays ». Vous pouvez voir ce
paramètre par vous-même dans la définition de procédure ci-dessus :

Array Europe.Pays(1)

Ceci montre le nom du paramètre, le suffixe du type de tableau structuré et ensuite les dimensions dans le tableau
passé. Si tout ceci est codé correctement comme ci-dessus, alors un tableau monodimensionnel structuré « Pays »
passera parfaitement dans cette procédure. Je rappel que pour le mot-clé « Array ». Il est Important de le séparés par
un espace dans le parametre de la procédure.

Transfert des listes dans Procédures


Parfois, en programmant avec PureBasic, vous pouvez vouloir passer une NewList à une procédure. C'est très similaire
au passage d'un tableau. Tout d'abord, jetez un coup d'œil à cet exemple :

NewList Nombres.i()

AddElement(Nombres())
Nombres() = 25

AddElement(Nombres())
Nombres() = 50

AddElement(Nombres())
Nombres() = 75

Procedure VoirList(List MaList.i())


ForEach MaList()
Debug MaList()
Next
EndProcedure

VoirList(Nombres())

Ici, j'ai créé une liste de liens standard appelée « Nombres » qui contiendra des éléments de type Long. Après avoir
ajouté trois éléments à cette liste, j'ai défini la procédure « VoirList() » dans laquelle cette NewList sera passée. Le
paramètre de NewList est codé de manière très similaire à un paramètre de tableau, en ce sens qu'il commence par le
nom du paramètre, suivi du suffixe du type de liste et enfin d'un ensemble de parenthèses. Les NewLists n'utilisent pas
d'index comme les tableaux, vous n'avez donc pas besoin de taper un nombre entre parenthèses. Une fois tout cela fait,
vous pouvez alors appeler la procédure, en passant la liste liée comme un tableau, sans aucun type, etc. Comme ceci :

VoirList(Nombres())

Bien sûr, à l'intérieur de la procédure « VoirList() », la NewList « Malist() » contient maintenant toutes les informations
que la NewList passée avait et peut être utilisée exactement de la même manière que n'importe quelle autre NewList
standard. Vous pouvez voir à l'intérieur de la procédure « VoirList() », j'ai utilisé une boucle standard « Foreach » pour
itérer rapidement à travers la NewList et faire affiché ses valeurs dans la fenêtre Debug.

Transfert des listes structurées


Les listes de liens structurées peuvent également être facilement transmises en tant que paramètres de procédure.
Encore une fois, comme pour la transmission de tableaux structurés dans des procédures, vous devez vous rappeler de
définir la structure dans le paramètre de procédure comme étant la même que la structure utilisée pour définir la liste liée
qui doit être transmise.

Structure Drapeau
Pays.s
Drapeau.s
EndStructure

NewList Info.Drapeau()

AddElement(Info())
Info()\Pays = "Grande Bretagne"
Info()\Drapeau = "Union Jack"
78 Procédures et sous-routines

AddElement(Info())
Info()\Pays = "Etats Unis"
Info()\Drapeau = "Etoiles et Rayures"

AddElement(Info())
Info()\Pays = "France"
Info()\Drapeau = "Bleu Blanc Rouge"

Procedure VoirList(List MaList.Drapeau())


ForEach MaList()
Debug MaList()\Pays + " le Drapeau c'est : " + MaList()\Drapeau
Next
EndProcedure

VoirList(info())

Comme vous pouvez le voir dans l'exemple ci-dessus, le paramètre de la procédure ressemble à ceci:

List MaList.Drapeau())

J'ai fait en sorte que le paramètre de NewList « List » inclue maintenant le type « Drapeau() » pour que la
NewList structurée soit passée correctement.

Les Tableaux et les Listes sont Passés par Référence


Contrairement aux variables, les tableaux et les listes liées sont passés par référence. Cela signifie que les
valeurs ne sont pas réellement passées des tableaux et des NewList dans les procédures et « Copiée » dans les
paramètres. Au lieu de cela, un pointeur de mémoire interne est passé à la procédure et ceci est utilisé pour
manipuler le tableau ou la NewList

Tout cela est fait en interne pour que vous ne remarquiez rien de différent de l'utilisation de variables. La seule
chose dont vous devez tenir compte est que lorsque vous passez un tableau ou une NewList dans une procédure,
le nom du paramètre utilisé ne sera pas un tableau local séparé ou une NewList. Quel que soit le nom que vous
donnez au paramètre tableau ou NewList à l'intérieur de la procédure, vous manipulez toujours le tableau original
ou la NewList.

Par exemple, si vous passez un tableau appelé « Chiens() » dans une procédure comme paramètre, ce paramètre
pourrait avoir un nom différent et être appelé « Chats() » par exemple. Ensuite, à l'intérieur de la procédure, vous
pouvez assigner différentes valeurs au tableau « Chats() ». Quand on sort de la procédure, vous remarquerez que
le tableau « Chiens() » a été modifié de la même manière que le tableau « Chats() ». C'est parce que le paramètre
« Chats() » sera juste une référence passée au tableau original « Chiens() »

Ceci n'est vrai que pour les tableaux et les listes liées, les variables d'autre part sont passées par valeur, ce qui
signifie qu'une variable La valeur réelle est copiée dans le paramètre variable. Ainsi, si vous modifiez un
paramètre variable dans une procédure, il va ne pas modifier la variable d'origine qui lui a été transmise.

Valeur de Retour de Procédure


Une autre grande caractéristique des procédures est qu'elles peuvent retourner une valeur. Cette valeur peut être de
n'importe quel type de PureBasic intégré. Retourner une valeur d'une procédure est une excellente façon de pouvoir
calculer ou manipuler des données au sein d'une procédure et ensuite retourner quelque chose d'utile. Il peut s'agir d'un
résultat de calcul, d'un code d'erreur ou même d'une chaîne descriptive de ce que la procédure vient de faire ou de
réaliser. Voir Fig.2 et Fig.3 pour une liste des types qui peuvent être retournés par les procédures.

La syntaxe pour retourner une valeur d'une procédure est la simplicité même. Tout d'abord, vous devez définir le type
qui doit être retourné à partir de la procédure, ceci est fait en étendant légèrement la définition de la procédure.
Regardez cet exemple :
Procédures et sous-routines 79

Procedure.l AddEnsemble(a.i, b.i)


ProcedureReturn a + b
EndProcedure

Debug AddEnsemble(7, 5)

La définition de la procédure ci-dessus a reçu un nouveau suffixe de type à la fin du mot-clé « Procédure ». C'est ici que
vous définissez le type à retourner par cette procédure. La définition ci-dessus a reçu le suffixe « .i », ce qui signifie que
cette procédure renvoie une valeur de type Long. Pour que la procédure retourne une valeur, nous devons utiliser le
mot-clé « ProcedureReturn ». La valeur ou l'expression qui suit ce mot-clé est celle qui est retournée. Dans ce cas, la
valeur résultante évaluée à partir de « a + b » est retournée.

Vous pouvez aussi voir que si nous procédure ci-dessus avec « JoinString(7, 5) » appel renvoie une valeur directement,
qui lui-même peut être utilisé à nouveau dans une expression ou une déclaration. Dans ce cas, je l'ai utilisé comme une
expression de la déclaration du « Debug ». La valeur « 12 » est renvoyée par l'appel de procédure, puis affiché
directement au moyen de mot clé « Debug » dans la fenêtre Debug

Si nous voulons qu'une procédure renvoie une chaîne de caractères, il suffit de changer le type de retour en « .s ».
Comme on peut le voir ici :

Procedure.s JoinString(a.s, b.s)


ProcedureReturn a + b
EndProcedure

Debug JoinString("Rouge ", "Camion")


Debug JoinString("Jaune ", "Camion")

Notez que le type de retour est spécifié dans le mot-clé « Procedure.s ». Ceci spécifie maintenant que cette procédure
retournera une chaîne. Dans ce nouvel exemple, je passe deux chaînes de caractères dans la procédure, qui sont
ensuite concaténées et renvoyées depuis la ligne « ProcedureReturn a + b ». J'appelle cette procédure trois fois en
l'utilisant avec le mot-clé « Debug » pour faire afficher les valeurs retournées dans la fenêtre Debug et pour démontrer
les valeurs retournées.

Les procédures qui retournent des valeurs peuvent être utilisées partout où se trouvent des expressions. Par
exemple, ils pourraient être utilisés dans un autre appel de procédure, comme celui-ci :

Procedure.l AddEnsemble(a.l, b.l)


ProcedureReturn a + b
EndProcedure

Debug AddEnsemble(7, 5)

Ici, j'ai utilisé la procédure « AddEnsembler(a.i, b.i) » pour retourner les valeurs additionnées de deux appels séparés à
la même procédure. Tout d'abord, le « AddEnsemble (2, 3) » est appelé et ceci retourne « 5 » puis « AddEnsemble (4,
1) » est appelé et ceci retourne « 5 » aussi. Ces deux appels de procédure sont utilisés comme paramètres dans un
autre appel de procédure. Cet appel final additionne à la fois les valeurs retournées et renvoie cette valeur pour qu'elle
soit répercutée dans la fenêtre Debug.

Le Paramètre ne Modifie pas le Type de Retour


Une chose à retenir lorsque vous utilisez les types de retour de procédure est qu' ils n'ont pas besoin d'être identiques
aux types de paramètres définis. Par exemple :

Procedure.s AfficheValeur(a.l, b.s)


ProcedureReturn Str(a) + b
EndProcedure

x = 5
While x >= 0
Debug AfficheValeur (x, " bouteilles vertes suspendues au mur. ")
x - 1
Wend
80 Procédures et sous-routines

Même si j'ai utilisé un type long et un paramètre de type chaîne dans la procédure « AfficheValeur (a.i, b.s) », il peut
toujours retourner une chaîne telle que définie par le suffixe type dans le mot-clé « Procedure.s ». Les types de retour et
les types de paramètres peuvent être mélangés autant que vous le souhaitez.

Les types de retour sont cependant très stricts, tout comme les types variables. Si vous avez défini une procédure pour
retourner une chaîne de caractères et que vous souhaitez retourner une valeur de type Long, vous devez convertir cette
valeur dans le bon type de retour (chaîne) avant de la retourner, sinon vous aurez une erreur de syntaxe. Vous pouvez
le voir en action dans l'exemple ci-dessus. J'ai utilisé la commande intégrée « Str() » pour convertir « a » en chaîne de
caractères avant de concaténer et renvoyer correctement.

Limites des Valeurs de Retour


L'utilisation de procédures pour retourner les résultats comporte toutefois deux limites. Premièrement, les procédures ne
peuvent renvoyer qu'un seul résultat par appel. Cela signifie que vous ne pouvez pas retourner deux valeurs ou plus
dans un appel de procédure. Deuxièmement, vous ne pouvez pas retourner les tableaux, les listes liées ou tout autre
type défini par l'utilisateur à partir des procédures. Vous ne pouvez retourner que les types PureBasic intégrés. Il est
cependant possible de contourner ces limitations, en renvoyant un pointeur. Voir le chapitre 13 (Conseils) pour une
explication de cette technique.
Àide pour les commandes intégrées 81

7. Utiliser les commandes intégrées


Les langages de programmation ne sont rien sans bibliothèques intégrées de commandes utiles, donc PureBasic
dispose de plus de huit cents commandes intégrées pour être utilisées dans vos programmes. Celles-ci vont de la
manipulation des chaînes de caractères, aux mathématiques, à la gestion des fichiers et même aux commandes
graphiques. Ils couvrent presque toutes les tâches de programmation imaginables et s'il n'existe rien qui réponde à vos
besoins, vous avez également la possibilité de créer vos propres procédures.

Dans ce chapitre, je vais présenter et expliquer les commandes intégrées les plus couramment utilisées que PureBasic
a à offrir. Bien que cette liste ne soit en aucun cas exhaustive, cette introduction devrait servir à expliquer en détail
certaines des commandes les plus courantes que vous rencontrerez dans la programmation générale.

Ce chapitre commence par une description de la lecture de la syntaxe de la commande dans le fichier d'aide de
PureBasic et passe ensuite aux descriptions et explications des commandes. Je termine ce chapitre avec une section
sur la façon de gérer les fichiers, comme le chargement, l'écriture et la lecture, puis l'enregistrement, le tout en utilisant
les commandes intégrées PureBasic.

Utilisez l'Aide PureBasic


Ici, nous allons jeter un coup d'oeil au fichier d'aide de PureBasic et j'explique comment les pages sont organisées,
comment les lire et, plus important encore, comment utiliser les commandes intégrées qui y sont décrites.

Lorsque vous visualisez une page de commande dans le fichier d'aide PureBasic, vous êtes confronté à une mise en
page standard, cela ressemble à ce qui suit :

Description
Syntaxe
Exemple
Systèmes d'exploitation
compatibles

Les trois dernières sections de chaque page du fichier d'aide sont pour la plupart auto-explicatives, alors concentrons-
nous sur un fichier minute dans la section syntaxe. La partie syntaxique en haut de chaque page d'aide est un exemple
de la façon dont la commande est réellement tapée dans l'IDE et des paramètres qui doivent lui être transmis. Par
exemple, regardons la commande « SaveImage() » dans le fichier d'aide. Voici comment naviguer jusqu'à la bonne
page : (Fichier d'aide:Manuel de référence->Bibliothèques générales->Image->SaveImage). Sur cette page, tout en
haut, sous l'en-tête syntaxique, apparaît cet exemple syntaxique :

SaveImage(#Image, NomFichier$ [, ImagePlugin [, Options [, Profondeur]]])

La première chose sur cette ligne est le nom réel de la commande, dans ce cas-ci « SaveImage », après cela est une
paire de parenthèses et si cette certaine commande peut accepter des paramètres, ils seront affichés entre ces
parenthèses. Dans l'exemple de syntaxe « SaveImage », il est montré que cette commande peut accepter quatre
paramètres et donc les quatre sont entre parenthèses. Vous remarquerez également que les deux derniers paramètres
sont également indiqués entre crochets. Ceci signifie que ces deux derniers paramètres sont optionnels et ne doivent
pas être utilisés lorsque vous devez appeler la commande « SaveImage ». Si nous gardons cela à l'esprit, la commande
« SaveImage » peut être utilisée correctement comme ces trois exemples :

SaveImage(1, "Image.bmp")
SaveImage(1, "Image.jpg", #PB_ImagePlugin_JPEG)
SaveImage(1, "Image.jpg", #PB_ImagePlugin_JPEG, 10)

Le premier exemple enregistrera une image appelée « Image.BMP » dans le format Bitmap 24 bits par défaut. Le
deuxième exemple enregistre l'image au format « JPEG » et utilise la valeur de compression standard. Le troisième
exemple enregistre l'image au format « JPEG » et utilise la valeur de compression maximale de dix («10 »). C'est très
Simple !
82 Àide pour les commandes intégrées

Qu'est-ce que les Crochets dans les Exemples?


Les crochets entre crochets indiqués dans les exemples syntaxiques ne sont jamais utilisés lors de l'utilisation de
ces commandes. Ils ne sont inclus dans les exemples que pour montrer quels paramètres (le cas échéant) sont
facultatifs, lors de l'utilisation de ces commandes. Les crochets ne sont jamais utilisés dans le code réel que
lorsque vous utilisez des tableaux statiques. Pour plus d'informations sur les tableaux statiques, voir le chapitre 5
(Tableaux).

La première chose que vous pouvez réaliser en utilisant les commandes intégrées est qu'elles ressemblent et agissent
exactement comme des appels de procédure normale. Toutes les commandes intégrées appellent simplement des
procédures pré-écrites qui sont définies dans le cadre du paquet PureBasic. L'astuce pour les utiliser correctement est
que lorsque vous appelez une commande intégrée, vous devez lui passer les bons paramètres tels que définis dans
l'exemple syntaxique de cette commande, sinon une erreur syntaxique sera déclenchée par le compilateur.

La structure de l'exemple syntaxique ci-dessus est émulée dans tout le fichier d'aide, donc si vous comprenez comment
lire celui-ci, vous comprendrez comment lire tous les exemples syntaxiques pour toutes les autres commandes intégrées.

Numéros PureBasic et les Identificateurs de Système d' Exploitation


Lorsque vous utilisez des commandes intégrées, il est important de comprendre le rôle du système de numérotation
d'objets de PureBasic et celui des identificateurs du système d'exploitation, car ils sont utilisés directement pour contrôler
ce qui se passe dans votre programme. Les deux ne sont rien de plus que des nombres, mais les deux sont utilisés pour
identifier les objets dans les programmes. Par exemple, pour identifier des parties d'une interface utilisateur graphique ou
différentes images, vous devez les identifier par un numéro. Savoir comment et quand les utiliser est essentiel, non
seulement pour PureBasic mais aussi pour la programmation en général.

Le fichier d'aide de PureBasic est inestimable pour les informations qu'il contient, mais il peut devenir un peu confus
lorsque vous essayez de comprendre le système de numérotation des objets et les identifiants du système d'exploitation
de PureBasic. C'est parce que parfois le fichier d'aide fait référence au fait que les deux sont des identificateurs. Laissez-
moi vous expliquer exactement de quoi il s'agit pour que vous puissiez mieux comprendre le fichier d'aide.

Explication des Numéros PureBasic


PureBasic fonctionne sur un système de numération pour identifier chaque objet que vous créez dans votre programme.
Un objet PureBasic, entre autres, peut être une fenêtre, un gadget ou même une image. Ces numéros, que nous
appellerons numéros PB, sont ensuite utilisés par votre programme pour faire référence à ces objets plus tard lorsque
vous voulez effectuer une action sur eux.

De nombreuses commandes PureBasic ont un ou deux PB est passé en un nombre de paramètres afin qu'ils travail
correctement. Ceux-ci sont affichés dans l'aide Pure Basic dans le exemple de syntaxe de la commande correspondante.
Lorsqu'une commande nécessite un certain nombre de PB, ce qui est généralement caractérisée par une constante.
Cela commence par un signe dièse (#) suivi du nom de la bibliothèque est stockée dans la commande. Ainsi, par
exemple « #Image » pour un numéro d'image et « #Fenetre » utilisé pour un numéro de fenêtre, etc.

Voici un exemple de commande intégrée de la bibliothèque « Image » qui utilise un numéro PB:(Fichier d'aide: Manuel de
référence-> Bibliothèques générales-> Image-> CreateImage)

CreateImage(#Image, Width, Height)

Comme vous pouvez le voir, cette commande s'attend à ce qu'un numéro PB lui soit passé comme premier paramètre,
affiché par « #Image ». Bien que cela soit montré comme une constante dans l'exemple syntaxique, cela ne signifie pas
nécessairement qu'une constante doit être passée à la commande, cela signifie simplement que les constantes sont
généralement utilisées. En fait, n'importe quel entier peut être utilisé comme numéro PB pour un objet, à condition qu'il
soit unique parmi d'autres si plusieurs des mêmes objets sont utilisés. Ce numéro se réfère à cet objet nouvellement créé
à partir de ce moment dans l'ensemble de votre programme.

Le même Type d’Objets ne peut pas Partager les Numéros de PB


Les nombres PureBasic fournissent un excellent moyen de se référer à tout ce que PureBasic crée sur une base
individuelle. Pour cette raison, vous ne pouvez pas avoir deux objets du même objet partageant le même numéro PB.
Àide pour les commandes intégrées 83

Si vous créez une image avec un numéro de « 1 », puis plus tard dans votre programme vous créez une autre image
avec le numéro de « 1 », PureBasic détruit automatiquement la première et libère la mémoire utilisée avant de créer la
seconde. Ceci permet de s'assurer que deux objets d'une même bibliothèque ne partagent pas le même numéro PB.
Cette fonction est également très pratique si vous souhaitez remplacer des objets à tout moment.

Les numéros PureBasic peuvent cependant être partagés entre bibliothèques. Par exemple, vous pouvez créer une
fenêtre en utilisant « 1 » comme numéro PB, puis créer un gadget de bouton avec « 1 » comme numéro PB. Ces deux
nombres ne sont pas en conflit l'un avec l'autre parce qu'ils font référence à des objets de deux bibliothèques différentes.

Lorsque vous utilisez différentes commandes pour créer des objets, les choses peuvent devenir confuses lorsque vous
essayez de garder la trace de tous les nombres qui doivent être utilisés. Pour éviter ce problème, de nombreux
programmeurs PureBasic (y compris moi) utilisent des constantes pour ces numéros PB. Ces constantes sont
généralement définies dans un bloc d'énumération pour garder les nombres séquentiels. En voici un exemple :

Enumeration
#IMAGE_DOG
#IMAGE_CAT
#IMAGE_BIRD
EndEnumeration

CreateImage(#IMAGE_CHIEN, 100, 100)


CreateImage(#IMAGE_CHAT, 250, 300)
CreateImage(#IMAGE_OISEAUX, 450, 115)

Une fois les constantes définies, je peux les utiliser pour créer les images ci-dessus (ou tout autre objet) et ne pas
m'inquiéter de leurs valeurs contradictoires. Tout au long du programme, je peux également utiliser ces constantes pour
faire référence aux images par leur nom. Par exemple, je peux maintenant me référer à la première image en utilisant la
constante « #IMAGE_DOG ». Cette méthode d'utilisation de constantes pour les nombres PureBasic garantit un code
clairement organisé et lisible.

Numéros de PB Dynamiques
Au lieu d'utiliser des blocs de dénombrement pour traiter les numéros PB des objets nouvellement créés, vous pouvez
utiliser une constante spéciale pour tous ces objets. Cette constante est :

#PB_Any

Cette constante peut être utilisée partout où un numéro PB est attendu dans une commande de création d'objet. La
valeur de cette constante est le prochain numéro PB disponible. Ainsi, par exemple, la première fois qu'il est utilisé, sa
valeur peut être « 1 », puis la deuxième fois qu'il est utilisé, sa valeur peut être « 2 ». Ce comportement est idéal pour
construire des programmes dynamiques, où vous pouvez ou non savoir combien d'objets vous allez créer.

La seule chose à garder à l'esprit lors de l'utilisation de « #PB_Any » comme numéro PB, est que pour que vous
puissiez vous référer à cet objet plus tard, vous devez savoir quelle valeur « #PB_Any » avait lors de la création de
l'objet. Ceci est simplifié par PureBasic, parce que vous utilisez cette constante spéciale comme paramètre dans une
commande, cette commande retourne le numéro PB de l'objet nouvellement créé. Voici un exemple d'utilisation d'un
numéro PB dynamique dans la commande « CreateImage() » :

ImageDog.l = CreateImage(#PB_Any, 100, 100)

Ici la commande « CreateImage() » retourne maintenant le numéro PB de l'image nouvellement créée car nous avons
utilisé la constante « #PB_Any » comme paramètre du numéro PB. Cela fonctionne exactement de la même manière
pour toutes les commandes de création d'objet.

Les numéros PB sont uniques à PureBasic et permettent de se référer rapidement et facilement aux différents objets de
votre programme. Pour les visualiser sous forme d'exemples pratiques, voir le chapitre 9.

Identificateurs de Système d'Exploitation (Descripteurs)


Certains objets que vous créez à l'aide des commandes intégrées de PureBasic se voient également attribuer des
numéros à partir du système d'exploitation. Ces nombres sont la façon dont le système d'exploitation actuel garde la
trace de choses telles que les fenêtres, les polices et les images, etc. Le fichier d'aide PureBasic les appelle,
Identificateurs d'OS ou simplement IDs. Lors de la programmation en PureBasic, vous remarquerez que certaines
commandes retournent des identifiants OS tandis que d'autres peuvent en avoir besoin comme paramètres.
84 Àide pour les commandes intégrées

Voici quelques commandes qui retournent un identifiant OS de l'objet défini par le paramètre numéro PB :

WindowOSId.i = WindowID(#Window)
GadgetOSId.i = ID du gadget(#Gadget)
ImageOSId.i = ImageID(#Image)

J'en ai énuméré trois ici, mais il y en a d'autres. Les noms de commandes qui se terminent par « ...ID() » retournent
généralement des identificateurs d'OS. Comme mentionné précédemment, voici un exemple d'une commande qui utilise
un OS Identifier comme paramètre :

UseGadgetList(WindowOSId)

Cette commande est utilisée pour créer une liste de gadgets dans une fenêtre et utilise un identifiant de système
d'exploitation pour définir où la liste est créée. Un identifiant OS est utilisé dans cette commande au lieu d'un numéro PB
pour une compatibilité maximale, juste au cas où la fenêtre a été créée par l'API native du système d'exploitation. Si
vous vouliez utiliser cette commande pour créer une liste de gadgets sur une fenêtre créée en utilisant le système de
numérotation de PureBasic, alors nous pourrions faire quelque chose comme ceci :

UseGadgetList(WindowID(#Window))

Notez que nous utilisons la commande « WindowID() » comme paramètre qui retourne l'identifiant OS d'une fenêtre
numérotée PB.

Chaque système d'exploitation possède une interface de programmation d'application native ou API en abrégé. Il s'agit
d'un jeu de commandes intégré pour tous les langages de programmation à utiliser, pour contrôler le système
d'exploitation et dessiner une interface pour lui. Les identificateurs d'OS sont utilisés pour garder la trace de tous les
objets que contient le système d'exploitation et y accéder. Tous les identifiants d'OS sont uniques pour chaque
programme et ils existent pour tous les objets, même pour ceux qui ne sont pas écrits en PureBasic. Pour qu'un système
d'exploitation puisse suivre des milliers d'éléments, les nombres utilisés peuvent être assez grands, alors ne soyez pas
surpris de voir des identificateurs d'OS de plus de huit chiffres.

Les identificateurs d'OS n'ont pas besoin d'être utilisés pour créer des programmes PureBasic complets mais il est bon
pour les débutants de comprendre ce qu'ils sont même s'ils ne les utilisent probablement pas. Les identificateurs d'OS
jouent un rôle majeur dans l'utilisation de l'API de n'importe quel système d'exploitation, en particulier l'API Windows,
que je couvre un peu plus dans le chapitre 13.

Exemples de Commandes Courantes


Dans cette section, je vais vous présenter quelques-unes des commandes les plus couramment utilisées dans
PureBasic. Ces commandes se trouvent généralement dans la plupart des programmes PureBasic et pour cette raison,
apprendre leur syntaxe et leur but est très avantageux. Toutes ces commandes existent dans différentes bibliothèques
et ne sont pas nécessairement liées, elles sont juste très utiles pour des tâches de programmation générale. Ici, ils sont
présentés ci-dessous par ordre alphabétique, avec l'emplacement de leur fichier d'aide et des exemples d'utilisation.

« Asc() »
(Fichier d'aide: Manuel de référence-> Bibliothèques générales-> String-> Asc)
Exemple de syntaxe:

ASCIIValue.l = Asc(Character.s)

Cette commande retourne la valeur ASCII du caractère associé récupérée dans un graphique ASCII standard. Dans le
jeu de caractères ASCII standard, des nombres de « 0 » à « 255 » sont utilisés pour représenter les caractères et les
codes de contrôle informatique. Le paramètre passé à cette commande est une chaîne de caractères d'un caractère,
avec laquelle cette commande récupère sa valeur ASCII associée.
Àide pour les commandes intégrées 85

Texte.s = "Ceci est un test"


For x.l = 1 To Len(Texte)
Debug Mid (Texte, x, 1) + ":" + Str(Asc(Mid (Texte, x, 1)))
Next x

L'exemple ci-dessus utilise une boucle « For » et la commande « Mid() » intégrée pour diviser le texte contenu dans la
variable « Texte » en lettres séparées. Pendant l'exécution de la boucle, chaque lettre est passée à la commande «
Asc() » et leur valeur ASCII associée est récupérée. Ces valeurs ainsi que les lettres associées sont répercutées dans la
fenêtre Debug. J'ai utilisé de nouvelles commandes dans cet exemple, mais ne paniquez pas, elles sont expliquées un
peu plus loin dans cette section. Voir l'annexe B (Graphiques utiles) pour un tableau ASCII complet, montrant tous les
caractères et les nombres associés de « 0 » à « 255 ».

« Chr() »

(Fichier d'aide: Manuel de référence-> Bibliothèques générales-> String-> Asc)

Exemple de syntaxe:

Character.s = Chr(ASCIIValeur.l)

Cette commande retourne une chaîne d'un caractère, extraite d'un graphique ASCII standard. La chaîne retournée est le
caractère ASCII associé de la valeur passée en paramètre. Dans le jeu de caractères ASCII standard, les nombres de «
33 » à « 126 » sont des caractères imprimables que vous pouvez trouver sur un clavier Francais standard.

Le paramètre est passé à cette commande : « ASCIIValue.l », est le numéro avec lequel vous récupérez le caractère
associé.

Texte.s = Chr (84) + Chr (104) + Chr (105) + Chr (115) + Chr (32)
Texte.s + Chr (105) + Chr (115) + Chr (32)
Texte.s + Chr (97) + Chr (32)
Texte.s + Chr (116) + Chr (101) + Chr (115) + Chr (116)
Debug Texte

L'exemple ci-dessus construit la chaîne « Ceci est un test » en concaténant les résultats de plusieurs commandes «
Chr() ». Par exemple, la première commande « Chr (84) » renvoie le caractère « T », les autres sont ensuite
concaténés à la variable « Texte ». Voir l'annexe B (Graphiques utiles) pour un tableau ASCII complet, montrant tous les
caractères et les nombres associés de « 0 » à « 255 ».

« Delay() »

(Fichier d'aide: Manuel de référence-> Bibliothèques générales-> System->Delay)

Exemple de syntaxe:
Délay(millisecondes)

Cette commande interrompt toute activité de programme pendant la durée spécifiée dans le paramètre « millisecondes
». Le temps est mesuré en millisecondes (soit un millième de seconde).

Debug "Start..."
StartTime.l = ElapsedMilliseconds()
Delay(5000)

Quand l'exemple ci-dessus est exécuté, la deuxième instruction'Debug' est exécutée cinq secondes après la première
car j'ai utilisé la valeur « 5000 » millisecondes (5 secondes) dans la commande « Delay() ».
86 Àide pour les commandes intégrées

« ElapsedMilliseconds() »
(Fichier d'aide: Manuel de référence → Bibliothèques générales → Divers → ElapsedMilliseconds)

Exemple de syntaxe:

Result.i = ElapsedMilliseconds()

Cette commande renvoie le nombre de millisecondes qui se sont écoulées depuis la mise sous tension de l'ordinateur

Debug "Start..."
StartTime.l = ElapsedMilliseconds()
Delay(5000)
Debug "en pause pour: "+Str(ElapsedMilliseconds() - StartTime)+" milliseconds."

Cette commande est idéale pour effectuer n'importe quel type d'opération de chronométrage dans votre programme. Par
exemple, si vous voulez mesurer le nombre de millisecondes écoulées, vous devez d'abord enregistrer l'heure de début
dans une variable Longue en utilisant cette commande. Ensuite, lorsque vous voulez que cette minuterie s'arrête, vous
enregistrez à nouveau l'heure à l'aide de « ElapsedMilliseconds() ». Pour obtenir le résultat, soustrayez l'heure de fin de
l'heure de début et vous obtenez le nombre de millisecondes qui se sont écoulées entre chaque commande. Tout cela
est démontré dans l'exemple ci-dessus. Lorsque vous utilisez cette commande pour la première fois, vous risquez d'être
choqué par le grand nombre de données qu'elle renvoie. Vous devez vous rappeler qu'il enregistre les millisecondes
écoulées depuis la mise sous tension du système. Ne paniquez pas devant les gros chiffres, rappelez-vous simplement
qu'il s'agit d'un bon point dans le temps comme référence et vous pouvez utiliser la méthode ci-dessus pour calculer le
temps écoulé à partir de n'importe quel point.

« FindString() »

(Fichier d'aide: Guide de référence → bibliothèques générales → chaîne → FindString)

Exemple de syntaxe:

Position.l = FindString(String.s, StringToFind.s, StartPosition.l)

Cette commande essaie de trouver le paramètre « StringToFind » dans le paramètre « String », à partir de la position
indiquée par le paramètre « StartPosition ».. S'il trouve cette chaîne, il retourne immédiatement la position de la
première occurrence. Ces positions sont les nombres de caractères à partir du début du paramètre « String.s », à partir
de « 1 ».

String.s = "J'aime pêcher et attraper beaucoup de poissons"


StringToFind.s = "Poisson"

PremiereOccurrence.l = FindString(String, StringToFind, 1)


SecondeOccurrence.l = FindString(String, StringToFind, PremiereOccurrence + 1)
Debug "Index de la première occurrence:" + Str(PremiereOccurrence)
Debug "Index de la seconde occurrence :" + Str(SecondeOccurrence)

Cet exemple montre comment trouver une chaîne dans une autre chaîne. La première commande « FindString() »
essaie de trouver la chaîne « poissons » à partir d'une position « 1 », ce qu' elle fait avec succès et affecte la position
« 14 » à la variable« PremièreOccurrence ». La seconde commande « FindString() » essaie de trouver la même Chaîne
mais à partir d'une position de « PremièreOccurrence + 1 » pour s'assurer que l'on évite de retrouver la première
occurrence. Ceci renvoie la position « 40 » qui est assignée à la variable « SecondOccurrence ». Les deux sont alors
répercutés dans la fenêtre Debug.

« Len() »
(Fichier d'aide: Guide de référence → bibliothèques générales → chaîne → Len)

Exemple de syntaxe:
Laenge.i = Len(String.s)

Cette commande renvoie la longueur du paramètre « string » en nombre de caractères.


Àide pour les commandes intégrées 87

Alphabet.s = "abcdefghijklmnopqrstuvwxyz"
LongueurString.l = Len(Alphabet)
Debug LongueurString

Cet exemple est très simple car la commande « len() » est elle-même très simple. L'alphabet est assigné à une variable
Chaîne appelée « alphabet ». Cette variable est ensuite passée à la commande « len() » qui retourne « 26 » (c'est le
nombre de caractères que contient la variable « alphabet ». Cette valeur est assignée à la variable « Longueur String »
qui est ensuite répercutée dans la fenêtre Debug.

« MessageRequester() »

(Fichier d'aide: Guide de référence → bibliothèques générales → demandeur → MessageRequester)

Resultat.l = MessageRequester(Title.s, Texte.s [, drapeau])

;Possible drapeau:
#PB_MessageRequester_Yes
#PB_MessageRequester_YesNo
#PB_MessageRequester_ YesNoCancel

;Possible Retour Valeurs:


#PB_MessageRequester_Yes
#PB_MessageRequester_No
#PB_MessageRequester_Cancel

Cette commande est utilisée pour créer une petite fenêtre qui peut afficher n'importe quelle information dans votre
programme. Il peut être utilisé dans n'importe quel type de programme, pas seulement les programmes avec une
interface utilisateur graphique. Le premier paramètre de cette commande est la chaîne de caractères affichée dans la
barre de titre de la fenêtre. Le deuxième paramètre est la chaîne de messages affichée dans la fenêtre elle-même. Le
troisième et dernier paramètre est disponible pour les indicateurs optionnels. En utilisant différents indicateurs pour le
dernier paramètre, vous pouvez modifier le style de la fenêtre du demandeur pour inclure différents boutons. Votre
programme est arrêté jusqu'à ce que l'un de ces boutons soit enfoncé. Pour savoir laquelle, vous pouvez tester la valeur
de retour, comme ceci :

Title.s = "Information"

Message.s = "Ceci est le demandeur de message de style par défaut"


MessageRequester(Titre.s,Message.s,#PB_MessageRequester_Ok)

Message.s = "Dans ce style, vous pouvez choisir: Oui ou Non"


Resultat.l = MessageRequester (Titre, Message, #PB_MessageRequester_YesNo)

If Resultat = #PB_MessageRequester_YesNo
Debug "Vous avez appuyé sur 'Oui'"
Else
Debug "Vous avez appuyé sur 'Non'"
EndIf

Message.s = "Dans ce style, vous pouvez sélectionner [Oui], [Non] ou [Annuler]."


Resultat.l = MessageRequester (titre.s,message.s,#PB_MessageRequester_YesNoCancel)

Select Resultat
Case #PB_MessageRequester_Yes
Case #PB_MessageRequester_No
Debug "Vous avez appuyé sur [Non]"
Case #PB_MessageRequester_Cancel
Debug "Vous avez appuyé sur [Annuler]"
EndSelect

Cet exemple montre toutes les différentes façons dont la commande « MessageRequester » peut être utilisée. Il vous
montre également comment utiliser les constantes de valeur de retour pour déterminer quel bouton a été appuyé.
L'utilisation de constantes de ce type permet de ne plus se soucier de la mémorisation des valeurs numériques. Vous
n'avez pas besoin de savoir quelles valeurs sont assignées à ces constantes en interne, nous sommes juste intéressés
si elles sont égales (ou non) à la valeur de retour de la commande.
88 Àide pour les commandes intégrées

« Mid() »

(Fichier d'aide: Guide de référence → bibliothèques générales → chaîne → Mid)

Exemple de syntaxe:

Resultat.s = Mid(String.s, StartPosition.l, Longueur.l)

Cette commande retourne une chaîne recadrée qui est extraite d'une autre. La chaîne de départ est passée comme
paramètre « String ». La chaîne extraite peut alors être prise depuis n'importe quelle position dans la chaîne de départ,
définie par le paramètre « StartPosition » . La longueur de la nouvelle chaîne à extraire est définie dans le paramètre «
Longueur » . En voici un exemple :

DepartString.s = "La vie continue"


ExtraireString.s = Mid(DepartString.s, 4, 3)
Debug ExtraireString

Ici j'extrait la chaîne « DepartString.s » en spécifiant la position de départ comme « 4 », puis j'extrait « 3 » caractères.
Comme la commande « FindString() » , la position dans la chaîne de caractères de départ est mesurée en caractères.

« Random() »

(Fichier d'aide: Guide de référence → bibliothèques générales → Divers → Random)

Exemple de syntaxe:

Resultat.l = Random(Maximum.l)

Cette commande est simple à démontrer car elle ne fait que retourner un entier aléatoire entre (et incluant) « 0 » et la
valeur définie dans le paramètre'Maximum'.

Debug Random(100)

Dans l'exemple ci-dessus, la commande « Random() » renvoie une valeur aléatoire comprise entre « 0 » et « 100 »

« Str() », « StrF() », « StrD() »


((Fichier d'aide: Guide de référence → bibliothèques générales->Chaine->Str)

Exemple de syntaxe:

Résultat.s = Str (valeur.q) ; "Tous les types entiers de .b à .q"


Résultat.s = StrF (valeur.f [, nombre de décimales.i])
Résultat.s = StrD (valeur.d [, nombre de décimales.i])

Ces trois commandes ont en réalité la même tâche. Son but est numérique Convertir des valeurs en chaînes. Il existe
trois commandes différentes pour trois types de pour traiter les valeurs numériques, « Str() » pour traiter les entiers (« b
» à « .q »), « StrF() » pour Traitez les valeurs flottantes et « StrD() » pour gérer les valeurs doubles. Vous avez le bon
Sélectionnez la commande « Str() » pour votre application spécifique. Dans le cas de « StrF() » et « StrD() » vous avez
encore un paramètre optionnel nommé « Nombres de Décimales » Avec ce paramètre Vous pouvez spécifier le nombre
de décimales auxquelles la valeur est ensuite arrondie avant celle-ci. est converti en chaîne.

Debug "Long converti en String: " + Str(2147483647)


Debug "Quad converti en String: " + Str(9223372036854775807)
Debug "Float converti en String: " + StrF(12.05643564333454646, 7)
Debug "Double converti en String: " + StrD(12.05643564333454646, 14)

L'exemple ci-dessus montre comment convertir quatre différents types de valeurs numériques en chaînes de caractères.
Dans chaque cas, j'ai concaténé une chaîne littérale à la chaîne convertie pour former des phrases complètes, puis j'ai
fait écho à ces derniers à la fenêtre Debug Output. Une chose importante à noter est que si vous omettez le paramètre «
Nombres de Décimales » dans les commandes de type Flottant ou Double, alors elles seront toutes les deux par défaut
à six décimales et vous pourriez perdre beaucoup de précision.
Àide pour les commandes intégrées 89

« Val() », « ValF() », « ValD() »


(Fichier d'aide: Guide de référence → bibliothèques générales → chaîne → Val)

Exemple de syntaxe:

Resultat.l = Val(String.s)
Resultat.f = ValF(String.s)
Resultat.q = ValQ(String.s)
Resultat.d = ValD(String.s)

Ces trois commandes ont exactement la même tâche et sont l'exact opposé de la « Str() » Commande. La différence est
que ces commandes prennent une chaîne en tant que paramètre et une renvoie la valeur numérique (en fonction de la
commande Val() que vous utilisez). « Val() » admet Par exemple, renvoyez une valeur quadruple, « ValF() » renvoie
une valeur flottante et « ValD() » renvoie une valeur double. ici un exemple simple:

LongTypVariable.l = Val("2147483647")
QuadTypVariable.q = Val("9223372036854775807")
FloatTypVariable.f = ValF("12.05643564333454646")
DoubleTypVariable.d = ValD("12.05643564333454646")

Debug LongTypVariable
Debug QuadTypVariable
Debug FloatTypVariable
Debug DoubleTypVariable

Dans cet exemple, j'ai utilisé les quatre types différents de la commande « Val() » pour convertir quatre chaînes de
caractères en leurs types numériques respectifs. Vous devez cependant noter que si vous convertissez des nombres à
partir de chaînes de caractères qui sont numériquement plus grands que ce que le type résultant peut contenir, il se
produira alors un certain écrêtage. Par exemple, si vous regardez la ligne « ValF ("12.05643564333454646") » dans
l'exemple ci-dessus, ce nombre est beaucoup trop grand ou précis pour qu'un type de flottant normal puisse tenir, donc
quand il est converti par la commande « ValF() » il est coupé pour correspondre au type de destination.

Utilisation des Fichiers


L'utilisation de fichiers est un moyen naturel pour tout programme de stocker et de récupérer des données. PureBasic
fournit un support complet pour lire et écrire des fichiers, et peut lire et écrire à partir de n'importe quel nombre de
fichiers en même temps. Toutes les commandes de manipulation de fichiers sont stockées dans la même bibliothèque
Fichier, située ici dans le fichier d'aide PureBasic :

(Fichier d'aide: Guide de référence → bibliothèques générales → fichier)

Toutes les commandes de fichiers ne seront pas expliquées en détail dans cette section, mais je vais vous donner une
bonne base sur la lecture et l'écriture des fichiers afin que les autres commandes deviennent faciles à comprendre,
lorsque vous les utilisez.

Ecrire dans un Fichier


Commençons par un exemple sur la façon d'écrire des données dans un fichier, ici nous allons écrire quelques chaînes
de caractères dans un simple fichier texte.

#FILE_RHYME = 1

Dim Rhyme.s (3)


Rhyme (0) = "Bee bee mouton noir, avez-vous de la laine?"
Rhyme (1) = "Oui monsieur, oui monsieur, trois sacs pleins!"
Rhyme (2) = "Un pour le maître, un pour la dame"
Rhyme (3) = "Et un pour le petit garçon qui vit dans la ruelle."

If CreateFile (#FILE_RHYME, "Bee bee.txt")


For x.i = 0 To 2
WriteStringN (#FILE_RHYME, Rhyme(x))
Next x
CloseFile (#FILE_RHYME)
EndIf
90 Àide pour les commandes intégrées

Au début, j'ai créé la constante « #FILE_RHYME » que nous appelons le numéro PB pour notre nouveau Objet File et
j'ai défini un tableau de chaînes contenant la contine. après nous avons ajouté les chaînes au tableau « Rhyme() »
écrivons à propos de notre fichier. Si je veux ouvrir un fichier existant, je peux utiliser la commande « OpenFile() » mais
ci-dessus Par exemple, je veux créer un nouveau fichier, j'utilise donc la commande « CreateFile() ».

La commande « CreateFile() » prend deux paramètres, le premier est le numéro PB auquel ce nouvel objet fichier sera
associé, et le second est le nom de fichier réel que ce fichier sera nommé une fois créé. J'ai également utilisé la
commande « CreateFile() » dans une instruction « If » pour tester que la commande retourne vrai. Si c'est le cas, le
fichier a été créé avec succès et je peux continuer avec mon programme. C'est toujours une bonne idée de tester la
création d'un fichier, car les choses pourraient mal tourner si vous essayez d'écrire dans un fichier invalide.

Pour écrire une chaîne dans le fichier, j'ai utilisé la commande « WriteStringN() ». Cela prend deux paramètres, le
premier est le numéro PB associé à l'objet fichier sur lequel je veux écrire, le second est la chaîne de caractères que je
souhaite écrire. J'utilise une boucle pour itérer à travers le tableau pour écrire tout son contenu dans le fichier, écrivant
ainsi la comptine entière. La commande « WriteStringN() » utilisée dans cet exemple est une version étendue de la
commande « WriteString() ». En fait, la seule différence est le « N » avant les parenthèses. Ce « N » indique qu'un
caractère'nouvelle ligne' est écrit après la chaîne pendant l'exécution de la commande. Parce que je veux qu'une
nouvelle ligne commence après chaque chaîne que j'écris dans ce fichier, j'utilise la commande « WriteStringN() », sinon
tout serait sur la même ligne.

Différentes Façons de Créer ou d'Ouvrir des Fichiers


Lorsque vous utilisez les commandes de fichiers de PureBasic pour lire ou écrire des fichiers, vous devez choisir
la bonne commande en fonction de la façon dont vous souhaitez utiliser ce fichier. La liste ci-dessous décrit les
commandes qui permettent de prendre en charge toute lecture ou écriture.

« ReadFile() » ouvrira le fichier défini pour lecture et empêchera toute écriture sur celui-ci.
« OpenFile() » ouvrira le fichier défini pour lecture ou écriture et le créera s'il n'existe pas.
« CreateFile() » crée un fichier vide pour l'écriture. Si le fichier existe déjà, il le remplace par un fichier vide.

Chacun fonctionne exactement de la même manière et partage les deux mêmes paramètres. Le premier
paramètre est le numéro PB à associer à l'objet fichier et le second paramètre est le nom réel du fichier sur le
disque.

Une fois que j'ai écrit toutes les chaînes dans le fichier et que la boucle sort, je ferme le fichier en utilisant la commande
« CloseFile() ». Cela ne prend qu'un seul paramètre qui est le numéro PB de l'objet fichier que vous souhaitez fermer.

Ce fichier contenant la contine devrait maintenant se trouver quelque part sur votre disque dur. Si vous créez un fichier
en utilisant un nom de fichier relatif tel que « Bee Bee.txt », alors le fichier nouvellement créé sera dans le même
répertoire que votre fichier de code source. Si vous avez besoin qu'un fichier soit créé à un endroit plus spécifique, vous
devez spécifier un chemin d'accès absolu qui doit inclure le nom du lecteur, tout répertoire et le nom du fichier, quelque
chose de similaire à ceci :

If CreateFile(#FILE_RHYME, "C:\My Directory\Bee bee.txt"), , ,

Lorsque vous utilisez cette méthode, vous devez toujours vous assurer que tous les répertoires spécifiés dans le chemin
existent avant d'écrire le fichier, sinon la création du fichier échouera.
Àide pour les commandes intégrées 91

La Commande « CloseFile() » est très Importante

Lorsque vous avez fini de lire et surtout d'écrire dans les fichiers, vous devez fermer correctement le fichier en
utilisant la commande « CloseFile() ». Cette commande permet non seulement de fermer le fichier sélectionné,
mais aussi de le libérer pour qu'il puisse être ouvert par un autre programme si nécessaire. Un autre rôle important
que joue la commande « CloseFile() » est qu'elle écrit complètement dans le fichier toutes les données qui ont été
laissées dans le buffer du fichier. PureBasic utilise un système buffer pour augmenter les performances d'accès
aux fichiers, donc si vous ouvrez un fichier dans un autre éditeur et qu'il vous manque des données, vous devez
vérifier que vous avez bien fermé le fichier en utilisant« CloseFile() ». Cette commande garantit que toutes les
données restant dans le buffer de fichiers sont écrites sur le disque.

Les tampons de fichiers sont totalement transparents pour l'utilisateur régulier, vous n'aurez donc pas à beaucoup
vous soucier d'eux, il vous suffit de fermer chaque fichier une fois que vous en avez fini avec lui pour éviter toute
erreur.

Comment puis-je écrire des Valeurs d'autres Types Intégrés?


Ecrire les autres types intégrés dans un fichier est aussi facile que d'écrire Strings. Maintenant que vous comprenez
comment fonctionne la commande « WriteString() », les autres sont simples à comprendre. Voici des exemples de
syntaxe pour écrire les autres types intégrés :

WriteByte(#fichier, valeur.b)
WriteCharacter(#fichier, valeur.c)
WriteUnicodeCharacter(#fichier, valeur.u)
WriteWord(#fichier, valeur.w)
WriteLong(#fichier, valeur.l)
WriteInteger(#fichier, valeur.i)
WriteQuad(#fichier, valeur.q)
WriteFloat(#fichier, valeur.f)
WriteDouble(#fichier, valeur.d)

Ceux-ci peuvent être utilisés pour écrire n'importe quelle valeur de type intégrée dans un fichier et toutes les
commandes peuvent être utilisées autant de fois que vous le souhaitez. Ces valeurs, ainsi que les chaînes de
caractères, peuvent être mélangées et appariées dans un seul fichier, encore et encore, si nécessaire. Pour rendre les
choses encore plus simples, ces commandes sont toutes utilisées de la même manière que la commande «
WriteString() », le premier paramètre est l'objet fichier sur lequel écrire et le second est la valeur réelle à écrire.

Lecture d'un Fichier


La lecture de fichiers est aussi simple que l'écriture. PureBasic le rend extrêmement simple avec de puissantes
commandes de lecture de fichiers. Si vous regardez l'exemple suivant, j'ai lu Strings à partir d'un fichier appelé «
Rapport.txt », et je les place dans une NewList appelée « Contenu_fichier ». Le contenu de cette NewList est alors
répercuté dans la fenêtre Debug, uniquement pour afficher les données de chaîne qu'elle contient. Vous n'avez pas
besoin de faire afficher ces données cependant, vous pouvez continuer à manipuler les chaines de n'importe quelle
manière que vous jugez appropriée pendant votre programme.
#FICHIER_RAPPORT = 1

NewList Contenu_Fichier.s()

If ReadFile(#FICHIER_RAPPORT, "Rapport.txt")
While Eof(#FICHIER_RAPPORT) = #False
AddElement(Contenu_Fichier())
Contenu_Fichier() = ReadString(#FICHIER_RAPPORT)
Wend
CloseFile(#FICHIER_RAPPORT)
EndIf

ForEach Contenu_Fichier()
Debug Contenu_Fichier()
Nextt

Au début du code, j'ai utilisé une constante qui doit être utilisée comme numéro PB du fichier ouvert. Ensuite, je crée
une NewList appelée « Contenu_Fichier » pour contenir les chaînes que nous allons lire. Vous n'avez pas besoin
d'utiliser une NewList pour tenir ces Chaines, je trouve que ça rend les choses un peu plus organisées si on fait comme
ça. J'ai utilisé une NewList ici parce qu'ils sont faciles à utiliser et peuvent évoluer avec de nouveaux éléments,
contrairement aux tableaux dont la taille est prédéfinie.
92 Àide pour les commandes intégrées

J'ouvre le fichier à l'aide de la commande « ReadFile() », ce qui l'ouvre avec une permission de lecture seule et
empêche toute écriture sur le fichier lorsqu'il est ouvert. Comme la commande « CreateFile() », le premier paramètre est
un numéro PB auquel ce fichier nouvellement ouvert sera associé, tandis que le second est le nom du fichier à lire.
Comme précédemment, j'ai utilisé cette commande dans une instruction « If » pour m'assurer que la commande
retourne vrai. Si c'est le cas, je peux être sûr que ce fichier a été ouvert correctement et que je suis capable d'y accéder
correctement.

Une fois le fichier ouvert, je dois lire les informations qu'il contient. J'ai utilisé une boucle « While » ici, donc je n'ai pas
besoin de taper des commandes répétées pour lire les chaînes à l'intérieur. La boucle est construite à l'aide de la
commande « Eof() » , « Eof() » signifie « Fin de Fichier » et cette commande retournera true si vous avez atteint la fin
d'un fichier ouvert. Dans la boucle, je vérifie si cela renvoie false à chaque itération, si c'est le cas, je sais que je ne suis
pas à la fin du fichier et je peux continuer à le lire. La commande « Eof() » prend un paramètre, qui est le numéro PB du
fichier que vous voulez tester.

Lorsque le fichier est ouvert, j'utilise la commande « ReadFile() » pour lire une chaîne à la fois. La chaîne retournée par
cette commande commence au début de la ligne courante et se termine lorsqu'une nouvelle ligne est rencontrée, ce qui
déplace également le pointeur d'accès au fichier vers l'avant d'une ligne. Chaque fois que je lis une chaîne à partir du
fichier, je crée un nouvel élément dans la NewList « Contenu_Fichier » et je lui assigne la chaîne. Je continue à faire
ceci jusqu'à ce que la commande « Eof() » retourne vrai, provoquant la sortie de la boucle.

Une fois la boucle rompue, je ferme correctement le fichier ouvert avec la commande « CloseFile() ». La fermeture du
dossier est importante et doit être faite dès que vous avez terminé. Une simple boucle « ForEach » est alors utilisée
pour faire écho aux données lues dans la fenêtre Debug

Comment Lire d'autres Valeurs de Type Intégrées?


Alors que le dernier exemple traitait des chaînes de caractères, vous pouvez également lire d' autres types de valeurs
tout aussi facilement. PureBasic fournit des commandes spécifiques pour chacun des types intégrés afin de les lire
correctement.

ReadByte(#Fichier)
ReadChar(#Fichier)
ReadUnicodeChar(#Fichier)
ReadWord(#Fichier)
ReadLong(#Fichier)
ReadInteger(#Fichier)
ReadQuad(#Fichier)
ReadFloat(#Fichier)
ReadDouble(#Fichier)

Pour simplifier les choses, toutes ces commandes utilisent le même paramètre de lecture avec « ReadString() ». Ce
paramètre est le numéro de PB de l'objet de fichier ouvert à partir duquel se lit. la La seule différence entre ces
commandes « ReadString() ». est qu'elles n'ont qu'une valeur à lire à partir du fichier, à savoir le nombre d'octets
approprié pour le type approprié. Autrement La commande « ReadString() ». ne le lit pas jusqu'à la fin de la ligne. Par
exemple, si j'ai une valeur de type « Long » à partir du fichier, j'utilise la commande « ReadLong() »., qui lit les octets du
fichier par lots de « 4 » et renvoie ces octets sous forme de valeur longue. Cette action déplace le pointeur d'accès au
fichier.pour les « 4 » octets plus en avant, prêt à être utilisés.la prochaine commande de lecture..
Àide pour les commandes intégrées 93

Pointeur d'Accès aux Fichiers

Dans chaque fichier ouvert, il existe un pointeur invisible d'accès aux fichiers. Cette position imaginaire est celle
où vous allez lire ou écrire dans un fichier ouvert. Lorsque vous utilisez les commandes « ReadFile() », «
OpenFile() » ou « CreateFile() », le pointeur d'accès commence au début du fichier prêt pour l'opération suivante.
Une fois que vous commencez à lire ou à écrire, le pointeur d'accès au fichier commence à se déplacer. Si vous
écrivez dans le fichier, le pointeur d'accès progressera à travers celui-ci, se déplaçant juste après la dernière
valeur écrite, prêt pour la suivante. Si vous lisez à partir d'un fichier, le pointeur d'accès se déplacera après
chaque lecture jusqu'à la fin de la dernière valeur lue jusqu'à la fin du fichier, et la commande « EoF() » retourne
true.

Localisation du Pointeur d'Accès au Fichier


A tout moment pendant la lecture ou l'écriture d'un fichier, vous pouvez récupérer l'emplacement du pointeur d'accès au
fichier en utilisant la commande « Loc() ». qui signifie « Localisation ». La valeur de retour est mesurée en octets.

(Fichier d'aide: Guide de référence → bibliothèques générales → fichier → Loc)

Exemple de syntaxe:

Position.q = Loc(#Fichier)

Cette commande renvoie la position du pointeur d'accès au fichier (en octets) dans l'objet fichier spécifié dans le
paramètre PB number. La position est retournée sous la forme d'une valeur de type « Quad » pour prendre en charge
les fichiers volumineux.

Déplacement du Pointeur d'Accès de Fichier


Le pointeur d'accès aux fichiers peut être déplacé à tout moment en utilisant la commande « FileSeek() »

(Fichier d'aide: Manuel de référence-> Bibliothèques générales-> Fichier-> FileSeek)

Exemple de syntaxe:
« Quad »., pour les fichiers volumineux.
FileSeek(#Fichier, NouvellePosition.q)

Cette commande prend deux paramètres, le premier est le numéro PB de l'objet fichier à modifier et le second est la
nouvelle position (en octets) du pointeur d'accès fichier. Ceci vous permet de lire depuis n'importe quelle position, dans
n'importe quel fichier et à tout moment. Le paramètre « NouvellePosition » est de type « Quad » pour la prise en charge
des fichiers volumineux.
Connaitre la Taille du Fichier en Cours
Pour déterminer la taille du fichier en cours d' utilisation, utilisez la commande « Lof() ». qui signifie Longueur du fichier

(Fichier d'aide: Guide de référence → bibliothèques générales → fichier → Lof)

Exemple de syntaxe:

Longueur.q = Lof(#Fichier)

Cette commande renvoie la longueur en octets en arrière du fichier spécifié sur l'objet numéro PB. La longueur valeur
retournée en « Quad »., pour les fichiers volumineux.

Exemples « Loc() », « Lof() » et « FileSeek() »


Dans ce prochain extrait, je vais vous montrer l'utilisation de « Loc() ». « Lof() ». et « FileSeek() » et vous donner un
exemple pertinent de ces commandes. Dans le code ci-dessous, je suis en train de lire un fichier de musique MP3 pour
découvrir s'il contient une étiquette ID3(v1). Ces balises contiennent généralement des informations telles que le nom de
l'artiste, le nom et le genre de la chanson, etc.

Après avoir lu les spécifications des balises MP3 ID3 sur Internet, j'ai découvert que l'information des balises est
toujours ajoutée à la fin d'un fichier MP3 normal et que cette balise fait toujours « 128 » octets. La spécification
mentionne que les premiers « 3 » octets de cette balise sont les caractères « TAG », c'est donc ce que je vais vérifier.
94 Àide pour les commandes intégrées

#FICHIER_MP3 = 1

MP3Fichier.s = "Test.mp3"

If ReadFile(#FICHIER_MP3, MP3Fichier)
FileSeek(#FICHIER_MP3, Lof(#FICHIER_MP3) - 128)
For x.l = 1 To 3
BaliseText.s + Chr(ReadByte(#FICHIER_MP3))
Next x
CloseFile(#FICHIER_MP3)

If BaliseText = "TAG"
Debug "'" + MP3File + " a une balise ID3v1 intégrée."
Else
Debug "'" + MP3File + " ne contient pas de balise ID3v1."
EndIf
EndIf

Après avoir ouvert le fichier en utilisant « ReadFile() », je déplace le pointeur d'accès au fichier à l'endroit correct en
trouvant la longueur du fichier, puis en remontant à « 128 » Bytes. Comme ceci :
FileSeek(#FICHIER_MP3, Lof(#FICHIER_MP3) - 128)

Une fois cette commande terminée, le pointeur d'accès au fichier se trouve à l'endroit correct. J'utilise donc une boucle
pour effectuer une opération « ReadByte() » trois fois et je passe chaque octet à la commande « Chr() » pour retourner
un caractère. Ces caractères sont ensuite concaténés pour former une variable Chaîne appelée « BaliseText » . Une
fois la boucle terminée et le fichier fermé, je vérifie la valeur de « BaliseText » . Si la chaîne contenue dans « BaliseText
» est égale à « TAG », alors une balise ID3(v1) est présente dans le fichier MP3.

Lire le Fichier d'Aide


Cela a été le cri de guerre de nombreux bons programmeurs pendant des années, en particulier sur les forums Internet.
Pour vraiment comprendre quelque chose, il faut l'étudier, et pour l'étudier correctement, il faut tout lire à son sujet. Il n'y
a pas moyen de contourner le fait que les gens qui lisent davantage sur un sujet sont généralement plus aptes à le
comprendre. C'est particulièrement vrai avec les langages de programmation.

Le meilleur conseil que je puisse vous donner pour commencer à apprendre PureBasic est de lire le fichier d'aide de
PureBasic du début à la fin et de lire chaque page sur chaque commande. Cela semble extrêmement ennuyeux, mais
croyez-moi, cela augmentera considérablement votre compréhension de PureBasic et vous donnera un excellent aperçu
de ce qu'il est possible d'utiliser avec ce langage formidable.

Parfois, la seule chose qui distingue un bon programmeur d'un grand programmeur est la quantité de lecture et d'étude
des informations pertinentes qui ont eu lieu.

Nous espérons que ce chapitre vous donnera suffisamment d'informations pour pouvoir lire le fichier d'aide et
comprendre comment utiliser la plupart des commandes intégrées uniquement à partir de leurs exemples de syntaxe de
fichier d'aide.
Bon Style de Programmation 95

8. Un bon style de programmation


Jusqu'à présent, je me suis concentré sur l'explication des bases essentielles de la programmation PureBasic. Ses
types, énoncés et expressions intégrés, etc. Je pense qu'il est maintenant temps que je vous parle du style de rédaction
d'un programme.

Dans ce chapitre, je vais parler de quelque chose que tous les programmeurs devraient reconnaître et utiliser et c'est un
bon style de programmation. Apprendre à programmer peut être très amusant, mais ce plaisir peut rapidement s'éroder
lorsque vous êtes confronté (et essayez de comprendre) un code mal écrit, surtout si vous êtes l'auteur. L'écriture d'un
code bien formaté donne non seulement un aspect plus professionnel, mais elle vous aide aussi à mieux le lire et le
comprendre.

Dans les paragraphes suivants, je vais décrire comment vous pouvez formater votre code pour une lisibilité maximale.
Ce n'est pas nécessairement la bonne ou la mauvaise façon de le faire, juste la façon dont je travaille habituellement.
Espérons qu'après avoir lu plus loin, vous vous installerez dans votre propre style et que vous vous y tiendrez.

Plus loin dans ce chapitre, je vais vous montrer des trucs et astuces pour vous aider à éviter les erreurs dans votre code
et vous donner des exemples sur la façon de les gérer quand elles se produisent. J'ai également inclus quelques
conseils sur la façon d'utiliser le débogueur PureBasic pour localiser les problèmes qui peuvent survenir dans votre
code.

Pourquoi S' Embêter à Formater le Code Proprement?


Cette question est parfois posée par les débutants et devrait être abordée. Une réponse serait, si j'écrivais ce livre sans
titres, sous-titres, paragraphes ou majuscules et que j'écrivais le texte en un seul grand bloc, serait-il aussi facile à lire
qu'il l'est maintenant ?

Le formatage du code proprement n'a absolument rien à voir avec la compilation du programme et il n'altère pas non
plus la fonction ou l'exécution du programme compilé, c'est purement fait pour rendre le code facile à lire. Alors pourquoi
s'embêter ? Eh bien, je peux vous garantir qu'à l'avenir, vous travaillerez sur le code source que vous allez revisiter
maintes et maintes fois. Parfois parce que vous ne terminez pas ce que vous faites en une journée ou parce que vous
révisez un ancien programme pour y inclure de nouvelles fonctionnalités. Chaque fois, vous devrez relire votre code et
comprendre ce qu'il fait. Si vous avez un code laid et non organisé, je vous garantis que vous aurez de la difficulté à le
lire et à poursuivre votre projet.

Si un bogue apparaît dans votre programme et que le code du programme n'est pas très bien organisé, vous aurez
aussi plus de difficulté à trouver où se trouve l'erreur dans votre code. Un programme qui est parfaitement clair à
comprendre aujourd'hui peut ne pas l'être demain. S'il vous faut du temps pour le découvrir, combien de temps faudrait-il
à quelqu'un d'autre pour le découvrir ?

Le travail en équipe est une autre bonne raison pour écrire du code bien formaté. Si vous travaillez sur un projet au sein
d'une équipe et que vous modifiez le code d'autres personnes, ainsi que pour écrire de nouvelles choses, il est essentiel
que toute l'équipe utilise le même standard de formatage. C'est ainsi que tous les membres de l'équipe peuvent
rapidement et facilement comprendre le code de n'importe quel programmeur et poursuivre le projet efficacement.

L'Importance des Commentaires


La toute première chose dont il faut parler lorsqu'on parle d'un bon style de programmation est l'utilisation de
Commentaires. Jusqu'à présent, les commentaires n'ont été utilisés dans aucun exemple. J'ai pensé, j'attendrais jusqu'à
ce chapitre pour avoir une chance de les décrire correctement car je considère les commentaires comme l'un des
aspects les plus importants de la rédaction d'un bon code.

En termes simples, les commentaires ne sont que des lignes de texte incluses dans votre programme qui sont utilisées
pour décrire ou documenter ce que vous faites avec votre code. Ils ne sont jamais compilés dans l'exécutable final ou
n'ont aucun autre rapport avec le programme. Vous pouvez en utiliser autant que vous le souhaitez car ils n'interféreront
jamais avec les performances du programme.
96 Bon Style de Programmation

Les commentaires sont une façon de fournir une explication plus détaillée de ce que vous écrivez ainsi qu'un aperçu de
la façon dont les différentes parties de votre programme sont censées fonctionner et comment elles interagissent avec le
reste du code. En voici un bref exemple :

; La procédurePi() est appelée pour renvoyer la valeur de PI.


; Ce calcul est précis à seulement six décimales.

Procedure.f Pi ()
ProcedureReturn 4 * (4 * ATan(1/5) - ATan(1/239))
EndProcedure

Diametre_Circle.i = 150

Debug "Un cercle de diamètre" + Str(Diametre_Circle) + "mm"


Debug "a une portée de" + StrF(Diametre_Circle * Pi()) + "mm"

Ici, j'ai utilisé des commentaires dans cet exemple pour décrire la fonction de la procédure « PI() » et surtout
expliquer la limitation de sa précision à six décimales près.

La création de commentaires est simple car tous les commentaires commencent par un point-virgule « ; » et c'est tout :

; Ceci est un Commentaire

Les commentaires peuvent apparaître absolument n'importe où dans votre code source, même sur la même ligne
qu'une autre commande, comme celle-ci :

Procedure.l AddEnsemble(a.l, b.l) ; Ajoutez deux nombres et renvoyez le résultat


ProcédureReturn a + b
EndProcedure

Vous devez vous rappeler est le point-virgule au début, ce qui définit où le commentaire commence. Le commentaire
sera alors aussi long que la ligne courante et lorsqu'une nouvelle ligne est rencontrée, le commentaire se termine. Si
vous voulez qu'un commentaire continue sur une nouvelle ligne, vous devez commencer cette nouvelle ligne avec un
autre point virgule.

Pour bien commenter le code, donnez de l'importance à chaque commentaire et résistez à la tentation de simplement
répéter votre code avec le commentaire. Les commentaires ne devraient pas être trop longs, mais assez longs pour
expliquer ce dont vous avez besoin. En règle générale, lorsque vous écrivez des commentaires, vous devez vous
imaginer que vous clarifiez les parties les plus compliquées de votre code à une autre personne. Dans six mois, lorsque
vous revisiterez votre code, vous serez heureux de recevoir des commentaires pour vous aider à comprendre votre
travail.

Les commentaires peuvent être utilisés pour les éléments suivants:

1). Ajout de licence et les informations de copyright.


2). Expliquez pourquoi une étape particulière a été prise.
3). Ajouter des notes où le code peut être améliorée.
4). Expliquer la fonction des procédures compliquées.
5). Expliquer le fonctionnement interne de procédures en dessinant des graphiques ou des formulaires avec l'art ASCII.

Ma Conception de Code
La disposition générale de mon code et la façon dont je structure certains bits et bobs est basée sur le format de code
standard de plusieurs langages de programmation. Tout ce livre a été écrit dans ce style, qui est, à mon avis, un format
facile à lire et à apprendre. Ici, je vais vous expliquer pourquoi, et vous montrer comment j'écris du code, pour vous
donner une longueur d'avance dans l'écriture de programmes propres et lisibles. Nous espérons que vous trouverez ce
style utile et que vous continuerez à l'utiliser.

Variables, Tableaux, Listes et Procédures


Je les nomme généralement avec des noms clairs, précis, prononçables et descriptifs basés sur la notation « Bosses
de Chameau » . Cette notation est facile à comprendre, vous mettez la première lettre du nom en majuscule et ensuite
les autres mots qui suivent. Les lettres majuscules servent de séparateur pour ces mots car aucun espace ne peut être
utilisé. Ce format de mise en majuscule donne l' impression que ces mots ont des bosses, d' où le nom de notation
« Bosses de Chameau » . C'est ainsi que je préfère formater toutes les variables, tableaux et listes liées que je trouve
cela les rend plus faciles à lire.
Bon Style de Programmation 97

Exemple de syntaxe:

NombresDeJoursDays.l = 365
Dim MoisEtAnnee.s(11)
NewList Jours.s()

« Constantes »
Je formate les constantes en utilisant le style standard de l'API C et Windows, qui est tout en majuscules. Si j'ai besoin
de distinguer des mots séparés à l'intérieur d'eux, j'utilise des tirets de soulignement.

Exemple de syntaxe:

#VITESSE_DE_LA_LUMIERE = 299792458; Mètres par seconde

« Structures »
J'utilise la même norme pour les structures que pour les constantes, j'utilise tous les noms en majuscules. Il s'agit là
encore du format standard de C et de l'API Windows. Aussi, comme les constantes, si j'ai besoin de distinguer des mots
séparés, j'utilise des tirets de soulignement. Notez que le nom de structure suivant est en majuscules.

Exemple de syntaxe:

Structure UTILISATEUR_SERVICE
ServiceType.s
ServiceCode.l
EndStructure

« Indentation »
Les indentations permettent de structurer le code et de voir facilement le début et la fin des procédures, des boucles et
des énoncés conditionnels. Les indentations sont très souvent utilisées pour donner des aides purement visuelles à la
lecture du code. Voici des exemples de bonne indentation :

; Renvoie une chaîne contenant un nombre à virgule flottante arrondi.


; 'Numbre' = nombre à arrondir et à renvoyer sous forme de chaîne.
; 'NombreDecimales ' = Nombre de décimales à arrondir.

Procedure.s StrFRound(Numbre.f, NombreDecimales.i)


Protected R.f
Protected T.f

If NombreDecimales <0
NombreDecimales = 0
EndIf

R.f = 0.5 * Pow (10, -1 * NombreDecimales)


T.f = Pow (10, NombreDecimales)

ProcedureReturn StrF (Int ((Numbre + R) * T) / T, NombreDecimales)


EndProcedure
Debug StrFRound(3.1415927, 4)

Dans cet exemple, vous pouvez voir, j'ai indenté le code en utilisant des onglets. Ceci définit clairement le code entre le
début et la fin des mots-clés d'un bloc de code tel qu'une procédure ou une instruction « If » . J'indente également le
code de cette façon pour les boucles, les procédures, les instructions « If » et « Select » et les blocs « Énumération » .
L'indentation est particulièrement utile dans les relevés imbriqués, comme celui-ci :

For x = 0 To 2
For y = 0 To 2
z.l = 0
While z =< 10
Debug x * y + z
z + 1
Wend
Next y
Next x
98 Bon Style de Programmation

Ici, vous pouvez voir clairement les mots-clés de début et de fin de chaque instruction de boucle et voir tout le code
qu'elle contient. Un seul onglet à droite est utilisé par bloc de code, de sorte que le code contenu dans un bloc particulier
n'est pas trop éloigné du début et de la fin des mots-clés, ce qui pourrait également rendre le code plus difficile à lire.

Si vous regardez la ligne: « For y = 0 To 2 » vous pouvez facilement tracer le code et trouver la ligne: « Next y ». C'est
le début et la fin d'une instruction « If ». En regardant ceci nous savons que tout le code indenté à droite, est à l'intérieur
de ce bloc. Cela deviendra de plus en plus utile au fur et à mesure que vos programmes prendront de l'ampleur.

Plusieurs Commandes sur la même Ligne


J'écris parfois plusieurs commandes sur la même ligne pour réduire le code source. Ceci se fait facilement en utilisant le
caractère deux-points « : » . Le caractère deux-points, lorsqu'il est utilisé, indique au compilateur qu'une nouvelle ligne
a démarré et traite la commande suivante comme si elle apparaissait sur sa propre ligne séparée. Regardez ceci:

Dim Oiseaux.s (3)


Oiseaux(0) = "Moineau": Oiseaux(1) = "Troglodyte": Oiseaux(2) = "Coucou":
Oiseaux(3) = "Chouette":

Certains programmeurs désapprouvent ce type de formatage car il peut nuire à la lisibilité. J'ai parfois l'impression que
ça peut aider, même si ce n'est pas trop utilisé.

En Divisant le Code Source ( Include, XInclude )


Quand j'écris un programme et qu'il commence à devenir gros, j'ai tendance à le diviser en plusieurs fichiers de code
source distincts. Ces fichiers sont des fichiers PureBasic standard mais ont l'extension « * .pb » ou « * .pbi » Les fichiers
« * .pb » sont des fichiers de code PureBasic standard tandis que les fichiers « * .pbi » sont des fichiers PureBasic
Include. Ces deux types de fichiers sont exactement les mêmes et sont associés à l'IDE pour une ouverture correcte.
L'extension « * .pbi » est cependant purement cosmétique pour pouvoir identifier rapidement les fichiers inclus du fichier
programme principal lorsqu'ils sont regroupés dans un dossier.

Dans ces fichiers séparés, je tiens différentes parties du programme principal, puis je les inclus toutes dans le fichier
de code source principal en utilisant le mot clé « IncludeFile » ou « XIncludeFile »

Par exemple, si je définis beaucoup de procédures, je peux créer un fichier source séparé appelé « Procedures.pbi » où
toutes mes procédures seront définies. Ensuite, en haut de mon fichier de code source principal, j'inclurai le code des
procédures comme ceci :

IncludeFile "Procedures.pbi"

Ceci a pour effet de prendre toutes les lignes de code du fichier « Procedures.pbi » et de les coller dans mon code
source principal à partir de cette ligne. Chaque fois que la commande « IncludeFile » apparaît, c'est ici que le code du
fichier inclus sera ajouté à votre code principal. Ceci est fait avant la compilation pour que tout ce que le compilateur
voit soit un gros fichier à compiler.

Si vous ajoutez une ligne « IncludeFile » plusieurs fois dans votre code principal en utilisant le même nom de fichier,
vous obtiendrez des morceaux de code en double insérés dans votre fichier de code principal. Si, toutefois, vous voulez
éviter cela, vous devez utiliser le mot-clé « XIncludeFile ». Ceci est utilisé de la même manière que ci-dessus :

XIncludeFile "Procedures.pbi"

La ligne « XIncludeFile » inclura le code du fichier « Procedures.pbi » , seulement si cette ligne n'a pas été utilisée
auparavant. J'utilise rarement la commande « IncludeFile » car vous n'avez généralement besoin que d'un seul fichier
de chaque fichier include, y compris dans un programme donné. Je préfère utiliser « XIncludeFile » pour tout, car cela
réduit les erreurs.
Bon Style de Programmation 99

Bonne Terminaison d'un Programme


Pour terminer un programme correctement, vous devez toujours utiliser le mot-clé « End » . Ceci ferme tout
correctement dans votre programme et libère la mémoire qu'il utilise. Un code de sortie optionnel peut également être
utilisé avec le mot-clé « End » si nécessaire. La syntaxe d'utilisation est simple, il suffit d'utiliser ce mot-clé où vous
souhaitez que votre programme se termine. Plusieurs instructions « End » peuvent également apparaître dans n'importe
quel programme si vous devez potentiellement terminer votre programme à plus d'un endroit dans votre code.

Sans valeur de retour:

End ;Termine immédiatement le programme, libère la mémoire utilisée par celui-ci.

Avec valeur de retour:

End 1 ; Termine le programme immédiatement, libère la mémoire et renvoie 1.

Règles d' Or pour l'Ecriture d'un Code Lisible


Voici une liste de règles d'or que je suis tout en écrivant un programme. Je m'en tiens à ces règles même lorsque j'écris
de très petits programmes. Si vous suivez cette liste, vous aussi vous écrirez du bon code, propre et compréhensible.
L'utilisation d'une méthode de travail standard donne une structure claire et concise à tous ceux qui le lisent et rendra
votre code plus professionnel.

1). Donnez à toutes les variables, procédures, tableaux, etc. des noms clairs, précis, prononçables, descriptifs.
2). Groupez les variables ou les données connectées logiquement dans des tableaux ou des structures.
3). Les procédures doivent remplir une fonction et l’exercer correctement.
4). Utilisez l'indentation pour afficher la structure du code.
5). Utilisez des parenthèses (crochets) dans les expressions pour éviter toute confusion lors de l’évaluation.
6). Utilisez des lignes vides pour des procédures séparées et d'autres blocs de code.
7). Essayez de ne pas utiliser le mot clé "Goto" ou "Gosub".
8). Utilisez des commentaires pour aider les gens (ou vous-même) à comprendre votre code plus clairement.
9). Essayez de ne pas écrire de mauvais code avec des commentaires, réécrivez le code correctement.
10). Lorsque vous travaillez en équipe, définissez un style de mise en forme avant de commencer, puis respectez-le.

Comment Minimiser et Gérer les Erreurs


Dans ce chapitre, je vais parler des méthodes qui vous aideront à détecter les erreurs dans votre code. Même le
programmeur le plus expérimenté et le plus dévoué peut commettre des erreurs ou oublier de gérer les erreurs
courantes ou même les ignorer complètement. Ici, je révèle de bonnes pratiques de travail ainsi que de précieux conseils
et astuces, vous permettant d'être plus vigilant dans votre programmation, minimisant ainsi les risques de problèmes
éventuels.

Utilisez une Procédure de Gestion des Erreurs


Si vous utilisez PureBasic pour de grands projets, vous constaterez peut-être que vous ferez de nombreux tests pour
confirmer une valeur réelle. C'est parce qu'un grand nombre de commandes retournent une valeur. Cette valeur est
presque toujours un entier et toujours au-dessus de « 0 » si tout s'est bien passé. Certains programmeurs utilisent les
instructions'If' pour tester les commandes pour une valeur réelle avant de continuer, car si vous vous souvenez du
chapitre 4, tout ce qui est au-dessus de « 0 » est considéré comme une valeur réelle dans PureBasic.

Bien que certaines personnes utilisent les énoncés « If » pour vérifier que les choses se sont bien passées avant de
continuer, je trouve que cette approche n'est utile que pour les petits programmes, car elle peut mener à beaucoup
d'énoncés « If » emboîtés et déroutants lorsqu'elle est utilisée pour des programmes plus importants. Ce que j'ai
tendance à faire est d'utiliser une procédure comme un gestionnaire d'erreur au lieu d'une instruction « If ». Cela rend
non seulement votre code source beaucoup plus facile à lire, mais vous pouvez également passer des messages définis
par l'utilisateur à cette procédure pour informer les utilisateurs de l'endroit exact où les choses ont mal tourné dans votre
programme et avec quelle commande. Pour voir les deux côtés, voici un exemple d'utilisation d'une instruction « If »
pour tester une commande :
100 Bon Style de Programmation

#TEXTFILE = 1

If ReadFile(#TEXTFILE, "TextFile.txt")
Debug ReadString(#TEXTFILE)
CloseFile(#TEXTFILE)
Else
MessageRequester("Erreur", "Impossible d'ouvrir le fichier: 'TextFile.txt'.")
EndIf

Ici, je teste pour m'assurer que je peux lire le fichier « TextFile.txt » si je peux lire une chaîne à partir de celui-ci. Bien
que cette méthode convienne aux petits programmes, je préfère cette méthode pour les grands projets :

#TEXTFILE = 1

Procedure HandleError(Result.l, Text.s)


If Result = 0
MessageRequester("Erreur", Text, #PB_MessageRequester_Ok)
End
EndIf
EndProcedure
HandleError(ReadFile(#TEXTFILE,"TextFile.txt"),"Impossible d'ouvrir: 'TextFile.txt'.")
Debug ReadString(#TEXTFILE)
CloseFile(#TEXTFILE)

Ici, j'ai utilisé une procédure appelée « HandleError() » pour tester les valeurs de retour des commandes qui lui sont
passées. Le premier paramètre appelé « Résult », est l'endroit où la valeur de retour d'une commande est passée. Si
une commande est passée ainsi à une procédure, cette commande sera toujours exécutée avant que la procédure ne
soit appelée. Ceci afin de s'assurer que toutes les valeurs de retour sont transmises correctement. Le deuxième
paramètre « Text.s », est la chaîne de caractères que vous souhaitez afficher si la commande passée renvoie « 0 ». On
va décomposer ça un peu plus.

Que se passe-t-il si je passe cette commande à la procédure « HandleError() »

ReadFile(#TEXTFILE, "TextFile.txt")

Si le fichier « TextFile.txt » n'existe pas sur votre disque dur ou si un autre problème survient, la commande « ReadFile()
» renvoie « 0 ». Cette valeur de « 0 » est ensuite transmise au premier paramètre de la procédure de traitement des
erreurs. A l'intérieur de la procédure, ce paramètre est testé pour voir si sa valeur est égale à « 0 », si c'est le cas, le
message d'erreur passé dans le second paramètre sera affiché en utilisant un demandeur de message et le programme
prendra fin. Ceci est pratique pour donner des messages d'erreur clairs et concis pour chaque commande qui soulève
une erreur.

Si la commande passée à la procédure de traitement des erreurs renvoie une valeur supérieure à « 0 », alors cette
commande est considérée comme réussie et la procédure de traitement des erreurs ne prend aucune mesure.

La procédure démontrée dans l'exemple ci-dessus peut sembler exagérée pour un si petit exemple, mais ce genre de
chose n'est pas ce à quoi elle servirait principalement. L'utilisation d'une procédure de gestion des erreurs devient
vraiment utile dans les grands programmes, où de nombreuses commandes doivent être testées les unes après les
autres. Une fois la procédure définie, vous pouvez l'utiliser pour tester autant de commandes que vous le souhaitez et
chacune peut être testée sur une ligne, contrairement à une instruction « If ». Regardez cet exemple de test de
commandes multiples :

HandleError (InitEngine3D (), "Echec de l'initialisation de InitEngine3D ()!")


HandleError (InitSprite (), "Echec de l'initialisation de InitSprite ()!")
HandleError (InitKeyboard (), "Echec de l'initialisation de InitKeyboard ()!")
HandleError (OpenScreen (1024, 768, 32, "Jeu"), "Un écran n'a pas pu être ouvert!")

Pouvez-vous utiliser les instructions« If » pour tester toutes ces commandes ? Ce serait un cauchemar de mots-clés
« If », et ce n'est même pas encore un programme complet ! L'utilisation de procédures de gestion des erreurs rend
votre code plus clair, plus propre et plus lisible.

En travaillant de cette façon, vous découvrirez que les erreurs sont plus faciles à repérer et que les problèmes imprévus
sont plus faciles à gérer. Le seul problème avec cette approche est que « HandleError » apparaît au début de chaque
ligne, ce que certaines personnes trouvent intrusif.
Bon Style de Programmation 101

Utilisez la Commande « EnableExplicit »


Cette commande est une aubaine pour certaines personnes et un obstacle pour d'autres et c'est pourquoi son utilisation
est totalement facultative. Cette commande permet de définir des variables explicites dans l'ensemble de votre
programme. Alors, qu'est-ce que cela signifie ? Eh bien, au chapitre 2, j'ai expliqué que si vous ne spécifiez pas de
suffixe de type pour une variable, alors le type de cette variable sera par défaut le type par défaut courant, qui est
normalement un Long. Si le mot-clé « Define » a été utilisé pour définir un autre type par défaut, toutes les variables non
tapées l'utiliseront à la place. La commande « EnableExplicit » arrête ce comportement et exige après utilisation que
toutes les nouvelles variables aient leur portée et leur type strictement définis. Laissez-moi vous montrer comment cette
commande peut s'avérer utile.

Disons par exemple, j'ai une procédure qui doit être passé une variable d'une valeur cruciale et puis le résultat de cette
procédure doit être utilisé, je pourrais l'écrire comme ceci :

WeeklyAmount.l = 1024

Procedure CalculateYearlyAmount(Value.l)
YearlyAmount.l = Value * 52
ProcedureReturn YearlyAmount
EndProcedure

Debug CalculateYearlyAmount(WeaklyAmount)

Maintenant, cela semble correct et si vous parcourez rapidement cet exemple, vous ne voyez aucun problème. Si vous
l'exécutez cependant, la procédure « CalculateYearlyAmount() » renvoie « 0 ». Ce n'est évidemment pas juste car nous
sommes supposés lui passer la variable « WeeklyAmount » qui a une valeur de « 1024 ».. Si vous regardez
attentivement l'appel de procédure, vous pouvez voir que je passe réellement une variable appelée « WeaklyAmount ». .
Notez que cette variable est mal orthographiée et donc traitée comme une nouvelle variable. Lorsque vous passez des
variables de ce type, si elles n'ont pas été définies auparavant, PureBasic crée automatiquement une nouvelle variable
et la passe. Les variables dont le type ou la valeur n'a pas été défini lors de la création se voient toujours attribuer le
type par défaut, et une valeur nulle leur est attribuée. Cette nouvelle variable nommée'WeaklyAmount' dans l'exemple ci-
dessus a donc une valeur « 0 ».

Le fait de définir automatiquement des variables qui ont été tapées de cette façon est considéré par certains
programmeurs comme étant négligentes et très sujettes aux erreurs. Ce comportement par défaut peut être désactivé et
le compilateur peut être invité à être plus strict sur la définition des variables en utilisant la commande « EnableExplicit
» . Si nous utilisions cette commande dans l'exemple ci-dessus, nous obtiendrions quelques messages nous informant
que certaines variables doivent être définies plus strictement. Cela signifie que toutes les variables utilisées après la
commande « EnableExplicit » doivent être définies en utilisant l'un des mots-clés de définition de variable. Il s'agit det «
Défine », « Global », « Protégé », « Static » et « Shared », comme expliqué aux chapitres 2 et 6.

Si nous passons par l'exemple ci-dessus, en définissant strictement toutes les variables et en relançant ensuite le
programme,le compilateur attirerait notre attention sur la dernière ligne et montrerait un message nous informant que
la variable « WeeklyAmount » doit également être définie plus strictement. Ce serait un peu étrange car cela devrait
déjà être fait plus tôt dans le programme. Au terme d'une enquête plus approfondie, on constatera que
cette variable est mal orthographiée et doit être corrigée. Voici à quoi ressemblerait l'exemple ci-dessus en utilisant
la commande « EnableExplicit » et toutes les variables définies de manière plus explicite.

EnableExplicit

Define WeeklyAmount.l = 1024

Procedure CalculateYearlyAmount(Value.l)
Protected YearlyAmount.l = Value * 52
ProcedureReturn YearlyAmount
EndProcedure

Debug CalculateYearlyAmount(WeeklyAmount)

Espérons que l'utilisation de cette commande devrait éviter beaucoup plus de fautes d'orthographe basées sur les
variables car chaque fois qu'une faute d'orthographe est rencontrée, le compilateur la traitera comme un nom de
variable séparé et il vous sera demandé de clarifier la portée et la définition de cette variable. Vous avez ainsi la
possibilité de corriger la variable et de restaurer les valeurs qui pourraient être perdues à cause de ces erreurs.

A tout moment, si vous souhaitez revenir au comportement PureBasic par défaut, vous pouvez désactiver l'influence de
la commande'EnableExplicit' en utilisant la commande « DisableExplicit ».
102 Bon Style de Programmation

Définition des variables à l'aide de la commande « Défine »


La commande « Défine » peut être utilisée de deux façons. Tout d'abord, il définit le type par défaut pour les
variables non tapées, comme indiqué au chapitre 2. De cette façon, le mot-clé « Défine » est utilisé avec un
suffixe de type qui définit le nouveau type par défaut, comme ceci :

Define.s
MyString = "Hello"

Deuxièmement, la commande « Défine » peut être utilisée pour définir des variables après qu'une commande«
EnableExplicit » ait été utilisée. Si la commande« EnableExplicit » a été utilisée, toutes les variables de votre
programme doivent être strictement définies. Dans ce cas, la commande « Défine » peut être utilisée comme
ceci :

EnableExplicit
Define MyVar.b = 10

Notez que ce type d'utilisation n'ajoute pas de suffixe au mot clé « Défine ». parce que nous définissons le type
de la variable avec son suffixe.

Introduction au Débogueur PureBasic


PureBasic fournit un débogueur complet qui aide à trouver les erreurs et les bogues dans votre code. Ce débogueur est
inestimable car il vous donne la possibilité de contrôler le flux du programme et de jeter un coup d'oeil aux valeurs. de
variables, tableaux et listes liées à tout moment pendant l'exécution de votre programme. Il fournit également des
fonctions avancées permettant aux programmeurs d'assemblage d'examiner et de modifier les registres CPU ou de
visualiser les valeurs stockées dans les adresses mémoire associées. Il est également possible de visualiser l'utilisation
CPU de votre programme à l'aide du moniteur CPU intégré.

Si vous exécutez votre programme et que le débogueur rencontre une erreur, le programme s'arrêtera et la ligne où
l'erreur s'est produite sera marquée dans l'IDE (en rouge) et l'erreur sera affichée dans le journal des erreurs de l'IDE et
la barre d'état de l'EDI. Lorsqu'une erreur est détectée de cette manière, vous pouvez utiliser les fonctions de contrôle
du programme ou mettre fin au programme en cours. Pour terminer le programme en cours d'exécution, utilisez
l'élément de menu « Quit programme » (Menu:Debugger->Quit programme) ou son bouton associé dans la barre
d'outils. Si le débogueur est désactivé, aucune erreur ne sera détectée et pourrait entraîner un plantage du programme.

Lors de l'écriture d'un programme dans l'EDI, le débogueur est activé par défaut. Vous pouvez le voir d'un coup d'œil en
regardant le bouton de bascule du débogueur situé dans la barre d'outils de l'IDE, voir Fig.23. Si ce bouton est affiché
comme enfoncé, le débogueur est activé, s'il est affiché comme étant en haut, le débogueur est désactivé. Ce bouton est
également un raccourci vers l'élément de menu « Utiliser le débogueur », (Menu:Débogueur->Utiliser le débogueur) qui
est aussi un basc u l e. Le débogueur peut également être activé dans les options du compilateur de votre programme
(Menu:Compiler->Compiler Options...->Compiler O p t i o ns - > E n a b le Debugger) . Toutes ces différentes façons de
basculer l'état du débogueur sont liées. Si l'un est utilisé, les autres reflètent son statut.

Le package Windows de PureBasic est livré avec trois types de débogueur différents à utiliser. Ceux-ci peuvent tous
être utilisés pour déboguer votre programme mais certains n'ont pas les mêmes fonctionnalités. Le premier est le
débogueur intégré qui est le plus riche en fonctionnalités parmi les différents et est utilisé par défaut car il est intégré
directement dans l'IDE. l'IDE PureBasic fonctionnant sur certains systèmes d'exploitation ne supporte pas cette version
intégrée, un débogueur autonome est donc fourni avec l'installation. Cette version autonome a presque les mêmes
fonctionnalités que le débogueur intégré, mais parce qu'elle est séparée de l'EDI, une partie de l'efficacité de l'accès
direct depuis l'IDE est perdue. Le troisième débogueur ne fonctionne que dans une console. L'utilisation principale de
cette version est pour les environnements non graphiques tels que les systèmes d'exploitation Linux basés sur le texte
ou les applications développées à distance travaillant avec des clients utilisant le protocole SSH. Les débogueurs
disponibles peuvent être sélectionnés par défaut dans les préférences de l'EDI, (Menu:Fichier->Préférences-
>Débogueur).
Bon Style de Programmation 103

Même si le débogueur est un excellent outil pour traquer les problèmes, toutes ces fonctionnalités de débogage ont
cependant un prix. Vous constaterez que les programmes en cours d'exécution lorsque le débogueur est activé seront
beaucoup plus lents que si vous les exécutez avec le débogueur désactivé. Cela ne devrait pas poser de problème, car
la grande majorité des exécutables finaux sont compilés sans le débogueur pour une vitesse et une compacité
maximales. Ceci doit être gardé à l'esprit si vous développez des programmes critiques pour la vitesse ou si vous avez
besoin de chronométrer certains bits de code, etc.

Si vous avez besoin d'utiliser le débogueur pour déboguer votre code mais que, dans certaines sections, vous pourriez
le désactiver, vous pouvez utiliser les commandes de débogage intégrées, « DisableDebugger » et « EnableDebugger
».. Ils sont assez explicites à utiliser, la commande « DisableDebugger » a désactivé le débogueur à partir de ce
moment dans votre code et la commande « EnableDebugger » le réactive. Si vous désactivez le débogueur, vous
remarquerez également que cela désactive toutes les commandes de débogage. En effet, les commandes « Debug »
font également partie du débogueur et ne seront pas compilées si le débogueur est désactivé.

Utilisation du Débogueur
Les fonctions du débogueur peuvent être utilisées à tout moment pendant l'exécution de votre programme, elles sont
accessibles depuis le menu du débogueur ainsi qu'à l'aide des boutons de la barre d'outils associée. Le journal des
erreurs (Menu:De bu g ge r - > L o g d e s erreurs) e t l e moniteur CP U (Menu:Debugger->Moniteur CPU) sont t oujours
accessibles. Pendant que vous utilisez le débogueur, tous les fichiers de code source qui sont connectés à votre
programme en cours d'exécution sont immédiatement mis en lecture seule jusqu'à ce que le programme soit terminé.
Ceci permet de s'assurer que le code actuellement utilisé n'est pas modifié de quelque façon que ce soit, pour fournir un
simple contrôle de version sur votre code.

Les Boutons de la Barre d’Outils du Débogueur

Continuer Pas à Pas


Arrêt Passer au delà
Utiliser le Débogueur Sortir
Terminez le programme

Fig. 23

Pour vous donner un aperçu du débogueur, je vais commencer par vous expliquer les fonctions de contrôle de
programme qu'il fournit. Ces contrôles vous permettent d'arrêter le programme à tout moment et d'examiner toute
variable, tableau ou valeur de liste liée. Il vous permet également de parcourir votre programme une ligne à la fois pour
examiner exactement comment votre programme s'exécute. L'état de tout programme pendant l'utilisation du débogueur
sera affiché dans la barre d'état de l'IDE et dans le journal des erreurs. Les boutons de la barre d'outils de contrôle des
programmes du débogueur sont illustrés à la Fig.23, ils sont également reflétés par des commandes dans le
menu'Debugger'.

Pour arrêter votre programme à tout moment et utiliser les commandes du débogueur, vous pouvez soit utiliser le mot-
clé « CallDebugger » dans votre code, soit utiliser « Stop » dans le menu du débogueur (Menu:Debugger->Stop) ou
appuyer sur le bouton « Stop » dans la barre d'outils lorsque votre programme est lancé. Vous pouvez également utiliser
les points d'arrêt pour arrêter l'exécution du programme. Pour utiliser un point d'arrêt dans l'IDE, placez le curseur sur la
ligne à l'endroit où vous souhaitez que le programme s'arrête et activez le débogueur. Choisissez ensuite la commande
de menu « Point d'Arret » (Menu:Debugger->Point d'Arret) pour ajouter un point d'arrêt. Vous remarquerez qu'un petit
cercle apparaît dans la gouttière de numérotation des lignes de l'IDE. Il s'agit d'une indication visuelle pour montrer où
les points de rupture sont définis. Lors de la prochaine exécution de ce programme, il s'arrêtera sur la ligne où le point
d'arrêt est défini et les fonctions de contrôle du programme de débogage seront alors disponibles. Vous êtes alors en
mesure d'examiner toutes les valeurs de données ou de passer à travers votre programme pour analyser votre code de
plus près. Voici une brève description des fonctions de contrôle du programme :

« Stop »
Arrête le programme et affiche la ligne en cours

« Continuer »
Continue l'exécution du programme jusqu'à l'apparition d'une nouvelle commande d'arrêt
104 Bon Style de Programmation

« Step »
Exécute une ligne dans le programme et met le programme en pause avant la ligne suivante.

Passer au Delà
Exécute la ligne du programme actuellement affichée et stoppe de nouveau l'exécution, comme un « Pas » normal. La
différence survient si la ligne contient un ou plusieurs appels à des procédures. Dans ce cas, les procédures seront
toutes exécutées, sans arrêt, contrairement au mode «Pas» qui rentre dans chaque procédure. Ceci permet de passer
rapidement sur des procédures qui sont connues comme étant correctes.

« Sortir »
Exécute le code restant dans la procédure en cours et s'arrête après le retour de cette procédure. encore une fois. Si la
ligne courante n'est pas dans une procédure, une « étape » normale est est exécutée.

« Fin du Programme »
Ceci force le programme à se terminer, et ferme toutes les fenêtres de débogage associées.

Voici un petit exemple pour arrêter l'exécution du programme avec la commande « CallDebugger »:

CallDebugger
For x.l = 1 To 10
Debug x
Next x
End

Une fois que le programme ci-dessus a été arrêté en utilisant la commande « CallDebugger ». Vous pouvez le parcourir,
ligne par ligne, à l'aide du bouton de la barre d'outils « Pas à pas ». Cliquez dix fois dessus et vous verrez la valeur de
« x » répercutée dans la fenêtre Debug, incrémentée d'une unité à chaque fois que ce bouton est pressé. Lorsqu'un
programme est arrêté de cette façon, vous pouvez visualiser n'importe quelle variable, tableau ou valeur de liste liée en
ouvrant le Visualiseur de variables (Menu:Debugger->Liste des Variables). Ce petit aperçu devrait vous suffire pour
apprendre les bases du débogueur. Pour plus d'informations sur ce dont il est capable, consultez le fichier d'aide
PureBasic.

La Bibliothèque « OnError »
La bibliothèque intégrée « OnError » vous donne la possibilité d'effectuer la vérification d'erreur dans votre exécutable
fini, si le débogueur n'est plus disponible. En phase de développement, vous utilisez le débogueur pour attraper des
erreurs dans votre programme. Mais si vous compilez votre programme fini, vous désactivez généralement le
débogueur pour créer l’exécutable le plus petit et le plus rapide possible. La vitesse du programme est multipliée par six
lorsque le débogueur est désactivé. Avec la bibliothèque « OnError » on facilite l'intégration de la gestion avancée des
erreurs dans votre programme, et Vous avez toujours la vitesse maximale de PureBasic disponible.

Il y a beaucoup de commandes très avancées qui peuvent être utilisées à partir de cette bibliothèque, mais elles
dépassent le cadre de ce livre, donc je vais me concentrer sur les commandes les plus couramment utilisées et les plus
facilement comprises. Tout d'abord, je vais vous montrer comment attraper et décrypter efficacement une erreur sans
utiliser le débogueur. Regardez le exemple suivant:

;Définir le gestionnaire d'erreurs


OnErrorGoto(?ErrorHandler)

;Déclenchement d'une erreur classique de «division par zéro».


Null.l = 0
TestVariable.l = 100 / Null

;Traitez toutes les erreurs système qui se produisent dans le programme.


ErrorHandler:
Text.s = "Nombre d'erreurs:" + #TAB$ + #TAB$ + Str(GetErrorCounter()) + #CRLF$
Text.s + "Numéro d'identification de l'erreur:" + #TAB$ + #TAB$ +
Str(GetErrorNumber()) + #CRLF$
Text.s + "Description de l'erreur:" + #TAB$ + #TAB$ + GetErrorDescription() +
#CRLF$
Text.s + "Une erreur est survenue en ligne:" + #TAB$ + Str(GetErrorLineNR()) +
#CRLF$
Text.s + "Une erreur s'est produite dans le module:" + #TAB$ +
GetErrorModuleName() + #CRLF$
MessageRequester("ERREUR", Text)
End
Bon Style de Programmation 105

Ici, j'utilise la commande « OnErrorGoto() » pour spécifier où sauter si une erreur est rencontrée. Le paramètre de cette
commande est une destination d'étiquette où sauter. Si vous regardez attentivement l'étiquette que j'ai passée en
paramètre, vous remarquerez que j'ai ajouté un point d'interrogation au début du nom de l'étiquette. C'est parce que la
commande « OnErrorGoto() » a besoin d'un pointeur de l'étiquette qui passe au lieu d'une simple étiquette. L'utilisation
d'un point d'interrogation comme celui-ci renvoie l'adresse mémoire de l'étiquette. Un pointeur est une variable qui
contient une adresse mémoire de l'endroit où quelque chose est stocké, voir le chapitre 13 (Pointeurs) pour une
explication plus complète. Comme pour les commandes « Goto » et « Gosub », nous omettons également les deux
points à la fin de l'étiquette lorsque nous lui passons le nom de l'étiquette.

Après que l'étiquette ait été spécifiée à l'aide de la commande « OnErrorGoto() », d'autres commandes de la
bibliothèque « OnError » nous aident à comprendre ce qui a mal tourné et où. Dans l'exemple ci-dessus, j'ai utilisé ces
commandes :

« ErrorCode() »
Cette commande renvoie le numéro unique de la dernière erreur survenue.

« ErrorMessage() »
Cette commande renvoie une chaîne contenant une description de l'erreur survenue en "Anglais"

« ErrorLine() »
Cette commande renvoie le numéro de ligne de votre code source dans lequel l'erreur s'est produite, soit dans le texte
source principal ou dans un fichier à inclure. Pour que cette commande fonctionne correctement, vous devez utiliser
l'option « OnError » Activer le support Sélectionnez l'option Compilateur avant de compiler votre programme.

« ErrorFile() »
Cette commande renvoie une chaîne qui vous informe dans quel fichier source l'erreur est eu lieu. Ceci est très utile si
vous utilisez plusieurs fichiers include dans votre projet. Pour que cette commande fonctionne correctement, vous devez
activer l'option de compilateur « OnError support ». avant de compiler votre programme.

Les deux dernières commandes répertoriées ici nécessitent l’activation de la prise en charge de « OnError ». activez
l'option compilateur avant de compiler votre programme. Ceux-ci peuvent être trouvés dans le compilateur Options dans
l'EDI, (menu: Compilateur → Options du compilateur ... → Options du compilateur → OnError-Activez le support).

Pour démontrer le traitement des erreurs à l’aide des commandes « OnError », j’ai reproduit une Erreur intégrée au
programme. Cette erreur est une simple erreur de « division par zéro » et devient un Exemple programmé:

;Déclenchez une erreur classique de division par zéro.


Null.l = 0
TestVariable.l = 100 / Null

Si le débogueur est activé, il l'attraperait facilement, mais si nous le désactivons, cette erreur est manquée. Nous
pouvons utiliser la bibliothèque « OnError » pour récupérer cette erreur sans avoir besoin du débogueur. Pour exécuter
l'exemple et le voir fonctionner correctement, vous devez d'abord désactiver le débogueur et activer l'option « Enable
OnError support ». du compilateur. Maintenant quand vous compilez le programme, il devrait intercepter l' erreur de
« division par zéro » et vous donner un retour détaillé, le tout sans l'aide du débogueur. La Fig.24 montre cet exemple
en action et montre les informations collectées par les autres commandes « OnError ».

Fig. 24
Dans le dernier exemple, j'ai utilisé la commande « OnErrorGoto() » pour spécifier une étiquette de saut, qui est
démarrée en cas d'erreur. En raison de la structure de cette commande, le traitement d Erreur n’est pas conseillé pour
accéder aux données de votre programme car les adresses des variables peuvent avoir perdu leur validité. Le meilleur
plan d'action est simple
106 Bon Style de Programmation

Capturez des informations sur l'erreur, affichez-la, puis quittez le programme. Voulez-vous toujours donner à l'utilisateur
la possibilité de sauvegarder des données non sécurisées, par exemple? Vous devez utiliser la commande
« OnErrorCall() » pour appeler la procédure de traitement des erreurs. Avec cela dans la procédure de traitement des
erreurs, il est toujours possible d’accéder aux données du programme et si nécessaire, sécurisez-les. Cependant, tout
cela doit faire partie de la procédure de traitement des erreurs parce que le programme se termine à la fin de la
procédure. Voici un exemple

;Traitement des erreurs système éventuelles


Procedure ErrorHandler()
Text.s = "Nombre d'erreurs:" + #TAB$ + Str(GetErrorCounter()) + #CRLF$
Text.s + "Numéro d'identification de l'erreur:" + #TAB$ + Str(GetErrorNumber()) + #CRLF$
Text.s + "Description de l'erreur:"" + #TAB$ + GetErrorDescription() + #CRLF$
Text.s + "Survenue en ligne:" + #TAB$ + Str(GetErrorLineNR()) + #CRLF$
Text.s + "S'est produite dans le module:" + #TAB$ + GetErrorModuleName() + #CRLF$+#CRLF$
Text.s + "Voulez-vous continuer à exécuter le programme?"
ReturnValue.l = MessageRequester("ERREUR", Text, #PB_MessageRequester_YesNo)
If ReturnValue = #PB_MessageRequester_No
End
EndIf
EndProcedure

;Définir le gestionnaire d'erreurs


OnErrorGosub(@ErrorHandler())
;Déclenchement d'une erreur classique de «division par zéro
Null.l = 0
TestVariable.l = 100 / Null

;Si le programme arrive jusqu'ici alors le programme continue


MessageRequester("STATUS", "Le programme est autorisé à continuer de fonctionner")
End

Ici, je montrer comment vous pouvez transporter dans votre programme après un nettoyage erreur. Ici, l'utilisateur en
cas de besoin peuvent sauvegarder leurs données avec une forte probabilité, même avant la fin du programme.

« OnErrorGoto » et « OnErrorCall »

Ces deux commandes sont très similaires en ce sens qu'elles vous permettent de spécifier un endroit où sauter en
cas d'erreur afin que vous puissiez gérer et décrire l'erreur. La principale différence entre ces deux commandes
est que le gestionnaire d'erreurs vous permet de revenir au déroulement normal du programme.

La commande « OnErrorGoto » vous permet de spécifier une étiquette vers laquelle vous pouvez sauter
lorsqu'une erreur se produit mais que vous ne pouvez pas en revenir. Cela signifie qu'une fois qu'une erreur est
traitée, le programme doit quitter immédiatement.

La commande « OnErrorCall » vous permet de spécifier une étiquette ou une procédure à utiliser comme
gestionnaire d'erreur, vous donnant la possibilité d'y revenir avec le mot-clé approprié. Cela signifie que vous avez
la possibilité de reprendre l'exécution normale du programme après qu'une erreur ait été traitée.

Disons, par exemple, que vous avez écrit un éditeur de texte et que Bob s'en sert pour écrire une lettre. Si après une
heure d'écriture une erreur inexpliquée se produit et que le programme affiche un message d'erreur, Bob ne veut pas
avoir perdu cette dernière heure et perdre sa lettre à cause d'une erreur. Dans ce cas, Bob peut être informé de ce qui
s'est passé et avoir le choix de reprendre l'exécution du programme pour enregistrer sa lettre dans un fichier avant de
redémarrer le programme. Une adresse courriel pourrait même s'afficher dans le message d'erreur pour que Bob puisse
communiquer avec lui et lui expliquer ce qui s'est mal passé afin que l'auteur du programme puisse le corriger.

La Génération et l'Evaluation des Erreurs Définies par l'Utilisateur


Jusqu'à présent, je vous ai montré une façon d'attraper et de documenter les erreurs système qui peuvent se produire
dans votre programme et de cette façon, vous pourrez détecter presque toute erreur système grave que vous pourriez
rencontrer. Parfois, cependant, vous pouvez vouloir soulever votre propre erreur pour des raisons de personnalisation.
Si c'est le cas, vous pouvez utiliser la commande« SetErrorNumber() » pour créer et lancer votre propre erreur.
Bon Style de Programmation 107

La commande « SetErrorNumber() » a besoin d'un paramètre pour fonctionner correctement et ce paramètre est un
numéro de type Long qui identifie cette erreur. J'utilise généralement des constantes pour définir des numéros
d'erreur personnalisés, puis je peux me référer à ceux-ci par leur nom, comme ceci :

#ERROR_READFILE = 1
#ERROR_WRITEFILE = 2
#FILE_TEXT = 1

;Définir le gestionnaire d'erreurs


OnErrorGoto(?ErrorHandler)

If ReadFile(#FILE_TEXT, "Report.txt") = #False


;Si le fichier lu échoue, il déclenche une erreur.
SetErrorNumber(#ERROR_READFILE)
EndIf
End

;Traiter toute erreur personnalisée qui se produit


ErrorHandler:
Text.s = "Nombre d'erreurs:" + #TAB$ + #TAB$ + Str(GetErrorCounter())
+ #CRLF$
Text.s + "Numéro d'identification de l'erreur:" + #TAB$ + #TAB$ +
Str(GetErrorNumber()) + #CRLF$
Select GetErrorNumber()
Case #ERROR_READFILE
Description.s = "Le fichier n'a pas pu être lu."
Case #ERROR_WRITEFILE
Description.s = "Le fichier n'a pas pu être écrit."
EndSelect
Text.s + "Description de l'erreur:" + #TAB$ + #TAB$ + Description +
#CRLF$
Text.s + "Une erreur est survenue en ligne:" + #TAB$ +
Str(GetErrorLineNR()) + #CRLF$
Text.s + "Une erreur s'est produite dans le module:" + #TAB$ +
GetErrorModuleName() + #CRLF$
MessageRequester("ERREUR", Text)
End

Dans l'exemple ci-dessus, si le fichier « Report.txt » ne peut pas être lu en utilisant la commande « ReadFile() », je crée
une erreur personnalisée en utilisant la commande « SetErrorNumber() ». Cette erreur est identifiée par la constante
« #ERROR_READFILE » qui a la valeur « 1 ». Une fois qu'une erreur a été déclenchée de cette façon, l'étiquette ou la
procédure de gestion des erreurs est appelée. Dans le gestionnaire d'erreurs, vous pouvez vérifier quel numéro d'erreur
a été augmenté en utilisant la commande « GetErrorNumber() ». En fonction du résultat de cette commande, vous
pouvez alors adapter la description de l'erreur au contenu de votre cœur. Ici, je teste la commande « GetErrorNumber()
» avec une instruction « Select » et en utilisant différentes chaînes de description en fonction de sa valeur. Le message
d'erreur contextuel affiche alors cette description.

Comme vous pouvez le constater à partir de ces exemples, l’utilisation de la bibliothèque « OnError » permet une
vérification avancée des erreurs, mais en utilisant une syntaxe très simple.
108 Créer des Interfaces Utilisateur

II. Interfaces utilisateur graphiques


Dans cette prochaine section, je vais parler des interfaces utilisateur graphiques et de la façon dont elles sont créées
dans PureBasic. Presque tous les systèmes d'exploitation modernes disposent d'une interface utilisateur graphique
intégrée, permettant à l'utilisateur d'interagir de manière fluide avec les programmes qui choisissent de l'utiliser. Le
système d'exploitation expose l'interface utilisateur à des programmes par le biais d'une interface de programmation
d'application (ou API) par laquelle un programme peut indiquer au système d'exploitation comment dessiner son
interface utilisateur. Cela peut paraître extrêmement compliqué, mais c'est simple et élégant dans PureBasic en utilisant
« Window », « Menu » et Bibliothèques « Gadget ».

PureBasic crée ces interfaces graphiques pour vos programmes en utilisant l'interface de programmation native du
système pour lequel ils ont été compilés. En d'autres termes, lorsque vous codez une interface pour un programme et
que vous la compilez sur un système particulier, ce programme aura l'apparence correcte du système d'exploitation
pour lequel il a été compilé. C'est essentiel pour tout développement d'applications professionnelles.

Cette section commence par expliquer et démontrer les programmes qui utilisent une console comme interface
utilisateur, ce qui est sans doute l'interface utilisateur la plus simple de toutes. Plus tard, j'expliquerai comment créer des
programmes avec des interfaces utilisateur natives et comment ajouter des menus et des graphiques. Dans la dernière
section, je vous donne un aperçu du PureBasic Visual Form Designer. En utilisant cet outil, vous pouvez concevoir une
interface visuellement comme si vous la peigniez sur un programme.

Après avoir lu cette section, vous devriez bien comprendre comment créer des interfaces utilisateur graphiques pour vos
programmes et comment gérer l'interaction de l'utilisateur.

9. Créer des Interfaces Utilisateur


Dans ce chapitre, je vais vous expliquer comment créer des interfaces utilisateur graphiques pour vos programmes.
PureBasic rend cette tâche très facile en distillant des interfaces de programmation d'applications complexes en
commandes simples et faciles à apprendre. J'explique en détail comment coder l'interface graphique, avec des menus et
parfois des graphiques. J'explique également comment gérer les événements à partir de l'interface de votre programme,
par exemple, lorsque l'utilisateur appuie sur un bouton ou sélectionne un élément de menu. Nous espérons qu'après
avoir lu ce chapitre, vous serez bien équipé pour créer des interfaces utilisateur pour tout programme que vous
déciderez de développer.

Programmes de Consoles
Pour commencer, nous ne devrions pas courir avant de pouvoir marcher, donc je vais d'abord vous présenter ce que l'on
appelle un programme de console. Les programmes de console, comme leur nom l'indique, sont des programmes qui
utilisent une console comme interface utilisateur. Une console est une interface basée sur le texte qui peut accepter
l'entrée dactylographiée et l'affichage de sortie en utilisant des caractères de texte. Sur certains systèmes d'exploitation,
la console peut afficher des graphiques simples en remplaçant les symboles graphiques par certains caractères ASCII.

Les interfaces de console sont généralement utilisées dans les programmes où une interface utilisateur complète n'est
pas nécessaire. Ces types de programmes sont généralement des outils en ligne de commande qui sont exécutés à
partir d'autres consoles ou des programmes CGI qui s'exécutent en arrière-plan sur des serveurs Web, etc.
Fondamentalement, une console est utilisée pour afficher les informations de sortie de base du programme et pour
accepter les entrées de texte de base de l'utilisateur. Les commandes qui créent et utilisent une interface console sont
regroupées dans la bibliothèque « Console » ((Fichier d'aide: Guide de référence → bibliothèques générales->Console).
Cette bibliothèque offre aux programmeurs PureBasic diverses commandes pour imprimer du texte, accepter les entrées
de l'utilisateur, effacer la console et même changer ses couleurs. Voici un exemple de création d'un programme de
console dans PureBasic :

If OpenConsole()
Print("Ceci est un programme test de la console, appuyez sur Entrée pour quitter ...")
Input()
CloseConsole()
EndIf
End
Créer des Interfaces Utilisateur 109

Dans cet exemple, j'ai utilisé les commandes « OpenConsole() » et « CloseConsole() » pour ouvrir et fermer la fenêtre
de la console. La deuxième commande que j'ai utilisée est la commande « Print() » qui accepte un paramètre chaine qui
est imprimé sur l'interface console. Cette commande est presque identique à l'autre commande de la bibliothèque de la
console « PrintN() ». Le « PrintN() » imprimera également une ligne de texte mais il ajoutera un caractère de fin de ligne
à la fin pour se déplacer vers une nouvelle ligne après que le texte ait été imprimé. Ce comportement est très similaire à
celui des commandes d'écriture de fichiers « WriteString() » et «WriteStringN() » comme mentionné au Chapitre 7
(Gestion des fichiers).

La dernière commande utilisée dans l'exemple ci-dessus est « Input() ». Cette commande arrête l'exécution du
programme jusqu'à ce que vous appuyiez sur la touche Entrée du clavier. Cette commande renvoie ensuite tous les
caractères (sous forme de chaîne) qui ont été entrés dans la console avant que la touche Entrée ne soit enfin enfoncée.
Parce que dans mon exemple, je ne traite aucune valeur de retour de cette commande, il est utilisé ici uniquement pour
garder la console ouverte afin que les gens puissent lire le texte que j'ai imprimé sur elle. Si cette commande était
omise, la console se fermerait presque immédiatement dès qu'elle serait ouverte. L'utilisation de « Input() » comme ceci,
peut fournir un moyen simple de garder la console ouverte pendant que nous lisons ce qui y est imprimé, tant que nous
informons l'utilisateur que pour continuer l'exécution du programme il ou elle doit appuyer sur Entrée.

Lecture des Entrées Utilisateur


Parfois, dans les programmes de votre console, vous pouvez vouloir lire les entrées de l'utilisateur, il peut s'agir d'un
simple nombre ou d'une chaîne de texte. Bien qu'il soit assez simple de rassembler n'importe quelle entrée utilisateur,
vous devez toujours vous rappeler que la commande « Input() » renvoie uniquement des chaînes de caractères. Le
code suivant le montre, tout en introduisant de nouvelles commandes dans la console :

If OpenConsole()

EnableGraphicalConsole(#True)

Repeat

ConsoleColor(10, 0)
PrintN("GÉNÉRATEUR DE TABLES DE TEMPS")
PrintN("")
ConsoleColor(7, 0)
PrintN("S'il vous plaît entrer un nombre, puis appuyez sur la touche de retour..")
PrintN("")

Number.q = Val(Input())
If Number = 0
ClearConsole()
Continue
Else
Break
EndIf

ForEver
PrintN("")
For x.l = 1 To 10
PrintN(Str(x) + " x " + Str(Number) + " = " + Str(x * Number))
Next x
PrintN("")

Print("Appuyez sur Retour pour quitter ...")


Input()
CloseConsole()
EndIf
End

Cet exemple semble assez compliqué mais ce n'est pas vraiment le cas si vous le lisez une ligne à la fois. La première
nouvelle commande que j'ai utilisée ici est la commande « EnableGraphicalConsole() ». Ceci active ou désactive les
capacités graphiques du programme de la console en passant les constantes « #True » ou « #False » comme
paramètre. Comme nous utiliserons plus tard « ClearConsole() » qui ne fonctionne qu'avec une console graphique, nous
avons mis « EnableGraphicalConsole() » à true.
110 Créer des Interfaces Utilisateur

Différences entre le Mode Console Graphique et le Mode Console non Graphique


En utilisant la commande « EnableGraphicalConsole() » vous pouvez passer du mode texte au mode graphique
de la console actuelle. Voici les différences pour chaque mode :

Mode texte (par défaut):


Les caractères de contrôle ASCII fonctionnent correctement (plage ASCII « 0 » à « 33 » ). La redirection de
sortie à l'aide de Pipes fonctionne correctement (Essentiel pour les programmes CGI). Les longues chaînes de
texte imprimé s'enroulent sur une nouvelle ligne si elles atteignent la fin de la fenêtre de la console. Vous pouvez
lire et écrire sur la console des données qui ne sont pas nécessairement textuelles.

Mode Graphique (Modifiez avec « EnableGraphicalConsole (#True) »):


Les caractères de texte en dehors de la plage ACSII « 33 » à «126 » sont affichés sous forme de petits
graphiques simples. Les longues chaînes de texte imprimé sont tronquées si elles atteignent la fin de la fenêtre
de la console « ClearConsole() » efface la console entière de toute sortie. « ConsoleLocate() » Déplace le
curseur pour pouvoir imprimer du texte à n'importe quel endroit de la fenêtre de la console.

Cette liste contient quelques points avancés que vous ne connaissez pas encore, mais ils sont inclus dans cette
liste afin que vous puissiez les utiliser comme référence dans le futur quand vous serez plus à l'aise avec ces
choses.

J'ai aussi changé la couleur du texte de la console à certains endroits en utilisant la commande « ConsoleColor() » . Le
premier paramètre est la couleur du texte et le second est la couleur de fond du texte. Les paramètres sont des nombres
qui vont de « 0 » à « 15 » qui représentent différents presets de couleurs, voir le fichier d'aide pour voir quelle couleur
est associée à chaque nombre ((Fichier d' aide: Guide de référence → bibliothèques générales->Console-> Console
Color).

Aussi dans cet exemple, j'ai utilisé une boucle pour gérer la vérification de l'entrée de l'utilisateur, ceci est utilisé comme
un moyen de presque relancer le programme si l'utilisateur a entré une valeur incorrecte. Je veux qu'un nombre soit
entré donc j'utilise la commande « Val() » pour changer la chaîne retournée de la commande « Input() » en un Quad.
Cette valeur retournée est ensuite testée, si elle est égale à « 0 », l'utilisateur doit avoir tapé une chaîne non numérique
ou le nombre « 0 ». Si c'est le cas, j'efface toutes les sorties de la console en utilisant la commande « ClearConsole() »
et force la boucle à continuer depuis le début, en redessinant totalement le texte original et en demandant à l'utilisateur
d'entrer à nouveau. Si l'entrée de l'utilisateur est un nombre supérieur à « 0 », alors j' interromps la boucle et continue
avec le reste du programme qui dessine le tableau des temps pour ce nombre.

Lecture des Entrées Utilisateur en Temps Réel


Le dernier exemple présentait la commande« Input() » qui est correcte si vous avez besoin d'entrer une chaîne ou autre
mais sa seule limitation est que vous devez appuyer sur la touche Entrée pour qu'elle soit transmise au programme. Et
si vous souhaitiez que l'utilisateur saisisse en temps réel le moment où une touche a été appuyée pour déclencher une
action ? Eh bien, cela peut être réalisé en utilisant les commandes « Inkey() » et « RawKey() ». Regardez ce prochain
morceau de code pour un exemple sur l'utilisation des deux :

Procedure DisplayTitle()
ConsoleColor(10, 0)
PrintN("TROUVER LE CODE CLE")
PrintN("")
ConsoleColor(7, 0)
EndProcedure

Procedure DisplayEscapeText()
PrintN("")
ConsoleColor(8, 0)
PrintN("Appuyez sur une autre touche ou appuyez sur echap pour sortir")
ConsoleColor(7, 0)
EndProcedure
Créer des Interfaces Utilisateur 111

If OpenConsole()

EnableGraphicalConsole(#True)
DisplayTitle()
PrintN("Appuyez sur une touche ...")
Repeat
KeyPressed.s = Inkey()
RawKeyCode.l = RawKey()

If KeyPressed <> ""

ClearConsole()
DisplayTitle()
PrintN("Touche enfoncée: " + KeyPressed)
PrintN("Code clé: " + Str(RawKeyCode))
DisplayEscapeText()

ElseIf RawKeyCode
ClearConsole()
DisplayTitle()
PrintN("Touche enfoncée:" + "Non-ASCII")
PrintN("Code clé: " + Str(RawKeyCode))
DisplayEscapeText()

Else

Delay(1)

EndIf

Until KeyPressed = #ESC$


CloseConsole()
EndIf
End

Cet exemple est similaire à l'exemple précédent dans la mesure où nous ouvrons une console et la basculons en mode
graphique pour y imprimer du texte. La principale différence est que la boucle « Repeat » appelle en permanence deux
commandes pour déterminer quelle touche, le cas échéant, a été pressée. Ces deux commandes sont « Inkey() » et «
RawKey() ».

La première commande, « Inkey() » renvoie une chaîne d'un caractère de la touche maintenue enfoncée lorsque cette
commande a été appelée. Donc si j'appuie sur la touche « D » du clavier pendant que cette commande est appelée,
alors « Inkey() » retournerait la chaîne « d ». Bien que cette commande soit simple à comprendre, vous devez vous
rappeler que les touches d'un clavier standard sont généralement imprimées en majuscules, alors que la commande «
Inkey() » les renvoie en minuscules, à moins que la touche Shift ne soit maintenue enfoncée en même temps. Si une
touche non-ASCII est maintenue enfoncée pendant que cette commande est appelée, alors « Inkey() » retournera une
chaîne vide jusqu'à ce qu'une touche ASCII soit maintenue enfoncée.

La deuxième commande de collecte d'informations sur la touche qui a été pressée est un compagnon de la commande
« Inkey() » , son nom est « RawKey() ». Cette commande, comme son nom l'indique, retourne un code numérique brut
de la touche maintenue enfoncée pendant que cette commande est appelée. Dans l'exemple ci-dessus, vous pouvez
voir comment utiliser les deux commandes pour extraire des informations sur la touche maintenue enfoncée pendant la
boucle. C'est un excellent moyen de lire en temps réel les données saisies par l'utilisateur et de réagir en conséquence
lorsqu'une touche particulière est actionnée.

Retarder les Activités


Vous remarquerez peut-être que dans l'exemple ci-dessus, j'ai aussi utilisé une commande « Delay() » pour indiquer
au programme de se retarder de « 1 » milliseconde. Bien que cela semble un peu étrange et inutile, la commande «
Delay() » est là pour une raison. Comme vous utiliserez un système d'exploitation multitâche pour exécuter vos
programmes, c'est une bonne pratique de programmation de ne pas monopoliser le temps CPU si vous pouvez l'aider.
L'utilisation de la commande « Delay() » donne aux autres programmes une chance d'utiliser le CPU pendant que votre
programme est retardé. Même un délai de « 1 » milliseconde permet au système d'exploitation de libérer l'unité centrale
assez longtemps pour permettre à d'autres programmes d'avoir une chance de fonctionner. Cette commande est
112 Créer des Interfaces Utilisateur

particulièrement utile lorsque vous utilisez des boucles pour effectuer la même action encore et encore. Si une
commande « Delay() » n'est pas utilisée dans une telle boucle, votre programme prendra toutes les ressources du CPU
jusqu'à ce qu'il ait quitté, ne laissant aucune puissance de traitement disponible pour les autres programmes à exécuter.
Cela peut parfois donner l'impression que ces autres programmes sont lent et ne réagissent pas normalement.

Compiler un Vrai Programme de Console


Exécuter les exemples de programmes console dans l' IDE construira des programmes qui ressemblent et agissent
comme de vrais programmes console mais qui ne seront pas des programmes console dans le vrai sens du terme tant
que vous ne les aurez pas compilés en utilisant le format exécutable « console ».

Le format de
l'exécutable est
sélectionné ici

Fig. 25
La boîte de dialogue « Options du compilateur » telle qu'elle apparaît sous Microsoft Windows

La Fig.25 montre un diagramme de l'emplacement de l'option de format exécutable dans la boîte de dialogue « Compiler
Options » (Menu:Compiler->Compiler Options...). Une fois cette option sélectionnée, cliquez sur « OK » et compilez
votre programme à l'aide de« Créer un exécutable...». (Menu:Compiler->Créer un exécutable...) pour compiler votre
exécutable final. Le compilateur PureBasic va maintenant construire un véritable programme console.

La principale différence entre ces formats exécutables est que l'IDE compile par défaut tous les programmes en utilisant
le format exécutable du système d'exploitation natif. Ces programmes, lorsqu'ils sont exécutés en double-cliquant ou en
les évoquant depuis une interface en ligne de commande, ouvriront toujours une nouvelle fenêtre de console avant de
continuer. En utilisant le format exécutable « Console », vous pouvez déclarer explicitement que ce programme doit être
compilé comme un véritable programme console, ce qui signifie que le programme s'exécutera normalement s'il est
double-cliqué, mais quand il est exécuté depuis une interface en ligne de commande, il n'ouvre pas une nouvelle fenêtre
console, il agit correctement comme un outil dans la ligne de commande actuellement ouverte.

Et c'est tout ce qu'il y a à programmer des interfaces dans les programmes de console. Ils ne sont pas censés être
utilisés pour des interfaces compliquées (bien que dans le passé, les jeux aient été écrits en utilisant le mode console
graphique). Ces interfaces sont vraiment utilisées de nos jours pour afficher des sorties simples à partir d'outils en ligne
de commande.
Créer des Interfaces Utilisateur 113

Création d'Interfaces Utilisateur Communes au Système d'Exploitation


Dans cette prochaine section, je vais vous montrer comment créer des interfaces utilisateur qui ont le même aspect et la
même convivialité que tous les programmes en cours d'exécution sur votre système d'exploitation. Ces interfaces sont
appelées utilisateur parce que PureBasic utilise l'API du système d'exploitation sous-jacent pour dessiner les
composants de l'interface. Pour un exemple d'une telle interface, regardez l'IDE PureBasic, qui a été entièrement écrit à
partir de zéro en utilisant PureBasic qui utilise à son tour l'API du système d'exploitation.

Toute cette discussion sur l'API du système d'exploitation peut vous décourager, vous faisant penser que tout cela
semble très compliqué, mais ne paniquez pas. La bonne nouvelle, c'est que vous n'avez pas besoin de savoir ce qui se
passe sous le capot, car PureBasic gère cela automatiquement et vous cache les problèmes complexes. En utilisant
simplement les bibliothèques intégrées de PureBasic, vous pouvez créer des applications puissantes qui rivalisent avec
n'importe quel autre langage de programmation. En moyenne, les programmes PureBasic s'avèrent plus rapides et
compilent à une taille exécutable plus petite que de nombreux langages industriels. Cela a été prouvé à maintes
reprises par de petits concours créés par des membres des forums en ligne officiels de PureBasic.

Maintenant, allons de l'avant et créons notre première interface utilisateur commune de système d'exploitation.

Bonjour le Monde
Comme il est d'usage dans le monde de la programmation, le premier exemple de commande d'interface d'un langage
de programmation est généralement un programme « hello world ». Il s'agit d'une simple fenêtre qui dit bonjour à
l'utilisateur et permet de fermer le programme. Commencez un nouveau fichier dans l'IDE et tapez ceci :

#WINDOW_MAIN = 1
#FLAGS = #PB_Window_SystemMenu | PB_Window_ScreenCentered

If OpenWindow(#WINDOW_MAIN, 0, 0, 300, 200, "Bonjour le Monde", #FLAGS)


Repeat
Event.l = WaitWindowEvent()
Until Event = #PB_Event_CloseWindow
EndIf
End

Si vous exécutez ce morceau de code, vous verrez une fenêtre similaire à la Fig.26 au verso. Pour fermer cette fenêtre,
cliquez sur le bouton de fermeture dans le coin supérieur droit. Bien que cet exemple ne comporte qu'une fenêtre vide et
un bouton de fermeture dans la barre de titre, c'est le début de toutes les interfaces utilisateur natives dans PureBasic.

Bouton de Fermeture

(Exemple Microsoft Windows) Fig. 26

Dans l'exemple ci-dessus, j'utilise la commande « OpenWindow() » pour ouvrir la fenêtre et définir les fonctionnalités
qu'elle doit avoir. Si vous ouvrez le fichier d'aide et que vous vous référez à la commande « OpenWindow() » (Fichier
d'aide : Manuel de référence → Bibliothèques générales → Fenêtre →) puis regardez l'exemple de syntaxe, vous
pouvez voir que j'ai utilisé les drapeaux (Flags) « #PB_Window_SystemMenu » et « #PB_Window_ScreenCentered »
pour définir que cette fenêtre doit avoir un menu système fonctionnel, avec un bouton de fermeture et être centrée sur
l'écran lorsqu'il est ouvert. Lorsque vous utilisez plusieurs drapeaux comme celui-ci, vous les joignez ensemble en
utilisant l'opérateur binaire « OR » « | » comme indiqué dans le code ci-dessus. Cet opérateur combine la valeur de
tous les drapeaux utilisés au niveau binaire (pour une explication plus complète, voir chapitre 3).
114 Créer des Interfaces Utilisateur

Après avoir utilisé la commande« OpenWindow() », j'ai utilisé une boucle « Repeat » comme boucle principale pour
traiter tous les événements que cette fenêtre peut rencontrer.

Pourquoi les Paramètres de Position de la Fenêtre sont-ils Réglés à « 0 »?


Lors de l'ouverture d'une fenêtre à l'aide de la commande « OpenWindow() », les deuxième et troisième
paramètres de cette commande déterminent les coordonnées où cette fenêtre sera dessinée à l'écran.
Cependant, si vous utilisez les drapeaux (Flags) « #PB_Window_ScreenCentered » ou « #PB_Window_Window
Centered » dans la même commande, les paramètres de position sont ignorés. En effet, PureBasic remplace ces
paramètres de position pour centrer la fenêtre sur l'écran ou sur une autre fenêtre. Si c'est le cas, vous pouvez
utiliser « 0 » pour les deux paramètres de position ou utiliser la constante« #PB_Ignore » pour montrer
explicitement dans votre code source que ces deux paramètres sont ignorés à cause des drapeaux utilisés.

La Boucle Principale
La boucle principale d'un programme est ce qui le maintient en vie. Il permet au programme de continuer à fonctionner
tout en redessinant l'interface (s'il est déplacé sur le bureau) et de gérer tous les événements que l'interface peut
générer. Heureusement, PureBasic gère automatiquement tout redessin de l'interface, nous n'avons donc qu'à utiliser
une boucle principale pour maintenir le programme en marche et pour traiter d'autres événements.

Dans mon petit programme « Hello World », j'ai utilisé une boucle « Repeat » comme boucle principale, ce qui me donne
la possibilité de continuer la boucle jusqu'à ce qu'une condition particulière soit remplie, dans ce cas, jusqu'à ce que j'ai
rencontré un événement de type « #PB_Event_CloseWindow » , qui est l'événement déclenché quand vous cliquez le
bouton fermer. Une fois cet événement reçu, la boucle se termine et le programme se termine.

Comprendre les Evénements


Chaque programme que vous écrivez en utilisant n'importe quel langage de programmation utilisera à peu près la même
façon de gérer les événements. Ceci implique la détection d'un événement pendant la boucle principale, puis l'exécution
d'un autre morceau de code par le programme en fonction de l'événement en question. Quels types d'événements y a-t-
il ? Eh bien, un événement peut être déclenché par de nombreuses actions dans vos programmes, un événement peut
être déclenché en cliquant sur un gadget, en appuyant sur un bouton du clavier, en sélectionnant un élément dans un
menu ou simplement en déplaçant ou fermant le programme. Le truc, c'est de savoir quel événement s'est produit pour
que vous puissiez le gérer correctement. Pour ce faire, nous utilisons les commandes « WaitWindowEvent() » ou «
WindowEvent() ».

C'est Quoi un Gadget ?


Dans PureBasic, un gadget est un objet sur une interface utilisateur graphique qui fournit une certaine interactivité
pour votre programme. Dans Microsoft Windows, ces objets sont appelés « contrôles » et dans certaines
distributions Linux, ils sont appelés « widgets ». Les gadgets sont des boutons, des cases à cocher, des curseurs,
des champs de saisie, des onglets, des cadres, des barres de progression, etc. Tous ces différents composants
interactifs sont appelés gadgets PureBasic.

Ces deux commandes sont presque identiques car elles renvoient toutes les deux un identificateur d'événement sous la
forme d'un numéro de type long lorsqu'un événement se produit. La différence entre les deux est que la commande «
WaitWindowEvent() » arrête votre programme jusqu'à ce qu'un événement soit détecté, puis renvoie l'identifiant de
l'événement et laisse le programme continuer normalement jusqu'à ce qu'il soit appelé à nouveau. (C'est idéal pour
l'utilisation dans les interfaces utilisateur graphiques car cela permet au programme d'utiliser aussi peu de CPU que
possible, en l'utilisant seulement quand un événement se produit réellement.) La commande « WindowEvent() » n'arrête
cependant pas du tout le programme, elle teste juste pour voir s'il y a des événements à revenir. Si c'est le cas, cette
commande retournera son identifiant. Cette commande est très rarement utilisée dans les interfaces utilisateur car elle
peut les rendre très gourmandes en CPU, monopolisant la puissance de traitement de l'ordinateur sur lequel elles
fonctionnent. La commande « WindowEvent() » est souvent utilisée lorsque vous avez besoin de faire tourner la boucle
principale à tout prix, par exemple, si vous affichez un graphique dynamique dans votre programme qui doit être
continuellement redessiné, etc. Si c'est le cas et que vous devez utiliser la commande « WindowEvent() », un bon style
de programmation dicte que vous essayez d'utiliser l'astuce « Delay(1) » avec lui (comme expliqué dans la section
programme console) pour vous assurer que votre programme est compatible CPU. Si aucun événement n'est détecté,
utilisez « Delay(1) » pour permettre aux autres programmes d'utiliser le CPU.
Créer des Interfaces Utilisateur 115

Dans le programme « Hello World », j'ai utilisé une commande « WaitWindowEvent() » pendant la boucle « Repeat »
pour arrêter le programme jusqu'au déclenchement d'un événement. Une fois qu'un événement est déclenché, la
commande « WaitWindowEvent() » renvoie son identifiant qui est stocké dans une variable de type long appelée « Event
». La boucle est ensuite codée pour sortir si « Event » est égal à la valeur de « #PB_Event_CloseWindow », qui est une
constante intégrée qui contient l'identifiant d'un événement « Fermer la Fenêtre » de l'interface. Si ces deux valeurs
sont égales, un événement « Fermer la fenêtre » doit s'être produit pour que la boucle se ferme et que le programme
soit terminé.

Les Evénements se Produisent tout le Temps


Même si aucun autre événement n'est traité dans ce petit exemple, cela ne veut pas dire qu'il ne se produit pas. Si nous
prenons le même programme « Hello World » et ajoutons une autre ligne contenant une commande « Debug », il
affichera maintenant les identifiants des événements dans la fenêtre Debug pendant l'exécution.

Exécutez le morceau de code suivant, puis déplacez-vous et cliquez dans et autour de la fenêtre. Vous verrez de
nombreux événements se produire.

#WINDOW_MAIN = 1
#FLAGS = #PB_Window_SystemMenu |
#PB_Window_ScreenCentered

If OpenWindow(#WINDOW_MAIN, 0, 0, 300,
200, "Bonjour le Monde", #FLAGS)
Repeat
Event.l = WaitWindowEvent()
Debug Event
Until Event = #PB_Event_CloseWindow
EndIf
End

C'est la commande « WaitWindowEvent() » qui renvoie les identifiants de tous les événements déclenchés, même s'ils
ne sont pas gérés par votre programme. Ceci est tout à fait normal et ne ralentira pas sensiblement votre programme.

Ajouter desGadgets
Jusqu'à présent, nous avons vu une simple fenêtre créée qui affichait « Hello World » dans la barre de titre, bien qu'il
s'agisse d'une belle introduction aux interfaces utilisateur, elle ne montre aucune forme d'interaction avec l'utilisateur
autre que la possibilité de fermer la fenêtre. Dans cette prochaine section, je vais vous montrer comment vous pouvez
ajouter des gadgets à la fenêtre de votre programme pour augmenter la fonctionnalité et l'interactivité.

Dans l'exemple suivant, j'ai ajouté deux boutons et je vous montre comment capturer les événements à partir de ceux-ci.

Enumeration
#WIN_MAIN
#BUTTON_INTERACT
#BUTTON_CLOSE
EndEnumeration
Global Quit.b = #False
#FLAGS = #PB_Window_SystemMenu | #PB_Window_ScreenCentered
If OpenWindow(#WIN_MAIN, 0, 0, 300, 200, "Interaction", #FLAGS)
ButtonGadget(#BUTTON_INTERACT, 10, 170, 100, 20, "Click moi")
ButtonGadget(#BUTTON_CLOSE, 190, 170, 100, 20, "Fermer la Fenêtre")
Repeat
Event.l = WaitWindowEvent()
Select Event
Case #PB_Event_Gadget
Select EventGadget()
Case #BUTTON_INTERACT
Debug "Le bouton a été enfoncé."
Case #BUTTON_CLOSE
Quit = #True
EndSelect
EndSelect
Until Event = #PB_Event_CloseWindow Or Quit = #True
EndIf
End
116 Créer des Interfaces Utilisateur

Si vous lisez ce code, il devrait être assez facile à comprendre pour vous, alors je vais passer en revue certains des
domaines clés qui seront nouveaux pour vous. La Fig.27 vous montre à quoi ressemble cette fenêtre.

(Exemple Microsoft Windows) Fig. 27

Dans cet exemple, j'ai inséré deux boutons dans la fenêtre avec la fonction « ButtonGadget() ». regardez dans l'aide à
la page « ButtonGadget() » (fichier d'aide : Manuel de référence → Bibliothèques générales → Gadget →
ButtonGadget), vous verrez dans l'exemple syntaxique les paramètres requis pour cette commande.

Avec les paramètres de position de la fonction « ButtonGadget() » j'ai placé les boutons en bas de la fenêtre.

Pour mettre en évidence une autre zone clé, si vous regardez la boucle principale, après qu'un identificateur
d'événement ait été retourné depuis la commande « WaitWindowEvent() » et assigné à la variable « Event », j'ai utilisé
une instruction « Select » pour tester sa valeur, comme ceci :

...
Select Event
Case #PB_Event_Gadget
...
EndSelect
...

Vous remarquerez que la première instruction « Case » teste la valeur « #PB_Event_Gadget ». Il s'agit d'une valeur
d'événement global spéciale, utilisée pour tester un identificateur afin de déterminer s'il provient d'un gadget, en d'autres
termes, si « Event » est égal à « #PB_Event_Gadget » alors « Event » doit contenir un identifiant d'événement
provenant d'un gadget.

Une fois que nous savons qu'un événement provient d'un gadget, nous devons alors distinguer de quel gadget il
provient. Nous le faisons en utilisant la commande « Event_Gadget ». qui retourne le numéro PB du gadget d'origine.
Donc dans cet exemple, je teste la valeur de retour de « Event_Gadget » en utilisant un autre « Select ».

...
Select EventGadget()
Case #BUTTON_INTERACT
Debug "Le bouton a été enfoncé."
Case #BUTTON_CLOSE
Quit = #True
EndSelect
...
Créer des Interfaces Utilisateur 117

Ici, j'ai deux instructions « Case », un test pour « #BUTTON_INTERACT » et un test pour « #BUTTON_CLOSE ». Si la
valeur de retour de « EventGadget() » est égale à« #BUTTON_INTERACT » alors le bouton « Click moi » a été
appuyé. Nous le savons parce que le numéro PB de ce gadget a été renvoyé par « EventGadget() ». Ensuite, je tape un
code que je veux exécuter lorsque ce bouton est pressé sur la ligne suivante après l'instruction « Case ».

La même théorie s'applique à l'énoncé suivant du « Case ». Si la valeur retournée est égale à« #BUTTON_CLOSE »,
le bouton « Fermer la Fenêtre » a été pressé. Si c'est le cas, j'assigne une valeur vraie à la variable « Quit » qui fait la
sortie de la boucle principale et termine éventuellement le programme.

C'est pourquoi l'utilisation d'un bloc « Enumeration » constant est si utile. Après avoir défini des constantes numériques
pour tous les gadgets au début du code source, je peux alors me référer à chacun d'eux par un nom de constante au lieu
d'un nombre, ce qui rend le code source infiniment plus clair et lisible.

Acceptation de la saisie de texte


Développons le dernier exemple un peu plus et ajoutons un gadget String pour que nous puissions entrer du texte que
le programme puisse utiliser. Les gadgets String sont très pratiques car ils fournissent un moyen simple de permettre à
votre programme d'accepter des chaînes de texte. L'exemple suivant vous montre comment récupérer la valeur du
gadget String, c'est-à-dire récupérer le texte et l'utiliser dans votre programme. Créez-en une qui correspond à la largeur
totale de la fenêtre. La Fig.28 au verso, montre à quoi devrait ressembler ce programme compilé, voici le code :

Enumeration
#WIN_MAIN
#TEXT_INPUT
#STRING_INPUT
#BUTTON_INTERACT
#BUTTON_CLOSE
EndEnumeration

Global Quit.b = #False


#FLAGS = #PB_Window_SystemMenu | #PB_Window_ScreenCentered

If OpenWindow(#WIN_MAIN, 0, 0, 300, 200, "Interaction", #FLAGS)


TextGadget(#TEXT_INPUT, 10, 10, 280, 20, "Entrer le texte ici:")
StringGadget(#STRING_INPUT, 10, 30, 280, 20, "")
ButtonGadget(#BUTTON_INTERACT, 10, 170, 120, 20, "Afficher le texte")
ButtonGadget(#BUTTON_CLOSE, 190, 170, 100, 20, "Fermer la Fenêtre")
SetActiveGadget(#STRING_INPUT)

Repeat
Event.l = WaitWindowEvent()
Select Event
Case #PB_Event_Gadget
Select EventGadget()
Case #BUTTON_INTERACT
Debug GetGadgetText(#STRING_INPUT)
Case #BUTTON_CLOSE
Quit = #True
EndSelect
EndSelect
Until Event = #PB_Event_CloseWindow Or Quit = #True

EndIf
End

Dans cette version mise à jour, j'ai ajouté quelques constantes supplémentaires au bloc « Enumeration » pour pouvoir
ajouter quelques gadgets supplémentaires facilement. Le premier nouveau gadget que j'ai ajouté est un gadget texte qui
affiche littéralement une chaîne de texte non modifiable sur la fenêtre, j'en utilise une pour afficher la chaîne: « Entrer le
texte ici ». Le deuxième nouveau gadget que j'ai utilisé est un gadget String qui crée un champ de saisie sur la fenêtre
qui vous permet d'entrer votre propre texte.
118 Créer des Interfaces Utilisateur

Si vous ouvrez l'aide de PureBasic et allez à la page « StringGadget() » (fichier d'aide : Manuel de référence →
Bibliothèques générales → Gadget → StringGadget), vous pouvez voir les paramètres dont ce gadget a besoin. J'ai
défini la position et les paramètres de taille pour afficher le gadget string en haut de la fenêtre, sous le gadget texte.
Comme paramètre j'ai passé une chaîne vide « "" », qui est représentée par deux guillemets qui suivent directement.
C'est simplement une chaîne sans contenu. J'ai choisi une chaîne vide parce que le paramètre « "" » représente la
chaîne de début du gadget de chaîne et je voulais démarrer le programme avec un gadget vide.

(Microsoft Windows Beispiel) Fig. 28

Une fois que ce programme est en cours d'exécution, vous remarquerez que le curseur texte clignote immédiatement
dans le gadget String. Ce n'est pas le comportement par défaut, normalement vous devriez cliquer sur le gadget pour lui
donner le focus pour que le curseur y apparaisse. Dans mon programme, j'ai configuré ce gadget pour être le gadget
actif au démarrage en utilisant la commande « SetActiveGadget() » . Cette commande prend un numéro PB comme
paramètre du gadget auquel vous voulez donner le focus, ce qui en fait le gadget actuellement actif. Je l'ai fait dans ce
petit exemple pour aider l'utilisateur et pour lui sauver un clic de souris.

Pour tester l'interactivité de ce programme, entrez du texte dans le gadget String une fois que le programme est lancé,
puis appuyez sur le bouton'Echo text'. Vous verrez maintenant ce texte répercuté dans la fenêtre Debug. C'est parce
que j'ai changé l'instruction « Case » « #BUTTON_INTERACT » pour changer ce qui se passe une fois que le bouton «
Affiche texte » est appuyé. Cette ligne de code a été modifiée pour devenir « Debug GetGadgetText(#STRING_INPUT)
»

La commande « GetGadgetText() » prend un paramètre qui est le numéro PB du gadget dont vous voulez récupérer le
texte, ici je l'utilise pour récupérer le texte du gadget String. Cette commande peut être utilisée avec de nombreux
gadgets dans PureBasic mais avec un gadget String, elle retourne simplement le texte sous la forme d'une chaîne de
caractères que j' édite en utilisant une commande « Debug ».

Afficher le Texte
Allongeons un peu le programme et affichons le texte pour qu'il soit lu non pas dans la fenêtre Debug, mais dans un
gadget directement dans notre programme. Dans l'exemple suivant, j'ai ajouté un gadget ListView pour afficher le texte
saisi dans une liste de chaînes non éditables.

Un gadget ListView est un bon moyen d'afficher une liste de chaînes, puisque chaque chaîne a sa propre ligne dans le
gadget.

PureBasic fournit beaucoup de commandes pour travailler avec les gadgets ListView. Celles-ci vont de l'ajout et de la
suppression au comptage et au tri des éléments contenus. Dans le petit exemple suivant, j'ai seulement utilisé la
fonction « AddGadgetItem() » pour ajouter de nouvelles chaînes. La figure 29 montre le nouveau programme en
fonctionnement, voici le code :

Enumeration
#WIN_MAIN
#TEXT_INPUT
#STRING_INPUT
#LIST_INPUT
#BUTTON_INTERACT
#BUTTON_CLOSE
EndEnumeration

Global Quit.b = #False


#FLAGS = #PB_Window_SystemMenu | #PB_Window_ScreenCentered
Créer des Interfaces Utilisateur 119

If OpenWindow(#WIN_MAIN, 0, 0, 300, 200, "Interaction", #FLAGS)


TextGadget(#TEXT_INPUT, 10, 10, 280, 20, "Entrer le texte ici:")
StringGadget(#STRING_INPUT, 10, 30, 280, 20, "")
ListViewGadget(#LIST_INPUT, 10, 60, 280, 100)
ButtonGadget(#BUTTON_INTERACT, 10, 170, 120, 20, "Afficher le texte")
ButtonGadget(#BUTTON_CLOSE, 190, 170, 100, 20, "Fermer la Fenêtre")
SetActiveGadget(#STRING_INPUT)

Repeat
Event.l = WaitWindowEvent()
Select Event
Case #PB_Event_Gadget
Select EventGadget()
Case #BUTTON_INTERACT
AddGadgetItem(#LIST_INPUT, -1, GetGadgetText(#STRING_INPUT))
SetGadgetText(#STRING_INPUT, "")
SetActiveGadget(#STRING_INPUT)
Case #BUTTON_CLOSE
Quit = #True
EndSelect
EndSelect
Until Event = #PB_Event_CloseWindow Or Quit = #True

EndIf
End

Cet exemple est très similaire au précédent, en fait la seule différence réelle est l'inclusion du gadget listView. La lecture
du fichier d'aide PureBasic sur la page « ListViewGadget() » (fichier d'aide : Manuel de référence → Bibliothèques
générales->Gadget->ListViewGadget) vous donnera un bon aperçu de ce gadget et de ce que vous pouvez faire avec.
La lecture de l'exemple syntaxique contenu ici vous permet également de savoir exactement quels paramètres ce
gadget accepte. J'ai utilisé les paramètres de position et de taille pour placer le gadget d'affichage de liste au milieu de
la fenêtre principale, au-dessus des boutons mais sous le gadget String.

(Exemple Microsoft Windows) Fig. 29

Lorsque vous avez démarré ce programme, entrez un texte dans le gadget chaîne et appuyez sur le bouton « Entrer le
texte ici:» Ceci lira le texte du gadget String et l'ajoutera au gadget ListView. Lorsque cela est fait, le gadget chaîne est
vidé et le programme attend une nouvelle entrée.

Tout cela se produit parce que j'ai changé la fonctionnalité de l'instruction « Case » « #BUTTON_INTERACT » , qui est
appelée en appuyant sur le bouton « Entrer le texte ici: ». Voici les trois nouvelles lignes que j'ai ajoutées à l'instruction
« Case » « #BUTTON_INTERACT » .

...
Case #BUTTON_INTERACT
AddGadgetItem(#LIST_INPUT, -1, GetGadgetText(#STRING_INPUT))
SetGadgetText(#STRING_INPUT, "")
SetActiveGadget(#STRING_INPUT)
...
120 Créer des Interfaces Utilisateur

La première ligne après l'instruction « Case » ajoute un élément au gadget ListView. Lorsque vous ouvrez la page
« AddGadgetItem() » de l'Aide (fichier d'aide : Manuel de référence → Bibliothèques générales → Gadget →
AddGadgetItem), vous verrez les paramètres requis par cette commande. Le premier paramètre est le numéro PB du
gadget auquel vous voulez ajouter un élément, dans notre cas « #LIST_INPUT » est la constante qui contient ce
numéro PB. Le deuxième paramètre spécifie la position dans la liste où vous voulez insérer la nouvelle entrée.
Rappelez-vous que les index commencent à « 0 ». Dans l'exemple ci-dessus, je veux m'assurer que le texte est toujours
inséré à la fin de la liste, quel que soit l'index courant, donc je mets ce paramètre à « 1 ». Ceci indique à la commande
d'insérer l'entrée à la fin de la liste, peu importe la taille de la liste.

Le troisième paramètre est la chaîne de caractères que vous voulez ajouter au gadget. J'ai utilisé la fonction
« GetGadgetText() » pour passer la chaîne retournée du gadge string « #STRING_INPUT » comme paramètre.
« AddGadgetItem() » a plus de paramètres que ce que j'ai utilisé, mais les autres sont optionnels et donc
pas obligatoires, donc je ne les ai pas utilisés.

La deuxième ligne après l'instruction « Case » utilise la fonction « SetGadgetText() » avec une chaîne vide pour définir
la valeur du gadget à zéro. Après avoir transféré la valeur au gadget ListView, je veux vider le gadget string pour qu'il
soit prêt pour une nouvelle entrée.

La dernière ligne utilise à nouveau la fonction « SetActiveGadget() » pour redonner le focus au gadget
« #STRING_INPUT » Ceci repositionnera le curseur texte dans le gadget string et sauvera l'utilisateur d'un autre clic de
souris.

Qu'Avons-Nous Appris Jusqu'à Présent ?


Nous espérons que les derniers exemples ont été une bonne introduction aux interfaces graphiques natives et qu'ils
constituent un bon point de départ pour la suite de l'apprentissage. Dans ce livre, je ne peux pas vous donner des
exemples de toutes les interfaces que vous voulez probablement construire, tout ce que je peux faire est de vous
donner les éléments de base d'une interface et de vous laisser construire sur eux.

Le début de la création d'interfaces utilisateur dans PureBasic est toujours le même. Vous devez d'abord ouvrir
une fenêtre avec la fonction « OpenWindow() ». La deuxième étape consiste à ajouter des gadgets si nécessaire
et la troisième étape consiste à créer une boucle principale pour maintenir le programme en marche et gérer
tous les événements qui se produisent. Tous les événements qui se produisent seront retournés par la fonction
« WaitWindowEvent() » ou « WindowEvent() » dans la boucle principale.

Lire la Section Gadget de l'Aide


Si vous avez compris ce qui a été écrit jusqu'à présent, vous êtes sur la bonne voie pour comprendre comment
construire des interfaces natives dans PureBasic. Une fois que vous avez compris les bases, le reste est d'apprendre
quels gadgets sont disponibles et comment les utiliser. Ceci peut être réalisé en lisant le fichier d'aide PureBasic dans la
section « Gadget » (Fichier d'aide : Manuel de référence → Bibliothèques générales->Gadget). Je recommande de lire
cette section de l'avant vers l'arrière pour comprendre ce qui est disponible pour vous à utiliser et pour comprendre
quelles commandes fonctionnent avec chaque gadget.

Prenons par exemple la commande « SetGadgetText() », qui peut être utilisée avec de nombreux gadgets différents. Si
vous regardez la page « SetGadgetText() » dans le fichier d'aide (fichier d'aide : Manuel de référence → Bibliothèques
générales->Gadget-> SetGadgetText) liste tous les gadgets avec lesquels cette commande fonctionne ainsi que toutes
les instructions spéciales à utiliser avec un gadget particulier.

Couvrir tous les gadgets et les commandes qui les utilisent prendrait beaucoup trop de temps ici et serait probablement
un autre livre en soi. Je pense donc que c'est peut-être une meilleure idée de vous familiariser avec la section « Gadget
» dans le fichier d'aide. En attendant, si vous avez besoin d'une référence rapide sur les gadgets disponibles pour une
utilisation avec PureBasic, consultez l'Annexe B (Tableaux utiles) pour une liste complète de tous les gadgets et une
brève description de chacun.

Ajout d'un Menu


Ajouter un menu natif à une interface est très facile dans PureBasic et très similaire à ajouter des gadgets. Lorsque des
éléments de menu sont sélectionnés, ils déclenchent des événements tout comme les gadgets et ces événements sont
traités dans la boucle principale à côté des événements gadgets.
Créer des Interfaces Utilisateur 121

Tous les éléments de menu sont définis avec leur propre numéro PB, comme les gadgets, qui sont utilisés plus tard
pour distinguer quel élément de menu a déclenché un événement. Voici un petit exemple :
Enumeration
#WINDOW_MAIN
#MENU_MAIN
#MENU_QUIT
#MENU_APROPOS
EndEnumeration

Global Quit.b = #False


#FLAGS = #PB_Window_SystemMenu | #PB_Window_ScreenCentered

If OpenWindow(#WINDOW_MAIN, 0, 0, 300, 200, "Exemple Menu ", #FLAGS)


If CreateMenu(#MENU_MAIN, WindowID(#WINDOW_MAIN))
MenuTitle("File")
MenuItem(#MENU_QUIT, "Quit")
MenuTitle("Help")
MenuItem(#MENU_APROPOS, "a propos de"
de...")
Repeat
Event.l = WaitWindowEvent()
Select Event
Case #PB_Event_Menu
Select EventMenu()
Case #MENU_QUIT
Quit = #True
Case #MENU_APROPOS
MessageRequester("a propos de", "C'est ici que vous décrivez votre programme.")
EndSelect
EndSelect
Until Event = #PB_Event_CloseWindow Or Quit = #True

EndIf
EndIf
End

Ce petit exemple montre un menu commun ajouté à une fenêtre. Deux menus, contenant chacun un élément de
menu, s'affichent. Si vous regardez l'exemple ci-dessus, vous pouvez voir comment un tel menu est créé.

Nous devons d'abord créer une fenêtre, car un menu est assigné à une fenêtre. Après avoir créé la fenêtre, nous
utilisons la fonction « CreateMenu() » pour créer un arborescence de menu. Cette fonction nécessite deux paramètres,
le premier est le numéro PB de cet objet de menu et le second est l'identifiant du système d'exploitation de la fenêtre à
laquelle le menu est affecté. Ici j'utilise la fonction « WindowID() » pour obtenir l'identifiant du système d'exploitation de
la fenêtre principale.

Une fois que le cadre de menu a été créé avec succès, vous pouvez le remplir avec les titres de menu et les éléments
de menu réels. Pour cela je commence avec la fonction « MenuTitle() ». Cette commande crée un titre de menu qui
s'affiche en haut de la fenêtre (ou, dans le cas de Mac OS X, en haut de l'écran). Cette commande nécessite un
paramètre chaîne contenant le nom du menu.

Une fois qu'un titre de menu a été défini, tous les éléments de menu créés apparaissent maintenant sous ce titre. Les
éléments de menu sont créés avec la fonction « MenuItem() ». Cette fonction nécessite deux paramètres, le premier est
le numéro PB auquel l'élément est lié et le second est la chaîne avec laquelle l'élément doit être affiché dans le menu.

Dans mon exemple, j'ai défini un élément nommé'Exit' sous le menu'File'. Puis j'ai utilisé à nouveau la fonction
« MenuTitle() » pour créer un autre menu avec le nom « Help ». Si un autre titre de menu est créé, tous les éléments
nouvellement ajoutés seront désormais affichés en dessous de ce titre, comme le nouveau « A propos de...». Élément
de menu.

Reconnaissance des Evénements du Menu


Une fois que le menu a été créé, y compris tous les titres et éléments du menu, nous détectons les événements
suivants déclenchés par eux dans la boucle principale. Presque exactement comme pour la détection d'événements à
partir de gadgets, nous utilisons un système global appelée « #PB_Event_Menu ».
122 Créer des Interfaces Utilisateur

Si l'événement retourné par « WaitWindowEvent() » est égal à « #PB_Event_Menu », il s'agit d'un événement depuis
un élément de menu. J'ai utilisé cette commande dans une instruction « Select », comme celle-ci :
...
Select Event
Case #PB_Event_Menu
Select EventMenu()
Case #MENU_QUIT
Quit = #True
Case #MENU_APROPOS
MessageRequester("a propos de", "C'est ici que vous décrivez votre programme.")
EndSelect
EndSelect
...

Pour déterminer exactement quel élément de menu a déclenché cet événement, nous devons utiliser la commande «
EventMenu() ». Cette commande retourne le numéro PB de l'élément de menu qui a déclenché l'événement. J'ai utilisé
cette commande dans une autre instruction « Select » pour gérer plusieurs cas d'événements, de sorte que je peux
élégamment gérer les événements à partir de n'importe quel élément de menu. Dans cette instruction « Select » , si la
valeur retournée par la commande « EventMenu() » est égale à « #MENU_QUIT », alors l'élément de menu « Quit » a
été sélectionné et j'assigne une valeur vraie à la variable « End » qui termine la boucle principale, terminant ainsi le
programme. Si la valeur retournée par la commande « EventMenu() » est égale à « #MENU_APROPOS », alors
l'élément de menu « a propos de » a été sélectionné et j'affiche une boite de message affichant des informations sur
mon programme.

Éléments de Sous-Menu
Jusqu'à présent, j'ai montré comment créer des menus standard, mais vous pouvez aussi créer ce que l'on appelle des
sous-menus. Ce sont des menus qui passent d'un menu parent à un autre menu enfant connecté. Fournir une structure
de menu arborescente, un peu comme le menu « Démarrer » sous Microsoft Windows. Tous les éléments de menu à
l'intérieur de ces nouveaux menus enfants déclenchent des événements exactement de la même manière que n'importe
quel autre élément de menu et peuvent être capturés de la même manière dans la boucle principale. En voici un
exemple :

Enumeration
#WINDOW_MAIN
#MENU_MAIN
#MENU_CHILD
#MENU_QUIT
#MENU_APROPOS
EndEnumeration

Global Quit.b = #False


#FLAGS = #PB_Window_SystemMenu | #PB_Window_ScreenCentered

If OpenWindow(#WINDOW_MAIN, 0, 0, 300, 200, "Exemple Menu", #FLAGS)


If CreateMenu(#MENU_MAIN, WindowID(#WINDOW_MAIN))
MenuTitle("Fichier")
OpenSubMenu("Element du menu parent")
MenuItem(#MENU_CHILD, "Sub Menu Item")
CloseSubMenu()
MenuBar()
MenuItem(#MENU_QUIT, "Quit")
MenuTitle("Aide")
MenuItem(#MENU_APROPOS, "a propos de...")
Repeat
Event.l = WaitWindowEvent()
Select Event
Case #PB_Event_Menu
Select EventMenu()
Case #MENU_CHILD
Debug "Element de sous-menu sélectionnée."
Case #MENU_QUIT
Quit = #True
Case #MENU_APROPOS
MessageRequester("a propos de", "C'est ici que vous décrivez votre programme.")
EndSelect
EndSelect
Until Event = #PB_Event_CloseWindow Or Quit = #True
EndIf
EndIf
End
Créer des Interfaces Utilisateur 123

Un sous-menu est créé en utilisant la commande « OpenSubMenu() » après une commande « MenuTitle() ». C'est ainsi
que le sous-menu est lié à un titre de menu comme n'importe quel autre élément de menu. La commande «
OpenSubMenu() » prend un paramètre qui est la chaîne de caractères qui est affichée dans le menu devant la flèche du
sous-menu. Une fois qu'une commande « OpenSubMenu() » est utilisée, toutes les commandes « MenuItem() »
utilisées par la suite placeront de nouveaux éléments de menu dans le sous-menu. Pour fermer ce sous-menu afin de
pouvoir ajouter plus d'éléments au menu principal, vous devez appeler la commande « CloseSubMenu() ». Cette
commande ramène la création d'un élément de menu au menu parent.

Les nouveaux éléments de menu ajoutés aux sous-menus déclenchent des événements qui peuvent être capturés dans
la boucle principale de la même manière que tout autre élément de menu. Si vous regardez l'instruction « EventMenu()
» « Select » , vous pouvez voir que j'ai ajouté une nouvelle valeur à gérer: « #MENU_CHILD ». Si la valeur de retour de
« EventMenu() » est égale à la valeur de « #MENU_CHILD » alors l'élément de menu enfant doit avoir été sélectionné,
donc je fais affiché du texte dans la fenêtre Debug pour afficher ceci.

Séparation des Eléments de Menu


Si vous regardez de plus près l'exemple ci-dessus, j'ai aussi ajouté une autre nouvelle commande. Cette commande
dessine une barre de séparation graphique dans le menu qui est utile pour séparer certains éléments du menu. Cette
nouvelle commande est la commande « MenuBar() ». Il ne nécessite aucun paramètre et est utilisé partout où vous
souhaitez placer un séparateur dans le menu en cours. Habituellement, on en place un pour séparer l'élément de menu
« Quit » du reste des éléments de menu dans le menu « Fichier », c'est donc ce que j'ai fait dans cet exemple.

Combiner des Gadgets et des Menus dans le Même Programme


Inclure des menus et des gadgets dans le même programme est facile. Tout d'abord, vous ouvrez une fenêtre et créez
un menu. Ensuite, vous créez une liste de gadgets et dessinez vos gadgets, c' est aussi simple que ça . Voici un
exemple de code :

Enumeration
#WINDOW_MAIN
#MENU_MAIN
#MENU_QUIT
#MENU_APROPOS
#TEXT_INPUT
#STRING_INPUT
#LIST_INPUT
#BUTTON_INTERACT
#BUTTON_CLOSE
EndEnumeration

Global Quit.b = #False


#FLAGS = #PB_Window_SystemMenu | #PB_Window_ScreenCentered

If OpenWindow(#WINDOW_MAIN, 0, 0, 300, 222, "Interaction", #FLAGS)


If CreateMenu(#MENU_MAIN, WindowID(#WINDOW_MAIN))
MenuTitle("Fichier")
MenuItem(#MENU_QUIT, "Quit")
MenuTitle("Aide")
MenuItem(#MENU_APROPOS, "A propos de..")
TextGadget(#TEXT_INPUT, 10, 10, 280, 20, "Entrer texte ici:")
StringGadget(#STRING_INPUT, 10, 30, 280, 20, "")
ListViewGadget(#LIST_INPUT, 10, 60, 280, 100)
ButtonGadget(#BUTTON_INTERACT, 10, 170, 120, 20, "Entrer le texte")
ButtonGadget(#BUTTON_CLOSE, 190, 170, 100, 20, "Fermer La Fenêtre")
SetActiveGadget(#STRING_INPUT)

Repeat
Event.l = WaitWindowEvent()
Select Event
Case #PB_Event_Menu
Select EventMenu()
Case #MENU_QUIT
Quit = #True
Case #MENU_APROPOS
MessageRequester("a propos de", "C'est ici que vous décrivez votre programme.")
EndSelect
124 Créer des Interfaces Utilisateur

Case #PB_Event_Gadget
Select EventGadget()
Case #BUTTON_INTERACT
AddGadgetItem(#LIST_INPUT, -1, GetGadgetText(#STRING_INPUT))
SetGadgetText(#STRING_INPUT, "")
SetActiveGadget(#STRING_INPUT)
Case #BUTTON_CLOSE
Quit = #True
EndSelect
EndSelect
Until Event = #PB_Event_CloseWindow Or Quit = #True

EndIf
EndIf
End

Pour gérer les événements à partir d'éléments de menu ou de gadgets, vous pouvez utiliser les différentes constantes
globales d'événement. Dans l'exemple ci-dessus, j'ai utilisé les deux dans la même instruction « Select » qui teste la
variable « Event », comme ceci :

...
Select Event
Case #PB_Event_Menu
Select EventMenu()
...
;Les événements du menu sont traités ici
...
EndSelect
...
Case #PB_Event_Gadget
Select EventGadget()
...
;Les événements gadgets sont traités ici
...
EndSelect
EndSelect
...

Si un événement est déclenché à partir d'un élément de menu, il est traité dans l'instruction « Case » «#PB_Event_Menu
» et l'élément de menu exact peut être déterminé en utilisant la commande « EventMenu() ». Si un événement est
déclenché à partir d'un gadget, il est traité dans l'instruction « Case » « #PB_Event_Menu » et le gadget exact peut être
déterminé en utilisant la commande « EventGadget() ». Ceci vous permet de gérer tous les événements des menus et
des gadgets à partir d'une instruction « Select » imbriquée, comme indiqué dans le snippet de la page précédente.

Ajout d'Icônes aux Eléments de Menu

Vous remarquerez probablement dans la Fig.30 qu'il y a des icônes dans les menus de l'IDE PureBasic mais qu'il
n'y a pas d'icônes natives. incluses dans PureBasic pour mettre des icônes dans les menus. PureBasic est une
programmation multiplateforme et le code PureBasic, une fois écrit, devrait être compilé pour toute plate-forme
supportée. Par conséquent, tous les doivent produire le même effet souhaité sur chaque plate-forme. Les icônes
dans les menus ont été prises en compte comme étant trop difficiles à supporter de manière multiplateforme, ils
ont donc été omis, dans la version finale de PureBasic commande set. Les icônes incluses dans l'IDE PureBasic
ont été codées à l'aide de l'API native de chaque plate-forme (comme WinAPI dans le cas de Microsoft
Windows). Pour en savoir plus sur ce qu'est une API native et en savoir plus à propos de l'API Win, voir chapitre
13.

Menu Raccourcis Clavier


De nos jours, la plupart des logiciels disposent d'une certaine forme de raccourcis clavier pour sélectionner les
éléments de menu. Ces raccourcis ne sont que des combinaisons de touches que vous pouvez appuyer sur le clavier
pour déclencher des éléments de menu afin de ne pas avoir à les sélectionner physiquement dans le menu. PureBasic
peut les insérer facilement dans votre programme.
Créer des Interfaces Utilisateur 125

Pour le démontrer, nous devons créer une fenêtre avec un menu. Dans ce menu, nous définissons nos éléments de
menu, mais cette fois-ci, nous les définirons à l'aide d'Accélérateurs. Un accélérateur est un terme informatique pour le
String on

Raccourcis

Fig. 30

la fin d'un élément de menu décrivant le raccourci à utiliser pour le déclencher, la Fig.30 montre les raccourcis définis
dans le menu fichier de l'IDE PureBasic. En regardant ceci vous pouvez voir que si vous voulez créer un nouveau
document dans l'IDE PureBasic vous pouvez appuyer sur « Ctrl + N » qui est la touche « Control » et la touche
« N » (en appuyant simultanément sur les touches) vous créez un nouveau document dans PureBasic IDE

Vous remarquerez également dans la Fig.30, que les raccourcis sont alignés sur le côté droit du menu. Il s'agit de
s'assurer qu'ils sont clairement marqués et de ne pas encombrer le menu lui-même.

Dans l'exemple de code suivant, j'ajouterai des raccourcis et des combinaisons de touches à l'exemple de menu
précédent. l'exécuter et les essayer par vous-même.

Enumeration
#WIN_MAIN
#MENU_MAIN
#M_QUIT
#MENU_APROPOS
EndEnumeration

Global Quit.b = #False


#FLAGS = #PB_Window_SystemMenu | #PB_Window_ScreenCentered

If OpenWindow(#WIN_MAIN, 0, 0, 300, 200, "Exemple Menu ", #FLAGS)


If CreateMenu(#MENU_MAIN, WindowID(#WIN_MAIN))
MenuTitle("Fichier")
MenuItem(#M_QUIT, "Quit" + #TAB$ + "Ctrl+Q")
MenuTitle("Aide")
MenuItem(#MENU_APROPOS, "a propos de.." + #TAB$ + "Ctrl+A")
AddKeyboardShortcut(#WIN_MAIN,#PB_Shortcut_Control|#PB_Shortcut_Q,#M_QUIT)
AddKeyboardShortcut(#WIN_MAIN,#PB_Shortcut_Control|#PB_Shortcut_A,#MENU_APROPOS)

Repeat
Event.l = WaitWindowEvent()
Select Event
Case #PB_Event_Menu
Select EventMenu()
Case #M_QUIT
Quit = #True
Case #MENU_APROPOS
MessageRequester("a propos de", "C'est ici que vous décrivez votre programme.")
EndSelect
EndSelect
Until Event = #PB_Event_CloseWindow Or Quit = #True
EndIf
EndIf
End
126 Créer des Interfaces Utilisateur

Si vous exécutez l'exemple, vous verrez qu'en plus des éléments de menu, il y a maintenant des raccourcis.
Celles-ci sont définies à l'aide d'un caractère de tabulation dans l'élément de menu Chaîne, comme ceci :

...
MenuItem(#M_QUIT, "Quit" + #TAB$ + "Ctrl+Q")
...

Cette commande prend toujours deux paramètres, mais le deuxième paramètre String est composé de trois parties. La
première partie est l'élément de menu String, qui dans ce cas est « Quit ». Ensuite, nous concaténons un caractère de
tabulation jusqu'à la fin en utilisant la constante de chaîne « #TAB$ » intégrée. Cette constante a la valeur ASCII « 9 »
sous forme de chaîne. Ensuite, nous concaténons une autre chaîne qui est le raccourci du menu; « Ctrl+Q ».

Une tabulation est utilisée ici à la place d'un espace pour que les raccourcis soient toujours alignés à droite du menu,
quelle que soit la longueur des chaînes de caractères de l'élément de menu.

Une fois que les raccourcis ont été saisis à côté des éléments de menu, c'est la partie visuelle qui est faite, les
raccourcis sont en fin de compte juste pour l'utilisateur une option de menu qui ajoute la fonctionnalité de raccourci,
nous devons utiliser la commande « AddKeyboardShortcut() ». J'ai utilisé ces commandes dans mon code comme ceci :

...
AddKeyboardShortcut(#WIN_MAIN,#PB_Shortcut_Control|#PB_Shortcut_Q,#M_QUIT)
AddKeyboardShortcut(#WIN_MAIN,#PB_Shortcut_Control|#PB_Shortcut_A,#MEMU_APROPOS)
...

Cette commande prend trois paramètres, le premier est le numéro PB de la fenêtre à laquelle ce raccourci est associé,
dans ce cas c'est « #WIN_MAIN » . Le deuxième paramètre est une valeur qui représente le raccourci clavier réel. Cette
valeur est composée de constantes intégrées qui représentent différentes combinaisons de touches du clavier. Sur la
première ligne de l'extrait ci-dessus, j'ai combiné les constantes « #PB_Shortcut_Control » et « #PB_Shortcut_Q » pour
spécifier que je veux que le raccourci soit « Control+Q » au clavier. Ces constantes sont combinées de la manière
habituelle en utilisant l'opérateur binaire « Or » « | ». Toutes les constantes de raccourcis disponibles pour créer toutes
les autres combinaisons de touches sont listées dans le fichier d'aide PureBasic sur la page « AddKeyboardShortcut()
» (fichier d'aide : Manuel de référence → Bibliothèques générales ->Fenêtre->Ajouter un raccourci clavier). Le troisième
paramètre est le numéro PB de l'élément de menu auquel vous souhaitez associer ce raccourci. Sur la première ligne de
l'extrait ci-dessus, j'ai utilisé « #M_QUIT » qui est le même numéro PB que celui que j'ai utilisé pour créer l'élément de
menu « Quit » plus tôt. Cela signifie qu'une fois que ce raccourci est appuyé sur le clavier, il déclenchera un événement
ayant la même valeur que si l'option de menu « Quitter » était sélectionnée.

Sur la ligne suivante de l'extrait, j'ai répété cette commande mais avec des paramètres différents pour fournir un
raccourci clavier pour l'élément de menu « a propos de...».

Les événements déclenchés par des raccourcis clavier sont traités exactement de la même manière que s'ils étaient
déclenchés par la sélection d'un élément de menu et il n'y a absolument aucune différence dans la boucle principale
comme vous pouvez le voir dans l'exemple de raccourci.

Touches de Raccourci sans Menu


En utilisant les mêmes commandes de raccourcis clavier, vous pouvez créer des raccourcis clavier sans avoir un menu
sur lequel les baser. Tout ce que vous avez à faire, c'est d'utiliser la commande « AddKeyboardShortcut() » pour créer
un raccourci associé à votre fenêtre et au lieu de refléter le numéro PB d'un élément de menu dans le troisième
paramètre, utilisez simplement une valeur unique. Vous testez ensuite cette valeur en tant qu'événement de menu dans
la boucle principale même s'il n'y a pas de menu. En voici un exemple :
Créer des Interfaces Utilisateur 127

#WIN_MAIN = 1
#SC_EVENT = 2
#FLAGS = #PB_Window_SystemMenu | #PB_Window_ScreenCentered
If OpenWindow(#WIN_MAIN, 0, 0, 300, 200, "Bonjour le Monde", #FLAGS)
AddKeyboardShortcut(#WIN_MAIN,#PB_Shortcut_Control|#PB_Shortcut_Z, #SC_EVENT)
Repeat
Event.l = WaitWindowEvent()
Select Event
Case #PB_Event_Menu
Select EventMenu()
Case #SC_EVENT
Debug "Le raccourci a été appuyé"
EndSelect
EndSelect
Until Event = #PB_Event_CloseWindow
EndIf
End

Pendant que l'exemple ci-dessus est en cours d'exécution, appuyez sur « Control+Z »sur votre clavier et vous devriez
voir le texte « Le raccourci a été appuyé » résonner dans la fenêtre Debug . Cet exemple fonctionne parce que la
commande « AddKeyboardShortcut() » déclenche un événement de menu qui est traité correctement dans la boucle
principale même si aucun menu physique n'est attaché à la fenêtre. C'est une astuce pratique pour savoir si vous voulez
ajouter des raccourcis clavier à vos programmes même si vous ne voulez pas de menu.

Intégration de Graphiques dans votre Programme


Parfois, dans vos programmes, vous voudrez peut-être inclure certaines images et PureBasic rend cela très facile. Dans
cette prochaine section, je vous montrerai comment ajouter des images à vos interfaces de deux façons. Tout d'abord,
vous pouvez les charger à partir d'une source externe, par exemple, l'image peut se trouver dans le même répertoire que
votre programme. Deuxièmement, vous pouvez intégrer l'image directement dans votre programme pour n'avoir qu'un
seul fichier exécutable. Les deux façons d'atteindre la même chose, mais cela dépend de la façon dont vous voulez gérer
le fichier image lui-même. Ces deux méthodes exigent qu'un gadget image soit placé sur votre fenêtre pour afficher
l'image. Il est placé sur votre fenêtre de la même manière que n'importe quel autre gadget et se conforme aux mêmes
règles.

Chargement d'Images dans votre Programme


Cette méthode de chargement des images à utiliser dans votre interface dépend des images externes. Contrairement à
l'intégration d'images, cette méthode exige que vous distribuiez toutes les images utilisées avec votre fichier exécutable.
En voici un exemple :
Enumeration
#WIN_MAIN
#IMAGE_FILE
#IMAGE_DISPLAY
#BUTTON_CLOSE
EndEnumeration

Global Quit.b = #False


#FLAGS = #PB_Window_SystemMenu | #PB_Window_ScreenCentered

If OpenWindow(#WIN_MAIN, 0, 0, 300, 200, "Exemple Image", #FLAGS)


If CreateGadgetList(WindowID(#WIN_MAIN))
If LoadImage(#IMAGE_FILE, "image.bmp")
ImageGadget(#IMAGE_DISPLAY, 10, 10, 280, 150, ImageID(#IMAGE_FILE))
ButtonGadget(#BUTTON_CLOSE, 100, 170, 100, 20, "Fermer la Fenêtre")
Repeat
Event.l = WaitWindowEvent()
Select Event
Case #PB_Event_Gadget
Select EventGadget()
Case #BUTTON_CLOSE
Quit = #True
EndSelect
EndSelect
Until Event = #PB_Event_CloseWindow Or Quit = #True
EndIf
EndIf
EndIf
End
128 Créer des Interfaces Utilisateur

Pour que cet exemple fonctionne correctement, vous devez disposer d’une image de la taille «280 x 150» en pixels.
Format bitmap. Ce fichier image doit se trouver dans le même répertoire que le texte source. Si tous les éléments sont
au bon endroit et que le programme est démarré, cela ressemble à la Fig. 31.

Dans cet exemple, j’ai utilisé la commande « LoadImage() » pour charger un fichier image du disque dur dans la
mémoire pour que je puisse l'afficher directement dans le programme, comme ici:

...
LoadImage(#IMAGE_FILE, "image.bmp")
...

Si vous regardez la commande « LoadImage() » dans le fichier d’aide PureBasic (Fichier d’aide: Manuel de référence →
Bibliothèques générales → Image → LoadImage), vous pouvez voir que la commande a trois paramètres nécessaire. Le
premier paramètre est le numéro de PB attribué à l'image chargée, Le deuxième qui est l'emplacement sur le disque dur
où le fichier image est stocké. Si aucune informations de chemin sont spécifiées, le nom spécifié fait référence au
chemin relatif du chemin.Programme. Je n'ai pas utilisé le troisième paramètre facultatif dans cet exemple. Comme
d'habitude Je vérifie la valeur de retour de la commande dans une instruction « If » pour m'assurer que l'image à été
chargé correctement avant de poursuivre l'exécution du programme.

Si l'image a été chargée correctement, vous pouvez l'utiliser dans un gadget image de votre programme. Si vous
regardez l'exemple du gadget, j'ai utilisé la commande « ImageGadget() » comme ceci:

...
ImageGadget(#IMAGE_DISPLAY, 10, 10, 280, 150, ImageID(#IMAGE_FILE))
...

La commande « ImageGadget() » est facile à comprendre. Le premier paramètre est le numéro de PB associé à ce
gadget et pas l'image chargée. Les quatre paramètres suivants définissent la taille et la position du gadget, comme
avec les autres gadgets. dans le cinquième paramètre, nous spécifions l'endroit où l 'image doit être affichée dans le
gadget. Ce paramètre doit donc être un identifiant de système d'exploitation d'une image précédemment chargée. pour
récupérer son identifiant OS. Dans le code ci-dessus, j'ai utilisé la commande « imageID() » pour récupérer
l'identificateur « # IMAGE_FILE » du système d'exploitation de l'image préalablement chargée à l'aide de la commande
« LoadImage() » avec la position et la taille de ce gadget,

(Exemple Microsoft Windows) Fig. 31

Cette façon de charger des images pour les afficher dans un gadget image est une façon simple de faire les choses,
mais vous vous souviendrez que lorsque vous regardez vos interfaces de cette façon, vous devez toujours distribuer les
images avec votre fichier exécutable final. Parce que votre programme cherche toujours à charger les images externes,
même lorsqu'il est compilé. Si vous souhaitez intégrer complètement vos images dans votre programme, lisez la suite.
Créer des Interfaces Utilisateur 129

Inclure des Images dans votre Programme


La méthode précédente de chargement des images est bonne, mais parfois vous voudrez peut-être Créez un
exécutable autonome qui intègre toutes les images que vous utilisez de sorte qu'il ne s'appuira sur aucun autre média
externe. Cette méthode utilise une « DataSection » , avec lequel vous pouvez intégrer des fichiers sous forme binaire
dans l'exécutable. Voici un exemple:

Enumeration
#WIN_MAIN
#IMAGE_MEMORY
#IMAGE_DISPLAY
#BUTTON_CLOSE
EndEnumeration
Global Quit.b = #False
#FLAGS = #PB_Window_SystemMenu | #PB_Window_ScreenCentered
If OpenWindow(#WIN_MAIN, 0, 0, 300, 200, "Image Example", #FLAGS)
If CreateGadgetList(WindowID(#WIN_MAIN))
If CatchImage(#IMAGE_MEMORY, ?Image)
ImageGadget(#IMAGE_DISPLAY, 10, 10, 280, 150,ImageID(#IMAGE_MEMORY))
ButtonGadget(#BUTTON_CLOSE, 100, 170, 100, 20, "Fermer la Fenêtre")
Repeat
Event.l = WaitWindowEvent()
Select Event
Case #PB_Event_Gadget
Select EventGadget()
Case #BUTTON_CLOSE
Quit = #True
EndSelect
EndSelect
Until Event = #PB_Event_CloseWindow Or Quit = #True
EndIf
EndIf
EndIf
End
DataSection
Image:
IncludeBinary "image.bmp"
EndDataSection

Cet exemple est très similaire au précédent, excepté que celui-ci incorpore l'image dans une « DataSection » lors de
la compilation. Une fois ce programme exécuté, l’image est lue à partir de la « DataSection » au lieu d’être lue à
partir du disque dur. Si vous regardez l'exemple, vous pouvez voir la section de données au bas du code source, elle
ressemble à ceci:

...
DataSection
Image:
IncludeBinary "image.bmp"
EndDataSection

Les commandes « DataSection » et « EndDataSection » sont le début et la fin de la section. Vous pouvez alors
incorporer des fichiers binaires dans la commande « IncludeBinary ». Cette commande n'utilise pas de parenthèses,
elle utilise simplement une chaîne après celle-ci pour définir un fichier à inclure.

Dans ce cas, j'ai intégré le fichier « image.bmp ». Vous remarquerez aussi que j'ai utilisé une étiquette avant la
commande « IncludeBinary », très similaire à une définition de sous-routine. Cette étiquette permet à votre programme
de trouver le début de cette image en mémoire une fois chargée avec ce programme. Une fois qu'une image a été
incorporée comme ceci, nous pouvons facilement l'utiliser dans notre code principal.

Dans le code principal, nous n'utilisons plus la commande « LoadImage() » pour charger l'image en mémoire. Une fois
qu'il est placé dans une « DataSection » , il est déjà chargé une fois que le programme est lancé. Nous utilisons donc
la commande « CatchImage() » pour récupérer l'image de la « DataSection », comme ceci :
130 Créer des Interfaces Utilisateur

...
CatchImage(#IMAGE_MEMORY, ?Image)
...

Si vous regardez la commande « CatchImage() » dans le fichier d'aide PureBasic ((Fichier d'aide: Guide de référence →
bibliothèques générales-> Image-> CatchImage), vous pouvez voir que cette commande prend trois paramètres. de
cette image. le premier est le numéro PB qui sera associé à cette image, Le deuxième paramètre est l'adresse mémoire
où se trouve cette image. Si vous vous souvenez, j'ai utilisé une étiquette dans la section des données pour le montrer,
donc j'ai besoin d'obtenir l'adresse mémoire de cette étiquette. Je le fais en utilisant un point d'interrogation devant
l'étiquette lorsque je l'utilise comme paramètre. Ce point d'interrogation est une fonction spéciale d'un caractère qui
renvoie l'adresse mémoire de toute étiquette. Ceci est expliqué plus en détail plus loin au chapitre 13 (Conseils). Je n'ai
pas utilisé le ce paramètre car il est optionnel.

L' affichage d'une image chargée avec la commande « CatchImage() » est exactement le même qu' avec la commande
« LoadImage() ». Encore une fois, nous utilisons un gadget image et remplissons ses paramètres de la même manière
qu'auparavant :

...
ImageGadget(#IMAGE_DISPLAY, 10, 10, 280, 150, ImageID(#IMAGE_MEMORY))
...

Une fois que vous exécutez cet exemple, il devrait ressembler à nouveau à la Fig.31. C'est parce que c'est le même
programme, mais maintenant il n'a plus besoin du fichier externe « image.bmp ».

Quels Formats d'Image Peuvent être Utilisés?


Dans les derniers exemples, je n'ai chargé que des images au format bitmap « * .bmp » et dans le programme mais
vous n' êtes pas limité à ce format.

En standard, PureBasic peut charger et afficher des fichiers aux formats Bitmap « * .bmp » et Icon « *.ico » mais parfois
ceux-ci peuvent être restrictifs. Si vous avez besoin d'utiliser d'autres formats, vous pouvez utiliser des commandes de
décodage optionnelles pour donner plus de fonctionnalités aux commandes de chargement d'images de PureBasic.
Ces autres décodeurs sont extrêmement simples à utiliser, il vous suffit d'utiliser la commande de décodage au début
de votre code source et à partir de ce moment dans votre programme toutes les commandes de chargement d'image
ont un support complet du décodeur de format d'image utilisé. Vous trouverez plus d'informations sur les décodeurs
dans le fichier d'aide PureBasic (Fichier d'aide: Guide de référence → bibliothèques générales-> ImagePlugin).

Voici les autres commandes du décodeur:

« UseJPEG2000ImageDecoder() »
Ce décodeur ajoute la prise en charge du format de fichier JPEG 2000 (* -jpg / * -jpeg).

« UseJPEGImageDecoder() »
Ce décodeur ajoute la prise en charge du format de fichier JPEG (* -jpg / * - jpeg).

« UsePNGImageDecoder() »
Ce décodeur ajoute la prise en charge du format de fichier PNG (*.png).

« UseTIFFImageDecoder() »
Ce décodeur ajoute la prise en charge du format de fichier TIFF (* .tif / *. Tiff).

« UseTGAImageDecoder() »
Ce décodeur ajoute la prise en charge du format de fichier TARGA (* .tga).

Comme mentionné précédemment, l'utilisation de ces commandes de décodeur est extrêmement facile. Laissez-faire
les décodeurs comme dans le dernier exemple pour ajouter le support pour les images JPEG, donc nous pourrons
utiliser des images JPEG à la place de d'une image bitmap.
Créer des Interfaces Utilisateur 131

UseJPEGImageDecoder()
Enumeration
#WIN_MAIN
#IMAGE_MEMORY
#IMAGE_DISPLAY
#BUTTON_CLOSE
EndEnumeration
Global Quit.b = #False
#FLAGS = #PB_Window_SystemMenu | #PB_Window_ScreenCentered
If OpenWindow(#WIN_MAIN, 0, 0, 300, 200, "Exemple Image", #FLAGS)
If CreateGadgetList(WindowID(#WIN_MAIN))
If CatchImage(#IMAGE_MEMORY, ?Image)
ImageGadget(#IMAGE_DISPLAY, 10, 10, 280, 150, ImageID(#IMAGE_MEMORY))
ButtonGadget(#BUTTON_CLOSE, 100, 170, 100, 20, "Ferme Window")
Repeat
Event.l = WaitWindowEvent()
Select Event
Case #PB_Event_Gadget
Select EventGadget()
Case #BUTTON_CLOSE
Quit = #True
EndSelect
EndSelect
Until Event = #PB_Event_CloseWindow Or Quit = #True
EndIf
EndIf
EndIf
End
DataSection
Image:
IncludeBinary "image.jpg"
EndDataSection

Dans cet exemple, la seule différence que j'ai faite au code source pour le rendre compatible avec les fichiers Jpeg est
d'avoir ajouté la commande « UseJPEGImageDecoder() » comme première ligne du code et d'avoir ensuite changé
l'image dans la section des données en format Jpeg. Ce programme intègre maintenant une image Jpeg au lieu d'une
image Bitmap.

Tous les autres décodeurs sont utilisés de la même manière. Il suffit d' ajouter la commande du décodeur au début du
programme pour assurer la prise en charge des autres formats de fichiers.

Un Premier Regard sur le Nouveau « Visual Designer »


Avec PureBasic, vous obtenez un puissant «Visual Designer» qui vous permet de créez des surfaces visuellement et
dynamiquement. Cela signifie que vous mettez littéralement vos gadgets sur la surface d'une fenêtre pour créér une
interface visuelle. Le code PureBasic sous-jacent sera généré automatiquement et en temps réel pour vous.

L'utilisation d'un tel outil peut vous faire gagner un temps considérable lors de la conception d'interfaces, en ajustant
l'apparence et la convivialité d'une interface tout en obtenant des résultats immédiats. Vous devriez également être en
mesure de charger le code à nouveau à une date ultérieure si vous avez besoin d'ajouter quelque chose ou de fournir
des fonctionnalités supplémentaires dans votre programme. Il y a actuellement une limitation concernant le chargement
des sources existantes, le code non écrit par le concepteur visuel pourrait ne pas être chargé correctement si vous
l'ouvrez pour le rééditer. C'est parce que le concepteur visuel génère du code d'une certaine manière et si un fichier
écrit à la main s'écarte de ce format, le concepteur peut avoir du mal à le lire. Le concepteur visuel, comme les autres
outils fournis, est entièrement écrit à partir de la base à l'aide de PureBasic et est désigné par la communauté
PureBasic comme le « VD ».
132 Créer des Interfaces Utilisateur

Pourquoi n'avez-vous pas Mentionné cela plus tôt?


Je pensais qu'il était très important que vous appreniez d'abord comment les choses fonctionnent dans PureBasic. Avec
la connaissance acquise des gadgets, des menus et des événements, vous avez maintenant une bonne base pour
mieux comprendre le code créé par «Visual Designer». C'est pourquoi je pensais mentionner le « VD » uniquement à la
fin de ce chapitre.

La Fenêtre Principale
Lorsque vous démarrez le concepteur visuel, il ressemble à la figure 32. La fenêtre principale est une « Interface Multi-
Document (MDI) », qui contient tous les outils nécessaires à la création de votre interface. Le concepteur visuel se
compose d’une barre de menus et d’une barre d’outils située en dessous. Sur le côté gauche est un grand panneau
d'outils qui affiche une palette de gadgets et une palette de propriétés. situé. Au milieu se trouve la fenêtre créée et en
dessous se trouve la fenêtre du code généré automatiquement.

L'utilisation du Concepteur Visuel


Si vous regardez la Fig.32, vous verrez l'interface en cours indiquée par une flèche vers la droite. Cette fenêtre est facile
à repérer car elle est couverte de petits points. Ces points sont une « Grille de Capture » qui permet aux gadgets placés
de s'encliqueter sur une grille définie pour les aligner beaucoup plus rapidement et plus facilement. Ces points
n'apparaissent pas sur le programme fini.

Barre d' Outils

Palette
Gadget Fenêtre de
Progression

Palette de
Propriété et
Drapeaux

Génération
Automatique
du Code

Fig. 32

Une fois que la fenêtre de l'interface a été redimensionnée aux dimensions désirées, vous pouvez alors commencer à y
placer des gadgets. Pour ce faire, choisissez un outil dans la boîte à outils Gadget et dessinez sur l'interface en utilisant
cet outil. Vous allez maintenant dessiner un gadget de redimensionnement dynamique du type d'outil sélectionné
directement sur la fenêtre. Une fois le gadget dessiné, vous verrez qu'il est entouré de gros points bleus. Il vous
permettent de redimensionner et de déplacer le gadget après qu'il ait été dessiné. Lorsque vous ajoutez des gadgets à
votre interface, vous remarquerez que le code PureBasic est automatiquement généré. Vous pouvez regarder la fenetre
Code-Viewer qui est automatiquement ajouté à votre projet.
Créer des Interfaces Utilisateur 133

Une fois que tous les gadgets sont placés et que vous avez terminé la conception de votre interface utilisateur, vous
pouvez enregistrer votre projet en cliquant sur le bouton disque dans la barre d'outils. Ceci vous permet d'enregistrer le
code généré automatiquement dans un fichier PureBasic standard afin de pouvoir l'ouvrir, le modifier et le compiler
normalement dans l'IDE PureBasic.

Avantages et Inconvénients du Concepteur Visuel


Bien que le concepteur visuel soit un excellent outil pour assembler rapidement et facilement des interfaces utilisateur,
le format du code généré ne peut pas être modifié. Par conséquent, vous devez accepter la façon dont le programme a
été codé et si des modifications sont nécessaires à la main dans l'IDE, vous devez vous conformer à ce format. Ce n'est
pas vraiment un problème si vous êtes expérimenté avec PureBasic mais pour l'utilisateur novice, le code exporté peut
être assez compliqué et avancé.

Le vrai point positif de l'utilisation du concepteur visuel est la vitesse. Vous pouvez créer une interface utilisateur utile en
quelques secondes et voir de quoi elle a l'air, puis tout aussi facilement déplacer et redimensionner les gadgets jusqu'à
ce que vous l'obtenez exactement comme il faut. On ne saurait trop insister sur ce point. Le temps que vous pourriez
économiser en concevant une interface utilisateur à l'aide du « VD » est stupéfiant, simplement parce que vous n'avez
plus besoin de compiler le programme pour voir à quoi il ressemble.

Certaines personnes aiment les concepteurs visuels et d'autres pas, c'est aussi simple que ça. Certains disent qu'il est
préférable de gérer tout le code soi-même pour vraiment savoir ce qui se passe « Sous le Capot » tandis que d'autres
affirment que dans le monde concurrentiel d'aujourd'hui, il faut une solution rapide pour concevoir des interfaces.
L'argument va faire rage, j'en suis sûr, mais c'est à vous de décider ce que vous voulez utiliser. Les outils sont là, c'est à
vous de décider si vous voulez les utiliser.

En savoir plus sur le Concepteur Visuel


PureBasic Visual Designer est livré avec un fichier d'aide complet qui couvre tous les rouages du « VD » dans un
style similaire à celui du fichier d'aide de l'EDI. Pour l'afficher, appuyez sur « F1 » dans le concepteur visuel et le
fichier d'aide se chargera. Je recommande de lire ce fichier d'aide en entier au moins une fois.

La nouvelle version du concepteur visuel (voir la figure 32) est en cours de développement, peut être téléchargée à
partir du site Web du concepteur visuel PureBasic. L'Annexe A (Liens Internet utiles) propose un lien Internet à cet effet.
134 Graphiques 2D

III Graphiques et Son


Les programmes qui utilisent des graphiques et du son sont maintenant une condition préalable dans ce monde de jeux
informatiques et d'applications interactives. Lors de la programmation de ces trucs cool, vous avez besoin d'un langage
informatique qui vous fournira les outils nécessaires pour réaliser vos idées. PureBasic offre des commandes simples,
puissantes et complètes qui permettent de créer des jeux de qualité professionnelle, des démos, des économiseurs
d'écran et autres programmes interactifs. Dans cette section, je vais vous montrer les bases de l'utilisation des
graphiques et du son dans vos programmes PureBasic.

J'expliquerai d'abord les commandes de dessin 2D qui vous permettent de dessiner des formes, des lignes et du texte
simples, puis je vous montrerai comment enregistrer ces images. Ensuite, je vais vous montrer comment ouvrir des
écrans graphiques pleine grandeur pour pouvoir dessiner des graphiques. Je vous présenterai aussi les sprites et
comment les utiliser pour créer de jolis effets graphiques.

Ensuite, nous passerons aux graphismes 3D où je vous présenterai le moteur 3D adopté par PureBasic et vous
montrerai les bases de l'utilisation des graphismes 3D dans PureBasic. Ce moteur s'appelle OGRE et est un moteur
tiers de qualité professionnelle capable de produire des graphiques et des effets étonnants.

Le dernier chapitre de cette section concerne la programmation sonore. Les sujets abordés,comment charger et lire
des données audio en mettant l’accent sur les fichiers « Wave », les modules Tracker, les « MP3 » et les « CD Audio ».

Les chapitres contenus dans cette section ne sont pas des guides complets sur la façon d'obtenir tous les effets
graphiques ou d'écrire des jeux, je vais laisser cela à d'autres textes. Ces chapitres sont là pour vous présenter les
bibliothèques de commandes qui rendent ces choses possibles et pour vous fournir un point de départ pour que vous
puissiez expérimenter et vous amuser. Nous espérons que cette section vous donnera un avant-goût de ce qu'il est
possible de faire graphiquement avec PureBasic et vous inspirera à créer une démo ou un jeu cool.

10. Graphiques 2D
Dans ce chapitre, je vais vous expliquer comment dessiner des graphiques 2D avec PureBasic. Le terme «
graphiques2D » englobe un sujet assez vaste et de nombreuses opérations de dessin tombent sous ce parapluie
descriptif. Quand je fais référence aux graphiques 2D dans ce livre, je veux dire des graphiques simples,
bidimensionnels qui peuvent être dessinés sur des interfaces utilisateur graphiques, des écrans, des images en RAM
ou même sur une imprimante. Ces types de graphiques peuvent également contenir différentes complexités, d'un seul
pixel jusqu'à une image en couleur. Tous les graphiques 2D sont bidimensionnels comme vous pouvez le deviner
d'après leur nom, contrairement aux graphiques 3D, qui affichent des modèles 3D qui ont une troisième dimension de «
profondeur ».

En utilisant des graphiques 2D, il est possible d'obtenir des visuels très impressionnants et en conséquence, de
nombreux jeux, économiseurs d'écran et démos ont été créés avec PureBasic. Espérons que vous serez en mesure de
copier, d'apprendre et d'adapter les exemples de ce chapitre pour créer des graphiques cool dans vos propres
programmes.

Commandes de Dessin 2D
PureBasic contient des commandes qui vous permettent de dessiner des formes et des couleurs simples dans votre
programme. Toutes ces commandes de dessin 2D simples sont incluses dans la bibliothèque « Dessin 2D » (fichier
d’aide: référence Manuel → Bibliothèques générales → Dessin 2D). Ces commandes sont utiles pour les formes
simples et Pour dessiner un texte de différentes couleurs. Il y a aussi quelques commandes à votre disposition qui vous
permettrons de dessiner sur une image précédemment créée ou chargée.

Sur Quoi puis-je Dessiner?


Les commandes de dessin 2D intégrées peuvent être utilisées pour dessiner sur différentes sorties telles qu'une fenêtre
d'interface utilisateur graphique, un écran PureBasic, un sprite, une image nouvellement créée en mémoire, une texture
de modèle 3D ou directement sur une imprimante. Ces six méthodes couvrent à peu près tout ce que vous pourriez
avoir besoin de dessiner, et chacune est aussi facile à utiliser que les autres. L'utilisation de ces différentes méthodes
de sortie est une question triviale dans PureBasic car vous n'avez besoin de spécifier qu'une seule fois où vous
souhaitez que le résultat du dessin soit envoyé, puis d'utiliser les commandes de dessin pour y accéder. Pour simplifier
encore plus les choses, toutes les méthodes de sortie partagent la même syntaxe de commande de dessin.
Graphiques 2D 135

Dessin sur une Fenêtre


Dans le premier exemple, je vous montre comment dessiner des graphiques 2D directement sur une fenêtre. Ils vont
probablement jamais le faire dans une application réelle, mais c'est un exercice simple pour vous aider apprendre la
forme de la syntaxe. Regardez ce code

#WINDOW_MAIN = 1

#FLAGS = #PB_Window_SystemMenu | #PB_Window_ScreenCentered


If OpenWindow(#WINDOW_MAIN, 0, 0, 200, 240, "Dessiner dans une Fenetre", #FLAGS)

If StartDrawing(WindowOutput(#WINDOW_MAIN))
Box(15, 15, 75, 75, RGB(255, 0, 0))
Circle(140, 125, 45, RGB(35, 158, 70))
;Les commandes de dessin 2D suivantes dessinent un triangle
LineXY(62, 140, 112, 220, RGB(0, 0, 255))
LineXY(112, 220, 12, 220, RGB(0, 0, 255))
LineXY(12, 220, 62, 140, RGB(0, 0, 255))
FillArea(62, 180, RGB(0, 0, 255), RGB(0, 0, 255))
StopDrawing()
EndIf

Repeat
Event.l = WaitWindowEvent()
Until Event = #PB_Event_CloseWindow
EndIf
End

Si vous exécutez l'exemple ci-dessus, vous verrez une fenêtre similaire à la Fig.33 ouverte, et un carré rouge, un cercle
vert et un triangle bleu dessinés dessus. Ces formes sont dessinées directement sur la fenêtre elle-même et aucun
gadget n'a été utilisé. Pour que vous compreniez parfaitement le code ci-dessus, j'ai besoin d'expliquer plus en détail la
syntaxe de la commande de dessin.

(Exemple Microsoft Windows) Fig. 33

Tout d'abord, vous verrez que j'ai utilisé une nouvelle commande appelée « StartDrawing() ». Cette commande indique à
PureBasic que je souhaite commencer à dessiner en utilisant les commandes graphiques 2D et spécifie sur quoi les
commandes de dessin doivent dessiner. Si vous regardez la page d'aide de la commande « StartDrawing() » (Fichier
d'aide: Guide de référence → bibliothèques générales> 2DDrawing-> StartDrawing), vous verrez que c et t e commande
peut prendre six autres commandes comme paramètre pour spécifier la méthode de sortie du dessin. Celles-ci le sont :

« WindowOutputimage bitmap »
Utilisez-la pour dessiner dans les fenêtres de l'interface utilisateur PureBasic. Cette méthode de sortie nécessite un
numéro PB comme paramètre pour spécifier dans quelle fenêtre dessiner.

« ScreenOutput »
Utilisez cette commande pour dessiner directement sur un écran PureBasic
136 Graphiques 2D

« SpriteOutput »
Utilisez-la pour dessiner sur un sprite PureBasic. Cette méthode de sortie nécessite un numéro PB comme paramètre
pour spécifier dans quel sprite dessiner.

« ImageOutput() »
Utilisez cette commande pour dessiner sur une image chargée ou recréée en mémoire. La méthode exige en paramètre
le numéro de PB de l'image sur laquelle vous voulez dessiner

« PrinterOutput() »
Utilisez cette commande pour rediriger les commandes de dessin directement vers l’imprimante

Dans mon exemple, j'ai indiqué que je souhaitais dessiner directement sur la fenêtre, comme ici

...
StartDrawing(WindowOutput(#WINDOW_MAIN))
...

Une fois que j'ai configuré la sortie de dessin comme ceci, je suis libre d'utiliser n'importe laquelle des commandes de
dessin 2D pour dessiner dessus. En d'autres termes, tout ce qui est dessiné par les commandes de dessin 2D sera
maintenant dessiné sur la fenêtre comme spécifié dans le paramètre de la commande « WindowOutput() ». Une fois
que vous avez utilisé une commande« StartDrawing() », vous devez toujours utiliser une commande « StopDrawing() »
pour terminer les opérations de dessin. Cela dit au compilateur PureBasic, je souhaite maintenant arrêter d'utiliser les
commandes de dessin 2D et je veux continuer comme d'habitude avec le reste de mon programme. Ceci est essentiel
car cela peut causer des bogues dans votre programme si vous ne dites pas au compilateur que vous avez arrêté de
dessiner.

Dans le bloc de dessin, j'ai utilisé quatre commandes de dessin 2D autour des formes réelles. dessinés sur la fenêtre.
Celles-ci sont « Box() », « Circle() », « LineXY() » et « FillArea() ». Toutes ces commandes seront expliquée en détail
dans l'aide et est accessible via des liens sur la page d'aide « Dessin 2D » (fichier d'aide:Manuel de référence →
Bibliothèques générales → Dessin 2D). Presque toutes les commandes 2D partagent des paramètres similaires. Il y a
habituellement des paramètres pour les positions « x » et « y » et parfois des paramètres de taille différents et alors
habituellement le dernier paramètre est la couleur que vous voulez que cette forme soit. Si l'on prend la commande «
Box() » par exemple, les deux premiers paramètres sont la position de la boîte sur la sortie. Les troisième et quatrième
paramètres sont la largeur et la hauteur de la boîte et le cinquième paramètre est sa couleur.

Travailler avec les Couleurs


Les couleurs dans PureBasic sont spécifiées à l'aide d'une seule valeur de couleur de 24 bits. Cette valeur est un grand
nombre qui représente différentes combinaisons de rouge, vert et bleu. Pour obtenir une valeur 24 bits d'une couleur il
faut utiliser la commande « RGB() ». Cette commande prend trois paramètres qui spécifient les valeurs de rouge, vert
et bleu individuellement. Chacun de ces paramètres a une plage de valeurs de « 0 » à « 255 ». En les utilisant, il est
possible pour la commande « RGB() » de retourner plus de 16,7 millions de couleurs sous forme de valeurs 24 bits
individuelles. Voici comment je l'ai utilisé dans l'exemple de dessin de fenêtre montré dans la Fig.33 :

...
Box(15, 15, 75, 75, RGB(255, 0, 0))
...

Ici, j'ai utilisé la commande « RGB() » en ligne comme paramètre de la commande « Box() ». Si vous regardez
attentivement, vous pouvez voir que j'ai spécifié une valeur maximale pour le paramètre rouge et la valeur minimale de
« 0 » pour les paramètres vert et bleu. Cela signifie que la commande « RGB() » retournera une valeur de 24 bits qui
décrit un rouge complet qui n'est pas mélangé avec un vert ou un bleu. Il en va de même pour le triangle :

...
LineXY(62, 140, 112, 220, RGB(0, 0, 255))
LineXY(112, 220, 12, 220, RGB(0, 0, 255))
LineXY(12, 220, 62, 140, RGB(0, 0, 255))
FillArea(62, 180, RGB(0, 0, 255), RGB(0, 0, 255))
...

Ces quatre lignes permettent de s’assurer que le triangle bleu est dessiné sur la fenêtre de la figure 33. Les trois
premières sont des commandes « LineXY() » qui dessinent les trois côtés du triangle. La dernière commande est sur
La commande « FillArea() », qui sélectionne un point au centre du triangle et le remplit avec la même couleur que les
côtés
Graphiques 2D 137

Vous pouvez voir que les quatre commandes utilisent la même couleur. les premier et deuxième paramètres de la
commande « RGB() » représentant le rouge et le vert sont tous deux « 0 », tandis que le troisième paramètre
représentant le bleu a la valeur « 255 ». Cela signifie que La commande « RGB() » retourne une valeur de 24 bits qui
renvoie un bleu complet sans proportions rouge et verte. Le vert du cercle de la figure 33 diffère légèrement des autres
éléments car il utilise les trois couleurs pour créer et obtenir la teinte désirée, comme ici

...
Circle(140, 125, 45, RGB(35, 158, 70))
...

Ici, j'ai utilisé un mélange de rouge, de vert et de bleu autour du cercle dans une belle couleur de l' herbe verte, au lieu
d'un vert plein, brillant. Créer des couleurs de cette façon dans PureBasic La chose est simple et facilite la
compréhension du débutant. avec l' utilisation de la commande « RGB() » Vous pouvez créer presque n'importe quelle
couleur que l'œil humain peut distinguer.

Alors que la commande « RGB() » peut prendre des valeurs rouges, vertes et bleues et retourner une valeur combinée
de 24 bits, il peut y avoir un moment où vous voulez extraire les valeurs des composantes rouge, verte et bleue d'une
seule valeur de couleur 24 bits. Si c'est le cas, vous pouvez le faire en utilisant les commandes « Red() », « Green() »
et « Blue() ». Regardez cet exemple :

ColorValue.l = RGB(35, 158, 70)

Debug "La valeur de couleur 24 bits est composée de:"


Debug "Red: " + Str(Red(ColorValue))
Debug "Green: " + Str(Green(ColorValue))
Debug "Blue: " + Str(Blue(ColorValue))

Chacune des commandes « Red() », « Green() » et « Blue() » prend une valeur de couleur 24 bits comme paramètre
puis retourne la valeur de la composante de couleur correspondante. Sur la première ligne de l'exemple ci-dessus, je
compose la valeur de couleur 24 bits en utilisant (entre autres) une valeur de paramètre rouge de « 35 ». Si je voulais
récupérer la valeur de la composante rouge de cette valeur de couleur 24 bits à un stade ultérieur, je pourrais passer
cette valeur à la commande « Red() » qui retourne la valeur de la composante rouge utilisée pour la composer, dans
ce cas « 35 ». Les autres commandes de couleur fonctionnent exactement de la même manière.

Pourquoi ne pourriez-vous pas dessiner directement sur Windows?


Dessiner sur des fenêtres bien que possible n'est pas nécessairement la bonne façon d'afficher les graphiques
dessinés avec les commandes de dessin 2D. Ceci est principalement dû à la façon dont les différents systèmes
d'exploitation gèrent le rafraîchissement de l'affichage de la fenêtre. Par exemple, sous Microsoft Windows, si vous
dessinez des graphiques directement sur une fenêtre et déplacez ensuite une autre fenêtre, les graphiques seront
effacés de la fenêtre originale. Ceci est dû à la gestion interne des événements qui a lieu dans Microsoft Windows. Il
détermine automatiquement si le contenu de la fenêtre doit être redessiné ou non et prend parfois la décision de ne
pas le faire. Vous pouvez forcer le redessin des graphiques après qu'une fenêtre soit passée devant une autre, mais il
s'agit d'un processus avancé qui nécessite l'utilisation de la connaissance de l'API du système d'exploitation particulier
auquel vous êtes confronté. Une façon plus élégante d'afficher les graphiques dessinés, serait de créer une nouvelle
image en mémoire, de dessiner des choses dessus, puis d'afficher cette image en utilisant un gadget image sur votre
fenêtre. L'utilisation d'un gadget image permet de s'assurer que la fenêtre s'occupe automatiquement de tout
rafraîchissement qui peut être nécessaire pour garder l'image visible.

Dessiner sur une Image


Travailler avec de nouvelles images dans PureBasic est facile, car il existe toute une bibliothèque écrite uniquement
pour créer et manipuler ces images. Dans l'exemple suivant, je vais essayer d'émuler le dernier programme mais avec
une différence. Je vais créer une nouvelle image en utilisant la commande « CreateImage() », y dessiner les formes
colorées puis afficher le résultat final dans un gadget image. Cela devrait alors éviter tout problème de
rafraîchissement des fenêtres et se comporter comme nous le pensons. Vous pouvez en savoir plus sur les
commandes d'image contenues dans PureBasic en consultant la page de la bibliothèque'Image' dans le fichier d'aide
(Fichier d'aide: Manuel de référence-> Bibliothèques générales-> Image). Voici notre exemple:

Enumeration
#WINDOW_MAIN
#IMAGE_GADGET
#IMAGE_MAIN
EndEnumeration
138 Graphiques 2D
If CreateImage(#IMAGE_MAIN, 180, 220)
If StartDrawing(ImageOutput(#IMAGE_MAIN))
;Comme une nouvelle image a un arrière-plan noir, dessinez-en un blanc:(
Box(0, 0, 180, 220, RGB(255, 255, 255))
;Maintenant, continuez à dessiner les formes:(
Box(5, 5, 75, 75, RGB(255, 0, 0))
Circle(130, 115, 45, RGB(35, 158, 70))
LineXY(52, 130, 102, 210, RGB(0, 0, 255))
LineXY(102, 210, 2, 210, RGB(0, 0, 255))
LineXY(2, 210, 52, 130, RGB(0, 0, 255))
FillArea(52, 170, RGB(0, 0, 255), RGB(0, 0, 255))
StopDrawing()
EndIf
EndIf

#FLAGS = #PB_Window_SystemMenu | #PB_Window_ScreenCentered

If OpenWindow(#WINDOW_MAIN, 0, 0, 200, 240, "Déssiner sur une nouvelle Image", #FLAGS)


ImageGadget(#IMAGE_GADGET, 10, 10, 180, 220, ImageID(#IMAGE_MAIN))
Repeat
Event.l = WaitWindowEvent()
Until Event = #PB_Event_CloseWindow
EndIf
End

La majeure partie de ce code devrait être auto-explicative car la seule différence dans ce code par rapport au dernier
exemple est que nous sommes en train de créer une nouvelle image en utilisant la commande « CreateImage() » et en
dessinant dessus au lieu d'une fenêtre. La commande « CreateImage() » prend quatre paramètres, le premier est le
numéro PB associé à cette nouvelle image. Les deuxième et troisième paramètres sont la largeur et la hauteur (en
pixels) de la nouvelle image et le quatrième paramètre est la profondeur de bits de la nouvelle image, qui est facultatif.
Si le quatrième paramètre n'est pas utilisé, comme dans mon exemple, alors il utilise la même profondeur de bit que
votre bureau.

Quelle est la Profondeur de Couleur d'une Image?

Chaque pixel d'un écran d'ordinateur ou d'une image numérique est décrit par des nombres binaires, comme on
peut s'y attendre sur un ordinateur. Plus le nombre de bits (ou de chiffres binaires) utilisé pour décrire un seul
pixel est grand, plus il permet à ce pixel d'exprimer une gamme de couleurs plus large. Le nombre de bits
décrivant un seul pixel d'une image numérique donnée ou d'un écran d'ordinateur est appelé sa profondeur de
bits. Les profondeurs de bits courantes sont 1 bit, 8 bit, 16 bit, 24 bit, et 32 bit.

Les images de 1 bit ne peuvent décrire que des images en noir et blanc (2 couleurs) puisque le seul bit qui décrit
chaque pixel peut avoir une valeur de « 1 » ou « 0 ».

Par contre, les pixels 32 bits sont capables d'afficher plus de couleurs que l'œil humain ne peut voir, donc ce
format est régulièrement utilisé dans les images de films numériques, photos numériques, jeux vidéo réalistes,
etc. De nos jours, les ordinateurs modernes ont tendance à n'utiliser que 32 bits par pixel.

Une fois la nouvelle image créée, je dis au programme que je veux dessiner sur l'image.
Pour cela, j'utilise la ligne suivante:

...
StartDrawing(ImageOutput(#IMAGE_MAIN))
...

Ici, en utilisant la commande « StartDrawing() » avec la méthode « ImageOutput() », j'ai spécifié que toutes les
commandes de dessin devraient maintenant dessiner sur cette image dont le numéro PB est « #IMAGE_MAIN ».

Cette façon de spécifier une image sur laquelle dessiner n'est pas limitée à une image nouvellement créée. Vous pouvez
tout aussi librement charger une image dans votre programme et dessiner là-dessus aussi. Tant qu'une image est
associée à un numéro PB, vous pouvez régler la sortie de dessin pour dessiner dessus.
Graphiques 2D 139

Une fois l'image créée et la sortie du dessin réglée, je suis alors libre de dessiner sur l'image. Comme toutes les images
nouvellement créées dans PureBasic commencent avec un fond noir, la première opération de dessin que je dois faire
est de colorer le fond avec du blanc. Je le fais en utilisant la commande « Box() » qui dessine une case blanche aussi
grande que la nouvelle image elle-même, couvrant tout le noir. Ensuite, je dessine les formes carrées, circulaires et
triangulaires comme avant. Quand j'ai terminé toutes les opérations de dessin nécessaires, j'appelle la commande
toujours importante « StopDrawing() ».

Pour afficher correctement cette image et éviter les problèmes de rafraîchissement précédents de dessin direct sur une
fenêtre, j'utilise un gadget image. Ceci permet au système d'exploitation de rafraîchir l'affichage du gadget si d'autres
fenêtres passent dessus, etc.

Changer le Mode de Dessin


Dans l'exemple suivant, je vais vous montrer comment changer le mode de dessin de certaines commandes dont le
texte. En utilisant la commande « DrawingMode() », vous pouvez passer en mode contour pour les commandes de
forme, dessiner du texte avec un fond transparent ou même mélanger « XOr » la sortie d'une commande de dessin
avec le fond. Voici l'exemple du mode dessin :

Enumeration
#WINDOW_MAIN
#IMAGE_GADGET
#IMAGE_MAIN
#FONT_MAIN
EndEnumeration

Global ImageWidth = 401


Global ImageHeight = 201
Global XPos.l, YPos.l, Width.l, Height.l, Red.l, Green.l, Blue.l
Global Text.s = "PureBasic - 2D Drawing Example"

Procedure.l MyRandom(Maximum.l)
Repeat
Number.l = Random(Maximum)
Until (Number % 10) = 0
ProcedureReturn Number
EndProcedure

If CreateImage(#IMAGE_MAIN, ImageWidth, ImageHeight)


If StartDrawing(ImageOutput(#IMAGE_MAIN))
For x.l = 0 To 1500
XPos.l = MyRandom(ImageWidth) + 1
YPos.l = MyRandom(ImageHeight) + 1
Width.l = (MyRandom(100) - 1) + 10
Height.l = (MyRandom(100) - 1) + 10
Red.l = Random(255)
Green.l = Random(255)
Blue.l = Random(255)
Box(XPos, YPos, Width, Height, RGB(Red, Green, Blue))
DrawingMode(#PB_2DDrawing_Outlined)
Box(XPos - 1, YPos - 1, Width + 2, Height + 2, RGB(0, 0, 0))
DrawingMode(#PB_2DDrawing_Default)
Next x
LineXY(ImageWidth - 1, 0, ImageWidth - 1, ImageHeight, RGB(0, 0, 0))
LineXY(0, ImageHeight - 1, ImageWidth, ImageHeight - 1, RGB(0, 0, 0))
Box(10, 10, 230, 30, RGB(90, 105, 134))
DrawingMode(#PB_2DDrawing_Outlined)
Box(10, 10, 231, 31, RGB(0, 0, 0))
DrawingMode(#PB_2DDrawing_Transparent)
DrawText(21, 18, Text, RGB(0, 0, 0))
DrawText(19, 18, Text, RGB(0, 0, 0))
DrawText(21, 16, Text, RGB(0, 0, 0))
DrawText(19, 16, Text, RGB(0, 0, 0))
DrawText(20, 17, Text, RGB(255, 255, 255))
StopDrawing()
EndIf
EndIf
140 Graphiques 2D

#FLAGS = #PB_Window_SystemMenu | #PB_Window_ScreenCentered


If OpenWindow(#WINDOW_MAIN,0,0,ImageWidth+20,ImageHeight+20,"Abstract",#FLAGS)
If CreateGadgetList(WindowID(#WINDOW_MAIN))
ImageGadget(#IMAGE_GADGET,10,10,ImageWidth,ImageHeight,ImageID(#IMAGE_MAIN))
EndIf
Repeat
Event.l = WaitWindowEvent()
Until Event = #PB_Event_CloseWindow
EndIf
End

Cet exemple est essentiellement une version étendue de la dernière dans laquelle je crée une nouvelle image, bien
qu'un peu plus grande, et je dessine des cases aléatoires partout dessus. Avec chaque case que je dessine, je change
le mode de dessin pour tracer un contour et dessine un contour noir avec les mêmes dimensions sur le dessus. Ce qui
fait que les boîtes vraiment se démarquer. Non seulement chaque boîte a une couleur aléatoire, mais chaque boîte a
aussi un contour noir. Pour changer de mode pendant que vous dessinez, utilisez la commande « DrawingMode() »
ainsi qu'une des différentes constantes utilisées comme paramètre. Voici ces constantes et ce qu'elles permettent de
réaliser :

« #PB_2DDrawing_Default »
C'est le mode par défaut, le texte est affiché avec une couleur d'arrière-plan et des formes graphiques fixes sont remplis

« #PB_2DDrawing_Outlined »
Ce paramètre bascule en mode mode plan pour les commandes de forme telles que « Box() »,« Circle() »,« Ellipse() »

« #PB_2DDrawing_Transparent »
Ce paramètre définit l'arrière-plan du texte sur Transparent. C' est pourquoi seule la couleur de premier plan est un
paramètre. de la commande « DrawText() » est utilisé

« #PB_2DDrawing_XOR »
Ce paramètre active le mode XOr, ce qui signifie que tous les graphiques créés sont enregistrés avec l' Image de fond
qui est liée XOR.

L'utilisation de cette commande est très simple. Lorsque vous voulez changer de mode de dessin dans un bloc de
commande « StartDrawing() », vous n'avez qu'à appeler cette commande avec la constante de votre choix comme
paramètre et le mode est immédiatement changé. Ces constantes peuvent également être combinées à l'aide de
l'opérateur binaire « OR ». Jetez un coup d'oeil au code, vous pouvez voir que j'ai changé de mode assez souvent. Une
fois que vous exécutez cet exemple, vous verrez une fenêtre très similaire à la Fig.34 montrant des cases colorées avec
des contours noirs et du texte blanc dans le coin supérieur gauche.

(Exemple Microsoft Windows) Fig. 34


J'ai utilisé le mode de dessin « # PB_2DDrawing_Transparent » lorsque j'ai dessiné le texte sur l'image, donc le texte a
un fond transparent au lieu d'une couleur solide. Pour dessiner le texte, j'ai utilisé la commande « DrawText() ». Cela
prend cinq paramètres, la position « x » et « y » sur la sortie, la chaîne à dessiner et les valeurs de couleur avant et
arrière. Comme j'ai utilisé un fond transparent, le cinquième paramètre est ignoré.

J'ai le contour par quatre opérations de dessin avec du noir en utilisant différents décalages Ensuite, j'ai dessiné le texte
en blanc dessus. Ce détour était nécessaire à cause de la Le mode « # PB_2DDrawing_Outlined » qui ne prend pas
encore en charge le dessin de texte.
Graphiques 2D 141

Dessin de Texte
Pour dessiner du texte sur un canal de sortie, vous pouvez utiliser la commande « DrawText() » (fichier d'aide: Manuel
de référence → Bibliothèques générales → Dessin 2D → DrawText). Si vous regardez le dernier exemple, vous pouvez
voir que j' ai utilisé cette commande plusieurs fois. Le premier et le deuxième paramètre sont l' emplacement « x » et
« y » du texte dessiné sur la sortie. Le troisième paramètre est la chaîne de texte à dessiner. Les quatrième et
cinquième paramètres sont les couleurs avant et arrière du texte. La couleur avant signifie la couleur du texte et la
couleur arrière signifie la couleur de fond. Si les deux derniers paramètres optionnels ne sont pas utilisés, les
informations de couleur sont extraites des valeurs par défaut, qui peuvent être modifiées en utilisant les commandes «
FrontColor() » et « Backcolor() ». Ces paramètres de couleur sont des valeurs de couleur 24 bits, composées facilement
à l'aide de la commande « RGB() »

Dessin à l'Aide d'une Image


Dans les deux derniers exemples, j'ai montré comment dessiner des formes et des lignes simples en utilisant les
commandes de dessin 2D intégrées, mais parfois elles peuvent être un peu contraignantes. Dans l'exemple suivant, je
vais vous montrer comment vous pouvez prendre une image externe et la dessiner sur une autre image nouvellement
créée, dans la position que vous voulez.

Enumeration
#WINDOW_MAIN
#IMAGE_GADGET
#IMAGE_SMALL
#IMAGE_MAIN
#FONT_MAIN
EndEnumeration

Global ImageWidth = 400


Global ImageHeight = 200
Global XPos.l, YPos.l, LoadedImageWidth.l, LoadedImageHeight.l
Global File.s
Global RequesterText.s = "Choisissez une image"
Global DefaultFile.s = ""
Global Pattern.s = "Bitmap (*.bmp)|*.bmp|Icon (*.ico)|*.ico"

File = OpenFileRequester(RequesterText, DefaultFile, Pattern, 0)


If LoadImage(#IMAGE_SMALL, File)
LoadedImageWidth = ImageWidth(#IMAGE_SMALL)
LoadedImageHeight = ImageHeight(#IMAGE_SMALL)
If CreateImage(#IMAGE_MAIN, ImageWidth,ImageHeight)
If StartDrawing(ImageOutput(#IMAGE_MAIN))
Box(0, 0,ImageWidth, ImageHeight, RGB(255, 255, 255))
For x.l = 1 To 1000
XPos = Random(ImageWidth) - (ImageWidth(#IMAGE_SMALL) / 2)
YPos = Random(ImageHeight) - (ImageHeight(#IMAGE_SMALL) / 2)
DrawImage(ImageID(#IMAGE_SMALL), XPos, YPos)
Next x
DrawingMode(#PB_2DDrawing_Outlined)
Box(0, 0, ImageWidth, ImageHeight, RGB(0, 0, 0))
EndIf
EndIf
#TEXT = "Dessiner avec des images"
#FLAGS = #PB_Window_SystemMenu | #PB_Window_ScreenCentered
If OpenWindow(#WINDOW_MAIN,0,0,ImageWidth+20,ImageHeight+20,#TEXT,#FLAGS)
ImageGadget(#IMAGE_GADGET,10,10,ImageWidth,ImageHeight,ImageID(#IMAGE_MAIN))
Repeat
Event.l = WaitWindowEvent()
Until Event = #PB_Event_CloseWindow
EndIf
End
EndIf

Dans le code ci-dessus, j'autorise l'utilisateur à ouvrir une image, au format Bitmap ou Icon en utilisant la commande
« OpenFileRequester() ». Une fois que cette commande renvoie correctement un nom de fichier image, je charge ce
fichier en utilisant la commande « LoadImage() », très similaire à l'exemple du gadget image du Chapitre 9. Une fois ce
fichier chargé, je peux créer une nouvelle image sur laquelle dessiner
142 Graphiques 2D

et utiliser la commande « DrawImage() » pour dessiner l'image chargée plusieurs fois. L'image résultante est affichée
dans une fenêtre à l'aide d'un gadget image. Si vous regardez la Fig.35, vous pouvez voir à quoi cela ressemble après
avoir chargé une icône en forme de sphère qui est ensuite dessinée au hasard sur toute la nouvelle image et ensuite
affichée.

Image originale chargée

(Exemple Microsoft Windows) Fig. 35

Si vous voulez dessiner une image chargée sur une image nouvellement créée, utilisez la commande « DrawImage() ».
Cette commande prend cinq paramètres et est très facile à comprendre. Le premier est l'identifiant du système
d'exploitation de l'image que vous souhaitez utiliser pour dessiner et peut être récupéré en utilisant la commande «
ImageID() ». Les deuxième et troisième paramètres sont la position horizontale et verticale de l'image dessinée en
pixels. Les quatrième et cinquième paramètres sont optionnels et je ne les ai pas utilisés ici mais ce sont la largeur et la
hauteur en pixels de l'image dessinée. Vous pouvez les utiliser si vous avez besoin de redimensionner l'image
dynamiquement avant de la dessiner. Dans mon exemple, j'ai randomisé la plupart des paramètres pour remplir
aléatoirement la nouvelle image avec un millier de copies de l'image chargée.

Aussi, je pense que c'est la première fois que vous voyez la commande « OpenFileRequester() », donc je vais expliquer
cela un peu plus clairement aussi, pour éviter toute confusion. Cette commande ouvre un demandeur de fichier
standard du système d'exploitation permettant aux utilisateurs de sélectionner facilement un fichier. Une fois qu'un
fichier a été sélectionné, la commande « OpenFileRequester() » retourne son nom sous forme de chaîne. Ceci peut
être démontré par ce petit bout de code autonome :

Global File.s
Global RequesterText.s = "Choisissez une image"
Global DefaultFile.s = ""
Global Pattern.s = "Bitmap (*.bmp)|*.bmp|Icon (*.ico)|*.ico"
File = OpenFileRequester(RequesterText, DefaultFile, Pattern, 0)
Debug File
Si vous consultez la page d’aide de la commande « OpenFileRequester() » (Fichier d’aide: Manuel de référence →
Bibliothèques générales → Demandeur → OpenFileRequester), vous verrez que cette commande prend quatre
paramètres. La première est une chaîne de caractères qui est le texte affiché dans la barre de titre du demandeur
lorsqu'il s'ouvre. Le second est un paramètre de chaîne de caractères d'un nom de fichier que ce demandeur peut
rechercher. Si ce paramètre est spécifié, ce nom de fichier est déjà entré dans la boîte de sélection une fois que le
demandeur s'ouvre. Le troisième paramètre est un modèle de fichier qui permet au programmeur de déterminer quels
fichiers doivent et ne doivent pas être affichés pour la sélection dans le demandeur. Le quatrième paramètre est le
type de fichier du modèle de fichier qui est d'abord sélectionné une fois que le demandeur s'ouvre. Dans cet extrait, «
Bitmap » est d'abord sélectionné parce que l'index du motif du fichier commence à « 0 ».

Le modèle de fichier a l'air assez compliqué mais il est très simple une fois que vous l'avez compris. Les types de
fichiers sont décomposés en morceaux à l'intérieur de la chaîne de motifs, divisés par des caractères de transmission
« | » est identique à l'opérateur « OR » au niveau du bit. Ces morceaux travaillent par paires pour pouvoir spécifier une
chaîne de caractères décrivant une extension de fichier, puis l'extension de fichier elle-même. Par exemple, dans
l'extrait ci-dessus, le motif ressemble à ceci :

"Bitmap (*.bmp)|*.bmp|Icone (*.ico)|*.ico"


Graphiques 2D 143

Si nous divisons cette ligne en sections et utilisons le caractère de renvoi comme séparateur, on peut voir plus
exactement ce qui a été défini:

Bitmap (*.bmp) *.bmp Icone (*.ico) *.ico

La première section est une chaîne qui apparaît dans le champ Type de fichier dans la boîte de dialogue et si elle est est
sélectionné, il utilise la section suivante pour indiquer au dialogue quels types de fichiers se trouvent dans le répertoire.
Fenêtre principale, dans ce cas tous les fichiers « .bmp ». Rappelez-vous, Caractère astérisque « * » est un caractère
générique pouvant désigner n'importe quel nom. La troisième section est une autre chaîne, qui peut être affichée dans le
champ Type de fichier et s’il est sélectionné, la boîte de dialogue affiche les fichiers dans la quatrième section, etc. Si
vous définissez plusieurs extensions de fichier pour un type de fichier Vous pouvez utiliser le point-virgule pour spécifier
plusieurs extensions de fichier dans une section. définir, comme ici:

"JPEG|*.jpg;*.jpeg"

Ceci affichera maintenant tous les fichiers avec les extensionsns « jpg » ou « .jpeg » lorsque la chaîneaîne « JPE est
sélectionnée dans la boîte de dialogue. Vous devez vous rappeler que si vous voulez charger plus de types d'images
autres que des Bitmaps ou des Icônes, vous devrez utiliser un autre décodeur d'images comme expliqué au Chapitre 9
(Inclure des graphiques dans votre programme).

Dessiner des Images avec Canal Alpha


Parfois, vous voudrez peut-être dessiner une image contenant un canal alpha, tel que pour créer des ombres portées ou
pour rendre certaines parties de l'image transparentes. Dans la figure 35, j'ai utilisé une icône pour dessiner sur la
nouvelle image créée et par défaut, PureBasic conserve toutes les informations de la couche alpha trouvées à l'intérieur
de cette icône. Mais que se passe-t-il si vous devez dessiner une image au format « PNG ou TIFF » et préserver son
canal alpha? C'est ici que la commande « DrawAlphaImage() » est utilisée, Cette commande obtient toutes les
informations alpha trouvées dans l'image. Les formats d’ image prenant en charge le canal alpha incluent les fichiers
« PNG ou TIFF » 32 bits.

La commande « DrawAlphaImage() » est utilisée exactement de la même manière que la commande « DrawImage() »,
la seule différence étant que la commande « DrawAlphaImage() » n'a que trois paramètres et ne permet donc pas un
redimensionnement dynamique de l'image pendant le dessin. Voici un exemple d'utilisation de la commande :

...
DrawAlphaImage(ImageID(#IMAGE_PNG), XPos, YPos)
...

La ligne ci-dessus afficherait une image au format Png et préserverait son canal alpha, en le mélangeant bien sur
n'importe quel fond. Une chose à ne jamais oublier cependant, c'est que lorsque vous chargez des images autres qu'un
format Bitmap ou Icon, vous devez utiliser la commande de décodage appropriée pour ajouter cette fonctionnalité à
votre programme, comme expliqué au chapitre 9.

Enregistrer des Images


Si vous avez créé une image dans votre programme, vous pouvez l'enregistrer sur le disque. PureBasic rend cela très
facile en fournissant la commande « SaveImage() » (Help Fichier: Manuel de référence → Bibliothèques générales →
Image → Enregistrer l'image). Cette commande permet d'enregistrer toute image de votre programme PureBasic ayant
un numéro PB. La commande « SaveImage() » prend quatre paramètres. Le premier est le numéro PB de l'image que
vous voulez enregistrer. Le second est le nom du fichier sous lequel vous voulez enregistrer votre image. Le troisième
paramètre est facultatif et définit sous quel format d'image cette image doit être enregistrée. Le quatrième paramètre
permet de spécifier une valeur optionnelle à utiliser quel que soit le format de fichier choisi.

Si nous voulions sauvegarder l'image créée à partir du dernier exemple, nous pourrions ajouter cette ligne de code à la
fin du code de l'exemple. Une fois le programme terminé, il sauvegardera notre image :

...
SaveImage(#IMAGE_MAIN, "Image.bmp")
...

Par défaut, PureBasic enregistre un fichier image au format Bitmap lorsque vous utilisez cette commande sans les deux
derniers paramètres optionnels. Le nom de fichier devra donc avoir l'extension correcte « * .bmp » lors de
l'enregistrement.
144 Graphiques 2D

Enregistrer des Images dans d'autres Formats


Vous pouvez enregistrer des images dans d'autres formats graphiques en spécifiant le troisième paramètre. il peut être
l'une de ces quatre constantes intégrées:

« #PB_ImagePlugin_BMP »
Enregistre l'image au format bitmap. Il s’agit du paramètre par défaut et je précise qu'il ne doit pas être nécessairement
modifié.

« #PB_ImagePlugin_JPEG »
Enregistre l'image au format JPEG. (Pour un bon fonctionnement la commande « UseJPEGImageEncoder() » sera
appelée avant d'utiliser cette commande).

« #PB_ImagePlugin_JPEG2000 »
Enregistre l'image au format JPEG2000 (Pour un bon fonctionnement La commande « UseJPEG2000ImageEncoder() »
sera appelée avant d'utiliser cette commande).
« #PB_ImagePlugin_PNG »
Enregistre l'image au format PNG. (Pour un bon fonctionnement La commande « UsePNGImageEncoder() » sera
appelée avant d'utiliser cette commande).

Si vous utilisez des images utilisant « #PB_ImagePlugin_JPEG » , « # PB_ImagePlugin_JPEG2000 » ou «


#PB_ImagePlugin_PNG », vous devez saisir la commande d'encodeur appropriée en haut de votre code source avant
d'utiliser la commande « SaveImage() » pour vous assurer qu'elle saura comment encoder au format d'image
correspondant. Les encodeurs correspondant ne doivent être appelé qu'une seule fois et seront alors disponible dans le
programme complet. Voici les encodeurs correspondants:

« UseJPEGImageEncoder() »
Cet encodeur ajoute le support pour les images au format JPEG (* .jpg / *. Jpeg).
« UseJPEG2000ImageEncoder() »
Cet encodeur ajoute un support pour les images au format JPEG2000 (* .jpg / *. Jpeg).
« UsePNGImageEncoder() »
Cet encodeur ajoute le support pour les images au format PNG (* .png).

Si vous utilisez le « UseJPEGImageEncoder() » ou la commande « UseJPEG2000ImageEncoder()» pour JPEG


(JPEG2000), vous pouvez utiliser le quatrième paramètre optionnel du paramètre de la commande « SaveImage() »
pour spécifier le niveau de compression de l'image à enregistrer. Se sont la les seuls formats d'image supportant
actuellement le quatrième paramètre.

Voici quelques exemples d'utilisation de la commande « SaveImage() »

SaveImage(#IMAGE_MAIN, "Image.bmp")

Ce premier exemple enregistrera une image appelée « Image.bmp » dans le format Bitmap 24 bits par défaut. Notez
qu'aucun encodeur n'est nécessaire car PureBasic supporte les images au format Bitmap en standard.
UseJPEGImageEncoder()
...
SaveImage(#IMAGE_MAIN, "Image.jpg", #PB_ImagePlugin_JPEG)
Le deuxième exemple enregistrera une image appelée « Image.jpg » au format JPEG en utilisant une valeur de
compression par défaut de « 7 » parce que nous n'en avons pas spécifié une nous-mêmes.
UseJPEGImageEncoder()
...
SaveImage(#IMAGE_MAIN, "Image.jpg", #PB_ImagePlugin_JPEG, 10)

Ce troisième exemple enregistrera une image appelée « Image.jpg » au format JPEG et utilisera la valeur de
compression maximale de « 10 » comme spécifié dans le quatrième paramètre.

UsePNGImageEncoder()
...
SaveImage(#IMAGE_MAIN, "Image.png", #PB_ImagePlugin_PNG)

Le quatrième exemple stocke une image nommée « Image.png » au format PNG.


Graphiques 2D 145

Présentation des « Ecrans »


Si vous avez jamais voulu créer votre propre jeu ou écrire votre propre économiseur d'écran en utilisant PureBasic alors
vous commencerez toujours par ouvrir un « Ecran ». Cet écran est un environnement purement graphique, créé dans le
seul but d'afficher des graphiques tels que des sorties de dessins 2D, des images chargées, des sprites chargés et des
modèles et mondes 3D chargés.

Qu'est-ce qu'un sprite?


À l'origine, les Sprites étaient des images spéciales accélérées par le matériel qui étaient utilisées pour créer des
graphiques 2D composites pour les jeux vidéo. Avec l'augmentation de la puissance de traitement des
ordinateurs au fil des ans, le matériel spécial utilisé pour déplacer et dessiner rapidement ces images n'était plus
nécessaire. Cependant, même aujourd'hui, le nom est toujours utilisé pour décrire des images 2D qui sont
dessinées à l'écran pour créer des jeux et d'autres choses semblables.

Aujourd'hui, un sprite peut être décrit comme un petit graphique (contenant généralement un fond transparent)
qui peut être positionné et dessiné indépendamment sur un écran pour simuler une animation

Les écrans sont normalement ouverts sur toute la largeur et la hauteur de votre écran, mais si vous en ressentez le
besoin, vous pouvez également en ouvrir un sur une fenêtre qui a déjà été créée. C'est ce qu'on appelle un écran
fenêtré. Un seul type d'écran peut être ouvert à la fois, soit un écran plein écran, soit un écran fenêtré.

La raison pour laquelle les écrans sont préférés à l'affichage de graphiques (au lieu de simplementdessiner sur les
fenêtres) pour créer des jeux et autres, est que les écrans sont rapides, ....très rapides !Sur toutes les plates-formes
pour lesquelles PureBasic est disponible, ses écrans sont optimisés pour offrir les meilleures performances possibles,
quel que soit le système d'exploitation sous-jacent.

Ouvrir votre Premier Ecran


Pour créer et ouvrir un écran dans PureBasic, vous devez suivre un modèle de code de base. L'écran et la manipulation
des sprites sont très étroitement liés, vous devez donc toujours initialiser le moteur sprite avant d'ouvrir un écran. Ceci
permet de s'assurer que tout est correctement initialisé en interne et que l'écran est prêt pour les opérations de dessin.
Une fois que le moteur de sprite a été initialisé et que l'écran est réellement ouvert, vous avez besoin d'une boucle
principale pour maintenir le programme en marche, tout comme un programme d'interface utilisateur graphique.

Le code ci-dessous montre un programme d'écran squelette avec tous les bits de code cruciaux présents pour initialiser
le moteur sprite, ouvrir un écran, créer une boucle principale et initialiser les commandes clavier pour fournir un moyen
de fermer le programme.

Global Exit.i = #False

; Procédure de vérification d'erreur simple


Procedure Error(Result.i, Text.s)
If result = 0 MessageRequester("erreur",
text,#PB_ M e s sageRequester_Ok)
End EndIf
EndProcedure

Error(InitSprite(), "InitSprite () a échoué.")


Error(InitKeyboard(), "InitKeyboard () a
échoué.")
Error(OpenScreen(1024, 768, 32, "Ecran"),
"Impossible d'ouvrir l'écran.")

Repeat
ClearScreen(RGB (0, 0, 0))
;Les opérations de dessin sont effectuées ici
FlipBuffers()
ExamineKeyboard()
If KeyboardReleased(#PB_Key_Escape)
Quit= #True
EndIf
Until Quit = #True
End
146 Graphiques 2D

Si vous examinez d’abord l’image-objet et la zone d’écran dans le centre d’aide (Fichier d’aide: Référence) Manuel →
Bibliothèques de jeux et multimédias 2D → Sprite et écran), vous pouvez trouver plus d’informations sur
les nouvelles commandes utilisées dans cet exemple.

Cet exemple ne fait rien d'autre que d'ouvrir un écran vide et si vous regardez cela maintenant vous pouvez quitter le
programme en appuyant « ESC ». Cet exemple est a l' Origine pour les jeux et autres, laissez-moi vous expliquer ce qui
se passe dans les parties importantes

Pour commencer, j'ai créé une procédure simple de vérification des erreurs comme expliqué dans le chapitre 8
(Comment minimiser et gérer les erreurs) et utilisé ceci pour m'assurer que les commandes « InitSprite() », «
InitKeyboard() » et « OpenScreen() » ne retournent pas « 0 ». Si l'un d'entre eux le fait, alors cette commande
particulière est considérée comme ayant échoué, alors je quitte immédiatement le programme. Si une telle panne se
produit pour quelque raison que ce soit, il est toujours préférable de fermer le programme et d'informer l'utilisateur du
problème. Sinon, si votre programme devait continuer, des pannes majeures sont susceptibles de se produire.

Les commandes nécessaires pour initialiser le moteur de sprite et le clavier sont de simples appels de commandes, ce
sont « InitSprite() » et « InitKeyboard() ». souvenez-vous que nous devons initialiser le moteur de sprite avant d'ouvrir un
écran. La commande « OpenScreen() » prend quatre paramètres, ce sont la largeur, la hauteur et la profondeur de bit
de l'écran plus sa légende. Cette légende est celle qui s'affichera dans la barre des tâches si vous deviez réduire l'écran
de la vue. le quatrième paramètre étant toujours un texte descriptif passé. Ce texte de description se trouve dans la
barre des tâches, à lire si vous minimiser l'écran. Avec les paramètres optionnels cinq et six, vous pourrez le
synchroniser lors de la commutation du buffer d'image ainsi que le taux de rafraîchissement. Le paramètre cinq sera
dans la prochaine section décrite plus en détail. Plus d'informations sur cette commande sont disponibles dans l'aide.

En Utilisant le Clavier
Dans cet exemple, j’ai utilisé quelques commandes du clavier pour initialiser le clavier et reconnaître les frappes
au clavier, etc. Ces commandes se trouvent sur la page d’aide « Clavier ». Bibliothèque (Fichier d’aide: Manuel
de référence → Bibliothèques générales → Clavier). C'est une bibliothèque très petite et facile à utiliser, utiliser,
vous devriez donc pouvoir la récupérer.

La commande « InitKeyboard() » initialise le clavier et doit précéder toutes les autres commandes du clavier
appelée. La commande « ExamineKeyboard() » vérifie l'état actuel du clavier pour voir si des touches ont été
enfoncées, etc. Les commandes « KeyboardPushed() » et « KeyboardReleased() » renvoie « True() » si la
touche transmise est enfoncée ou est libéré. Les valeurs de clé peuvent être assignées par des constantes
intégrées. dont la liste complète se trouve sur la page d'aide de chaque commande.

Les paramètres de largeur, de hauteur et de profondeur de bits sont très importants car ils définissent la taille et la
profondeur de bits de votre écran. Quel que soit l'ordinateur qui va exécuter ce programme et ouvrir cet écran, il doit être
capable de supporter toutes les tailles et profondeurs de bits utilisées. Les valeurs de largeur et de hauteur sont
collectivement appelées résolution et doivent être entièrement prises en charge par la carte graphique et le moniteur
connectés à l'ordinateur cible, sinon une erreur se produira et la commande « OpenScreen() » ne fonctionnera pas. Les
valeurs que j'ai utilisées dans cet exemple sont celles que la plupart des ordinateurs sont capables de supporter et ne
devraient présenter aucun problème. Cela vaut la peine d'en tenir compte lors de l'écriture d'un programme qui repose
sur un écran.

La Fig. 36 montre une liste des résolutions courantes et des profondeurs de couleur sur chaque écran moderne.
L'ordinateur devrait fonctionner. Comme pour les jeux sur ordinateur, plus la résolution est élevée, meilleur est le
résultat. plus nette l'image. Cependant, étant donné que plus de pixels doivent être dessinés dans une résolution plus
élevée, cela rend le programme plus lent. Plus la profondeur de couleur est élevée, plus il y a de couleurs à afficher, plus
les graphiques deviennent plus réalistes.
Graphiques 2D 147

Résolution d' Ecran Commune


Largeur Hauteur Profondeur de Couleur

640 480 8, 16 and 32 Bit

800 600 8, 16 and 32 Bit

1024 768 8, 16 and 32 Bit

Fig. 36

Au lieu de coder en dur de telles valeurs dans votre programme, vous devriez préférer recherchez sur l'ordinateur cible
les résolutions possibles et utilisez ces valeurs. Vous pouvez déterminer les résolutions prises en charge et les
profondeurs de couleurs d'un ordinateur à l'aide du code suivant:

InitSprite()
If ExamineScreenModes()
While NextScreenMode()
Width.l = ScreenModeWidth()
Height.l = ScreenModeHeight()
BitDepth.l = ScreenModeDepth()
Debug Str(Width)+" x "+Str(Height)+" x "+Str(BitDepth)
Wend
EndIf

Toujours dans cet extrait, nous initialisons le moteur de sprite avant d'utiliser la commande « ExamineScreenModes() »,
ceci initialise tout correctement pour nous permettre d'utiliser ces commandes basées sur l'écran. J'utilise ensuite une
boucle« while » pour itérer à travers chaque mode d'écran supporté et j'utilise les commandes « ScreenModeWidth() »,
« ScreenModeHeight() » et « ScreenModeDepth() » , pour construire une chaîne décrivant chaque mode. Ceci est
ensuite répercuté dans la fenêtre Debug pour que nous puissions l'examiner. Il s'agit d'un exemple simple que vous
devriez pouvoir comprendre vous-même en lisant les pages d'aide (Fichier d'aide: Manuel de référence → Bibliothèques
de jeux et multimédia 2D →Sprite & Screen)

Rendu à Double Buffer


Lorsque vous utilisez un écran pour afficher des graphiques, vous avez toujours besoin d'une boucle principale pour
faire fonctionner le programme, dessiner des graphiques et tester les entrées de l'utilisateur, etc. Voici la boucle
principale tirée du programme de l'écran squelette de la page précédente :

...
Repeat
ClearScreen(0)
;Les opérations de dessin démarre ici
FlipBuffers(2)
ExamineKeyboard()
If KeyboardReleased(#PB_Key_Escape)
Quit = #True
EndIf
Until Quit = #True
...

Au premier abord, vous pouvez voir que c'est très similaire à une boucle principale normale de n'importe quel autre
programme, mais il y a quelques différences. Il y a deux commandes qui sont cruciales pour faire un dessin d'écran
correctement, ce sont « ClearScreen() » et « FlipBuffers() ». Avant d'entrer plus en détail sur ces deux commandes, je
dois expliquer une technique graphique appelée « DoubleBuffer » Explication de la « Mise en mémoire buffer »

Le double buffering est une technique graphique utilisée par les écrans PureBasic pour éviter les graphiques corrompus
et le scintillement de l'affichage. Étant donné que les écrans d'ordinateur redessinent constamment l'écran de l'écran
d'ordinateur, habituellement de soixante à soixante-dix (parfois plus) fois par seconde, il est difficile d'apporter des
modifications à l'écran, comme déplacer et dessiner de nouveaux graphiques sans que l'écran affiche les modifications
avant que vous les ayez réellement effectuées. Il en résulte des graphiques déchirés, corrompus et d'autres artefacts
visuels étranges. Si vous vouliez éviter ce problème en effaçant l'écran à chaque fois avant de redessiner l'écran entier
à nouveau, cela corrigerait le problème graphique corrompu, mais cela ferait vaciller l'écran.
148 Graphiques 2D

En utilisant le double buffer, PureBasic résout ces problèmes. Une fois qu'un écran est ouvert, il reçoit automatiquement
deux buffers vidéo en mémoire, exactement de la même taille que l'écran ouvert. Lorsque vous dessinez des graphiques
à l'écran à l'aide des commandes graphiques de PureBasic, vous dessinez réellement sur le buffer arrière pendant que
le buffer avant est affiché à l'écran. Lorsque le moniteur a terminé d'afficher le buffer avant et que les opérations de
dessin sont terminées sur le buffer arrière, les deux sont retournées (inversées). Maintenant, l'avant devient l'arrière et
l'arrière devient l'avant, qui est ensuite affiché. Quand le programme dessine à nouveau ses graphiques, il dessine sur la
mémoire buffer qui vient d'être retournée. Ce nouveau buffer arrière contiendra probablement d'anciens graphiques
parce qu'ils ont déjà été affichés, c'est donc la procédure standard pour effacer complètement le buffer arrière en
utilisant une seule couleur (généralement noir) avant de commencer à dessiner à nouveau dessus. La Fig.37 montre
cette technique en action en montrant trois cycles des buffers.

La figure 37 montre cette technique en action, vous pouvez voir trois cycles de la mémoire Buffer.

Rendu à Double Buffer

Buffer B Buffer A Buffer B

Buffer A Buffer B Buffer A


FlipBuffers() FlipBuffers()

1 2 3
L'écran est ouvert et l'aperçu du personnage Les buffers sont échangés. Les buffers seront à nouveau remplacés.
la vitesse commence sur le buffer arrière. La nouvelle mémoire buffer est supprimée La nouvelle mémoire buffer est supprimée et
(Le buffer A est affiché à l'écran) et fournie avec le graphique mis à jour. fournie avec le graphique mis à jour.
(Le buffer B est affiché à l'écran) (Le buffer A est affiché à l'écran)

Fig. 37

Dans cette Figure, vous pouvez voir au démarrage du programme (indiqué par l'étape 1), que le buffer avant « Buffer A
» n'a pas de graphique dessiné dessus, donc rien n'est affiché à l'écran. Lorsque nous dessinons des objets à l'aide des
commandes de dessin PureBasic, nous dessinons sur la mémoire buffer arrière, indiquée par « Buffer B ». Une fois que
tout le dessin a eu lieu, nous pouvons appeler la commande « FlipBuffers() » et les buffers sont retournés. Ceci est
illustré à l'étape 2. Maintenant, « Buffer B » s'affiche à l'écran et nous continuons à dessiner sur « Buffer A » qui est
maintenant le « Buffer A ». nouveau buffer arrière. Encore une fois, une fois que toutes les opérations de dessin sont
terminées, nous pouvons retourner les buffers en utilisant « FlipBuffers() » et nous arrivons à l'étape 3, où « Buffer A »
est maintenant dessiné à l'écran et « Buffer B » est à nouveau le Buffer Arrière.

Lorsque les buffers sont retournés à l'aide de la commande « FlipBuffers() », le buffer qui arrive à l'arrière aura toujours
de vieux graphiques dessinés dessus. Si nous voulons créer l'illusion du mouvement pour animer des graphiques, nous
devrons les effacer et les redessiner dans une nouvelle position avant de retourner les buffers. Pour effacer les anciens
graphiques, nous utilisons la commande « ClearScreen() ». Celle-ci prend un paramètre qui est une valeur de couleur
24 bits de la couleur avec laquelle vous voulez effacer l'écran. Ceci peut être récupéré facilement à l'aide de la
commande « RBG() ».

Revenons à la commande « OpenScreen() ». Le cinquième mentionné dans la section précédente Le paramètre


influence le comportement de l'échange de buffer avec la commande « FlipBuffers() » et prendre trois valeurs
suivantes:

‘0’ : Désactive la synchronisation verticale du moniteur


‘1’ : Active la synchronisation verticale du moniteur (valeur par défaut)
'2’ : Active la synchronisation verticale du moniteur en utilisant le mode d’économie de la
CPU (mode plein écran uniquement)

Si « 0 » est utilisé comme paramètre, le « FlipBuffers() » permute les buffers aussi vite que possible pour obtenir la
fréquence d'images la plus élevée des graphiques dessinés. Le seul inconvénient est que le taux de rafraîchissement
du moniteur peut ne pas être assez rapide pour dessiner les nouveaux graphiques en temps réel, de sorte qu'un certain
déchirement visuel peut se produire pendant que le moniteur tente de permuter le buffer d'affichage.
Graphiques 2D 149

Si « 1 » est utilisé comme paramètre, la commande « FlipBuffers() » permute les tampons en parfaite synchronisation
avec la fréquence de rafraîchissement des moniteurs en s'assurant que tous les graphiques sont affichés correctement
et en douceur sur le moniteur. Le seul inconvénient est que la fréquence d'images ne peut jamais dépasser la fréquence
de rafraîchissement du moniteur. C'est le mode par défaut si aucun paramètre n'est utilisé.

L'utilisation de « 2 » comme paramètre aura le même effet que l'utilisation de « 1 », mais passera en mode d'économie
CPU pour s'assurer qu'il n'exécute pas le CPU à cent pour cent et que les autres programmes n'ont aucune chance de
fonctionner.

Dessiner sur un Ecran


Voici un exemple de rendu et d'animation à double buffer créé en dessinant des graphiques mis à jour entre chaque
commande « FlipBuffers() »: (quittez ce programme en appuyant sur « ESC » sur votre clavier)

#IMAGE_MAIN = 1
;Réglage de la largeur, de la hauteur et de la profondeur de couleur de l'écran
;En raison de la largeur des noms de variables abrégés ont été utilisés ici :(
Global ScrB.l = 1024
Global ScrH.l = 768
Global ScrT.l = 32
Global Exit.i = #False
XOrigin.f = (ScrW / 2) - 64 : YOrigin.f = (ScrH / 2) - 64

; Procédure de vérification d'erreur simple


Procedure HandleError(Result.l, Text.s)
If Result = 0
MessageRequester("Erreur", Text, #PB_MessageRequester_Ok)
End
EndIf
EndProcedure

;Initialize environment
HandleError(InitSprite(), "InitSprite () a échoué.")
HandleError(InitKeyboard(), "Échec de InitKeyboard ().")
HandleError(OpenScreen(ScrW, ScrH, ScrT, "Erreur", 2), "Impossible d'ouvrir l'écran.")
SetFrameRate(60)

; Créer une image


If CreateImage(#IMAGE_MAIN, 128, 128)
If StartDrawing(ImageOutput(#IMAGE_MAIN))
For x.i = 255 To 0 Step - 1
Cercle(64, 64, x / 4, RGB(0, 0, 255 - x))
Next x
StopDrawing ()
EndIf
EndIf

;Convertir des degrés en radians


Procedure.f DegToRad(Angle.f)
ProcedureReturn Angle.f * #PI / 180
EndProcedure

;Boucle principale
Repeat
ClearScreen (RGB (0, 0, 0))
Angle.f + 2.0
Radius.f = ((ScrH / 2) - 100) * Sin(DegToRad(Angle))
StartDrawing(ScreenOutput())
For x.l = 0 To 359 Step 45
XPos.f = XOrigin + (Radius * Cos(DegToRad(Angle + x)))
YPos.f = YOrigin + (Radius * Sin(DegToRad(Angle + x)))
DrawImage(ImageID(#IMAGE_MAIN), XPos, YPos)
Next x
StopDrawing()
FlipBuffers ()
150 Graphiques 2D

If KeyboardReleased(#PB_Key_Escape)
Quit = #True
Endif
Until Quit = #True
End

Dans cet exemple, j'ai créé une nouvelle image à l'aide de la commande « CreateImage() » et j'ai ensuite dessiné cette
image à l'écran en utilisant un bloc « StartDrawing() ». Même si ce code semble un peu compliqué, surtout lors du calcul
des valeurs « x » et « y » de l'image dessinée, cet exemple n'est que pour démontrer le retournement des buffers.

Dans la boucle principale, vous pouvez voir que je commence par effacer l'écran. Pour cela j'utilise la Commande «
ClearScreen() ». Cela me permet de commencer mon processus de dessin sur un buffer vide afin qu'aucun vieux
graphique ne soit laissé par les opérations de dessin précédentes. Après j'en utilise un petit calcul pour calculer les
coordonnées de mes surfaces d' images pour les utiliser dans une boucle et dessiner ceux-ci. Une fois l'opération de
dessin terminée, le dessin se trouve en mémoire du buffer arrière, je dois donc utiliser la commande « FlipBuffers() »
pour passer le dessin dans l'écran affichage. Et ainsi de suite, supprimer, dessiner, échanger et entre eux avec ce
processus d'échange, je change la position du dessin.

Vous avez peut-être remarqué une autre nouvelle commande que j'ai utilisée dans cet exemple et qui est «
SetFrameRate() » (Fichier d’aide: Manuel de référence → Bibliothèques de jeux et multimédia 2D->Sprite & Ecran-)
>SetFrameRate). Cette commande a un paramètre qui définit le nombre de fois que « FlipBuffers() » peut être exécuté
par seconde. Ceci est pour fournir une fréquence d'images standard sur d'autres ordinateurs qui pourraient exécuter ce
code. Ceci devrait limiter cet exemple à l'affichage de graphiques mis à jour soixante fois par seconde.

C'est ainsi que toute animation est produite sur ordinateur, très semblable aux dessins animés ou aux films. Rien ne
bouge vraiment à l'écran, c'est en fait un diaporama d'images différentes (buffers) dans lesquelles les graphiques sont
dans des positions légèrement différentes. Parce que tout se passe très vite (plus de soixante fois par seconde), les
images semblent bouger.

Un champ d'étoiles simple


C'est l'un des effets que tout programmeur de démo ou de jeu saura dessiner. Un champ d'étoiles comme celui-ci a été
utilisé dans des centaines de démos et de jeux pour donner l'effet de voyager dans l'espace. C'est un effet qui dessine
et anime des centaines de pixels à l'écran en utilisant différentes nuances de couleurs pour donner l'illusion de
profondeur et de mouvement. Il y a plusieurs façons de programmer cet effet, voici mon exemple :

#APP_NAME = "Stars 1.0"


#NUMBER_OF_STARS = 10000
;Définir la largeur, la hauteur et la profondeur de bits de l'écran
;Les variables abrégées sont ici dues aux contraintes de largeur de page :(
Global ScrW.l = 1024
Global ScrH.l = 768
Global ScrD.l = 32
Global Quit.b = #FalseStructure

Structure STAR
xPos.f
yPos.f
xStep.f
Color.l
EndStructure

Global Dim Stars.STAR(#NUMBER_OF_STARS)

;Procédure de vérification d'erreur simple


Procedure HandleError(Result.l, Text.s)
If Result =0
MessageRequester("Erreur", Text, #PB_MessageRequester_Ok)
End
EndIf
EndProcedure
Graphiques 2D 151

;init stars
Procedure InitializeStars()
For x = 0 To #NUMBER_OF_STARS
Stars(x)\xPos = Random(ScrW - 1)
Stars(x)\yPos = Random(ScrH - 1)
If x < #NUMBER_OF_STARS / 3
Stars(x)\xStep = (Random(10) / 100) + 0.2
Stars(x)\Color = RGB(40, 40, 40)
ElseIf x >= #NUMBER_OF_STARS / 3 And x < (#NUMBER_OF_STARS / 3) * 2
Stars(x)\xStep = (Random(10) / 100) + 0.6
Stars(x)\Color = RGB(100, 100, 100)
Else
Stars(x)\xStep = (Random(10) / 100) + 1.2
Stars(x)\Color = RGB(255, 255, 255)
EndIf
Next x
EndProcedure

;déplacer stars sur l'axe 'x'


Procedure MoveStarsX()
For x = 0 To #NUMBER_OF_STARS
Stars(x)\xPos - Stars(x)\xStep
If Stars(x)\xPos < 0
Stars(x)\xPos = ScrW - 1
Stars(x)\yPos = Random(ScrH - 1)
EndIf
Next x
EndProcedure

;Initialize environment
HandleError(InitSprite(), "La commande InitSprite () a échoué.")
HandleError(InitKeyboard(), "La commande InitKeyboard () a échoué.")
HandleError(OpenScreen(ScrW, ScrH, ScrD, #APP_NAME), "Impossible d'ouvrir l'écran.")
SetFrameRate(60)
InitializeStars()

Repeat
ClearScreen(RGB(0, 0, 0))
StartDrawing(ScreenOutput())
For x = 0 To #NUMBER_OF_STARS
Plot(Stars(x)\xPos, Stars(x)\yPos, Stars(x)\Color)
Next x
DrawingMode(#PB_2DDrawing_Transparent)
DrawText(20, 20, #APP_NAME, #White)
DrawText(20, 40, Str(#NUMBER_OF_STARS)+" Stars Animée ", #White)
DrawText(20, 60, "Resolution Ecran: "+Str(ScrW)+" x "+Str(ScrH), #White)
DrawText(20, 80, "Profondeur de l'écran: "+Str(ScrD)+"bit", #White)
StopDrawing()
FlipBuffers()
MoveStarsX()
ExamineKeyboard()
If KeyboardReleased(#PB_Key_Escape)
Quit = 1
EndIf
Until Quit = 1
End

Cet exemple utilise la commande de tracé 2D « Plot() », qui dessine un seul pixel chaque fois qu'on l'appelle (Fichier
d’aide: Manuel de référence → Bibliothèques générales → Dessin 2D → Tracé). Cette commande nécessite trois
Paramètre, le troisième est optionnel. Ces paramètres définissent les positions « x » et « y » ainsi que la couleur du
pixel dessiné. Si le dernier paramètre n'est pas utilisé, la commande utilise la commande Couleur de premier plan par
défaut pouvant être définie avec la commande « FrontColor() »

Dans l'exemple ci-dessus, j'ai utilisé une structure pour obtenir toutes les informations pour chaque pixel. J'ai ensuite
créé un tableau de variables utilisant cette structure comme type.Chacun de ces éléments du tableau contient la
position, la valeur de couleur et la valeur de pas d'un pixel. puis Je me déplace en boucle dans le tableau et dessine
chaque pixel à l'écran à l'aide du bouton Détails du processus d'élément de tableau respectif (position, couleur, etc.).
Quand le dessin est terminé, J'échange les buffers et met à jour les positions des pixels dans le tableau à l'aide du
152 Graphiques 2D

valeur de pas assignée. Lorsque cela est fait, je supprime le buffer et dessine à nouveau les pixels, et le tout continue
encore et encore. Ce faisant, le code source semble plus propre, est plus facile à lire et vous permet de mettre à jour
facilement le code à une date ultérieure

Ouvrir d'un Ecran dans une fenêtre


Parfois, vous voudrez peut-être ouvrir un écran sur une fenêtre, surtout si vous voulez faire un jeu ou une démo avec
des fenêtres, etc. Vous pouvez le faire en utilisant la commande « OpenWindowScreen() » . Pour ouvrir un écran sur
une fenêtre, vous devez d'abord créer une fenêtre et ensuite gérer les événements de cette fenêtre dans la boucle
principale, ainsi que le dessin. Voici un exemple d'utilisation d'un écran fenêtré :

#WINDOW_MAIN = 1
#IMAGE_MAIN = 1
;Réglez la largeur, la hauteur et la profondeur de couleur de l'écran.
;En raison de la largeur de page, des noms de variables abrégés ont été utilisés ici:((
Global ScrW.l = 800
Global ScrH.l = 600
Global ScrD.l = 32
Global Quit.b = #False
Global XOrigin.f = (ScrW / 2) - 64
Global YOrigin.f = (ScrH / 2) - 64
;Procédure simple pour la vérification des erreurs ;
Procedure HandleError(Result.l, Text.s)
If Result = 0
MessageRequester("Error", Text, #PB_MessageRequester_Ok)
End
EndIf
EndProcedure
;Convertir les degrés en radians ;
Procedure.f DegToRad(Angle.f)
ProcedureReturn Angle.f * #PI / 180
EndProcedure
;Initialiser l'environnement
HandleError(InitSprite(), "la commande InitSprite() a échoué.")
HandleError(InitKeyboard(), "la commande InitKeyboard() a échoué.")
#FLAGS = #PB_Window_SystemMenu | #PB_Window_ScreenCentered
If OpenWindow(#WINDOW_MAIN, 0, 0, ScrW, ScrH, "Window Screen", #FLAGS)
If OpenWindowedScreen(WindowID(#WINDOW_MAIN), 0, 0, ScrW, ScrH, 0, 0, 0)
SetFrameRate(60)
;Créez une image
If CreateImage(#IMAGE_MAIN, 128, 128)
If StartDrawing(ImageOutput(#IMAGE_MAIN))
For x.l = 255 To 0 Step -1
Circle(64, 64, x / 4, RGB(255 - x, 0, 0))
Next x
StopDrawing()
EndIf
EndIf
;Boucle principale ;
Repeat
Event.l = WindowEvent()
ClearScreen(RGB(0, 0, 0))
Angle.f + 2.0
Radius.f = ((ScrH / 2) - 100) * Sin(DegToRad(Angle))
StartDrawing(ScreenOutput())
For x.l = 0 To 359 Step 45
XPos.f = XOrigin + (Radius * Cos(DegToRad(Angle + x)))
YPos.f = YOrigin + (Radius * Sin(DegToRad(Angle + x)))
DrawImage(ImageID(#IMAGE_MAIN), XPos, YPos)
Next x
StopDrawing()
Graphiques 2D 153

FlipBuffers()
ExamineKeyboard()
If KeyboardReleased(#PB_Key_Escape)
Quit = #True
EndIf
Until Event = #PB_Event_CloseWindow Or Quit = #True
EndIf
EndIf
End

Cet exemple devrait être assez simple, parce que la plupart de ce code que vous avez déjà vu auparavant. La principale
différence étant la commande « OpenWindowedScreen() » qui prend huit paramètres! Le premier paramètre est
l'identifiant OS de la fenêtre sur laquelle il doit être ouvert. Les deuxième et troisième paramètres sont la position « x » et
« y » du nouvel écran sur la fenêtre. Les quatrième et cinquième paramètres sont la largeur et la hauteur du nouvel
écran. Le sixième paramètre est l'indicateur d'auto-taille ou d'auto-étirement. Si ce paramètre est réglé sur « 0 », aucun
redimensionnement automatique n'a lieu, mais s'il est réglé sur « 1 », l'écran se redimensionne automatiquement à la
taille maximale autorisée par la fenêtre, sans tenir compte des paramètres quatre et cinq .Cela signifie que même si
vous redimensionnez la fenêtre parent, l'écran changera automatiquement de taille pour toujours remplir toute la zone
de la fenêtre parent. Les septième et huitième paramètres sont des marges que vous pouvez spécifier lorsque l'auto-
stretch est activé. Celles-ci tireront l'écran de redimensionnement automatique un peu en arrière du côté droit ou du bas
respectivement, pour laisser de la place à une barre d'état ou à d'autres gadgets sur la fenêtre.

Il est également très important lors de l'utilisation d'un écran sur une fenêtre, que vous gériez toujours correctement les
événements en utilisant la commande « WindowEvent() ». Si vous vous souvenez du chapitre 9, cette commande
n'attend pas qu'un événement se produise avant de revenir, mais elle essaie toujours de détecter et de renvoyer tous les
événements qui doivent être traités. Utiliser cette commande au lieu de « WaitWindowEvent() » est une condition
préalable pour utiliser des écrans fenêtrés, car vous devez permuter la mémoire buffer qui ne doit pas être retardée plus
longtemps.

Sprites
Les Sprites dans PureBasic sont des images qui peuvent être dessinées dans n'importe quelle position sur un écran.
Contrairement aux images cependant, les sprites ont leur propre jeu de commandes, sont optimisés pour la vitesse et
peuvent être dessinés de plusieurs façons spéciales pour obtenir de nombreux effets spéciaux. Toutes les commandes
de sprite normales apparaissent dans la section « Sprite & Ecran » du fichier d'aide (Fichier d'aide: Manuel de référence
→ Bibliothèques de jeux et multimédias->Sprite & Ecran) mais il y a aussi quelques autres commandes de s p r i te
situées dans la section « Sprite3D » (Fichier d’aide: Manuel de référence → Bibliothèques de jeux et multimédia 2D-
>Sprite3D). Pour vous familiariser complètement avec ce qui est capable d'utiliser les commandes du sprite, je vous
recommande de lire ces deux sections.

Différence entre Sprites et Sprite3D


Dans PureBasic, il existe deux types de sprites différents. Le premier est ce que vous considérez comme un sprite
normal, qui est créé à partir d'une image dessinée ou chargée par l'utilisateur et qui est affiché et manipulé en utilisant la
bibliothèque de sprites standard.

Le second type est presque le même, sauf que PureBasic utilise un très petit moteur 3D pour afficher les sprites. De
plus, les commandes utilisées pour dessiner et manipuler ce type, permettent au programmeur d'obtenir des effets
graphiques impossibles avec des sprites normaux. Ces effets comprennent le zoom en temps réel, la transformation 3D
et le mélange de sprites. Le moteur 3D qui effectue la transformation et l'affichage des sprites 3D n'est pas le moteur
OGRE comme mentionné dans le chapitre suivant, mais un petit moteur 3D autonome spécialement conçu pour gérer
ce type de sprite.

Utilisez des Sprites Normaux


Pour créer un sprite à utiliser dans un programme normal, vous pouvez en créer un avec la Commande « LoadSprite ()
» Load (Fichier d’aide: Manuel de référence → Bibliothèques de jeux et multimédia 2D → Sprite & Écran → LoadSprite)
ou créez-en un nouveau avec la commande « CreateSprite() » (fichier d'aide: référence Manuel → Bibliothèques de jeux
2D → Sprite et écran → CreateSprite).
154 Graphiques 2D

Pour charger une image existante que vous souhaitez utiliser comme image-objet, utilisez la commande « LoadSprite() »
Commande très similaire à la commande « LoadImage() » et qui nécessite trois paramètres. Le premier paramètre est le
numéro de PB que vous souhaitez attribuer à ce sprite. Le deuxième paramètre est le nom de fichier de l'image, que
vous voulez charger en tant sprite, n’oubliez pas de charger le bon décodeur d’image lorsque vous en avez besoin. Le
troisième Le paramètre spécifie le mode de ce sprite, qui définit l'utilisation de ce sprite. nous y reviendrons après.

Pour créer votre propre sprite afin que vous puissiez y dessiner à l'aide des commandes de dessin 2D, nous utilisons «
CreateSprite() » '. Etant très similaire à « CreateImage() », cette commande prend quatre paramètres. Le premier
paramètre, est le numéro PB que vous souhaitez associer à ce sprite. Les deuxième et troisième paramètres sont la
largeur et la hauteur en pixels du nouveau sprite, et le quatrième paramètre est le mode sprite.

Ces deux commandes créent un nouveau sprite et ont toutes deux un paramètre« mode » optionnel. Ce paramètre de
mode détermine le format interne du sprite afin que des sprites particuliers puissent être affichés correctement en
utilisant d'autres commandes du sprite. Ce paramètre de format est généralement défini comme une constante intégrée,
la Fig.38 montre ces constantes de mode et une description de chaque mode.

Selon la commande de sprite que vous voulez utiliser pour afficher votre sprite, vous devez utiliser un sprite
correctement formaté avec lui, et ce format est défini lorsque vous créez ou chargez ce sprite.

Modes Sprite

Constante utilisée Description du mode


aucun Le mode standard. Si possible, le sprite pénètre dans la RAM vidéo chargé.

#PB_Sprite_Memory Le sprite ne sera pas dans la RAM vidéo, mais dans la RAM normale La
mémoire est chargée avec la commande « StartSpecialFX() » peut être
utilisé.

#PB_Sprite_Alpha
Le sprite doit être une image en niveaux de gris de 8 bits, utilisables avec les
commandes « DisplayAlphaSprite() » ou « DisplaySchadowSprite() » est
préparé. Si vous avez le Ensuite, vous devez utiliser la commande «
StartSpecialFX() » « #PB_Sprite_Memory » est également spécifié.

#PB_Sprite_Texture Le sprite est créé avec le support 3D, vous avez donc un sprite 3D avec la
commande « CreateSprite3D() ».

#PB_Sprite_AlphaBlending Le sprite est créé avec le support du canal alpha. l'image chargée doit être
d'un format d'image comportant un canal alpha. Les seuls formats d'image
actuellement pris en charge avec Cette propriété est PNG et TIFF.
(Si vous avez l'intention de Vous devez également convertir le sprite en
sprite 3D. le mode « #PB_Sprite_Texture ». doit être également spécifié )

Les modes peuvent être utilisés comme d'habitude avec l'opérateur « OR » « | » être combiné au niveau bit. Fig. 38

Voici des exemples de la façon de spécifier correctement le mode pour chaque commande d'affichage de sprite. Le cas
échéant, j'ai donné un exemple de la façon de créer et de charger un sprite avec les paramètres de mode corrects, afin
qu'il s'affiche correctement lors de l'utilisation de la commande avant lui.

« DisplaySprite() » et « DisplayTransparentSprite() »
Format standard
CreateSprite (#PB_NOMBRE, width.i, height.i)
LoadSprite (#PB_NOMBRE, "Image.bmp")

« DisplaySprite3D() »
Sans canal alpha
CreateSprite (#PB_NOMBRE, width.i, height.i, #PB_Sprite_Texture)
LoadSprite (#PB_NOMBRE, "Image.bmp", #PB_Sprite_Texture)
Graphiques 2D 155

;Avec canal alpha


CreateSprite(#PB_NOMBRE, width.i, height.i,,#PB_Sprite_Texture | #PB_Sprite_AlphaBlending)
LoadSprite(#PB_NOMBRE, "Image.bmp", #PB_Sprite_Texture | #PB_Sprite_AlphaBlending)

« DisplayTranslucentSprite() »
;Chargement dans la RAM normale pour édition avec la commande 'StartSpecialFX ()'
CreateSprite (#PB_NOMBRE, width.i, height.i, #PB_Sprite_Memory)
LoadSprite (#PB_NOMBRE, "Image.bmp", #PB_Sprite_Memory)

« DisplayAlphaSprite() » , « DisplayShadowSprite() » et « DisplaySolidSprite() »


; Chargement dans la RAM normale pour édition avec la commande 'StartSpecialFX ()'
; et spécifier comme sprite de type alpha
CreateSprite (#PB_NOMBRE, width.i, height.i, #PB_Sprite_Memory | #PB_Sprite_Alpha)
LoadSprite (#PB_NOMBRE, "Image.bmp", #PB_Sprite_Memory | #PB_Sprite_Alpha)

Ces exemples devraient vous donner une bonne idée de la façon de charger et de créer vos propres sprites pour
chaque commande d'affichage.

Vous pouvez aussi Dessiner sur des Sprites


Une fois que vous avez créé ou chargé un sprite, vous pouvez dessiner dessus. Comme pour dessiner sur une image,
vous pouvez le faire en utilisant la commande standard « StartDrawing() » et en réglant la sortie sur « SpriteOutput() » .
Ceci vous permet d'utiliser les commandes de dessin 2D pour dessiner sur la surface du sprite. Vous pouvez même
dessiner un sprite sur un autre sprite. Pour ce faire, vous devez basculer la sortie de dessin du sprite de la mémoire
buffer arrière vers votre sprite cible. Pour cela, vous devez utiliser la commande « UseBuffer() » . Cette commande
prend un paramètre qui est le numéro PB du sprite vers lequel vous voulez diriger toute la sortie du sprite. Une fois
commutés, tous les autres sprites affichant des commandes dessinent des sprites sur le sprite cible. Lorsque vous avez
terminé, vous pouvez retourner la sortie d'affichage du sprite dans le buffer arrière en utilisant à nouveau la commande
« UseBuffer() » , mais cette fois avec un paramètre « #PB_Default ».

Commandes de Sprite « SpecialFX »


Dans les exemples de mode, j'ai mentionné les sprites « SpecialFX ». Ce sont encore des sprites normaux mais ils
fonctionnent beaucoup plus rapidement s'ils sont entourés des commandes « StartSpecialFX() » . Tous les sprites qui
utilisent des effets spéciaux comme celui-ci sont capables de produire de beaux graphiques, mais parce que tout est
rendu dans la RAM principale de l'ordinateur, ces sprites ne sont pas aussi rapides que sprites3D's. Voici un bref extrait
montrant l'utilisation de ces commandes :

StartSpecialFX()

DisplayAlphaSprite (#SPRITE_NUMBER, 64, 64)


DisplayRGBFilter (100, 100, 100, 100, 0, 255, 0)
DisplayTranslucentSprite (#SPRITE_NUMBER, 128, 128, 128) ; Etc .

StopSpecialFX ()

Comme vous pouvez le voir, la commande « StartSpecialFX() » démarre le bloc et « StopSpecialFX() » le termine.
Toutes les commandes d'effets spéciaux doivent entrer dans ces deux commandes. Ceci est fait pour augmenter la
vitesse de rendu de ces effets spéciaux, sinon sans le bloc « StartSpecialFX() » les performances d'affichage seraient
très mauvaises.

Si vous utilisez ces commandes, il est très important de comprendre qu'elles doivent être utilisées avant toute autre
commande graphique. Ceci est dû à la façon dont PureBasic gère les internes du dessin des effets spéciaux. Sinon, si
vous utilisez d'autres commandes graphiques avant un bloc d'effets spéciaux, elles seront écrasées sur le backbuffer
lorsque le bloc « StartSpecialFX() » démarrera. Si vous utilisez une commande « ClearScreen() » pour effacer le
buffer avant de dessiner, vous devriez aussi l'inclure dans le bloc « StartSpecialFX() » . Un autre point important à
préciser est qu'il ne devrait jamais y avoir qu'un seul bloc « StartSpecialFX() » dans une boucle principale, car cela
augmente encore les performances. Comme vous pouvez le voir dans l'exemple: « StartSpecialFX() » initialise le bloc
156 Graphiques 2D

Les commandes suivantes utilisent un bloc « StartSpecialFX() »:


'DisplayAlphaSprite()'
'DisplaySolidSprite()'
'DisplayShadowSprite()'
'DisplayRGBFilter()'
'DisplayTranslucentSprite()'
Vous trouverez plus d’informations sur ces commandes dans le fichier d’aide de la bibliothèque « Sprite & Ecran ». (Aide
Fichier: Manuel de référence → Bibliothèques de jeux et multimédias 2D → Sprite et écran)

Voir les Sprites Normaux


Les sprites normaux sont à la base de la réalisation d'un jeu 2D en PureBasic. Ce type de sprite a été utilisé à maintes
reprises, à maintes reprises, à maintes reprises, pour produire des visuels cool dans de nombreux jeux de haut niveau.
Voici un exemple simple de création d' un nouveau sprite et de rendu à l' écran avec la commande standard
« DisplayTransparentSprite() »:

#SPRITE_MAIN = 1
#NUMBER_OF_BALLS = 500

;Définir la largeur, la hauteur et la profondeur de bits de l'écran


;Les variables abrégées sont ici dues aux contraintes de largeur de page :(

Global ScrW.l = 1024


Global ScrH.l = 768
Global ScrD.l = 32
Global Quit.b = #False

Structure BALL
x.f
y.f
XOrigin.l
YOrigin.l
Radius.l
Angle.f
Speed.f
EndStructure

Global Dim Balls.BALL(#NUMBER_OF_BALLS)

;Procédure de vérification d'erreur simple


Procedure HandleError(Result.l, Text.s)
If Result = 0
MessageRequester("Erreur", Text, #PB_MessageRequester_Ok)
End
EndIf
EndProcedure

;Convertir les degrés en radians


Procedure.f DegToRad(Angle.f)
ProcedureReturn Angle.f * #PI / 180
EndProcedure

;Initialize all ball data


Procedure InitialiseBalls()
For x.l = 0 To #NUMBER_OF_BALLS
Balls(x)\XOrigin = Random(ScrW) - 32
Balls(x)\YOrigin = Random(ScrH) - 32
Balls(x)\Radius = Random(190) + 10
Balls(x)\Angle = Random(360)
Balls(x)\Speed = Random(2) + 1
Next x
EndProcedure

;Initialize environment
HandleError(InitSprite(), "La commande InitSprite () a échoué")
HandleError(InitKeyboard(), "La commande InitKeyboard () a échoué.")
HandleError(OpenScreen(ScrW, ScrH, ScrD, "Blobs"), "Impossible d'ouvrir l'écran.")
SetFrameRate(60)
Graphiques 2D 157

;Créer an image
Global Offset.f = 32

If CreateSprite(#SPRITE_MAIN, 64, 64)


If StartDrawing(SpriteOutput(#SPRITE_MAIN))
Box(0, 0, 64, 64, RGB(255, 255, 255))
For x.l = 220 To 1 Step -1
Offset + 0.025
Circle(Offset, 64 - Offset, x / 8, RGB(0, 255 - x, 0))
Next x
StopDrawing()
EndIf
EndIf

TransparentSpriteColor(#SPRITE_MAIN, RGB(255, 255, 255))


InitialiseBalls()

;Boucle principale
Repeat
ClearScreen(RGB(56, 76, 104))
For x.l = 0 To #NUMBER_OF_BALLS
Balls(x)\x=Balls(x)\XOrigin+(Balls(x)\Radius*Cos(DegToRad(Balls(x)\Angle)))
Balls(x)\y=Balls(x)\YOrigin+(Balls(x)\Radius*Sin(DegToRad(Balls(x)\Angle)))
Balls(x)\Angle + Balls(x)\Speed
DisplayTransparentSprite(#SPRITE_MAIN, Balls(x)\x, Balls(x)\y)
Next x
FlipBuffers()
ExamineKeyboard()
If KeyboardReleased(#PB_Key_Escape)
Quit = #True
EndIf
Until Quit = #True
End
La commande « DisplayTransparentSprite() » vous permet d'afficher un sprite à l'écran très similaire à
«DisplaySprite()» , mais lorsque vous affichez un sprite en utilisant « DisplayTransparentSprite() » , il sélectionne une
seule couleur dans l'image et il traite comme transparent. Ceci permet au sprite de ne pas toujours paraître rectangle.

Dans cet exemple, j'ai créé un nouveau sprite et je l'ai immédiatement rempli de blanc en utilisant la commande « Box()
» . Une fois que ceci est fait, je dessine alors une sphère verte ombrée sur elle en utilisant la commande « Circle() »
dans une boucle. Cela me laisse avec une sphère verte sur fond blanc. Une fois les commandes de dessin terminées,
j'ai configuré tous les pixels blancs du nouveau sprite pour qu'ils soient marqués comme transparents, en utilisant la
commande « TransparentSpriteColor() ». Cette commande prend deux paramètres, le premier est le numéro PB du
sprite à changer et le second est la couleur que vous souhaitez être marqué comme transparent. Une fois la couleur
choisie, la prochaine utilisation de « DisplayTransparentSprite() » affiche un sprite, moins la couleur transparente. Une
fois cet exemple exécuté, vous devriez voir un écran rempli de sphères vertes sans aucun blanc du tout. C'est une
excellente façon d'afficher les sprites avec une transparence.

Vous remarquerez également dans cet exemple que la commande d'affichage d'un sprite normal n'a pas besoin d'être
dans des commandes spéciales telles que « StartSpecialFX() » ou « StartDrawing() », etc. Vous pouvez utiliser les
commandes normales d'affichage du sprite par elles-mêmes. Tant que le moteur de sprite est initialisé et qu'un écran a
été ouvert, vous pouvez utiliser les commandes standard de sprite pour afficher un sprite. Les commandes standard
d'affichage des sprites sont :

« DisplaySprite() »
« DisplayTransparentSprite() »

Utiliser Sprite3D
PureBasic appelle ses sprites 3D par le nom légèrement mélangé de « Sprite3D ». Chaque sprite3D est une surface 2D
composée de deux polygones. Ces polygones sont dessinés à l'aide d'un petit moteur 3D et peuvent être transformés en
3D mais chaque sprite3D est finalement dessiné en 2D sur l'écran. Confus ? Bien, continuons.

Un sprite3D en PureBasic est vraiment un sprite normal qui a reçu un support 3D et en tant que tel, ce type différent
nécessite un petit moteur 3D pour les afficher. Pour utiliser n'importe quel sprite3D dans votre programme, vous devez
initialiser le moteur sprite3D avant d'utiliser toute autre commande liée à sprite3D. Ceci est fait en utilisant la commande
« InitSprite3D() ». Cette commande est cependant une commande enfant de'InitSprite()', qui doit aussi être appelée
avant elle.
158 Graphiques 2D

Chaque sprite3D démarre sa vie comme un sprite normal, chargé ou créé mais avec le mode « #PB_Sprite_Texture ».
défini. Cette version normale n'est pas affichée à aucun moment, au contraire, ce sprite normal est transformé en
version 3D à l'aide de la commande « CreateSprite3D() ». Cette commande prend deux paramètres, le premier est le
numéro PB que vous souhaitez associer au nouveau sprite3D. Le second est le sprite d'abord créé ou chargé que vous
voulez transformer en sprite3D.

Voici la procédure de conversion dans PureBasic:

LoadSprite(#NORMALES_SPRITE, "image.bmp", #PB_Sprite_Texture)


CreateSprite3D(#SPRITE_3D, #NORMALES_SPRITE)

Une fois que le sprite3D a été créé comme ceci, nous pouvons ensuite l'afficher à l'écran en utilisant la commande «
DisplaySprite3D() ». Pour expliquer les choses un peu plus clairement, voici un exemple d'affichage et de manipulation
de sprites3D's :

UsePNGImageDecoder()
Enumeration
#SPRITE_2D
#SPRITE_3D
EndEnumeration
#NUMBER_OF_FLOWERS = 150
;Définir la largeur, la hauteur et la profondeur de bits de l'écran
;Les variables abrégées sont ici dues aux contraintes de largeur de page :(
Global ScrW.l = 1024
Global ScrH.l = 768
Global ScrD.l = 32
;Autres variables globales
Global Quit.b = #False
Global XOrigin.l = ScrW / 2
Global YOrigin.l = ScrH / 2
Structure FLOWER
XPos.f
YPos.f
Width.f
Height.f
Angle.f
Radius.f
RadiusStep.f
EndStructure
Global Dim Flowers.FLOWER(#NUMBER_OF_FLOWERS)
;Procédure de vérification d'erreur simple
Procedure HandleError(Result.l, Text.s)
If Result = 0
MessageRequester("Error", Text, #PB_MessageRequester_Ok)
End
EndIf
EndProcedure
;Convertir les Degrees to Radians
Procedure.f DegToRad(Angle.f)
ProcedureReturn Angle.f * #PI / 180
EndProcedure
; Initialiser toutes les fleurs
Procedure InitialiseAllFlowers()
For x.l = 0 To #NUMBER_OF_FLOWERS
Flowers(x)\Width = 0
Flowers(x)\Height = 0
Flowers(x)\Angle = Random(360)
Flowers(x)\Radius = 1.0
Flowers(x)\RadiusStep = (Random(30) / 10) + 1.0
Next x
EndProcedure
Graphiques 2D 159

;Réinitialiser une fleur


Procedure ResetFlower(Index.l)
Flowers(Index)\Width = 0
Flowers(Index)\Height = 0
Flowers(Index)\Angle = Random(360)
Flowers(Index)\Radius = 1.0
Flowers(Index)\RadiusStep = (Random(30) / 10) + 1.0
ProcedureReturn
EndProcedure

;Initialiser l'environnement
HandleError(InitSprite(), "La commande InitSprite () a échoué.")
HandleError(InitSprite3D(), "La commande InitSprite3D() a échoué.")
HandleError(InitKeyboard(), "La commande InitKeyboard () a échoué.")
HandleError(OpenScreen(ScrW, ScrH, ScrD, "Flowers"), "Impossible douvrir l'écran.")
SetFrameRate(60)

Sprite3DQuality(1)
;Charge le sprite
LoadSprite(#SPRITE_2D,"Flower.png",#PB_Sprite_Texture|#PB_Sprite_AlphaBlending)
CreateSprite3D(#SPRITE_3D, #SPRITE_2D)
InitialiseAllFlowers()
;Boucle principale
Repeat
ClearScreen(RGB(200, 100, 100))
HandleError(Start3D(), "La commande Start3D () a échoué.")

For x.l = 0 To #NUMBER_OF_FLOWERS


Flowers(x)\Width + 1.5
Flowers(x)\Height + 1.5
Flowers(x)\Angle + 1.0
If Flowers(x)\Width > 512.0 Or Flowers(x)\Height > 512.0
Flowers(x)\Width = 512.0
Flowers(x)\Height = 512.0
EndIf
If Flowers(x)\Radius > ScrW
ResetFlower(x)
EndIf
Flowers(x)\Radius + Flowers(x)\RadiusStep
Flowers(x)\XPos=XOrigin+(Flowers(x)\Radius*Cos(DegToRad(Flowers(x)\Angle)))
Flowers(x)\YPos=YOrigin+(Flowers(x)\Radius*Sin(DegToRad(Flowers(x)\Angle)))
Flowers(x)\XPos - Flowers(x)\Radius / 3.5
Flowers(x)\YPos - Flowers(x)\Radius / 3.5
ZoomSprite3D(#SPRITE_3D, Flowers(x)\Width, Flowers(x)\Height)
RotateSprite3D(#SPRITE_3D, Flowers(x)\Angle, 0)
DisplaySprite3D(#SPRITE_3D, Flowers(x)\XPos, Flowers(x)\YPos)
Next x

Stop3D()
FlipBuffers()
ExamineKeyboard()
If KeyboardReleased(#PB_Key_Escape)
Quit = #True
EndIf
Until Quit = #True
End

Pour me permettre d'utiliser sprite3D dans mon exemple, j'ai initialisé le moteur de sprite normal, puis j'ai initialisé le
moteur sprite3D en utilisant la commande « InitSprite3D() ». Ceci est essentiel pour utiliser toutes les commandes liées
à sprite3D. Après cela, j'ai ensuite utilisé la commande « LoadSprite() » pour charger une image au format Png. Cette
image qui s'appelle « flower.png » , utilise un canal alpha pour créer un fond transparent. Charger une image au format
Png avec un canal alpha comme celui-ci nécessite de définir correctement le mode sprite dans la commande «
LoadSprite() ». Si vous regardez le code de l'exemple, j'ai spécifié le modee « #PB_Sprite_Texture |
#PB_Sprite_Alphablending », Ceci indique au compilateur que je souhaite utiliser ce sprite comme un sprite3D et qu'il
contient un canal alpha. Après le chargement correct, je peux ensuite créer un sprite3D à partir de celui-ci en utilisant la
commande « CreatSprite3D() » et son canal alpha reste préservé
160 Graphiques 2D

Une fois les sprites créés, il est temps de les dessiner à l'écran. Ceci est réalisé en utilisant la commande
« DisplaySprite3D() » dans un bloc « Start3D() ». Ça ressemble à quelque chose comme ça :

...
Start3D()
DisplaySprite3D(#SPRITE_3D, x, y, Alpha)
Stop3D()
...

Si vous regardez l'exemple de la fleur, le bloc « Start3D() » est vérifié en utilisant une petite procédure de vérification
d'erreur pour s'assurer qu'il démarre correctement. Si c'est le cas, on peut continuer et dessiner les sprites. S'il ne
démarre pas correctement, nous ne devons pas dessiner de sprite3D's ou il peut y avoir un grave crash du programme.
Une commande « Stop3D() » est utilisée pour terminer le bloc sprite3D. A l'intérieur de ce bloc, vous ne devez utiliser
aucune commande de la bibliothèque de sprite normale, ce bloc est réservé aux commandes sprite3D.

Pour afficher réellement un sprite3D vous utilisez la commande « DisplaySprite3D() », qui prend quatre paramètres. Le
premier est le numéro PB du sprite3D que vous souhaitez afficher. Les deuxième et troisième sont les positions « x » et
« y » du sprite sur le buffer. Le quatrième paramètre optionnel est la valeur alpha du sprite. Cette valeur alpha définit le
degré de transparence de l'ensemble du sprite sur l'affichage. Il s'agit d'un entier qui va de« 0 », qui est complètement
transparent, à « 255 », qui est complètement opaque.

Dans l'exemple de fleur, j'ai aussi utilisé les commandes « ZoomSprite3D() » et « RotateSprite3D() » pour
redimensionner et tourner les sprite3D. Ces commandes sont très faciles à comprendre et peuvent être lues plus en
détail dans le fichier d'aide PureBasic dans la section « Sprite3D » (fichier d’aide:Manuel de référence → Bibliothèques
de jeux et multimédias 2D → Sprite3D)

Qualité des Sprite3D


Lors de l'utilisation de sprite3D dans votre programme, il est possible de basculer la qualité de rendu des sprites. Ceci
se fait avec la commande « Sprite3DQuality() ». Cette commande prend un paramètre qui est le mode de rendu de tous
les sprite3D de votre programme. Le paramètre est une valeur numérique égale à un mode particulier.

Voici les définitions:

« #PB_Sprite3D_NoFiltering »
Pas de filtrage (plus rapide, mais très pixelisé lors des zooms avant et arrière)

« #PB_Sprite3D_BilinearFiltering »
Filtrage bilinéaire (plus lent, mais mélange les pixels, donc lors du zoom et de la rotation propre des transitions
se produisent)

Dans mon exemple, j'ai utilisé « Sprite3DQuality (# PB_Sprite3D_BilinearFiltering) ». Ce sera le Le filtrage bilinéaire est
activé, ce qui permet au Sprite3D d’effectuer un zoom avant et d’activer une fonction propre, donne un aspect lisse. Si
vous n'utilisez pas cette commande, la qualité est Programmée par défaut « # PB_Sprite3D_NoFiltering ». Dans ce
cas, aucun filtrage n’est sélectionné. C’est pourquoi la Les Sprite3D deviennent pixellisés lors de la manipulation.
Graphiques 3D 161

11. Graphiques 3D
Dans ce chapitre, je vais parler des graphiques 3D et de la façon dont PureBasic utilise le moteur OGRE pour les
dessiner à l'écran. Les graphiques 3D utilisent des modèles 3D imaginaires pour créer des mondes crédibles qui
donnent l'impression de largeur, de hauteur et de profondeur, et l'écran d'ordinateur est généralement considéré comme
une fenêtre à travers laquelle vous pouvez voir ces mondes 3D. C'est bien sûr un peu imprécis, alors que même moi
j'aime à penser que je regarde un monde en 3D à travers mon écran (surtout quand je joue à des jeux en 3D) je sais
pertinemment que ce sont des routines mathématiques sophistiquées qui dessinent ces modèles 3D imaginaires sur
l'écran de mon ordinateur pour me donner l'impression des trois dimensions. Heureusement, PureBasic s'occupe de
toutes les mathématiques nécessaires pour dessiner des graphiques 3D à l'écran en utilisant le moteur 3D OGRE. Cela
vous permet d'appeler des commandes simples de haut niveau qui exécutent des effets graphiques 3D complexes. Cela
rend la programmation de graphiques 3D dans PureBasic rapide, amusante et très facile.

Ce chapitre, malheureusement, ne sera pas un texte exhaustif sur la programmation de graphiques 3D à l'aide de
PureBasic car ce serait un livre entier en soi, mais ce chapitre est vraiment une introduction à l'utilisation des
commandes et quelques solutions aux problèmes courants auxquels les débutants peuvent être confrontés.

Un aperçu du « moteur OGRE »


Pour qu'il soit possible de dessiner des graphiques tridimensionnels à l'écran, comme je l'ai déjà dit, il faut utiliser des
routines mathématiques compliquées pour calculer les formes, les textures, les positions, l'éclairage, etc. du modèle, ce
qui peut prendre beaucoup de temps et être très difficile pour le cerveau. Heureusement pour les utilisateurs de
PureBasic, le moteur OGRE 3D est utilisé pour s'occuper de toutes ces choses fastidieuses afin que vous puissiez vous
concentrer sur le codage de votre programme. OGRE (Open source Graphics Engine) est un moteur de rendu 3D temps
réel open source créé et développé par Torus Knot Software Limited. Ce moteur est fourni gratuitement sur Internet et
accessible à tous, gratuitement et à toutes fins.

Après avoir examiné le code source du moteur OGRE, le développeur principal de PureBasic, Frédéric Laboureur, a
décidé qu'il était d'une qualité si fantastique qu'il l'a intégré dans le jeu de commande de PureBasic. Le moteur lui-même
est inclus avec PureBasic en tant que bibliothèque dynamique liée (DLL) et la bibliothèque 3D intégrée de PureBasic y
est intégrée. Le seul inconvénient, c'est que le moteur OGRE a un moteur de type qui contient plusieurs centaines de
commandes et PureBasic ne les supporte pas toutes. Ceci est dû à certaines incompatibilités avec le langage dans
lequel OGRE a été programmé et le temps nécessaire à l'équipe PureBasic pour implémenter et tester de nouvelles
commandes. D'autres commandes pourraient être ajoutées à l'avenir, car l'équipe de PureBasic a exprimé son intérêt à
augmenter le jeu de commandes OGRE disponible pour les utilisateurs de PureBasic, donc je suppose que seul le
temps le dira. Vous pouvez voir la commande OGRE actuelle définie dans l’aide sous la rubrique (Jeux 3D & Afficher
les bibliothèques multimédias (Fichier d’aide: Manuel de référence → Bibliothèques de jeux 3D et multimédias)

Le Format Mesh (maillage) OGRE


Pour utiliser OGRE pour manipuler et afficher des modèles 3D dans votre programme, vous aurez besoin que ces
modèles soient dans un format particulier. Il s'agit du format OGRE « Mesh » et ces fichiers modèles auront
l'extension « * .mesh ».

Créez vos propres Mesh (maillages)

Pour créer vos propres maillages, vous devrez utiliser ce que l'on appelle un programme de modélisation 3D. Ce
type de programme vous permettra de créer un modèle à l'aide d'un affichage tridimensionnel. Cela vous permet
de voir un aperçu actualisé en temps réel de votre modèle sous n'importe quel angle pendant le processus de
création. Ce type de programme fournit également des outils pour vous permettre d'ajouter des textures d'image,
pour donner à votre modèle un habillage graphique pour quand il est rendu dans le moteur 3D. Des programmes
de modélisation 3D plus avancés vous permettent d'aligner précisément les textures de l'image sur un modèle en
déballant le modèle en une forme 2D. Ce formulaire bidimensionnel non emballé peut ensuite être exporté sous
forme d'image pour fournir un modèle à partir duquel vous pouvez dessiner votre texture. Lorsque cette texture
est appliquée de nouveau sur le modèle 3D original, elle correspondra parfaitement à la forme 3D. N'importe quel
programme de modélisation 3D peut être utilisé pour créer vos modèles 3D à condition que le modèle fini puisse
être exporté et sauvegardé sous forme de fichier « *.mesh »,
162 Graphiques 3D

Si vous regardez sur le site Web d'OGRE, dans la section des téléchargements, vous trouverez de nombreux outils et
plugins tiers qui offrent des fonctionnalités supplémentaires aux principaux logiciels de modélisation 3D. Ces outils
permettent à ces paquets d'enregistrer et d'exporter les modèles chargés et nouvellement créés dans le bon format de
maillage. En fait, c'est probablement une bonne idée de regarder d'abord ici avant de décider quel logiciel de
modélisation 3D utiliser pour la création de votre maillage.

Formats de Texture OGRE


Chaque modèle qui est affiché à l'aide d'un moteur 3D a besoin d'une texture. Ces textures ne sont rien de plus que des
images qui s'enroulent autour de modèles pour fournir une peau sur laquelle dessiner des détails. En fait, certaines
personnes appellent les textures «Peau» . Parfois, les modèles ont plus d'une texture pour fournir une plus grande
variété de textures ou pour fournir une finition plus détaillée.

Lorsque vous utilisez des textures pour fournir des skins pour vos modèles 3D, vous devez utiliser le bon format
d'image, sinon les textures n'apparaîtront pas une fois que votre programme sera compilé. Il est important de s'en
souvenir car la plupart des logiciels de modélisation 3D ont la capacité de charger et d'utiliser plusieurs types de formats
d'images qui ne sont pas pris en charge par OGRE. Le moteur OGRE utilisé par PureBasic utilise des fichiers Png, Tga
ou Jpg. Si vous utilisez ces formats d'image comme textures pour vos modèles, vous savez que tout fonctionnera
comme prévu.

Système de Coordonnées 3D d'OGRE


Lorsque vous dessinez et manipulez des objets dans un espace 3D, vous avez besoin d'un bon système de
coordonnées pour suivre la position d'un objet dans cet espace. OGRE utilise un système de coordonnées standard
droitier « x, y, z ». mais pour ceux d'entre vous qui ne savent pas ce que c'est, laissez-moi vous expliquer. Dans un
système de coordonnées comme celui-ci, les trois dimensions se voient attribuer une lettre différente et c'est de là que
vient le « x, y, z ». Savoir quelle lettre est affectée à quelle dimension est essentielle pour utiliser ce système. La figure
39 montre les dimensions et la lettre qui leur est affectée. Ce diagramme montre également comment l'espace
tridimensionnel peut facilement être divisé et référencé à l'aide de trois valeurs. Si vous imaginez qu'une scène 3D
entière se trouve à l'intérieur de cette boîte invisible, alors n'importe quel point de cette scène peut être décrit par un
ensemble de trois valeurs « x, y, z ».

Coordonnées dans l'espace 3D d'OGRE


-
Z
Chaque point dans l'espace 3D
défini par trois axes 'x, y, z'
+ 'X' = Largeur Les valeurs sont décrites.
10
'Y' = Hauteur Voici le point '5, 5, 5'
'Z' = Profondeur 9 décrit et par trois axes
8 imaginaires, se croisant en
lignes tracées
7
6
Y 5
4
0
3 1
2
2 3
4
1 5
6
0 7
8
- 0 1
9
X 2 3 4 5 6 7
10
8
+ 9 10

Fig. 39

Les coordonnées elles-mêmes sont assez simples à comprendre, chaque dimension peut être référencée par un
nombre positif ou négatif et le moteur OGRE les énumère d'une manière particulière. La case de gauche de la Fig.39 le
montre en utilisant les caractère « + » et « - » Si vous imaginez le coin inférieur gauche de votre écran d'ordinateur
comme existant aux coordonnées 3D; « 0, 0, 0 ». Le nombre de coordonnées « x » augmente numériquement plus vous
vous déplacez vers la droite de votre moniteur et la coordonnée « y ». augmente numériquement plus vous montez dans
l'écran du moniteur. La coordonnée « z » est un peu différente, en ce sens qu'elle augmente de valeur au fur et à
mesure que vous vous éloignez de l'écran et que vous vous déplacez. C'est encore une fois démontré dans l'encadré de
droite si vous regardez les chiffres sur les côtés.

Certaines personnes aiment utiliser les coordonnées « 0, 0, 0 » comme centre d'un espace 3D donné, puis les
coordonnées qui se réfèrent à d'autres objets dans ce monde peuvent être soit positives soit négatives selon la direction
du centre, le point que vous devez décrire est. Espérons que ce diagramme simple vous permettra de comprendre
comment les coordonnées « x, y, z » sont traitées.
Graphiques 3D 163

Identificateurs d'API OGRE


Tout en utilisant PureBasic et OGRE pour produire des visuels 3D, vous utilisez efficacement l'API OGRE (interface de
programmation d'applications) pour gérer les choses en coulisses. PureBasic n'expose aucune de ces API OGRE brutes
à vous, mais enveloppe plutôt les commandes API dans des commandes de base beaucoup plus conviviales.
Cependant, à l'occasion, vous devrez quand même faire référence à certains objets OGRE par leur OGRE. identifiant.
Ces identificateurs ne sont que des valeurs de type long et sont très similaires aux identificateurs d'OS qui sont
également nécessaires pour une API (Win32 API). Pour obtenir les identificateurs OGRE de divers objets, vous pouvez
utiliser ces commandes PureBasic :

« MaterialID(#MATERIAL) »
Renvoie l'identificateur OGRE de l'article que vous avez transféré comme numéro PB dans le paramètre.

« MeshID(#MESH) »
Renvoie l'identifiant OGRE du maillage que vous avez passé comme numéro PB dans le paramètre.

« TextureID(#TEXTURE) »
Renvoie l'identifiant OGRE de la texture que vous avez passée comme numéro PB dans le paramètre

Un Démarrage en Douceur
Dans l'exemple suivant, je vais vous montrer comment initialiser l'environnement 3D, charger un maillage 3D, lui
appliquer une texture et l'afficher à l'écran. Pour rendre les choses un peu plus excitantes, j'ai fait tourner le modèle et
j'ai inclus une lumière, pour que le modèle n'ait pas l'air trop plat quand il est affiché.

Enumeration
#MESH
#TEX
#MAT
#ENTITY_INVADER
#LIGHT
#CAMERA_ONE
EndEnumeration

;Définir la largeur, la hauteur et la profondeur de bits de l'écran


;Les variables abrégées sont ici dues aux contraintes de largeur de page :(

Global ScrW.l = 1024


Global ScrH.l = 768
Global ScrD.l = 32

;Autres variables globales


Global Quit.b = #False

;Procédure de vérification d'erreur simple


Procedure HandleError(Result.l, Text.s)
If Result = 0
MessageRequester("Erreur", Text, #PB_MessageRequester_Ok)
End
EndIf
EndProcedure

;Initialize environment
;HandleError(InitEngine3D(), "La commande InitEngine3D() a échoué."")
HandleError(InitSprite(), "La commande InitSprite () a échoué.")
HandleError(OpenScreen(ScrW, ScrH, ScrD, ""), "Impossible d'ouvrir l'écran.")
HandleError(InitKeyboard(), "La commande InitKeyboard () a échoué.")
SetFrameRate(60)

Add3DArchive("Data\", #PB_3DArchive_FileSystem)
HandleError(LoadMesh(#MESH, "Invader.mesh"), "Impossible de charger mesh")
HandleError(LoadTexture(#TEX, "Invader.png"), "Impossible de charger texture")
HandleError(CreateMaterial(#MAT, TextureID(#TEX)), "Impossible de créer Materiel")
CreateEntity(#ENTITY_INVADER, MeshID(#MESH), MaterialID(#MAT))
CreateLight(#LIGHT, RGB(255,255,255), 0, 5, 0)
CreateCamera(#CAMERA_ONE, 0, 0, 100, 100)
CameraLocate(#CAMERA_ONE, 0, 1, 2.5)
RotateCamera(#CAMERA_ONE, -15, 0, 0)
164 Graphiques 3D

;Boucle principale
Repeat
y.l + 2
RotateEntity(#ENTITY_INVADER, 0, y, 0)
RenderWorld()
FlipBuffers()
ExamineKeyboard()
If KeyboardReleased(#PB_Key_Escape)
Quit = #True
EndIf
Until Quit = #True
End

Cet exemple devrait vous être très utile car il montre toutes les étapes nécessaires pour afficher un modèle 3D à l'écran.
Comme toujours, le code devrait être assez facile à suivre mais je vais passer en revue les points principaux pour que
vous ne manquiez rien.

Une fois les constantes, variables et procédures déclarées, vous verrez que j'ai utilisé la commande « InitEngine3D() ».
pour initialiser l'environnement 3D. Cet appel de commande est nécessaire pour charger le moteur 3D à partir du
répertoire des compilateurs. Ce fichier DLL contient le moteur OGRE sous une forme pré-compilée, qui comme ceci,
peut être utilisé facilement dans vos programmes.

Une fois l'environnement 3D initialisé, un écran peut être créé de la manière habituelle. D'abord initialiser le moteur
sprite et ensuite ouvrir un écran. Ceci doit être fait dans cet ordre ou une erreur de compilation se produira et l'IDE
commencera à se plaindre. Si cela se produit, il se peut que vous deviez tuer le programme et réorganiser les
initialisations dans l'ordre correct avant de le relancer.

Intégrez OGRE dans votre Programme 3D


Lorsque vous créez un programme 3D à l'aide de PureBasic et que vous souhaitez le partager avec d'autres
personnes, que ce soit à titre commercial ou gratuit, vous devez penser à distribuer le moteur 3D OGRE avec
votre programme.

PureBasic utilise OGRE comme DLL compilé pour fournir toutes les fonctions 3D de manière compacte et
portable. Lorsque vous compilez votre programme, les commandes OGRE ne sont pas intégrées dans votre
programme comme les commandes PureBasic intégrées régulières. Au lieu de cela, toutes les commandes
OGRE sont appelées dynamiquement depuis une DLL. Cela signifie que le fichier DLL doit toujours
accompagner votre fichier exécutable pour qu'il fonctionne correctement.

Cela se fait automatiquement lors du développement, car lorsque vous cliquez sur « F5 » depuis l'IDE pour
compiler et exécuter votre programme, un fichier exécutable temporaire est créé dans le répertoire « \ Compilers
», qui est exactement l'endroit où le moteur OGRE est installé. De cette façon, le test des commandes 3D est
toujours aussi simple que possible. Cependant, une fois compilé dans un fichier exécutable ailleurs, le moteur
doit être copié dans le même répertoire

Les deux fichiers que vous devez distribuer avec votre programme 3D pour qu' il s' initialise et fonctionne
correctement, sont : « Engine3D.dll » (Moteur3D.dll) « stlport_vc646.dll ».
Ces DLLs se trouve dans le répertoire « \ Compilers » du dossier PureBasic. Ces fichiers doivent être dans le
même répertoire que votre programme, (pas dans un autre dossier) sinon ils ne seront pas accessibles.

Créer une Archive 3D Contenant un Média


Une fois toutes les initialisations effectuées, nous pouvons commencer à utiliser les commandes 3D et la toute première
chose à faire est de spécifier un'Archive 3D'. Il s'agit d'un chemin dans lequel OGRE recherche les fichiers externes lors
du chargement de médias tels que modèles, textures, cartes, etc. Vous devez avoir au moins une archive 3D spécifiée
dans votre programme 3D sinon le compilateur affichera une erreur. Pour spécifier une telle archive, vous devez utiliser
la commande « Add3DArchive() », (Fichier d'aide: Manuel de référence-> Bibliothèques de jeux 3D-> Engine3D->
Add3DArchive). Cette commande prend deux paramètres, le premier est une chaîne de caractères spécifiant un chemin
de fichier et le second est une constante intégrée qui indique au compilateur de quel type de chemin il s'agit. Les
constantes intégrées sont :
Graphiques 3D 165

« #PB_3DArchive_FileSystem »
Indique au compilateur que le chemin donné est un répertoire normal.

« #PB_3DArchive_Zip »
Indique au compilateur que le chemin d'accès transmis est un fichier ZIP compressé

Dans mon exemple d' Invader, j'ai créé une archive 3D en utilisant un chemin relatif, cela indique à OGRE de regarder
dans le même répertoire que mon programme et de regarder dans le dossier appelé « \ Data ». Une fois spécifié comme
ceci, tous les médias requis doivent se trouver dans ce dossier. Ceci permet ensuite d'utiliser des commandes simples
comme :

...
LoadMesh(#MESH, "Invader.mesh")
...

Lorsqu'une commande comme celle-ci est rencontrée dans notre programme qui a besoin de charger un média externe,
OGRE cherchera ce fichier dans toutes les archives 3D spécifiées, dans ce cas OGRE cherchera le fichier «
Invader.mesh » dans le répertoire « \Data ».

Si vous voulez ranger vos médias dans un système de classement plus strict et inclure d'autres sous-répertoires dans le
dossier « \Data ». alors vous pouvez le faire par tous les moyens. Vous devrez ensuite charger ce média à partir de
leurs nouveaux emplacements comme ceci :

...
LoadMesh(#MESH, "Meshes\Invader.mesh")
LoadTexture(#TEX, "Textures\Invader.png")
...

Une fois de plus, cela permet de rechercher ces dossiers dans l' archive 3D originale « \ Data » les sous - dossiers
« \ Meshes » et « \ Textures ». et de charger le média à l'intérieur de ces dossiers. Si cette syntaxe semble un peu
maladroite, au lieu de définir les noms de dossiers dans les commandes de chargement, vous pouvez tout aussi bien
ajouter d'autres archives 3D pour qu'OGRE puisse les consulter lors de la demande de média, comme ceci :

...
Add3DArchive("Data\", #PB_3DArchive_FileSystem)
Add3DArchive("Data\Meshes\", #PB_3DArchive_FileSystem)
Add3DArchive("Data\Textures\", #PB_3DArchive_FileSystem)
...

Nous pouvons maintenant utiliser des commandes de chargement plus simples comme celle-ci :

...
LoadMesh(#MESH, "Invader.mesh")
LoadTexture(#TEX, "Invader.png")
...

OGRE recherche ces fichiers dans les dossiers « \ Data », « \ Data \ Meshes » et « \ Data \ Textures ».

Vous pouvez également utiliser des fichiers ZIP comme archives 3D. Cela peut être très utile si vous désirez que votre
programme et tous les supports soit dans un fichier compressé. Si vous utilisez ce genre d'archive Lors de la création,
vous devez spécifier que l'archive3 D est un Fichier ZIP. Ceci peut être réalisé avec la constante intégrée «
#PB_3DArchive_Zip », que vous pouvez utiliser en tant que paramètre de type avec la commande « Add3DArchive() »
Si vous avez créé des sous-dossiers dans le fichier ZIP, vous pourrez y accéder via les commandes de chargement en
utilisant le format standard:

...
Add3DArchive("Data.zip", #PB_3DArchive_Zip)
LoadMesh(#MESH, "Meshes\Invader.mesh")
LoadTexture(#TEX, "Texturen\Invader.png")
...

Créer un Objet 3D ou ( Entité3D )


Lorsque vous avez créé une archive 3D, vous êtes prêt à créer un objet capable d'utiliser votre média. Cet objet va être
affiché à l'écran et peut être manipulé en trois dimensions à l'aide de différentes commandes intégrées. OGRE appelle
ces objets 3D, « Entités ».
166 Graphiques 3D

Une « Entité » est un objet qui est un élément constitutif de tout jeu ou démo, ce sont les modèles 3D affichés à l'écran
qui utilisent un maillage comme une structure et une texture comme une peau. Les entités peuvent être tout ce qui est
modélisé en 3D, il peut s'agir de cartes de jeu ou des personnages qui les peuplent.

Processus pour Créer une Entité

1. 2.

Charge Mesh Charge Texture

Chargement de 3.
la mesh
Chargement de
la texture

4.

Créer du matériel hors de la texture

5.
L'objet est rendu avec le 'RenderWorld ()'
Commande affichée automatiquement

Fig. 40

Savoir créer correctement ces « Entité » est essentiel pour tout objet 3D que vous recherchez. Sur l'organigramme de la
Fig. 40 vous montre comment créer correctement un objet 3D et dans laquelle vous commanderez les étapes
nécessaires qui doivent être suivies. J'ai ce diagramme comme guide. Exemple précédent Invader suivi à la lettre. Le
tout ressemble à du code comme suit

...
GestionErreur(LoadMesh(#MESH, "Invader.mesh"), "Impossible de charger la mesh")
GestionErreur(LoadTexture(#TEX, "Invader.png"), "Impossible de charger la texture")
GestionErreur(CreateMaterial(#MAT, TextureID(#TEX)), "Impossible de créer matérial")
CreateEntity(#OBJET_INVADER, MeshID(#MESH), MaterialID(#MAT))
...

Les commandes utilisées pour compléter ce processus sont simples. La première est la commande « LoadMesh()
» (Fichier d’aide: Manuel de référence ->Bibliothèques de jeux et multimédias 3D ->Maillage ->LoadMesh) qui prend
deux paramètres. Le premier est le numéro PB qui sera associé à ce maillage et le second est le fichier de maillage réel
à charger depuis l'archive 3D. La commande suivante est « LoadTexture() » (Fichier d'aide: Manuel de référence-
>Bibliothèques de jeux 3D->Texture->LoadTexture) qui prend également deux paramètres. Le premier est le numéro PB
associé à la texture nouvellement chargée et le second est le nom de l'image à utiliser comme texture. Lors de
l'utilisation d'images pour les textures, une chose à noter est la taille de l'image en pixels. Les cartes graphiques plus
anciennes ne peuvent prendre en charge que des textures carrées et dont la taille de l' image est d'une puissance de
« 2 ». Pour une compatibilité maximale avec les cartes plus anciennes, je vous suggère d'utiliser également ces tailles.
La Fig.41 montre les tailles d'image de texture standard que vous pouvez utiliser pour créer des matériaux en toute
sécurité.

La commande suivante ne charge rien, elle crée simplement un matériau. Ce matériau est une texture spéciale de
format OGRE qui peut avoir de nombreuses propriétés différentes. Parce que nous en créons une à partir d'une texture,
c'est la forme la plus simple de matériau. Je parlerai des matériaux plus avancés un peu plus tard.
Graphiques 3D 167

Tailles d'image de texture standard

Largeur en pixels Hauteur en pixels Profondeur de couleur en bits


32 32 8, 16 and 32
64 64 8, 16 and 32
128 128 8, 16 and 32
256 256 8, 16 and 32
512 512 8, 16 and 32
1024 1024 8, 16 and 32
Toutes les tailles de texture standard sont des puissances de « 2 »
Fig. 41

Pour créer un matériau, utilisez la commande « CreateMaterial() » (Fichier d’aide: Manuel de référence → Bibliothèques
de jeux 3D et multimédias → Matériel → Créer un matériau), qui nécessite deux paramètres. Le premier est le numéro
de PB associé à la matière et le second est l'identifiant OGRE d'une Texture. Cet identifiant peut être déterminé à l’aide
de la commande « TextureID() », qui est le numéro de PB d’une Texture en tant que paramètre nécessaire

Une fois que nous avons les « ingrédients » nécessaires, nous pouvons alors créer notre entité. Ceci se fait en utilisant
la commande « CreateEntity() » (Fichier d'aide: Manuel de référence → Bibliothèques de jeux et multimédias 3D →
Entité → CreateEntity), comme ce ci :

...
CreateEntity(#OBJET_INVADER, MeshID(#MESH),MaterialID(#MAT))
...

Comme vous pouvez le voir sur cette ligne, cette commande prend trois paramètres. Le premier est le numéro PB
auquel cette entité sera associée. Le deuxième est l'identifiant OS du maillage dont nous voulons faire cette Entité, et le
troisième est l'identifiant OGRE du matériau dont nous voulons couvrir le maillage.

Ces deux derniers identifiants OGRE peuvent être retournés en utilisant respectivement les commandes « MeshID() »
et « MaterialID() ». Ces deux commandes prennent un numéro PB comme paramètre et retournent un identifiant OGRE.

Une fois qu'une entité 3D a été créée, elle est mise en file d'attente, prête à être dessinée sur l'écran aux coordonnées «
0, 0, 0 » dans un espace tridimensionnel. D'ici là, nous poursuivrons notre analyse de l'exemple de l'Invader.

Éclairages des Scenes


Après la création de l'entité, j'ai créé une lumière pour mieux éclairer la scène. Cette lumière fournit une source
d'illumination brillante, qui peut être de n'importe quelle couleur, pour mieux faire ressortir cette entité. Lorsque vous
créez un environnement 3D, il contient déjà une quantité par défaut de lumière ambiante, mais cette lumière n'est pas
émise d'un point en particulier, mais comme son nom l'indique, elle est ambiante. Cela peut donner l'impression que
l'entité a l'air plate parce qu'elle ne peut pas calculer quels côtés doivent briller et quels côtés doivent avoir de l'ombre.
Lorsque vous ajoutez une lumière à une scène, vous permettez à l'entité de changer son éclairage facial pour simuler
l'ombre et la lumière en fonction de l'endroit où la lumière est située par rapport au maillage utilisé. Pour créer une
lumière, j'ai utilisé la commande « CreateLight() ». (Fichier d'aide: Manuel de référence-> Bibliothèques de jeux 3D->
Light-> CreateLight)

...
CreateLight(#LIGHT, RGB(255, 255, 255), 0, 5, 0)
...

Cette commande prend cinq paramètres, dont le premier est le numéro PB qui sera associé à cette lumière. La seconde
est la couleur de la lumière qui doit être émise et qui doit être entrée sous la forme d'une valeur de couleur 24 bits (la
commande « RGB() » peut être utilisée pour cela). Les troisième, quatrième et cinquième paramètres sont facultatifs et
spécifient la position de la lumière dans l'espace 3D en utilisant le système de coordonnées « x, y, z ». Si ces
paramètres ne sont pas utilisés, la lumière est créée à une position « 0, 0, 0 », qui est le centre de l'espace 3D. Dans
l'exemple de l'envahisseur, j'ai utilisé la position « 0, 5, 0 », qui élève la lumière du sol de « 5 » unités. Voir Fig.39 pour
une représentation graphique de l'espace 3D en utilisant le système de coordonnées « x, y, z ».
168 Graphiques 3D

La Caméra Tourne
Maintenant que les éléments 3D sont en place, nous devons créer une fenêtre d'observation à travers laquelle regarder
notre scène 3D. OGRE appelle ces hublots, Caméras, mais il faut vraiment faire la distinction entre les deux pour éviter
toute confusion. Une fenêtre est une fenêtre 2D qui existe sur l'écran actuellement ouvert et qui affiche ce que la caméra
3D regarde. Une fois qu'une fenêtre de caméra est créée, elle crée automatiquement une caméra 3D positionnée aux
coordonnées « 0, 0, 0 » et la fenêtre nouvellement créée affiche ce que la caméra 3D regarde. La caméra 3D peut être
positionnée et tournée à volonté mais la fenêtre est toujours verrouillée dans la même position à l'écran.

Pour créer une fenêtre de vue d'une caméra et créer automatiquement une caméra 3D dans le monde 3D actuel, vous
utilisez la commande« CreateCamera() ». (Fichier d'aide: Guide de référence → bibliothèques de jeux 3D-> Caméra->
CreateCamera) Cette commande prend cinq paramètres et comme d'habitude le premier est le numéro PB qui sera
associé à cet objet caméra. Les deuxième et troisième paramètres sont les positions « x » et « y » du coin supérieur
gauche de la fenêtre sur l'écran 2D. Les quatrième et cinquième paramètres sont la largeur et la hauteur de la fenêtre à
travers laquelle la scène 3D est visualisée. Lorsque vous utilisez cette commande, il est très important de comprendre
les valeurs qu'elle utilise car elles sont très différentes de la plupart des valeurs de PureBasic. des commandes. Les
valeurs des paramètres que la commande « CreateCamera() » utilise ne sont pas en pixels, mais en pourcentages de
l'écran actuellement ouvert. Dans l'exemple de l' invader, je crée une caméra comme celle-ci :

...
CreateCamera(#CAMERA_UN, 0, 0, 100,
100) ...

Pour bien comprendre cela, décomposons cet appel de commande sur une base de paramètres individuels. Le premier
paramètre est le numéro PB, qui est assez facile à comprendre pour que nous passions rapidement outre celui-là. Le
deuxième paramètre a été défini comme « 0 ». Cela signifie que cette valeur sera calculée comme étant égale à zéro
pour cent de la largeur de l'écran « 1024 » qui est « 0 ». Le troisième paramètre est également défini comme « 0 ». Il
s'agit également d'un pourcentage mais d'un pourcentage de la hauteur de l'écran « 768 », donc cela équivaut
également à « 0 ». Le quatrième paramètre a été défini comme « 100 ». Cela équivaut à cent pour cent de la largeur de
l'écran, qui est dans ce cas-ci de « 1024 ». Le cinquième paramètre est également défini comme « 100 », ce qui
correspond à 100% de la hauteur de l'écran, qui est « 768 ». Cela nous donne les coordonnées globales de l'écran de
cette vue de caméra comme étant « x = 0 », « y = 0 », largeur = 1024, hauteur = 768, ce qui couvre complètement
l'écran pour nous donner une vue plein écran de la caméra dans le monde 3D.

Des pourcentages sont utilisés pour cette commande à la place des pixels, de sorte que la position de la fenêtre de la
caméra est totalement indépendante de la taille de l'écran. Il s'agit d'un moyen facile de prendre en charge les positions
de la caméra dans différentes résolutions d'écran. Par exemple, si je crée la moitié de la largeur et de la hauteur de
l'écran d'une caméra, cette fenêtre sera toujours la moitié de la largeur et de la hauteur de l'écran, quelle que soit la
résolution utilisée.

Plusieurs Fenêtres d'Affichage des Caméras


L'utilisation de pourcentages est également un bon moyen de prendre en charge les vues de plusieurs caméras.
Imaginez si vous avez besoin de coder un jeu en écran partagé ou en quadravision, vous aurez besoin d'un bon moyen
de calculer la taille de la fenêtre d'affichage pour chaque résolution d'écran donnée (si elle est sélectionnable par
l'utilisateur). Tout cela est fait pour vous dans PureBasic en utilisant des pourcentages en s'assurant que chaque fenêtre
de caméra occupe toujours le même espace d'écran quelle que soit la résolution d'écran utilisée. De plus, lors de la
création de plusieurs caméras, l'ordre de création est très important. Toutes les vues créées plus tard dans votre code
apparaîtront toujours au-dessus des vues créées plus tôt. Par exemple, regardez ce code :

...
CreateCamera(#CAMERA_UN, 0, 0, 100, 100)
CreateCamera(#CAMERA_DEUX, 75, 0, 25, 25)
...

Ici, je crée une vue caméra qui prend le plein écran et une autre vue caméra au-dessus, dans le coin en haut à droite.
Cette plus petite fenêtre serait positionnée aux trois quarts de la largeur de l'écran et sa largeur et sa hauteur seraient
un quart de l'écran actuel. Si la plus petite fenêtre d'affichage a été créée en premier, elle sera masquée par la plus
grande fenêtre de la caméra.
Graphiques 3D 169

Chaque caméra multiple créée peut également être déplacée et pivotée indépendamment dans le monde 3D pour
donner aux utilisateurs plus de vues de votre monde à l'écran. Par exemple, vous pouvez utiliser une deuxième caméra
comme rétroviseur dans un jeu de conduite 3D à la premièrepersonne. Cette caméra peut être positionnée en haut de
l'écran 2D et avoir sa caméra 3D dirigée vers l'arrière de la voiture.

Déplacement et Rotation des Caméras


Une fois que vous avez créé une fenêtre, vous créez automatiquement une caméra 3D qui peut tourner et se déplacer à
volonté dans la scène 3D. Vous pouvez déplacer et positionner cette caméra 3D n'importe où et n'importe quand en
utilisant des commandes de position dans la boucle principale. Dans mon exemple d'Invader, j'ai utilisé deux
commandes pour affiner la position de la caméra, comme ceci :

...
CameraLocate(#CAMERA_UNE, 0, 1, 2.5)
RotateCamera(#CAMERA_UNE, -15, 0, 0)
...

La première commande, « CameraLocate() » déplace la caméra vers une position absolue dans la scène 3D et prend
quatre paramètres. Le premier paramètre est le numéro PB de la caméra que vous voulez déplacer, tandis que les
deuxième, troisième et quatrième paramètres sont les coordonnées « x, y, z » de l'endroit où vous souhaitez la
déplacer. La deuxième commande utilisée est « RotateCamera() », qui fait tourner la caméra autour d'un axe spécifié.
Cette commande prend également en charge quatre paramètres, le premier étant le numéro PB de la caméra que vous
souhaitez faire pivoter. Les deuxième, troisième et quatrième paramètres sont des angles de rotation relatifs le long de
chacun des axes « x, y, z ».

Rotation dans l'espace 3D


/DURWDWLRQOHORQJGX
<
/
D[H
VHGpURXOHODWpUDOHPHQW
&HSURFHVVXVV
DSSHOOH
<DZ

/DURWDWLRQOHORQJGX
;

$[LVHVWHQSODFHHWFLGHVVRXV
/DURWDWLRQOHORQJGHO
D[H
=
&HSURFHVVXVV
DSSHOOH
VHGpURXOHjJDXFKHHWjGURLWH
SLWFK

Ce processus s'appelle
'Roll'

 Fig. 42
Les flèches indiquent le sens de rotation positif

Si vous regardez la Fig.42, vous verrez quel axe se réfère à quel type de rotation. Par exemple, si je voulais que ma
caméra tourne d'un côté à l'autre, j'utiliserais la rotation sur l'axe « y ». Lorsque vous spécifiez des nombres pour les
coordonnées « x, y, z » dans n'importe quelle commande de rotation 3D, le nombre peut être aussi bien négatif que
positif, ce qui permet d'inverser la rotation. Si vous regardez les flèches de rotation de la Fig.42, elles indiquent la
direction dans laquelle la rotation se produira si des nombres positifs sont utilisés. Si des nombres négatifs sont utilisés,
cette rotation sera inversée. Par exemple, si je voulais tourner ma caméra de quarante-cinq degrés vers la gauche,
j'entrerais « 45 » pour le paramètre de rotation« y ». Si je voulais tourner ma caméra de quarante-cinq degrés vers la
droite, j'utiliserais « -45 » pour la rotation « y ».

Toutes les commandes de déplacement et de rotation peuvent être utilisées à l'intérieur ou à l'extérieur de la boucle
principale pour faire pivoter et déplacer des caméras ou d'autres entités. L'utilisation de ces commandes en dehors de
la boucle principale est bonne pour quand vous avez besoin de configurer la position des objets statiques. L'utilisation
de ces commandes à l'intérieur de votre boucle principale permet de déplacer et de faire tourner vos entités en temps
réel, en réagissant souvent aux entrées des utilisateurs.

Toutes les commandes de PureBasic qui utilisent des rotations 3D utiliseront le même système « x, y, z ». Si vous
regardez dans la boucle principale de l'exemple de l'Invader, j'ai utilisé la commande « RotateEntity() » ((Fichier d'aide:
Guide de référence → bibliothèques-> Jeux 3D Bibliothèques-> Entité-> RotateEntity) pour faire tourner l'entité invader
pendant son exécution. Encore une fois, cette commande utilise le même jeu d'axes de rotation que celui décrit à la
Fig.42. Lors de l'utilisation d'une commande qui utilise la rotation 3D, la Fig.42 peut fournir une référence pour la
rotation qui pourrait être nécessaire.
170 Graphiques 3D

Dans l'aide de PureBasic, vous en apprendrez davantage sur les commandes disponibles pour OGRE. Caméras
(Fichier d’aide: Manuel de référence → Bibliothèques de jeux 3D et multimédias → Caméra)

Rendu du Monde 3D à l' Ecran (Rendering)


Lorsque vous utilisez les commandes 3D pour créer un monde 3D, contrairement aux commandes 2D, vos maillages,
lumières et particules, etc. ne sont pas immédiatement attirés à l'écran. Au lieu de cela, ils existent dans la mémoire,
prêts à être capturés et dessinés. Une fois que tout est en place dans votre scène 3D, vous devez utiliser la commande
« RenderWorld() » (Fichier d'aide: Manuel de référence → Bibliothèques de jeux et multimédias 3D → Engine3D →
RenderWorld) pour indiquer à toutes les caméras 3D existantes de prendre une photo de ce qu'elles indiquent. Ces
instantanés sont ensuite dessinés sur la mémoire buffer arrière, mis à l'échelle et positionnés en fonction de la taille et
de la position de la fenêtre d'affichage de la caméra concernée. Ensuite, une fois que la commande « FlipBuffers() » est
appelée, le buffer arrière est deplacé vers l'avant et la scène 3D est dessinée sur l'écran de l'ordinateur. Vous pouvez le
voir en action dans l'exemple de l'invader. Si vous n'utilisez pas la commande « RenderWorld() », aucun graphique 3D
ne sera dessiné sur le buffer arrière. Espérons que c'est l'exemple de l'invader expliqué en détail maintenant, donc vous
devriez être capable de charger et d'afficher vos propres modèles en utilisant cet exemple comme référence.

Un appareil photo simple « premier plan »


Après avoir lancé l'exemple d'Invader, vous êtes probablement impatient d'écrire votre propre programme 3D ou même
d'essayer d'écrire un jeu. La première chose à laquelle j'ai pensé en voyant les capacités 3D de PureBasic est, je me
demande si je pourrais faire un jeu de tir au premièr plan? J'ai créé ce prochain morceau de code pour illustrer
comment coder une caméra au premièr plan dans un monde en 3D. Certes, ce n'est pas un jeu complet, loin de là,
mais il peut servir d'exemple d'apprentissage pour les débutants. Ce code vous montrera comment créer un terrain et
déplacer la caméra à l'aide des touches curseur et de la souris :

Enumeration
#TEXTURE_GLOBAL
#TEXTURE_DETAIL
#MATERIAL_TERRAIN
#CAMERA_ONE
EndEnumeration

#MOVEMENT_SPEED = 1
;Définir la largeur, la hauteur et la profondeur de bits de l'écran
;Les variables abrégées sont ici dues aux contraintes de largeur de page :(

Global ScrW.l = 1024


Global ScrH.l = 768
Global ScrD.l = 32

;Autres variables globales


Global Quit.b = #False
Global MouseXRotation.f,MouseYRotation.f,KeyX.f,KeyZ.f,DesiredCameraHeight.f
Global CurrentCamXPos.f = 545
Global CurrentCamZPos.f = 280

;Procédure de vérification d'erreur simple


Procedure HandleError(Result.l, Text.s)
If Result = 0
MessageRequester("Erreur", Text, #PB_MessageRequester_Ok)
End
EndIf
EndProcedure

;Initialize environment
HandleError(InitEngine3D(), "La commande InitEngine3D() a échoué.")
HandleError(InitSprite(), "La commande InitSprite () a échoué.")
HandleError(OpenScreen(ScrW, ScrH, ScrD, ""), "Impossible d'ouvrir l'écran.")
HandleError(InitMouse(), "La commande InitMouse() a échoué.")
HandleError(InitKeyboard(), "La commande InitKeyboard() a échoué.")
SetFrameRate(60)
Graphiques 3D 171

;Set 3D Archive
Add3DArchive("Data\", #PB_3DArchive_FileSystem)
;Create Terrain
HandleError(LoadTexture(#TEXTURE_GLOBAL, "Global.png"), "Impossible de charger texture")
HandleError(LoadTexture(#TEXTURE_DETAIL, "Detail.png"), "Impossible de charger texture")
CreateMaterial(#MATERIAL_TERRAIN, TextureID(#TEXTURE_GLOBAL))
AddMaterialLayer(#MATERIAL_TERRAIN,TextureID(#TEXTURE_DETAIL),#PB_Material_Add)
CreateTerrain("Terrain.png", MaterialID(#MATERIAL_TERRAIN), 1, 2, 1)
;Créer une fenêtre et une caméra
CreateCamera(#CAMERA_ONE, 0, 0, 100, 100)
DesiredCameraHeight.f = TerrainHeight(CurrentCamXPos, CurrentCamZPos) + 10
CameraLocate(#CAMERA_ONE,CurrentCamXPos,DesiredCameraHeight,CurrentCamZPos)
;Boucle Principale
Repeat
;mise à jour souris
If ExamineMouse()
MouseYRotation = -MouseDeltaX() / 10
MouseXRotation = MouseDeltaY() / 10
EndIf
RotateCamera(#CAMERA_ONE, MouseXRotation, MouseYRotation, 0)

;Mettre à jour les touches et positionner la caméra en conséquence


If ExamineKeyboard()
If KeyboardPushed(#PB_Key_Left) : KeyX = -#MOVEMENT_SPEED : EndIf
If KeyboardPushed(#PB_Key_Right) : KeyX = #MOVEMENT_SPEED : EndIf
If KeyboardPushed(#PB_Key_Up) : KeyZ = -#MOVEMENT_SPEED : EndIf
If KeyboardPushed(#PB_Key_Down) : KeyZ = #MOVEMENT_SPEED : EndIf
MoveCamera(#CAMERA_ONE, KeyX, 0, KeyZ)
KeyX = 0
KeyZ = 0
CurrentCamXPos.f = CameraX(#CAMERA_ONE)
CurrentCamZPos.f = CameraZ(#CAMERA_ONE)
DesiredCameraHeight.f = TerrainHeight(CurrentCamXPos, CurrentCamZPos) + 10
CameraLocate(#CAMERA_ONE,CurrentCamXPos,DesiredCameraHeight,CurrentCamZPos)
EndIf

RenderWorld()
FlipBuffers()
If KeyboardReleased(#PB_Key_Escape)
Quit = #True
EndIf
Until Quit = #True
End

Cet exemple est similaire à l'exemple de l'Invader en ce sens qu'il configure l'environnement 3D de la même manière,
vous devriez donc vous en rendre compte maintenant. La principale différence ici dans cet exemple est que j'ai créé un
terrain pour fournir un plancher sur lequel marcher.

Terrains Dimensions Niveaux et détails


Pour créer un terrain, vous devez d'abord créer un matériau multicouche qui servira de surface du terrain. Pour créer un
matériau multicouche, vous devez créer un matériau normal puis lui appliquer une autre couche de matériau. Si vous
regardez l'exemple FPS, vous verrez les lignes suivantes dans le code :

...
HandleError(LoadTexture(#TEXTURE_GLOBAL, "Global.png"), "Impossible de charger texture")
HandleError(LoadTexture(#TEXTURE_DETAIL, "Detail.png"), "Impossible de charger texture")
...

Ces deux commandes chargent dans deux images au format Png comme textures standard en utilisant la commande «
LoadTexture()» . La première image, « Global.png », sera le matériau principal qui sera appliqué sous la forme d'une
immense couverture qui couvre la surface du nouveau terrain. La deuxième image, « Detail.png », est une texture
secondaire qui est mélangée avec la première et est carrelée à travers le terrain pour fournir plus de détails à travers
elle. Pour créer le matériau multicouche, j'ai utilisé ces deux commandes :
172 Graphiques 3D

...
CreateMaterial(#MATERIAL_TERRAIN, TextureID(#TEXTUR_GLOBAL))
AddMaterialLayer(#MATERIAL_TERRAIN, TextureID(#TEXTUR_DETAIL), #PB_Material_Add)
...

La première ligne crée un matériau standard à une couche, comme expliqué dans l'exemple de l'invader. La deuxième
charge une autre texture à ajouter comme deuxième calque au matériau précédemment créé. La commande «
AddMaterialLayer() » (Fichier d'aide: Manuel de référence Jeux 3D) Bibliothèques multimédias Matériel
AddMaterialLayer) prend trois paramètres. Le premier est le numéro PB de l'article auquel vous souhaitez ajouter un
rang. Le second est l'identifiant OGRE de la texture que vous souhaitez ajouter comme autre calque. Le troisième
paramètre est le mode de mélange de la nouvelle texture avec le matériau existant. Ce mode de mélange peut être défini
comme l'une des quatre constantes intégrées :

« #PB_Material_Add »
Fusionne la nouvelle couche de matériau avec la couche existante au moyen d’une opération « ajouter »

« #PB_Material_Replace »
Fusionne la nouvelle couche de matériau avec la couche existante en utilisant une opération de remplacement..

« #PB_Material_AlphaBlend »
Fusionne la nouvelle couche de matériau avec la couche existante au moyen d’une opération « ajouter ». Ce mode
évalue en outre toutes les informations alpha trouvées dans la texture. Seules les textures au format d'image Png et Tga
sont prises en charge.

« #PB_Material_Modulate »
Fusionne la nouvelle couche de matériau avec la couche existante au moyen d’une opération de « modulation »

Lorsque vous avez créé votre matériau multicouche, vous êtes prêt à créer un Terain à l’aide de la commande «
CreateTerrain() ». Commande (Fichier d'aide: Manuel de référence → Bibliothèques de jeux 3D et multimédias →
Terrain → Créer un terrain) pour créer. Dans l'exemple « Caméra au premier plan », j'ai procédé comme suit

...
CreateTerrain("Terrain.png", MaterialID(#MATERIAL_TERRAIN), 1, 2, 1)
...

La commande « CreateTerrain() » prend six paramètres. Le premier paramètre est le nom d'une image qui servira de
carte de hauteur pour le terrain. Le second est un identificateur OGRE d'un matériau multicouche à utiliser comme
surface de terrain. Les troisième, quatrième et cinquième sont facultatives et peuvent être utilisées pour mettre à
l'échelle le terrain sur l'axe « x, y » ou « z ». Ces valeurs sont des valeurs de multiplication, ce qui signifie que si une
valeur de « 1 » est utilisée, le terrain restera de la même taille sur cet axe. Si une valeur de « 2 » est utilisée, cet axe
sera doublé, etc. Le sixième et dernier paramètre est une valeur optionnelle de qualité du terrain qui varie de « 1 » à
« 20 » . Plus la valeur est faible, la valeur passée, plus le terrain est élevé, plus la qualité de rendu du terrain est bonne
et plus l'utilisation du CPU pour le dessiner est élevée. Des valeurs plus élevées ont l'effet contraire.

Détails de la carte d'élévation du terrain


Lorsque vous utilisez une image de carte de hauteur pour créer un terrain, il y a quelques règles que vous devez suivre
lorsque vous créez l'image de carte de hauteur. Tout d'abord, cette image doit être carrée, car OGRE dans PureBasic
ne peut créer que des terrains carrés (bien que vous puissiez les mettre à l'échelle pendant la création). Deuxièmement,
l'image doit être sauvegardée dans un format de niveaux de gris de 8 bits pour fournir des niveaux de gris de « 256 ».
Le noir pur sera traité comme une hauteur de « 0 », tandis que le blanc complet sera traité comme une hauteur de
« 255 ». Troisièmement,cette image doit avoir une certaine taille car elle définit également le nombre de triangles
(polygones) utilisés dans le maillage du terrain. La taille d'une image de carte de hauteur doit être celle d'une texture
normale mais plus un pixel sur chaque dimension. Il s'agit de s'assurer que le a hauteur du terrain est calculée
correctement à partir de l'image. La Fig.43 montre les dimensions recommandées des images de cartes de hauteur et le
nombre de triangles (polygones) qui seront utilisés pour générer le maillage du terrain.

En regardant la Fig.43, vous pouvez voir comment le nombre de triangles augmente lorsque l'on utilise une image plus
haute résolution de la carte de hauteur. Une carte de hauteur à plus haute résolution peut améliorer la précision du
rendu du terrain par rapport à la carte de hauteur, mais au prix d'un ralentissement des performances. Les cartes à
grande résolution, telles que la résolution « 1025 x 1025 », ne sont normalement pas utilisées en raison du nombre
élevé de polygones du terrain nouvellement créé.
Graphiques 3D 173

Taille des Images et d'élévation des Cartes

Largeur en pixels Hauteur en pixels Polygones de terrain


65 65 8192
129 129 32768
257 257 131072
513 513 524288
1025 1025 2097152

Toutes les tailles de texture standard sont des puissances de « 2 » + « 1 » Fig. 43

Terrains et le niveau de détail automatique


Tous les terrains créés dans PureBasic avec OGRE ont des niveaux de détail automatiques et dynamiques. Cela
signifie que lorsqu'un terrain n'est pas montré par une caméra ou que certaines caractéristiques du terrain en cachent
d'autres (comme des collines), les parties cachées du terrain ne sont pas dessinées. De plus, lorsque la caméra a
parcouru une certaine distance par rapport à une caractéristique du terrain, cette caractéristique réduit automatiquement
sa complexité, diminuant le nombre de polygones à l'écran pour faciliter le dessin d'une scène plus grande. L'exemple
du FPS le démontre facilement en se concentrant sur une colline particulière, en s'en éloignant vers l'arrière et en
surveillant sa structure. Vous verrez que la colline est moins complexe lorsqu'elle est éloignée de la caméra.

Perspective au Premier Plan


Une fois que le terrain a été créé et que l'exemple de «caméra au premièr plan» est en cours d'exécution, j'utilise
d'autres Commandes pour collecter des informations à partir de la souris et du clavier. J'utilise cette information pour
positionner la caméra en continu. Les commandes de la souris sont

« MouseDeltaX() »
(Fichier d'aide: Manuel de référence → Bibliothèques de jeux et multimédia 2D → Souris → MouseDeltaX) Cette
commande retourne le nombre de pixels que la souris a déplacés sur l'axe de l'écran « X » (de gauche à droite) depuis
la dernière itération de la boucle principale.

« MouseDeltaY() »
(Fichier d'aide: Manuel de référence → Bibliothèques de jeux et multimédias 2D → Souris → MouseDeltaY) Cette
commande retourne le nombre de pixels que la souris a déplacés sur l'axe de l'écran « Y » (haut et bas) depuis la
dernière itération de la boucle principale.

Ces deux valeurs retournées seront alors dans les paramètres « x » et « y » de la commande « RotateCamera() » placé
pour faire pivoter la caméra 3D en fonction du mouvement de la souris. Voici le code actuel:

...
If ExamineMouse()
MouseYRotation - MouseDeltaX() / 10
MouseXRotation + MouseDeltaY() / 10
EndIf
RotateCamera(#CAMERA_UNE, MouseXRotation, MouseYRotation,
0) ...

Ceci crée notre caméra contrôlée par la souris. Notez le signe moins devant la commande « MouseDeltaX() ». est là
pour inverser la valeur retournée par cette commande, car si vous vous souvenez d'une commande précédente, vous
avez besoin de valeurs positives pour tourner à gauche et de valeurs négatives pour tourner à droite. La commande«
MouseDeltaX() » renvoie ces valeurs inversées car elle renvoie des coordonnées d'écran 2D au lieu des angles de
rotation.

Pour faire un panoramique de la caméra dans le monde 3D et ainsi créer l’effet qui donne l'impression que l'on se
déplace sur le terrain, j'ai utilisé le code suivant:

...
If ExamineKeyboard()
If KeyboardPushed (#PB_Key_Left) : KeyX = - #MOVEMENT_SPEED : EndIf
If KeyboardPushed (#PB_Key_Right): KeyX = #MOVEMENT_SPEED : EndIf
If KeyboardPushed (#PB_Key_Up) : KeyZ = - #MOVEMENT_SPEED : EndIf
174 Graphiques 3D

If KeyboardPushed(#PB_Key_Down) : KeyZ = #MOVEMENT_SPEED : EndIf


MoveCamera(#CAMERA_UNE, KeyX, 0, KeyZ)
KeyX = = 0
KeyZ = = 0
CurrentCamXPos.f = CameraX(#CAMERA_ONE)
CurrentCamXPos.f = CameraZ(#CAMERA_ONE)
DesiredCameraHeight.f = TerrainHeight(CurrentCamXPos, CurrentCamZPos) + 10
CameraLocate(#CAMERA_ONE,CurrentCamXPos,DesiredCameraHeight,CurrentCamZPos)
EndIf...

Ici, j'utilise la commande « KeyboardPushed() » pour tester si une touche est maintenue enfoncée ou non. Si c'est moi
qui assigne une valeur aux variables pertinentes, alors utilisez-les comme paramètres dans la commande «
MoveCamera() ». Ceci déplacera la caméra dans tout le monde 3D mais ne tient pas compte de la hauteur du terrain.

Pour déplacer la caméra vers le haut et vers le bas afin qu'elle soit toujours à une distance définie du terrain, j'utilise la
commande « CameraLocate() ». Comme cette commande utilise des valeurs absolues, j'ai besoin de récupérer les
coordonnées « x » et « z » actuelles de la caméra pour pouvoir les régler à nouveau lorsque je modifie la valeur « y ».
Pour obtenir les coordonnées actuelles de la caméra, j'utilise les commandes « CameraX() » et « CameraZ() » (Aide
Fichier: Manuel de référence → Bibliothèques de jeux 3D et multimédias → Camera). Ces deux commandes n'ont qu'un
seul paramètre qui est le numéro PB d'une caméra pour obtenir les valeurs. Une fois que j'ai ces valeurs, j'ai besoin de
savoir quelle est la hauteur du terrain à ces coordonnées. Pour le récupérer, j'utilise la commande « TerrainHeight()
» (Fichier d'aide: Manuel de référence→ Bibliothèques de jeux 3D → Terrain → TerrainHeight. Cette commande
nécessite deux paramètres. Ce sont les coordonnées « x » et « z » du point du terrain dont nous voulons connaître la
hauteur. Une fois que j'ai cette valeur, j'ajoute « 10 » pour soulever légèrement la caméra du sol et maintenant j'ai mes
trois coordonnées 3D nécessaires pour la commande « LocateCamera() ». Lors de chaque itération de boucle
principale, une nouvelle coordonnée « y » est calculée pour ajuster la hauteur de la caméra lors des déplacements sur le
terrain.

Un peu plus Avancé


Dans cette prochaine section, je parlerai des fonctionnalités légèrement plus avancées d'OGRE et de PureBasic. Ces
caractéristiques comprennent des particules et un matériel scripts. Les particules sont utilisées dans les moteurs 3D
pour une variété de choses différentes, principalement pour produire des effets visuels aléatoires tels que la neige, la
pluie, le feu et la fumée. Je les ai utilisés dans l'exemple suivant pour simuler un incendie. Les scripts matériels sont un
moyen d'encapsuler toutes les propriétés matérielles dans un seul fichier de script matériel, pour rendre votre code
source PureBasic beaucoup plus propre et plus facile à lire. Les scripts matériels vous permettent de charger un
maillage contenant une référence à un matériel et si ce matériel apparaît dans un fichier script, alors le maillage utilise
ce matériel en annulant la nécessité de faire quoi que ce soit de plus dans votre code source. Ceci permet une facilité
d'utilisation et une personnalisation accrue, car certaines propriétés avancées des matériaux ne sont disponibles qu'à
l'aide de scripts. Dans l'exemple suivant, j'ai utilisé un script matériel pour spécifier que le maillage chargé utilise le
mappage de texture de sphère, ce qui n'est pas disponible autrement. Voici le code :

Enumeration
#MESH
#TEXTURE
#MATERIAL
#ENTITY
#CAMERA_ONE
#LIGHT_ONE
#LIGHT_TWO
#PARTICLE_ONE
EndEnumeration

;Définir la largeur, la hauteur et la profondeur de bits de l'écran


;Les variables abrégées sont ici dues aux contraintes de largeur de page :(

Global ScrW.l = 1024


Global ScrH.l = 768
Global ScrD.l = 32
;Autres variables globales
Global Quit.b = #False
Graphiques 3D 175

;Procédure de vérification d'erreur simple


Procedure HandleError(Result.l, Text.s)
If Result = 0
MessageRequester("Erreur", Text, #PB_MessageRequester_Ok)
End
EndIf
EndProcedure

;Convertir les Degrees en Radians


Procedure.f DegToRad(Angle.f)
ProcedureReturn Angle.f * #PI / 180
EndProcedure

;Initialise environment
HandleError(InitEngine3D(), "La commande InitEngine3D() a échoué.")
HandleError(InitSprite(), "La commande InitSprite() a échoué.")
HandleError(OpenScreen(ScrW, ScrH, ScrD, ""), "Impossible d'ouvrir l'écran.")
HandleError(InitKeyboard(), "La commande InitKeyboard() a échoué.")
SetFrameRate(60)

Add3DArchive("Data\", #PB_3DArchive_FileSystem)
Parse3DScripts()
CreateEntity(#ENTITY, LoadMesh(#MESH, "Statue.mesh"), #PB_Material_None)
LoadTexture(#TEXTURE, "Flame.png")
CreateMaterial(#MATERIAL, TextureID(#TEXTURE))
DisableMaterialLighting(#MATERIAL, 1)
MaterialBlendingMode(#MATERIAL, #PB_Material_Add)
CreateParticleEmitter(#PARTICLE_ONE, 2, 2, 0,#PB_Particle_Point,12.9, 69, 15.7)

ParticleSize(#PARTICLE_ONE, 5, 5)
ParticleMaterial(#PARTICLE_ONE, MaterialID(#MATERIAL))
ParticleEmissionRate(#PARTICLE_ONE, 50)
ParticleTimeToLive(#PARTICLE_ONE, 0.25, 0.25)
ParticleColorRange(#PARTICLE_ONE, RGB(255, 0, 0), RGB(255, 200, 0))
ParticleVelocity(#PARTICLE_ONE, 1, 10)

CreateLight(#LIGHT_ONE, RGB(255,255,255))
CreateLight(#LIGHT_TWO, RGB(255, 200, 0), 12.9, 72, 15.7)
CreateCamera(#CAMERA_ONE, 0, 0, 100, 100)

;Boucle Principale
Repeat
Angle.f + 0.5
PosX.f = 75 * Sin(DegToRad(Angle))
PosY.f = (50 * Sin(DegToRad(Angle / 2))) + 65
PosZ.f = 75 * Cos(DegToRad(Angle))
LightLocate(#LIGHT_ONE, PosX, PosY + 100, PosZ)
LightColor(#LIGHT_TWO, RGB(255, Random(200), 0))
CameraLocate(#CAMERA_ONE, PosX, PosY, PosZ)
CameraLookAt(#CAMERA_ONE, 0, 60, 0)
RenderWorld()
FlipBuffers()
ExamineKeyboard()
If KeyboardReleased(#PB_Key_Escape)
Quit = #True
EndIf
Until Quit = #True
End

Cet exemple doit être simple car il suit le style des derniers exemples 3D. Tout d'abord, nous initialisons
l'environnement, ouvrons un écran et spécifions une archive 3D. Une fois cela fait, j' utilise une nouvelle commande
« Parse3DScripts() ». Cette commande, lorsqu'elle est appelée, regardera à l'intérieur de toutes les archives 3D
spécifiées et lira tous les fichiers script qu'elle trouve en elles. Il existe de nombreux types de fichiers de script OGRE,
mais pour le moment, PureBasic ne supporte que les scripts matériels.

Scripts Matériels
Une fois la commande « Parse3DScripts() » appelée, tous les scripts matériels sont lus et analysés à partir de toutes
les archives 3D spécifiées. Cela signifie que chaque script est lu pour voir quelles définitions de matériaux il contient et
ensuite les propriétés de chaque matériau sont lues en mémoire.
176 Graphiques 3D

Si un maillage qui utilise un matériau portant le même nom que celui spécifié dans un script matériel est chargé
ultérieurement, il utilisera les textures et les propriétés définies dans le script. Les noms des matériaux utilisés peuvent
être sauvegardés avec le maillage lors de la sauvegarde à partir d'un programme de modélisation 3D. Cela vous permet
de spécifier le matériau lorsque vous créez votre maillage et de le charger facilement dans un programme PureBasic
3D, en conservant toutes les propriétés du matériau.

Les scripts matériels peuvent être écrits à la main à l'aide d'un simple éditeur de texte ou ils peuvent être exportés
depuis certains programmes de modélisation 3D avec le maillage. La syntaxe des scripts matériels est décrite sur le site
Web de l'OGRE qui se trouve à l'annexe A (Liens Internet utiles). Voici le script matériel que j'ai utilisé pour le modèle de
statue dans l'exemple Statue, ce fichier script s'appelle « statue.material »:

material Statue
{
technique
{
pass
{
texture_unit
{
texture SphereMap.png
env_map spherical
filtering trilinear
}
}
}
}

Ce simple fichier décrit le matériau « Statue », plus précisément, il indique à OGRE d'utiliser l'image « SphereMap.png »
comme texture, d'utiliser un mappage de texture sphérique et d'utiliser un filtrage trilinéaire. Pour permettre au maillage
Statue d'utiliser ce matériau, j'ai spécifié son nom dans mon programme de modélisation 3D.

Si vous regardez l'exemple Statue, vous pouvez voir que je crée une entité, entièrement texturée en utilisant une ligne
de code par opposition à l'exemple Invader où j'ai dû utiliser plusieurs lignes pour charger des textures et créer des
matériaux etc. Cette ligne l'est :

...
CreateEntity(#ENTITY, LoadMesh(#MESH, "Statue.mesh"), #PB_Material_None)
...

Ceci charge le fichier « Statue.mesh » et utilise le matériel défini dans le script matériel. Comme nous utilisons un script
matériel pour définir le matériel, lorsque nous utilisons la commande « CreateEntity() », le paramètre Material ID doit
être « #PB_Material_None » . Cette constante intégrée garantit que cette entité n'est pas affectée à un matériau autre
que celui défini dans le script.

Effets de Particules
La création de particules peut être une histoire compliquée, surtout parce que vous en avez tellement peu créer des
effets avec eux. Actuellement, PureBasic prend en charge dix-neuf commandes pour la personnalisation. Créez des
particules de presque toutes les façons imaginables.

Des scripts de particules?


Tout comme les scripts matériels, les scripts de particules sont un moyen d'encapsuler des propriétés complexes
sous un nom simple. Ensuite, lorsque vous créez un émetteur de particules, vous pouvez spécifier le nom de la
propriété de particule et toutes les propriétés définies sous ce nom sont appliquées à l'émetteur. Cela permet de
tester et de créer des effets de particules plus rapidement et plus facilement.

Pour le moment, PureBasic ne supporte pas les scripts de particules mais le moteur OGRE le supporte.
Lorsqu'on lui a demandé, l'équipe de PureBasic a dit que le support des scripts de particules sera ajouté à
PureBasic dans un proche avenir. Donc peut-être que lorsque vous lisez ceci, PureBasic a déjà ce support. Pour
de plus amples renseignements, veuillez consulter le site Web de l'OGRE et les forums en ligne PureBasic les
deux adresses se trouvent à l'annexe A (Liens Internet utiles)
Graphiques 3D 177

Les particules, comme les mailles ont besoin d'un matériau qui leur est assigné pour s'afficher correctement et j'en ai
créé un dans l'exemple Statue en utilisant l'image « Flame.png » comme une texture. Cette image sera utilisée pour
chaque particule qui quitte l'émetteur. Un émetteur de particules est une coordonnée dans l'espace 3D qui sera le point
à partir duquel toutes les particules sont émises. J'ai défini ceci dans mon exemple comme ceci :

...
CreateParticleEmitter(#PARTICLE_ONE, 2, 2, 0,#PB_Particle_Point,12.9, 69, 15.7)
...

La commande « CreateParticleEmitter() » (Fichier d’aide: Manuel de référence → Bibliothèques de jeux 3D →Particle →


CreateParticleEmitter) prend huit paramètres. Le premier, comme d'habitude, est le numéro PB qui sera associé à cet
émetteur de particules. Les deuxième, troisième et quatrième paramètres sont la distance à laquelle les particules sont
émises le long des axes « x » , « y » e t « z ». du point central. Le cinquième est le mode particules. Il peut s' agir de
« #PB_Particle_Point » ou « #PB_Particle_Box ». Les points émetteurs sont généralement utilisés pour le feu et la
fumée, etc. lorsque les particules émanent d'un point particulier, tandis que les boîtes émettrices sont généralement
utilisées pour les effets de zone tels que la pluie ou la neige. Les trois derniers paramètres sont des coordonnées dans
le monde 3D qui définissent où cet émetteur sera placé. Ces trois derniers sont également optionnels et si l'émetteur
n'est pas utilisé, il sera placé à « 0, 0, 0 ». Vous pouvez ensuite déplacer l'émetteur en utilisant la commande
« ParticleEmitterLocate() ».

Les autres commandes de particules utilisées dans l'exemple Statue concernent toutes la configuration de l'émetteur de
particules pour produire l'effet souhaité. Ces autres commandes sont :

...
ParticleSize(#PARTICLE_ONE, 5, 5)
ParticleMaterial(#PARTICLE_ONE, MaterialID(#MATERIAL))
ParticleEmissionRate(#PARTICLE_ONE, 50)
ParticleTimeToLive(#PARTICLE_ONE, 0.25, 0.25)
ParticleColorRange(#PARTICLE_ONE, RGB(255, 0, 0), RGB(255, 200, 0))
ParticleVelocity(#PARTICLE_ONE, 1, 10)
...

Toutes ces commandes s'expliquent d'elles-mêmes et sont capables de produire des milliers d'effets différents. Elles
peuvent toutes être lues plus en détail dans le fichier d'aide PureBasic (fichier d’aide: Manuel de référence →
Bibliothèques de jeux 3D et multimédias → Particules).

Regard sur un point particulier


Dans l'exemple Statue, j'ai utilisé une autre nouvelle commande de caméra qui peut être très utile. Ceci est la
commande« CameraLookAt() » (Fichier d'aide: Manuel de référence->Bibliothèques de jeux et multimédias 3D->Camera
->CameraLookAt). En utilisant cette commande, il est possible d'incliner la caméra pour regarder n'importe quel point
dans l'espace 3D avec une seule commande. Dans mon exemple, je l'ai utilisé comme ceci :

...
CameraLookAt(#CAMERA_ONE, 0, 60, 0)
...

Le premier paramètre est le numéro PB de la caméra que vous voulez faire pivoter. Les deuxième, troisième et
quatrième coordonnées sont les coordonnées « x, y, z » que vous voulez que cette caméra regarde. Dans mon
exemple, la caméra regarde directement le centre de la statue pendant que la caméra tourne autour d'elle.

Éclairage Dynamique
Dans l'exemple de Statue, j'ai également utilisé quelques trucs d'éclairage pour améliorer la scène. La première est
d'avoir une lumière blanche qui suit toujours la caméra. Ceci permet de s'assurer que la maille de la statue est toujours
entièrement éclairée. Le deuxième truc d'éclairage que j'ai utilisé est d'avoir une lumière clignotante placée juste au-
dessus de l'émetteur de particules et de lui faire changer de couleur à chaque itération de la boucle principale. Je le fais
en plaçant cette commande dans la boucle principale :

...
LightColor(#LIGHT_TWO, RGB(255, Random(200), 0))
...

Cette commande change la couleur de la lumière spécifiée chaque fois qu'elle est utilisée. Dans la boucle principale de
l'exemple Statue, je randomise la composante verte de la couleur de cette lumière entre les valeurs de « 0 » et « 200 ».
Étant donné que la composante rouge est déjà réglée sur « 255 » et la composante bleue sur « 0 », cela signifie que
cette lumière passera du rouge au jaune. Une fois que ce programme est en cours d'exécution, vous pouvez régler le
scintillement de la couleur sur le visage de la statue.
178 *UDSKLTXHV'

L'utilisation de quelques astuces comme les scripts de matériaux pour construire des matériaux plus complexes et
l'utilisation de particules pour créer des effets cool aideront à élever votre jeu ou votre démo au-dessus du reste en
termes de qualité et de style. Je ne vous ai donné qu'une brève démonstration de ce qui est possible avec ces
commandes, le reste dépend de vous. Pour en savoir plus sur ces commandes, essayez de coder vos propres
programmes 3D et expérimentez avec quelques paramètres, en particulier avec les commandes de particules.

Et Ensuite?
J'espère que ce chapitre a été utile, quoique bref, sur la programmation de graphiques 3D à l'aide de PureBasic.
J'espère que vous avez été inspiré d'en savoir plus sur ce que PureBasic peut réaliser en utilisant le moteur OGRE. Je
vous recommande de lire toute la section'3D Games Libraries' du fichier d'aide de PureBasic pour bien comprendre ce
que PureBasic a à offrir. Ce chapitre n'a pas couvert toutes les commandes qui y sont contenues en raison de
contraintes d'espace et de temps, mais j'espère vous avoir donné une bonne introduction sur la façon de commencer, le
reste dépend maintenant de vous.

Apprendre à programmer des graphismes 3D peut s'avérer très délicat, car il faut parfois faire appel à des routines
mathématiques complexes et à des compétences en modélisation 3D. Les mathématiques utilisées dans les exemples
de ce chapitre sont assez élémentaires et je pense que tous les étudiants le sauront probablement. Cela dit, le seul
conseil que je donnerais à tous les débutants en programmation 3D est d'apprendre les mathématiques. Il y aura des
moments où la programmation de graphiques 3D que vous serez arrêté mort dans vos pistes parce que votre capacité
de mathématiques a pris du retard sur votre capacité de programmation, il est donc préférable d'être prêt.

Jetez un coup d'œil à Internet, où il y a aussi des centaines d'instructions pour les mathématiques dans le domaine de la
3D vous êtes capable de travailler de manière indépendante. En outre, il existe d'innombrables livres à lire reprenez
tous ces points en détail de cette aide
Son 179

12. Son
Il se peut que vous ayez besoin de jouer un son à certains moments de votre programme. Il peut s'agir d'une cloche
acoustique qui signale qu'un processus est terminé, ou d'un effet sonore dans un jeu. Peu importe les sons dont vous
avez besoin, vous devez savoir comment charger et lire certains fichiers sonores. Ce chapitre décrit comment charger
différents fichiers son et donne des exemples de lecture dans un programme.

Fichiers Wave
Les fichiers Wave sont l'un des formats sonores les plus répandus sur les ordinateurs personnels, en raison de leur
création par un effort conjoint entre Microsoft et IBM. Les fichiers Wave, qui ont généralement l'extension « *.wav » sont
le format sonore natif utilisé par tous les PC. Bien que ce format n'ait pas de compression native pour les données
sonores, il est toujours utilisé au quotidien.

L'exemple suivant charge un Fichier au format Wave nommé « Intro.wav » et le lit :

#SOUND_FILE = 1
If InitSound()
LoadSound(#SOUND_FILE, "Intro.wav")
PlaySound(#SOUND_FILE)
StartTime.l = ElapsedMilliseconds()
Repeat
Delay(1)
Until ElapsedMilliseconds() > StartTime + 8000
End
EndIf

Cet exemple ne serait pas utilisé dans un programme réel, mais il montre les étapes nécessaires pour lire un fichier
wave. Il faut d'abord initialiser l'environnement sonore avec la fonction « initSound() ». Ceci initialisera le matériel et le
logiciel nécessaires pour lire le fichier correctement. Si cette commande retourne Vrai, nous savons que tout a été
initialisé correctement et nous pouvons continuer. Si l'initialisation échoue, il n'y a aucun moyen de continuer avec le son,
il n'y a probablement pas de carte son installée sur l'ordinateur.

Si l'initialisation a réussi, nous chargeons le fichier son avec la fonction « LoadSound() » (fichier d'aide : Manuel de
référence → → 2D Games & Multimedia Libraries → Sound → Sound → LoadSound). Cette commande charge le fichier
son en mémoire, prêt à être lu. La fonction « LoadSound() » nécessite deux paramètres, le premier est le numéro
PB auquel vous voulez associer le fichier son et le second est une chaîne contenant le nom du fichier que vous
voulez charger

Une fois le fichier Wave chargé, vous pouvez le lire dans votre programme en utilisant la fonction « PlaySound() »
(fichier d'aide : Manuel de référence → → 2D Games & Multimedia Libraries → Sound → Sound → PlaySound). Cette
commande nécessite un paramètre. C'est le numéro PB du fichier son que vous voulez lire.

Si vous regardez de plus près l'exemple du fichier wave, vous verrez que j'ai inséré une boucle bien pensée à la fin du
programme. Cela permet d'éviter la fin prématurée du programme. Lorsque le programme se termine, tous les sons en
cours de lecture sont arrêtés et retirés de la mémoire. Comme je veux éviter cela, j'ai construit cette boucle, qui donne
au programme huit secondes pour lire le fichier son et ensuite quitter le programme. Vous ne trouverez pas cette
construction dans un programme réel, parce qu'une telle boucle a une boucle principale qui maintient le programme en
activité pendant que le fichier son est joué.

Intégration de Fichiers Wave


Parfois, vous ne voulez pas charger un fichier Wave externe, mais vous voulez intégrer ce fichier dans votre
programme afin de pouvoir transmettre tous les composants de votre programme dans un seul fichier. Vous
pouvez le faire en incorporant le fichier Wave dans une « DataSection », similaire à l'incorporation d'une image que j'ai
expliqué au chapitre 9 (Incorporer des graphiques dans votre programme). Mais il y a une différence, au lieu de «
CatchImage() » vous utiliserez « CatchSound() » pour charger le fichier depuis la zone « DataSection » . En voici un
exemple :
180 Son

#SOUND_FILE = 1
If InitSound()
CatchSound(#SOUND_FILE, ?SoundFile)
PlaySound(#SOUND_FILE)
StartTime.l = ElapsedMilliseconds()
Repeat
Delay(1)
Until ElapsedMilliseconds() > StartTime + 8000
End
EndIf
DataSection
SoundFile:
IncludeBinary "Intro.wav"
EndDataSection

Le fichier son est inclus dans la « DataSection » avec la commande « IncludeBinary » exactement de la même manière
que le fichier image. Le marqueur « SoundFile » marque le début du fichier en mémoire. Pour charger le fichier au
moment de l'exécution à partir de la « DataSection » , nous utilisons la fonction « CatchSound() » (fichier d'aide :
Manuel de référence → → 2D Games & Multimedia Libraries → Sound → Sound → CatchSound). Cette commande
nécessite deux paramètres. Le premier est le numéro PB attribué au son, le second est l'adresse en mémoire à partir de
laquelle le son doit être chargé. Cette adresse est l'adresse du marqueur de saut car elle marque le début du fichier son
en mémoire. Pour trouver l'adresse d'une étiquette, nous utilisons un point d'interrogation avant le nom de l'étiquette,
par exemple « SoundFile » . Notez que nous n'avons pas besoin des deux points après le nom de l'étiquette. Après
avoir « capturé » un fichier wave de cette façon, vous pouvez l'utiliser comme n'importe quel autre fichier wave. Dans ce
cas, j'ai joué le fichier wave avec la fonction « PlaySound() ».

Vous pouvez inclure plusieurs fichiers Wave dans votre programme de cette façon, il vous suffit de vous assurer que
vous attribuez un marqueur unique à chaque fichier pour qu'il puisse être trouvé avec la fonction « CatchSound() ».

Manipuler les Sons en Temps Réel


L'utilisation des commandes de la bibliothèque PureBasic Sound vous permet de modifier le volume, la balance et la
fréquence. Le volume augmente ou diminue le volume du son, Balance déplace le son d'une enceinte à l'autre,
généralement vers la gauche ou la droite, et le changement de fréquence entraîne une accélération ou un
ralentissement de la vitesse de lecture. Pour démontrer ces effets, j'ai créé un petit programme de lecteur de son qui
vous permet de changer le volume, l'équilibre et la fréquence en temps réel. Essayez-le vous-même. Ouvrez le
programme, chargez un fichier wave, appuyez sur le bouton « Play_File » et changez les curseurs.

Enumeration
#WINDOW_ROOT
#SOUND_FILE
#TEXT_FILE
#BUTTON_CHOOSE_FILE
#TEXT_VOLUME
#TRACKBAR_VOLUME
#TEXT_PAN
#TRACKBAR_PAN
#TEXT_FREQUENCY
#TRACKBAR_FREQUENCY
#BUTTON_PLAY_FILE
#BUTTON_STOP_FILE
EndEnumeration

Global FileName.s = ""


#FLAGS = #PB_Window_SystemMenu | #PB_Window_ScreenCentered

If OpenWindow(#WINDOW_ROOT, 0, 0, 500, 250,"Lecteur Son", #FLAGS)


TextGadget(#TEXT_FILE, 10, 10, 480, 20, "", #PB_Text_Border)
ButtonGadget(#BUTTON_CHOOSE_FILE, 10, 40, 150, 20, "Choisir un Fichier Wave...")
TextGadget(#TEXT_VOLUME, 10, 70, 480, 20, "Volume")
TrackBarGadget(#TRACKBAR_VOLUME, 10, 90, 480, 20, 0, 100)
SetGadgetState(#TRACKBAR_VOLUME, 100)
TextGadget(#TEXT_PAN, 10, 120, 480, 20, "Canal ")
TrackBarGadget(#TRACKBAR_PAN, 10, 140, 480, 20, 0, 200)
SetGadgetState(#TRACKBAR_PAN, 100)
TextGadget(#TEXT_FREQUENCY, 10, 170, 480, 20, "Frequence")
TrackBarGadget(#TRACKBAR_FREQUENCY, 10, 190, 480, 20, 100, 10000)
SetGadgetState(#TRACKBAR_FREQUENCY, 4400)
ButtonGadget(#BUTTON_PLAY_FILE, 10, 220, 100, 20, "Jouer le Fichier")
ButtonGadget(#BUTTON_STOP_FILE, 130, 220, 100, 20, "Arret du Son")
Son 181

If InitSound()
Repeat
Event.l = WaitWindowEvent()
Select Event
Case #PB_Event_Gadget
Select EventGadget()
Case #BUTTON_CHOOSE_FILE
FileName=OpenFileRequester("Choisir","","Fichier Wave (*.wav)|
*.wav",0)
If filename <> ""
SetGadgetText(#TEXT_FILE, GetFilePart(FileName))
LoadSound(#SOUND_FILE, filename)
EndIf
Case #TRACKBAR_VOLUME
If filename <> ""
SoundVolume(#SOUND_FILE, GetGadgetState(#TRACKBAR_VOLUME))
EndIf
Case #TRACKBAR_PAN
If filename <> ""
SoundPan(#SOUND_FILE, GetGadgetState(#TRACKBAR_PAN) - 100)
EndIf
Case #TRACKBAR_FREQUENCY
If filename <> ""
SetSoundFrequency(#SOUND_FILE,GetGadgetState(#TRACKBAR_FREQUENCY)
* 10)
EndIf
Case #BUTTON_PLAY_FILE
If filename <> ""
PlaySound(#SOUND_FILE)
EndIf
Case #BUTTON_STOP_FILE
If filename <> ""
StopSound(#SOUND_FILE)
EndIf
EndSelect
EndSelect
Until Event = #PB_Event_CloseWindow
EndIf
EndIf
End

Cet Exemple Introduit Trois Nouvelles Commandes de Son:

« SoundVolume() »
Cette commande permet de contrôler le volume du son chargé. Il ne modifie en aucune façon le fichier son original, il ne
modifie que le volume lors de la lecture du fichier son. Pour utiliser cette commande, vous devez lui passer deux
paramètres. Le premier paramètre est le numéro PB du son que vous voulez changer et le deuxième paramètre est le
niveau de volume. Ceci peut prendre des valeurs de « 0 » à «100 », où « 0 » représente le silence et « 100 » signifie la
lecture avec le son au maximum.

« SoundPan() »
Cette commande fait pivoter le son vers et depuis les canaux gauche et droit et nécessite deux paramètres. Le premier
paramètre est le numéro PB du son que vous voulez faire panoramique et le second paramètre est la valeur Pan (canal)
Cette valeur peut varier de « -100 » à « 100 ». Si vous utilisez une valeur de « -100 », le son est entièrement pivoté vers
la gauche, si vous utilisez « 100 », le son est entièrement pivoté vers la droite.
182 Son

« SetSoundFrequency() »
Cette commande modifie la fréquence du son joué. La fréquence du son est mesurée en Hertz et décrit la fréquence de
lecture d'une forme d'onde particulière par seconde. Par exemple, la musique d'un CD était stockée à une fréquence
d'échantillonnage de 44,1 kHz (kilohertz). Cela signifie que la forme d'onde contenant les informations sonores a été
échantillonnée quarante-quatre mille cent fois par seconde. Cela garantit une résolution suffisante pour afficher la
moindre variation du son. Si un son est codé à 44,1 kHz et que vous utilisez cette commande pour changer la fréquence
à 22 050 Hz, le son ne jouera qu'à la moitié de la vitesse originale. Pour changer la fréquence d'un son chargé dans
PureBasic avec cette commande, vous devez lui passer deux paramètres. Le premier paramètre est le numéro PB du
son que vous voulez changer et le second paramètre est une valeur numérique indiquant la nouvelle fréquence en
Hertz. La valeur du deuxième paramètre doit être comprise entre « 1.000 » et « 100.000 ».

Pour en savoir plus sur les commandes de manipulation des fichiers wave, consultez l'aide PureBasic dans la section
Sound Library (fichier d'aide : Manuel de référence → Jeux 2D et bibliothèques multimédias → Sound).

Fichiers du Module
Ces fichiers représentent la musique sous forme de motifs numériques. En interne, ils stockent plusieurs pages de
données musicales structurées sous une forme similaire à celle d'une feuille de calcul. Ces motifs contiennent les
valeurs des notes, les numéros d'instrument et les messages de contrôle qui indiquent au programme quels
échantillons sont utilisés et combien de temps ils sont joués. Les fichiers de module contiennent également une liste qui
définit l'ordre dans lequel les échantillons sont lus. Le nombre d'instruments pouvant être joués simultanément dépend
du nombre de pistes dans les échantillons. Les premiers programmes disponibles qui permettaient à l'utilisateur de
créer ses propres fichiers de modules utilisaient quatre pistes. Le plus grand avantage des fichiers modules par rapport
aux fichiers son standard (tels que les fichiers MIDI) est qu'ils incluent leurs propres échantillons audio et qu'ils sonnent
donc de la même manière partout.

Les fichiers de modules sont souvent appelés Modules tracker et l' art de composer des modules est appelé «
Tracking ». C'est historique parce que le premier programme qui permettait à l'utilisateur de créer des fichiers de
modules portait le nom de « Soundtracker » Le programme, bien que mal accepté au début, a finalement été publié
dans le domaine public et copié à plusieurs reprises. En conséquence, la fonctionnalité s'est développée et plusieurs
nouveaux produits comme « Noisetracker » ou « Protracker » ont été créés. Celles-ci sont devenues très populaires, en
particulier auprès des fabricants de jeux et de démos sur le Commodore Amiga. Les programmes qui créent aujourd'hui
des modules sont collectivement appelés « trackers ».

Les fichiers de module peuvent avoir de nombreuses extensions de fichiers différentes parce qu'ils se présentent dans
de nombreux formats différents. Ces extensions de fichiers décodent souvent le programme qui a créé le module.
PureBasic supporte entre autres les formats de modules courants suivants :

FastTracker (' *.xm ')


Scream Tracker (' *.s3m ')
Protracker (' *.mod ')
Impulse Tracker (' *.it ')

Ces différents formats de modules sont chargés et lus dans votre programme PureBasic de la même manière. Voici
un exemple qui montre comment charger et lire n'importe quel fichier de module supporté :

#MODULE_FILE = 1

If InitSound()
If InitModule()
LoadModule(#MODULE_FILE, "Eighth.mod")
PlayModule(#MODULE_FILE)
StartTime.l = ElapsedMilliseconds()

Repeat
Delay(1)
Until ElapsedMilliseconds() > StartTime + 15000

StopModule(#MODULE_FILE)
End
EndIf
EndIf
Son 183

Il faut d'abord initialiser l'environnement sonore avec la fonction « InitSound() » comme dans l'exemple Wave. Ensuite,
nous devons initialiser la jouabilité de PureBasic pour les fichiers de modules. Pour cela nous utilisons la fonction
« InitModule() ». Les deux fonctions doivent être vérifiées pour une initialisation correcte.

Après l'initialisation de l'environnement, nous pouvons utiliser la fonction « LoadModule() » (fichier d'aide : Manuel de
référence → 2D Games & Multimedia Libraries → Module → LoadModule). Cette commande nécessite deux
paramètres. Le premier est le numéro PB que vous voulez attribuer au module et le second est le nom de fichier du
fichier du module que vous voulez charger.

Quand le module est chargé, on peut le lire avec la fonction « PlayModule() » (fichier d'aide : Manuel de référence→ 2D
Games & Multimedia Libraries → Module → PlayModule). Comme la fonction « PlaySound() », il a besoin d'un
paramètre, à savoir le numéro PB du module que vous voulez jouer. Pour arrêter la lecture, vous pouvez utiliser la
commande « StopModule() ».

Inclure les Fichiers de Module


Comme les fichiers Wave, vous pouvez également intégrer des fichiers de modules dans votre programme fini. Le
module est également stocké dans une « Datasection » et est ensuite chargé depuis la mémoire. En voici un exemple :
#FICHIER_MODULE = 1
If InitSound()
If CatchModule(#FICHIER_MODULE, ?FichierModule, ?FichierModuleEnd - ?FichierModule)
PlayModule(#FICHIER_MODULE)
StartZeit.i = ElapsedMilliseconds()
Repeat
Delay(1)
Until ElapsedMilliseconds() > StartZeit + 15000
StopModule(#FICHIER_MODULE)
EndIf
EndIf
End
DataSection
FichierModule:
IncludeBinary "Eighth.mod"
FichierModuleEnd:
EndDataSection

Cet exemple est très similaire à l'exemple d'incorporation de fichiers wave, mais il y a une petite différence. Dans cet
exemple, le module est créé avec la fonction « CatchModule() » (fichier d'aide: Manuel de référence → Bibliothèques
de jeux 2D → Modules → CatchModules) de la « DataSection ». Ceci nécessite (contrairement à la fonction «
CatchSound() ») trois paramètres. Le premier paramètre est le numéro PB que vous voulez attribuer au module. Le
deuxième paramètre est l'adresse de départ du module en mémoire. Nous le déterminons à nouveau via la marque de
saut avant l'instruction « IncludeBinary » dans la « DataSection ». Pour déterminer l'adresse, un point d'interrogation
doit également être placé avant le nom du point d'interrogation. Le troisième paramètre est la taille du fichier du module
en octets. Vous pouvez le déterminer à l'aide d'un petit truc. Comme vous pouvez le voir, dans la « DataSection» sous
l'instruction « includeBinary », j'ai défini un autre marqueur de saut ( « FichierModuleEnd: »). Avec ce marqueur, je peux
trouver la fin du fichier module en mémoire. Si je soustrais maintenant l'adresse de début de l'adresse de fin, j'obtiens
exactement la longueur du fichier en octets entre les deux points et j'ai ainsi déterminé mon troisième paramètre. La
lecture du fichier de module est alors à nouveau avec le Commande « PlayModule() ».

Les Inconvénients de l'Utilisation des Modules


Il y a deux gros inconvénients à l'utilisation des modules dans vos programmes PureBasic. La première est qu'il
n'y a pas de moyen facile d'intégrer et de charger à partir de la mémoire tous les modules qui doivent être lus.
Cela signifie que vous devez distribuer tous les fichiers de module utilisés avec votre exécutable. Il existe
cependant des moyens de stocker le module dans votre exécutable, puis de l'écrire sur le disque avant de le char ger
et de le lire, mais c'est un peu encombrant. Le deuxième inconvénient est que vous devez distribuer le fichier «
Midas11.dll » avec votre programme. Cette bibliothèque dynamique liée est chargée par la commande; « InitModule()
» et sera erronée si elle ne la trouve pas. Vous pouvez penser que ce n'est pas si mal, mais la licence liée à
l'utilisation de cette « bibliothèque Midas » interdit son utilisation à des fins commerciales. Cette licence empêche
également d'inclure le fichier « Midas11.dll » dans le paquet PureBasic, vous devez donc le télécharger vous-même
à partir du site Web « Housemarque Audio System », qui se trouve à l'Annexe A (Liens Internet utiles).

Pour en savoir plus sur les commandes permettant de manipuler les fichiers de module, consultez PureBasic. Aide dans
la zone de la bibliothèque de modules après (Fichier d’aide: Manuel de référence → Jeux 2D & Multimédia
Bibliothèques → modules).
184 Son

MP3's
Les fichiers MP3 sont rapidement devenus le format de fichier son le plus populaire. C'est parce que les fichiers MP3
sont devenus la norme pour presque tous les fichiers musicaux qui peuvent être téléchargés à partir d'Internet. MP3 est
une abréviation de « MPEG-1 Audio Layer 3 » , il est donc compréhensible pourquoi vous l'avez abrégé.

Les fichiers MP3 sont traités différemment dans PureBasic. Pour les lire, nous devons utiliser les commandes de la
bibliothèque « Movie » (fichier d'aide : Manuel de référence → Bibliothèques générales → Movie). Il peut sembler un
peu confus que nous devions utiliser les commandes Vidéo pour lire des fichiers MP3, mais ces commandes peuvent
jouer beaucoup plus que de simples films. Les commandes Vidéo offrent la possibilité de charger et de lire presque tous
les fichiers multimédia pour lesquels un codec correspondant est installé sur l'ordinateur. Outre les formats vidéo, vous
pouvez également lire des formats audio avec ces commandes.

Voici une liste des formats de fichiers les plus populaires que la bibliothèque « Movie » est capable de lire tant que les
plugins et/ou codecs requis sont installés en premier. Il se peut même que vous puissiez lire plus de formats que ce qui
est indiqué dans cette liste :

Fichiers Video :
Audio Video Interleave ('*.avi')
MPEG Video ('*.mpg')

Fichiers Audio
Fichiers MIDI ('*.mid')
Fichiers MP3 ('*.mp3')
Fichiers Ogg Vorbis ('*.ogg')
Fichiers Wave ('*.wav')

La bibliothèque « Movie » semble être la « seule tribune » pour la lecture de fichiers multimédia et certains utilisateurs
ont demandé de la renommer en bibliothèque « Media », mais vous devez toujours garder à l'esprit qu'un fichier
multimédia qui est bien lu sur votre ordinateur peut ne pas être lu sur un autre ordinateur. Cela dépend des codecs
installés (ou non) sur votre ordinateur. Je maintiens, cependant, que la liste ci-dessus peut être jouée sur n'importe quel
ordinateur standard, mais ne me croyez pas!.

Dans l'exemple suivant, j'ai utilisé les commandes Vidéo pour créer un lecteur MP3 simple qui inclut un curseur de
volume et un curseur de balance. Il ne s'approche pas de « WinAmp », mais il montre à quel point il est facile de créer
un lecteur multimédia avec PureBasic.

Enumeration
#WINDOW_ROOT
#SOUND_FILE
#TEXT_FILE
#BUTTON_CHOOSE_FILE
#TEXT_VOLUME
#TRACKBAR_VOLUME
#TEXT_PAN
#TRACKBAR_PAN
#BUTTON_PLAY_FILE
#BUTTON_PAUSE_FILE
#BUTTON_STOP_FILE
EndEnumeration

Global FileName.s = ""


Global FilePaused.b = #False
#FLAGS = #PB_Window_SystemMenu | #PB_Window_ScreenCentered

If OpenWindow(#WINDOW_ROOT, 0, 0, 500, 215, "Lecteur MP3 ", #FLAGS)


TextGadget(#TEXT_FILE, 10, 10, 480, 20, "", #PB_Text_Border)
ButtonGadget(#BUTTON_CHOOSE_FILE, 10, 40, 150, 20, "Choisir MP3 File...")
TextGadget(#TEXT_VOLUME, 10, 70, 480, 20, "Volume")
TrackBarGadget(#TRACKBAR_VOLUME, 10, 90, 480, 20, 0, 100)
SetGadgetState(#TRACKBAR_VOLUME, 100)
TextGadget(#TEXT_PAN, 10, 120, 480, 20, "Pan")
TrackBarGadget(#TRACKBAR_PAN, 10, 140, 480, 20, 0, 200)
SetGadgetState(#TRACKBAR_PAN, 100)
ButtonGadget(#BUTTON_PLAY_FILE, 10, 180, 100, 20, "Jouer")
ButtonGadget(#BUTTON_PAUSE_FILE, 130, 180, 100, 20, "Pause")
ButtonGadget(#BUTTON_STOP_FILE, 250, 180, 100, 20, "Stop")
Son 185

If InitMovie()
Repeat
Event.l = WaitWindowEvent()
Select Event
Case #PB_Event_Gadget
Select EventGadget()
Case #BUTTON_CHOOSE_FILE
FileName=OpenFileRequester("Choisir","","MP3 File (*.mp3)|*.mp3",0)
If filename <> ""
SetGadgetText(#TEXT_FILE, GetFilePart(FileName))
LoadMovie(#SOUND_FILE, filename)
EndIf
Case #TRACKBAR_VOLUME, #TRACKBAR_PAN
If filename <> ""
Volume.l = GetGadgetState(#TRACKBAR_VOLUME)
Balance.l = GetGadgetState(#TRACKBAR_PAN) - 100
MovieAudio(#SOUND_FILE, Volume, Balance)
EndIf
Case #BUTTON_PLAY_FILE
If filename <> ""
PlayMovie(#SOUND_FILE, #Null)
FilePaused = #False
SetGadgetText(#BUTTON_PAUSE_FILE, "Pause")
EndIf
Case #BUTTON_PAUSE_FILE
If filename <> ""
If FilePaused = #False
PauseMovie(#SOUND_FILE)
FilePaused = #True
SetGadgetText(#BUTTON_PAUSE_FILE, "Resume")
Else
ResumeMovie(#SOUND_FILE)
FilePaused = #False
SetGadgetText(#BUTTON_PAUSE_FILE, "Pause")
EndIf
EndIf
Case #BUTTON_STOP_FILE
If filename <> ""
StopMovie(#SOUND_FILE)
FilePaused = #False
SetGadgetText(#BUTTON_PAUSE_FILE, "Pause")
EndIf
EndSelect
EndSelect
Until Event = #PB_Event_CloseWindow
EndIf
EndIf
End

Si vous regardez ce petit exemple, vous verrez que pour utiliser les commandes « Movie », vous devez d'abord
initialiser l'environnement, tout comme pour les fichiers Wave et les modules. Pour initialiser les fonctions vidéo, utilisez
la fonction « InitMovie() ». Après l'avoir appelé, vous pouvez utiliser toutes les autres commandes de la bibliothèque
« Movie ». Comme les autres commandes d'initialisation, il faut vérifier que l'initialisation est réussie. Si l'initialisation a
échoué, vous ne pouvez pas utiliser les commandes Vidéo.
186 Son

Pour charger une vidéo (ou dans ce cas un fichier MP3), nous utilisons la fonction « LoadMovie() » (fichier d'aide :
Manuel de référence → Bibliothèques générales → Movie → LoadMovie). Cette commande nécessite deux paramètres.
Le premier est le numéro PB que vous voulez associer au support et le second est une chaîne contenant le nom du
fichier à charger.

Après avoir chargé le fichier multimédia, nous pouvons le lire avec la commande « PlayMovie() » (fichier d'aide : Manuel
de référence → Bibliothèques générales →Movie→ PlayMovie). Cette commande nécessite deux paramètres pour
prendre en charge les supports vidéo et audio. Le premier paramètre est le numéro PB du support que vous voulez lire,
tandis que le second paramètre est l'identifiant du système d'exploitation d'une fenêtre. Cet identifiant du système
d'exploitation est nécessaire lorsque vous voulez lire une vidéo, car la vidéo est dessinée sur cette fenêtre lorsqu'elle est
lue. Si vous voulez lire des fichiers audio purs (comme des fichiers MP3), vous pouvez utiliser la constante intégrée «
#Null » comme identifiant du système d'exploitation. Cela signifie que la lecture n'est pas liée à une fenêtre existante :

...
PlayMovie(#SOUND_FILE, #Null)
...

J'ai aussi utilisé les fonctions « PauseMovie() » et « ResumeMovie() » de l'exemple, qui sont très faciles à utiliser.
Les deux ont juste besoin du numéro PB du support que vous voulez mettre en pause ou reprendre.

Pour vous donner la possibilité d'annuler la lecture du fichier, j'ai utilisé la fonction « StopMovie() » dans cet exemple.
Cette fonction est également très simple à utiliser, car il suffit d'avoir le numéro PB du support comme paramètre pour
arrêter la lecture.

Même s'il ne s'agit que d'un code minimaliste de lecteur multimédia et qu'il ne supporte que les MP3, il est
facile pour vous d'étendre le code jusqu'à ce qu'il supporte tous les formats mentionnés ci-dessus. Pourquoi tu ne
l'essaies pas ?

CD Audio
La lecture de CD audio est un bon moyen de fournir de la musique de haute qualité pour un jeu ou une application. Il
existe de nombreux outils gratuits sur Internet qui vous permettent de créer et graver des CD audio. L'utilisation de CD
pour offrir de la musique a l'avantage que très peu de performance système est nécessaire et la qualité est très élevée.
Voici un exemple qui utilise la bibliothèque « AudioCD » de PureBasic pour créer un simple lecteur CD :

Enumeration
#WINDOW_ROOT
#BUTTON_PREVIOUS
#BUTTON_PLAY
#BUTTON_STOP
#BUTTON_NEXT
#BUTTON_EJECT
#TEXT_STATUS
#PROGRESS_SONG
#LIST_TRACKS
EndEnumeration
;Global variables, etc.
Global NumberOfTracks.l
Global CurrentTrack.l
;Convertir les secondes en une chaîne de caractères contenant les minutes.
Procedure.s ConvertToMin(Seconds.l)
ProcedureReturn Str(Seconds / 60) + ":" + Str(Seconds % 60)
EndProcedure
;Définir la piste en cours
Procedure UpdateStatusText(Track.l)
If NumberOfTracks > 0
TrackLength.l = AudioCDTrackLength(Track)
TrackLengthString.s = ConvertToMin(TrackLength)
TrackTimings.s = " (" + TrackLengthString + ")"
SetGadgetText(#TEXT_STATUS, "Piste: " + Str(Track) + TrackTimings)
SetGadgetState(#PROGRESS_SONG, 0)
Son 187

If AudioCDStatus() > 0
TimeElapsed.l = AudioCDTrackSeconds()
TrackTimings.s=" ("+ConvertToMin(TimeElapsed)+" / "+TrackLengthString+")"
SetGadgetText(#TEXT_STATUS, "Piste: " + Str(Track) + TrackTimings)
Progress.f = (100 / TrackLength) * TimeElapsed
SetGadgetState(#PROGRESS_SONG, Progress)
EndIf
SetGadgetState(#LIST_TRACKS, Track - 1)
Else
SetGadgetText(#TEXT_STATUS, "Veuillez inserer un CD Audio")
EndIf
EndProcedure
;Aller à la piste suivante
Procedure NextTrack()
If CurrentTrack < NumberOfTracks
CurrentTrack + 1
UpdateStatusText(CurrentTrack)
If AudioCDStatus() > 0
PlayAudioCD(CurrentTrack, NumberOfTracks)
EndIf
EndIf
EndProcedure
;Aller à la piste précédente
Procedure PreviousTrack()
If CurrentTrack > 1
CurrentTrack - 1
UpdateStatusText(CurrentTrack)
If AudioCDStatus() > 0
PlayAudioCD(CurrentTrack, NumberOfTracks)
EndIf
EndIf
EndProcedure
;Remplissez la liste pour afficher toutes les pistes d'un disque
Procedure PopulateTrackListing()
ClearGadgetItems(#LIST_TRACKS)
NumberOfTracks = AudioCDTracks()
If NumberOfTracks > 0
For x.l = 1 To NumberOfTracks
TrackLength.s = ConvertToMin(AudioCDTrackLength(x))
AddGadgetItem(#LIST_TRACKS, -1, "Piste "+Str(x)+" ("+TrackLength+")")
Next x
If CurrentTrack = 0
CurrentTrack = 1
EndIf
Else
CurrentTrack = 0
EndIf
EndProcedure
#FLAGS = #PB_Window_SystemMenu | #PB_Window_ScreenCentered
If OpenWindow(#WINDOW_ROOT, 0, 0, 320, 250, "Lecteur CD", #FLAGS)
ButtonGadget(#BUTTON_PREVIOUS, 10, 10, 60, 20, "Précédent")
ButtonGadget(#BUTTON_PLAY, 70, 10, 60, 20, "Jouer")
ButtonGadget(#BUTTON_STOP, 130, 10, 60, 20, "Arrêt")
ButtonGadget(#BUTTON_NEXT, 190, 10, 60, 20, "Suivant")
ButtonGadget(#BUTTON_EJECT, 250, 10, 60, 20, "Eject")
TextGadget(#TEXT_STATUS, 10, 40, 300, 20, "", #PB_Text_Center)
ProgressBarGadget(#PROGRESS_SONG,10,65,300,10,0,100,#PB_ProgressBar_Smooth)
ListViewGadget(#LIST_TRACKS, 10, 90, 300, 150)
188 Son

If InitAudioCD()
PopulateTrackListing()
StartTime.l = ElapsedMilliseconds()

Repeat
Event.l = WindowEvent()

Select Event
Case #PB_Event_Gadget

Select EventGadget()
Case #BUTTON_PREVIOUS
PreviousTrack()
Case #BUTTON_PLAY
If NumberOfTracks > 0
PlayAudioCD(CurrentTrack, NumberOfTracks)
EndIf
Case #BUTTON_STOP
StopAudioCD()
Case #BUTTON_NEXT
NextTrack()
Case #BUTTON_EJECT
EjectAudioCD(#True)
PopulateTrackListing()
Case #LIST_TRACKS
If EventType() = #PB_EventType_LeftDoubleClick
CurrentTrack = GetGadgetState(#LIST_TRACKS) + 1
UpdateStatusText(CurrentTrack)
PlayAudioCD(CurrentTrack, NumberOfTracks)
EndIf
EndSelect
EndSelect

CurrentTime.l = ElapsedMilliseconds()
If CurrentTime > StartTime + 1000
PopulateTrackListing()
UpdateStatusText(CurrentTrack)
StartTime.l = ElapsedMilliseconds()
EndIf
Delay(1)
Until Event = #PB_Event_CloseWindow

StopAudioCD()
EndIf
EndIf
End

Cet exemple est un lecteur de CD très simple qui offre un minimum de fonctionnalités pour contrôler et lire des CD
audio. Toutes les commandes utilisées de la bibliothèque « AudioCD » se trouvent dans l'aide de PureBasic (fichier
d'aide : Manuel de référence → Bibliothèques générales → AudioCD).

Pour utiliser les commandes « AudioCD », vous devez d'abord initialiser l'environnement nécessaire. Ceci est fait avec
la fonction « InitAudioCD() ». Nous devons vérifier cette commande pour une initialisation réussie. Comme effet
secondaire, la commande retourne le nombre de lecteurs CD installés capables de lire de la musique. Si la valeur de
retour est « 0 »,, alors il n'y a aucun lecteur de CD installé dans l'ordinateur ou un autre problème est survenu que le
lecteur de CD empêche la lecture de musique. Si la valeur de retour est supérieure à « 0 », tout devrait bien se passer.

Après l' initialisation de l' environnement Audio CD, vous pouvez utiliser toutes les commandes de la bibliothèque
« AudioCD ».

Voici une liste des commandes que j'ai utilisées dans mon exemple de lecteur CD:

« PlayAudioCD() »
Cette commande permet de lire le titre actuel du CD inséré. La commande nécessite deux paramètres. Le premier est
le titre avec lequel la lecture est lancée et le second est le titre après lequel la lecture est interrompue. Par exemple,
si j'appelle la commande comme ceci :

PlayAudioCD(1, 3)

alors la lecture commence par le titre « 1 » et passe au titre suivant. La lecture sera interrompue lorsque la troisième
piste sera terminée.
Son 189

« StopAudioCD() »
Cette commande peut être utilisée à tout moment pour arrêter la lecture du titre en cours de lecture.

« EjectAudioCD() »
Cette commande ouvre ou ferme le lecteur de CD en fonction du paramètre passé. Cette commande nécessite un
paramètre. Si vous passez la valeur « 1 » en paramètre, le tiroir du lecteur CD s'ouvrira, plus précisément la lecture sera
interrompue et le CD sera éjecté. Si vous passez la valeur « 0 » comme paramètre, alors le tiroir du variateur est fermé
et le CD inséré est chargé.

« AudioCDStatus() »
Cette commande ne nécessite pas de paramètre et nous donne un état en temps réel du CD dans le lecteur. Si cette
commande retourne « -1 » lorsqu'elle est appelée, le lecteur n'est pas prêt, ce qui signifie qu'il n'y a pas de CD inséré ou
que le tiroir du lecteur n'est pas fermé. Si la valeur retournée est « 0 », cela signifie que le CD a été correctement
détecté, mais qu'il n'est pas en cours de lecture. Si la valeur de retour est supérieure à « 0 », un titre est en cours de
lecture. La valeur de retour est le numéro du titre en cours de lecture.

« AudioCDTracks() »
Cette commande ne nécessite aucun paramètre et retourne le nombre de pistes lisibles sur le CD chargé lorsqu'elle est
appelée.

« AudioCDTrackLength() »
Cette commande nécessite un paramètre, à savoir le numéro de piste d' un CD chargé. Avec cette information, la
commande retourne la durée de la piste en secondes.

« AudioCDTrackSeconds() »
Cette commande ne nécessite pas de paramètre. Lorsqu'il est appelé, il retourne le temps écoulé de la piste en cours
en secondes.

Si vous regardez de plus près mon exemple de lecteur CD, vous remarquerez que j'ai utilisé la fonction
« WindowEvent() » au lieu de « WaitWindowEvent() ». Cela signifie que la boucle principale fonctionne en
continu, qu'un événement se soit produit ou non. Ceci est nécessaire dans mon programme car j'appelle une
procédure dépendante du temps dans ma boucle principale qui met à jour l'affichage dans l'interface utilisateur
graphique du programme. Si je ne l'avais pas fait, l'affichage d'état ne se mettrait à jour que sur un événement
de la fenêtre. Alternativement, j'aurais pu utiliser la fonction « WaitWindowEvent() » avec un paramètre optionnel «
Timeout », par ex :

...
Event.i = WaitWindowEvent(10)
...

Les fonctions « WindowEvent() » et « WaitWindowEvent() » sont décrites plus en détail au Chapitre 9 (Comprendre les
événements).
190 Au-Delà de l'Essentiel

IV. Sujets Avancés


Dans cette section, je décris des choses qui sont légèrement plus avancées que les autres sections de ce livre. Cette
section est également destinée à ceux qui ont des questions sur un aspect spécifique de PureBasic, ou qui veulent
simplement en savoir plus sur ce qui se passe « sous le capot ».

Vous n'avez besoin de rien dans cette section pour créer de bons programmes stables et riches en fonctionnalités, mais
pour ceux d'entre vous qui veulent en savoir un peu plus, je l'ai ajouté ici.

13. Au-Delà de l'Essentiel


Ce chapitre contient un mélange de différents sujets, parce que j'ai pensé que tous ces points devraient être expliqués,
mais pas chaque point donne le contenu d'un chapitre complet. Ces sujets ne sont pas essentiels à la création de
programmes PureBasic, mais ils sont importants pour les programmeurs qui souhaitent approfondir leurs
connaissances sur les fonctionnalités avancées de PureBasic.

Les sujets abordés dans ce chapitre incluent : les directives du compilateur et comment contrôler le compilateur en
utilisant du code, les options avancées du compilateur pour obtenir plus du compilateur PureBasic, comment passer les
arguments de ligne de commande à votre programme pour écrire des outils de ligne de commande, comment
PureBasic stocke les types de données numériques, quels sont les pointeurs et comment les utiliser, quels sont les
threads et comment les utiliser, quelles bibliothèques liées de façon dynamique et comment les créer, comment utiliser
la fenêtre de programmation de l'application et la façon d'en nativement en PureBasic.

Directives et Fonctions du Compilateur


Les directives du compilateur sont des commandes qui contrôlent le compilateur PureBasic pendant la compilation. Ces
directives vous donnent un contrôle total sur les parties du code source qui doivent être compilées et vous donnent la
possibilité de récupérer les informations du compilateur. Les directives du compilateur n'ont d'effet que pendant la
compilation, seulement à ce moment elles sont évaluées et éditées. Ils ne peuvent pas être évalués au moment de
l'exécution.

Les fonctions du compilateur diffèrent des directives en ce qu'il s'agit de commandes qui vous permettent de collecter
des informations sur quelque chose déjà compilé (généralement un type de données). Contrairement aux directives, les
fonctions du compilateur peuvent être évaluées au moment de l'exécution.

Auparavant, dans ce livre, vous avez déjà vu les directives du compilateur et les fonctions du compilateur, mais vous ne
l'avez pas remarqué. Par exemple, au chapitre 8 (Minimiser les erreurs et leur traitement), je vous ai présenté la
commande « EnableExplicit ». Cette directive du compilateur met le compilateur en mode explicite et garantit que toutes
les variables sont explicitement déclarées, c'est-à-dire que tous les types et portées des nouvelles variables sont
définis. Vous avez également vu les fonctions « SizeOf() » et « OffsetOf() » au chapitre 5. Ces fonctions du compilateur
recueillent des informations sur les structures et les interfaces compilées, telles que la taille d'une structure en mémoire
(spécifiée en octets) ou le décalage d'un champ spécifique dans une structure ou une interface.

Il y a encore quelques directives et fonctions qui pourraient être ajoutées à cette liste, mais avant d'aller plus loin, je
dois expliquer les constantes intégrées et réservées du compilateur que presque toutes utilisent.

Constantes de Compilateur Réservées


Ces constantes intégrées et réservées sont en fait les mêmes que toutes les autres constantes, la différence étant que
leur valeur dépend fortement de l'état actuel du compilateur. Toutes ces constantes peuvent être interrogées pendant la
compilation pour prendre des décisions sur la façon de compiler. Certaines constantes fournissent également des
informations sur le processus de compilation lui-même. Voici une liste complète des constantes réservées du
compilateur et des informations qu'elles contiennent.

#PB_Compiler_OS
La valeur de cette constante spéciale dépend de la plate-forme sur laquelle le compilateur fonctionne. Il a également
quelques constantes associées qui vous aident à déterminer ce que signifie la valeur. Par exemple, si la constante a
une valeur « #PB_OS_Windows » , « #PB_OS_Linux » , « #PB_OS_AmigaOS » ou « #PB_OS_MacOS », alors le
compilateur fonctionnera sur cette plate-forme particulière.
Au-Delà de l'Essentiel 191

#PB_Compiler_Processor
Vous pouvez utiliser cette constante spéciale pour déterminer le type de processeur pour lequel le programme est
compilé. Il possède également quelques constantes associées qui vous aident à choisir le type de processeur. Vous
pouvez créer des programmes pour les architectures de processeurs « #PB_Processor_x86 » , « #PB_Processor_x64
» , « #PB_Processor_PowerPC » ou « #PB_Processor_mc68000 » .

#PB_Compiler_Date
La valeur de cette constante contient une date sous forme numérique. Cette date est l'heure à laquelle le programme a
été compilé. Cette valeur est stockée dans le format de date PureBasic afin qu'elle puisse être facilement traitée avec
les commandes de la bibliothèque « Date ». (Fichier d'aide : Manuel de référence → Bibliothèques générales → Date)

#PB_Compiler_File
La valeur de cette constante est une chaîne de caractères et contient le chemin complet et le nom du fichier (*.pb)
compilé.

#PB_Compiler_FilePath
La valeur de cette constante est une chaîne de caractères et contient le chemin complet du fichier (*.pb) compilé.

#PB_Compiler_Line
La valeur de cette constante est le numéro de ligne du fichier en cours de compilation.

#PB_Compiler_Procedure
La valeur de cette constante est une chaîne de caractères et contient le nom de la procédure (si la ligne est dans
une procédure) du fichier (*.pb) compilé.

#PB_Compiler_Version
La valeur de cette constante est une valeur entière indiquant la version du compilateur avec laquelle le programme a
été compilé (ex:« 451 » pour la version compilateur « 4.51 »).

#PB_Compiler_Home
La valeur de cette constante est une chaîne de caractères et contient le chemin complet du dossier d'installation
PureBasic sur votre ordinateur.

#PB_Compiler_EnumerationValue
La valeur de cette constante mémorise la valeur suivante d' une énumération. Il est ainsi possible de lier plusieurs
énumérations à partir de plusieurs textes sources, par exemple.

#PB_Compiler_Debugger
Cette constante a l' une des deux valeurs suivantes. Si cette valeur est'#True', alors le débogueur est activé. Si cette
valeur est'#False', alors le débogueur a été désactivé avant la compilation.

#PB_Compiler_Thread
Cette constante peut avoir l'une des deux valeurs suivantes. Si cette valeur est « #True », alors le mode thread-safe
était activé avant la compilation. Si cette valeur est « #False », alors le mode sans échec de thread n'a pas été utilisé.

#PB_Compiler_Unicode
Cette constante peut avoir l'une des deux valeurs suivantes. Si cette valeur est « #True » alors le mode Unicode était
activé avant la compilation. Si cette valeur est « #False » alors le mode « Unicode » n'a pas été utilisé.

Toutes ces constantes réservées du compilateur peuvent être utilisées dans des instructions et expressions normales,
en fait vous pouvez les utiliser partout où vous utilisez des constantes normales. Cependant, la plupart des constantes
du compilateur ne sont vraiment utiles que si elles sont utilisées avec les directives suivantes.

La Directive « CompilerIf »
Si vous comprenez comment utiliser une instruction « If » dans PureBasic, alors vous comprendrez aussi comment
utiliser « CompilerIf », Une instruction « CompilerIf » se comporte exactement comme toute autre instruction « If »,
mais elle n'est jamais compilée. C'est simplement la version compilateur d'une instruction « If ».
192 Au-Delà de l'Essentiel

Contrairement aux instructions « If » normales, « CompilerIf » décide quelle partie du code est compilée. Cette
décision est basée sur le résultat d'une expression constante, les variables ne sont pas autorisées. En revanche, une
instruction « If » normale décide quelle partie du code (déjà compilé) est exécutée, en fonction d'une expression
variable.

Laissez-moi vous montrer un exemple d'utilisation de'CompilerIf' sous une forme commune :

CompilerIf #PB_Compiler_OS = #PB_OS_Windows


MessageRequester("Info", "Ce compilateur fonctionne sous Microsoft Windows")
CompilerElse
MessageRequester("Info", "Ce compilateur ne fonctionne PAS sous Microsoft Windows")
CompilerEndIf

Ici le « CompilerIf » vérifie cette expression constante : « #PB_Compiler_OS = #PB_OS_Windows ». Si cette expression
renvoie Vrai, alors nous savons que ce code a été compilé sur un ordinateur sous Microsoft Windows. S'il retourne
Faux, ce n'est pas le cas, c'est aussi simple que ça. Cela semble très simple, mais la chose ingénieuse à propos de
l'utilisation de « CompilerIf » est qu'il ne compile que la section de code qui remplit la condition. Si nous gardons cela à
l'esprit, et avons compilé notre exemple sous Microsoft Windows, alors la ligne :

MessageRequester("Info", "Ce compilateur ne fonctionne PAS sous Microsoft Windows")

Ne sera jamais compilé et ne sera donc jamais inclus dans le fichier exécutable du programme.

Une instruction « CompilerIf » se compose de trois commandes, toutes utilisées dans l'exemple ci-dessus. Le
composant « CompilerElse » qui est comparable au composant « Else » normal est facultatif, mais l'instruction entière
doit être complétée par « CompilerEndIf ».

Certains programmeurs utilisent « CompilerIf » pour restreindre la fonctionnalité de leurs programmes, surtout s'ils le
compilent en version d'essai. Par exemple, si j'écris un programme utile et que je veux donner aux utilisateurs une démo
pour qu'ils puissent le tester avant de l'acheter, alors je dois vivre avec la peur que certains vont essayer de le casser
pour supprimer les limitations. Mais je peux aussi créer mon programme comme ceci :

#DEMO = #True

CompilerIf #DEMO

;Code démo Code démo


MessageRequester("Info", "Ceci est une démo, vous devez acheter la version complète.")

CompilerElse
;Code de version complète:
Procédure.d MyPI()
ProcédureRetour ACos(-1)
EndProcedure

Test.s = "Ceci est la version complète." #LF$ + #LF$ + #LF$


Test.s + "La valeur de Pi est : "StrD(MyPI(), 16)
MessageRequester("Info", Test)

CompilerEndIf

Le simple fait de changer la valeur de la constante « #DEMO » fait que le compilateur compile des versions
complètement différentes du code. C'est très utile car cela peut empêcher vos programmes de craquer car la version
de démonstration ne contient pas le code de la version complète. Essayez de définir la constante « #DEMO » sur
False et compilez la version complète du programme.

La Directive « CompilerSelect »
L'instruction « CompilerSelect » est une version compilatrice de l'instruction populaire « Select ». Cela signifie que
plusieurs sections du code source peuvent être compilées en fonction des différentes valeurs d' une constante. Tout
comme « CompilerIf », « CompilerSelect » ne peut vérifier que les valeurs constantes, car ce contrôle est effectué au
moment de la compilation et non à l'exécution. Voici une autre vérification du système d'exploitation, cette fois avec
« CompilerSelect » :
Au-Delà de l'Essentiel 193

CompilerSelect #PB_Compiler_OS
CompilateurCase #PB_OS_Windows
Code spécifique à Windows
MessageRequester("Info", "Ceci est compilé sous Microsoft Windows.")

CompilateurCase #PB_OS_Linux
Code spécifique à Linux
MessageRequester("Info", "Ceci est compilé sous Linux.")

CompilateurCase #PB_OS_MacOS_MacOS
Code spécifique à MacOS
MessageRequester("Info", "Ceci est compilé sous MacOS X")

CompilateurCase #PB_OS_AmigaOS
Code spécifique à l'AmigaOS
MessageRequester("Info", "Ceci est compilé sur Amiga OS.")
CompilerEndSelect

Avec une telle construction, vous avez la possibilité d'adapter votre programme individuellement aux besoins du
système d'exploitation respectif sur lequel vous le compilez. Vous pouvez également utiliser les commandes de l'API du
système d'exploitation correspondant. Comme ces commandes ne sont pas valables sur toutes les plates-formes, vous
pouvez utiliser un « CompilerSelect » pour séparer les commandes API individuelles du système respectif et générer le
même résultat pour toutes les plates-formes.

PureBasic fournit plusieurs mots-clés pour vous donner la même fonctionnalité avec un « CompilerSelect » qu' avec
une instruction « Select » normale. Ces mots-clés sont « CompilerSelect »,« CompilerCase »,« CompilerDefault » et
« CompilerEndSelect ». Vous avez déjà vu trois de ces commandes dans l'exemple ci-dessus « CompilerSelect ».
Le quatrième, « CompilerDefault » est utilisé comme mot-clé de repli pour fournir un repli si aucun « CompilerCase
» ne retourne un vrai, comme ici :

CompilerSelect #PB_Compiler_OS

CompilerCase #PB_OS_AmigaOS
;Code spécifique à l'AmigaOS
MessageRequester("Error", "Ce code source ne supporte pas Amiga OS.")

CompilerDefault
;Ce code sera compilé sur tous les autres systèmes d'exploitation.
MessageRequester("Info", "Ce code sera compilé correctement sur cet OS.")

CompilerEndSelect

Dans cet exemple, j'ai inclus un message d'erreur si quelqu'un essaie de compiler cet exemple sous AmigaOS, sur
tous les autres systèmes (contrôlés par le mot clé « CompilerDefault ») le code fonctionne correctement.

Bien que presque tous mes exemples pour « CompilerIf » et « CompilerSelect » n'utilisent que la constante
« #PB_Compiler_OS », vous devriez noter que toute constante, compilateur réservé ou non, peut être vérifié avec
ces commandes. Cela vous permet de contrôler le processus de compilation avec le code PureBasic d'une manière
que vous ne pouvez pas voir à première vue.

La Directive « CompilerError »
Cette directive peut être utilisée seule ou dans des directives comme « CompilerIf » ou « CompilerSelect » pour signaler
une erreur de compilation (avec un texte utile). C'est pratique si vous voulez arrêter le processus de compilation et
présenter un message d'erreur de compilateur significatif à l'utilisateur. Voici l'exemple ci-dessus « CompilerSelect »
sous une forme modifiée pour qu'il génère un véritable message d'erreur de compilateur :

CompilerSelect #PB_Compiler_OS

CompilerCase #PB_OS_MacOS_MacOS
CompilerError "Ce code source ne supporte pas MacOS."

CompilerDefault
MessageRequester("Info", "Ce code sera compilé correctement sur cet OS.")

CompilerEndSelect
194 Au-Delà de l'Essentiel

Si vous regardez cet exemple, vous remarquerez que la directive « CompilerError », contrairement aux
commandes normales, n' utilise pas de parenthèses pour inclure ses paramètres. Nous utilisons simplement la
directive « CompilerError » avec une chaîne suivante. Cette chaîne est le message d'erreur qui sera affiché si une
erreur se produit. Lorsque le compilateur rencontre une directive CompilerError, la compilation est arrêtée et le message
d'erreur est affiché.

La Fonction « Subsystem() » du Compilateur


Pour expliquer cette fonction du compilateur, je dois expliquer les sous-systèmes et comment ils sont liés à PureBasic.
Les sous-systèmes sont un concept facile à comprendre. Autrement dit, si vous n'êtes pas satisfait des fonctionnalités
d'une commande intégrée dans PureBasic, vous pouvez l'écraser avec votre propre version. Ces nouvelles versions
sont combinées dans un sous-système.

Si vous jetez un coup d'oeil dans le répertoire d'installation de PureBasic, vous trouverez un dossier appelé
« PureLibraries ». Ce dossier contient les fichiers de la bibliothèque qui à leur tour contiennent les commandes
intégrées de PureBasic. Ces bibliothèques seront remplacées si un sous-système est utilisé. Quand je dis remplacé,
bien sûr, je ne veux pas dire qu'ils seront effacés ou écrasés. Une bibliothèque de sous-système n'obtient qu'une priorité
plus élevée que la bibliothèque standard.

Pour créer un sous-système, vous devez d'abord réécrire une bibliothèque PureBasic puis la compiler (pour plus
d'informations, voir le sous-dossier PureBasic « SDK » Cette nouvelle bibliothèque doit contenir toutes les commandes
de la bibliothèque originale, et tous les noms de commandes doivent correspondre exactement aux originaux. Assurez-
vous ensuite que le nom de la bibliothèque nouvellement compilée correspond au nom de la bibliothèque que vous
voulez remplacer.

Lorsque vous avez fait tout cela, vous devriez avoir une copie presque identique de la bibliothèque originale, sauf pour
la fonctionnalité des commandes incluses (vous pouvez inclure n'importe quelle fonctionnalité dans ces commandes).
Pour installer cette bibliothèque en tant que sous-système, afin de pouvoir l'utiliser lors de la compilation, vous devez
créer un nouveau dossier dans le dossier « SubSystems », situé dans le répertoire d'installation PureBasic. Dans ce
nouveau dossier, vous devez créer un sous-dossier nommé « PureLibraries » et y copier vos bibliothèques de
remplacement. La structure des répertoires ressemble à ceci :

‘..\PureBasic\SubSystems\VotreSubSystem\PureLibraries\VotreNewLibrary’

Pour que PureBasic puisse utiliser votre nouveau sous-système, vous devez définir un indicateur de sous-système
dans le compilateur, puis il utilisera les bibliothèques de votre sous-système et non celles du dossier par défaut
« PureLibraries ». Pour ce faire, vous devez ouvrir la fenêtre « Compiler Options » (menu : Compiler → Compiler
Options...) et entrer le nom du dossier du sous-système (celui que vous avez créé dans le dossier « SubSystems »)
dans le champ « Library Subsystem: » et ensuite cliquer « OK ». La prochaine fois que vous compilerez votre
programme, le compilateur recherchera les bibliothèques dans le dossier « SubSystems » et dans le dossier «
PureLibraries ». S'il trouve des bibliothèques avec le même nom dans ces deux dossiers, le compilateur préférera celles
du sous-système spécifié aux originaux, donc remplacez le terme.

Vous pouvez déjà trouver un exemple de sous-système terminé dans le dossier « SubSystems » . Si vous regardez à
l'intérieur, vous trouverez un dossier nommé « OpenGL », qui à son tour contient un dossier « PureLibraries », et celui-ci
contient les bibliothèques de remplacement pour « Palette »,« Screen »,« Sprite » et « Sprite3D ». Ces bibliothèques
remplacent les originaux lorsque ce sous-système est sélectionné. Si ce sous-système est sélectionné en utilisant
Compiler Flag, il utilisera « OpenGL » au lieu de « DirectX » pour les graphiques 2D.

Comme mentionné précédemment, je vais maintenant expliquer la fonction de compilateur « Subsystem() ».

Pendant la compilation, la fonction de compilateur « Subsystem() » vous indique si un sous-système particulier a été
activé en utilisant le drapeau du compilateur. La syntaxe est assez simple à comprendre. Par exemple, si j'ai activé le
sous-système « OpenGL », le message de débogage suivant sera affiché :
Au-Delà de l'Essentiel 195

If Subsystem("OpenGL")
Debug "Le sous-système OpenGL est utilisé."
EndIf

La fonction « Subsystem() » du compilateur a un paramètre, c'est la chaîne littérale du sous-système que vous voulez
vérifier (les variables ne peuvent être utilisées ici). Si le sous-système correspondant est activé et utilisé pour compiler le
programme, alors le compilateur « Subsystem() » renvoie True.

La Fonction « Defined() » du Compilateur


Lorsque vous créez un logiciel, vous devez parfois vérifier si un objet de données particulier a été défini. Ceci est
possible en utilisant la fonction « Defined() » du compilateur. Cette fonction nécessite deux paramètres : le premier est
l'objet de données que vous voulez vérifier et le second est le type de données de l'objet. Si cet objet particulier est
défini, alors la fonction « Defined() » du compilateur retourne True. La valeur de l'objet contrôlé n'a pas d'importance,
seule l'information est définie. Cette fonction permet de vérifier les objets de données suivants : constantes, variables,
tableaux, listes, structures et interfaces.

Si vous utilisez la fonction de compilation « Defined() », le premier paramètre ne peut contenir que le nom de l'objet à
vérifier - aucun des préfixes ou suffixes habituels normalement utilisés avec cet objet. Par exemple, les noms des
constantes ne doivent pas contenir de caractères « # », et les noms de tableaux et de listes ne doivent pas contenir de
parenthèses. Pour le second paramètre, le type d'objet à vérifier, vous pouvez utiliser des constantes intégrées, voici
une liste complète des constantes disponibles :

« #PB_Constant »
« #PB_Variable »
« #PB_Array »
« #PB_LinkedList »
« #PB_Map »
« #PB_Structure »
« #PB_Interface »
« #PB_Procedure »
« #PB_Function »
« #PB_OSFunction »

Mon explication semble montrer que c'est compliqué d'utiliser cette fonction, donc je vais vous débarrasser de cette
impression et vous montrer un exemple de sa simplicité. Cet exemple vérifie si la variable « Nom.s » est déjà définie,
sinon elle sera définie :

Global Nom.s = "Nom 1"


If Not Defined(Nom, #PB_Variable)
;Ceci ne définira cette variable que si elle n'a pas été définie auparavant.
Global Nom.s = "Nom 2"
EndIf
Debug Nom

Vous pouvez tester cet exemple en commentant la première ligne. Si vous faites ceci, la définition de la variable a
maintenant lieu à l'intérieur de l'instruction « If » et la variable string a maintenant la valeur « Nom 2 ». Un code comme
celui-ci n'a pas de prix dans les grands projets parce que vous voudrez peut-être inclure beaucoup de fichiers sources
dans le code principal et vérifier quelque chose d'important pour voir s'il a déjà été défini. Si ce n'est pas le cas,
définissez-le.

Options Avancées du Compilateur


Si vous utilisez PureBasic, vous devrez peut-être modifier les paramètres du compilateur pour un programme spécifique
ou vous voudrez peut-être que le compilateur affiche certaines informations. PureBasic vous donne la possibilité de le
faire en fournissant quelques options de compilation. Vous pouvez activer ou désactiver visuellement la plupart de ces
options. Utilisez la fenêtre « Compiler Options » dans l'IDE (menu : Compiler → Compiler Options...). Pour avoir accès à
toutes les options du compilateur prises en charge, vous devez appeler le compilateur depuis un interpréteur de ligne
de commande et passer toutes les options comme paramètres.
196 Au-Delà de l'Essentiel

Qu'est-ce qu'un interpréteur de ligne de commande ? Eh bien, c'est un petit programme qui est généralement livré
avec votre système d'exploitation (parfois appelé « Shell »). Ce programme vous permet de naviguer dans les
lecteurs de votre ordinateur ou de démarrer des programmes et de contrôler les fonctions de l'ordinateur avec des
commandes connues. Il n'a pas d'autre interface utilisateur que la saisie de texte.

Il existe de nombreux interprètes en ligne de commande, et ceux-ci semblent être parmi les plus populaires :

« CLI » sous AmigaOS


« CMD » sous Microsoft
« Windows BASH » sous Linux
«Terminal » sous MacOS X

Pour que ces interpréteurs de ligne de commande fonctionnent correctement avec PureBasic, vous devez inclure le
chemin complet du répertoire du compilateur dans votre variable d'environnement « PATH ». Ceci est nécessaire pour
que l'interpréteur de ligne de commande sache toujours exactement où trouver le compilateur. L'utilisation de la variable
d'environnement vous permet de sauvegarder le chemin complet du répertoire vers le compilateur lorsque vous l'utilisez
depuis la ligne de commande. Utiliser un interpréteur de ligne de commande n'est pas très convivial à mon avis, mais
c'est le seul moyen d'utiliser certaines des fonctionnalités les plus avancées du compilateur PureBasic. Je le dis, bien
qu'un compilateur qui peut être contrôlé depuis la ligne de commande a aussi des avantages, surtout si vous utilisez
votre propre éditeur de source. Dans ce cas, vous pouvez configurer le compilateur comme un outil externe.

Utiliser le Compilateur en Ligne de Commande


L'utilisation du compilateur en ligne de commande est relativement facile, il vous suffit de vous assurer que vous passez
tous les paramètres optionnels correctement. La commande du compilateur proprement dite commence toujours par le
nom du compilateur PureBasic, suivi de tous les paramètres requis. Le seul paramètre obligatoire est un fichier qui est
transmis au compilateur pour traitement. Pour créer un fichier exécutable dans sa forme la plus simple avec le
compilateur en ligne de commande, vous n'avez pas besoin de paramètres optionnels, mais vous avez besoin du nom
d'un fichier « *.pb ». Ouvrez une fenêtre d'interprétation en ligne de commande, tapez la ligne ci-dessous et appuyez sur
«Entrée» :

PBCompiler MonProgram.pb

Si votre variable d'environnement « PATH » est correctement configurée, cela lancera le compilateur PureBasic et
passera le fichier « MonProgram.pb ». Le compilateur crée un exécutable temporaire dans le répertoire du compilateur
et le lance de la même manière que si vous appuyiez sur le bouton « Compiler/Start » de l'IDE. C'est la façon la plus
simple de compiler un programme sur la ligne de commande.

Si vous voulez créer un exécutable avec un nom défini par l'utilisateur à partir de votre programme, qui est situé dans le
même répertoire que le code source, vous pouvez utiliser la commande suivante :

PBCompiler MonProgram.pb /exe "MonProgram.exe"

Cette instruction compile le fichier « MonProgram.pb » et crée un programme exécutable à partir de celui-ci. Cet
exécutable compilé reçoit le nom « MonProgram.exe » et est créé dans le même répertoire que le fichier « *.pb » .
Note, dans cette directive, nous utilisons une nouvelle option de compilation: « /exe » . Ceci indique au compilateur que
nous voulons créer un exécutable avec un nom significatif. La chaîne qui suit cette option du compilateur spécifie le
nom du fichier. Toutes les options du compilateur de ligne de commande commencent par une barre oblique « / »
comme ceci. Ces deux exemples sont relativement faciles à comprendre, mais en fait ils sont rarement utilisés dans la
pratique. Les programmeurs préfèrent utiliser l'IDE PureBasic à la place pour effectuer de telles compilations simples.
Cependant, il est utile de connaître ces deux éléments, surtout si vous voulez concevoir un nouvel éditeur de sources.

Si vous utilisez le compilateur en ligne de commande, il est également important de comprendre que vous pouvez
utiliser plusieurs options en même temps. Par exemple, si je veux compiler un fichier « *.pb » dans un exécutable et lui
assigner une icône, j'utilise une ligne de commande comme celle-ci :

PBCompiler MonProgram.pb /exe "MonProgram.exe" /icon ".\icons\MonIcon.ico"


Au-Delà de l'Essentiel 197

Le compilateur reconnaît que la chaîne derrière l'option « /exe » est le nom du fichier exécutable à créer et la chaîne
derrière l'option « /icon » est le fichier icône que nous voulons appliquer à l'exécutable. Toutes les options du
compilateur de ligne de commande doivent toujours être séparées par des espaces.

Options du Compilateur en Ligne de Commande PureBasic


Ce qui suit est maintenant une liste complète des options du compilateur de ligne de commande PureBasic, y
compris une explication de chacune d'elles et un petit exemple à utiliser. Rappelez-vous que la plupart de ces options
peuvent être activées dans l'IDE à l'aide d'une case à cocher ou d'un menu déroulant dans la boîte de dialogue «
Compiler Options ». Cela vous permet de contrôler plus facilement le comportement du compilateur. Tous ces
paramètres de ligne de commande ne sont pas sensibles à la case, ce qui signifie que vous pouvez les mettre en
majuscules ou en minuscules selon vos préférences.

« /? »
Cette option n'est disponible que dans la ligne de commande et affiche sur une page utile toutes les options du
compilateur de ligne de commande disponibles dans PureBasic. Cette page d'aide s'affiche dans la fenêtre de la ligne
de commande. Cette option du compilateur écrase toutes les autres options avec les options passées.

PBCompiler /?

« /Commented »
C'est une autre option disponible uniquement sur la ligne de commande et crée un fichier assembleur commenté
nommé « PureBasic.asm » dans le dossier« PureBasic\Compilers », avec l'exécutable créé. Ce fichier contient la sortie
du compilateur PureBasic sous forme d'assembleur brut après compilation du fichier« *.pb ». Ce fichier peut être
recompilé si, par exemple, vous avez apporté des modifications. Utilisez simplement l'option « /reasm » du compilateur
pour créer un exécutable à partir du fichier assembleur.

PBCompiler /commented

« /Console »
Cette option de compilation vous permet de créer une application en console seule. En voici un exemple simple :

PBCompiler MonProgramm.pb /exe "MonProgramm.exe" /console

Pour obtenir plus d'informations sur les programmes de la console, passez au chapitre 9 (Programmes de la console).

« /Constant (Nom=Valeur »
Cette option n'est également disponible que sur la ligne de commande et vous permet de définir dynamiquement une
constante sur la ligne de commande. Ceci peut être utile lors de la création d'un programme qui modifie sa
fonctionnalité en fonction de la valeur d'une constante. Par exemple: « DEMO=1 » ou « DEMO=0 ».

PBCompiler MonProgram.pb /exe "MonProgram.exe" /constant MY_STRING="Bonjour le Monde"

Comme vous pouvez le voir dans cet exemple, vous ne devez pas utiliser le caractère « # » comme préfixe lors de la
définition de la constante, et il ne doit y avoir aucun espace à côté du signe égal (« = »). Si vous définissez une
constante de chaîne, vous devez la mettre entre guillemets, comme je l'ai fait dans mon exemple. Ce n'est pas
absolument nécessaire, car le compilateur essaie automatiquement de convertir la valeur en chaîne si des guillemets
manquent, mais des erreurs peuvent se produire si la chaîne contient des espaces. Par mesure de sécurité, utilisez des
guillemets pour les chaînes de caractères.

« /Debugger »
Si vous n'utilisez que cette option du compilateur, le débogueur autonome (GUI) sera activé pour l'exécutable
temporaire généré. Si cette option est utilisée en combinaison avec l'option « /exe », le débogueur de console sera
inclus dans l'exécutable. Le débogueur de console affichera alors une fenêtre de console pendant l'exécution du
programme. Ceci permet de déboguer le programme sur la ligne de commande. En voici deux exemples :

PBCompiler MonProgram.pb /debugger


PBCompiler MonProgram.pb /exe "MonProgram.exe" /debugger
198 Au-Delà de l'Essentiel

« /DLL »
Cette option de compilation vous permet de créer une DLL (Dynamic Linked Library) à partir de votre code
source PureBasic. Si vous utilisez cette option pendant la compilation, la DLL créée sera stockée dans le répertoire
« PureBasic\Compilers » sous le nom « PureBasic.dll ». Vous pouvez renommer ce fichier comme vous le
souhaitez. Comme sous-produit de la création de DLL, une bibliothèque statique nommée « PureBasic.lib » et un
fichier exporté nommé « PureBasic.exp » sont créés dans le même dossier.

PBCompiler MonProgramm.pb /dll

Les fichiers de code source PureBasic utilisés pour créer les DLL sont généralement constitués uniquement de
procédures. Certaines de ces procédures doivent être spécialement nommées pour donner la fonctionnalité de la
bibliothèque à l'extérieur. Plus loin dans ce chapitre, vous trouverez plus d'informations sur les DLL.

« /DynamicCpu »
Cette option de ligne de commande équivaut à utiliser les options « /mmx » , « /3dnow » , « /sse » et « /sse2 »
ensemble. Si votre programme contient des routines d'assembleur de code source qui supportent toutes ces extensions
de processeur, et que vous utilisez l'option « /DynamicCpu » , l'exécutable résultant contiendra tout le code spécifique
du processeur. Que se passe-t-il lorsque cet exécutable est lancé ? Le programme examine le type de processeur et
sélectionne parmi les routines compilées celles qui sont les mieux optimisées pour cette architecture de processeur.
Cela signifie que le programme utilise dynamiquement différents codes contenus dans le programme pour chaque
architecture de processeur. Cela rend l'exécutable plus grand que d'habitude parce qu'il contient de nombreuses
versions différentes des mêmes routines, mais il peut accélérer considérablement votre programme car une version
optimisée des routines est utilisée pour chaque processeur.

PBCompiler MonProgramm.pb /exe "MonProgramm.exe" /dynamiccpu

« /Exe "NomFichier" »
Cette option de compilation est simple et directe. La chaîne qui suit la partie « /exe » est le nom que l'exécutable reçoit
après la compilation. La chaîne avec le nom du fichier doit toujours suivre la partie « /exe » et doit toujours être placée
entre guillemets, sinon des résultats inattendus peuvent survenir. Si vous créez un exécutable avec cette option, il sera
créé dans le même répertoire où se trouve le code source du programme.

PBCompiler MonProgramm.pb /exe "MonProgramm.exe"

« /Icon "NomIcon" »
Cette option de compilation vous permet de spécifier une icône sur votre disque dur que votre programme doit utiliser.
La chaîne après la partie'/Icon' doit être définie et placée entre guillemets. Il indique où se trouve l'icône sélectionnée
sur votre disque dur. La chaîne peut aussi contenir un chemin relatif, comme dans l'exemple :

PBCompiler MonProgramm.pb /exe "MonProgramm.exe" /icon ".\icons\monIcon.ico"

« /IgnoreResident "NomFichier" »
Cette option n'est disponible que sur la ligne de commande et vous permet d'empêcher le chargement d'un fichier
résident pendant la compilation. Ceci est pratique si vous voulez recompiler un fichier résident qui se trouve déjà dans
le dossier PureBasic\Residents. Si le fichier résident installé n'est pas ignoré lors de la compilation, vous obtiendrez des
messages d'erreur indiquant que certaines parties de votre fichier sont déjà définies.

PBCompiler MonProg.pb /resident "MonResid.res" /ignoreresident "MonResid.res"


PBCompiler MonProgramm.pb /exe "MonProgramm.exe" /ignoreresident "MonResid.res"

La première ligne montre un exemple où une version précédemment installée d'un fichier résident est ignorée. La
deuxième ligne indique comment procéder si vous devez redéfinir des structures ou des constantes dans votre
programme qui existent déjà dans un fichier résident installé.

« /InlineAsm »
Cette option permet le support de l' assembleur en ligne dans votre fichier « *.pb ». En d' autres termes, si vous avez
utilisé des commandes d'assembleur dans votre programme, vous devez activer cette option pour que les commandes
d'assembleur soient traitées correctement par le compilateur PureBasic.

PBCompiler MonProgramm.pb /exe "MonProgramm.exe" /inlineasm


Au-Delà de l'Essentiel 199

« /LineNumbering »
Cette option de compilation ajoute la prise en charge de la numérotation en ligne de commande interne à votre
exécutable. Ceci est très utile pour les outils de débogage tiers ou si vous utilisez la bibliothèque « OnError ».

PBCompiler MonProgramm.pb /exe "MonProgramm.exe" /linenumbering

Notez que l'utilisation de la numérotation des lignes peut affecter négativement la vitesse d'exécution de votre
exécutable car vous ajoutez plus de frais généraux au programme que d'habitude.

« /Linker "NomFichier" »
Cette option n'est disponible que sur la ligne de commande et vous permet de passer un fichier de commande de linker
directement au linker.

PBCompiler MonProgramm.pb /exe "MonProgramm.exe" /linker "MaCommandeLinker.txt"

« /MMX » , « /3DNow » , « /SSE et /SSE2 »


Ces quatre options du compilateur créent des exécutables spécifiques au processeur en fonction de l'option utilisée.
Une seule des options peut être utilisée à la fois, car elles sont incluses dans les routines exécutables qui ne
s'exécutent que sur des processeurs qui supportent ces extensions spécifiques. Si vous avez créé plusieurs routines
d'assembleur qui prennent en charge toutes les extensions de processeur, alors seules les routines qui correspondent à
l'option compilateur seront incluses dans l'exécutable. Par exemple, si vous créez un exécutable avec l'option « /mmx »
du compilateur, seules les routines MMX du code source seront utilisées dans le programme fini, et il ne fonctionnera
que sur les processeurs qui supportent MMX.

PBCompiler MonProgramm.pb /exe "MonProgramm.exe" /mmx


PBCompiler MonProgramm.pb /exe "MonProgramm.exe" /3dnow
PBCompiler MonProgramm.pb /exe "MonProgramm.exe" /sse
PBCompiler MonProgramm.pb /exe "MonProgramm.exe" /sse2

« /Quiet »
Cette option n'est disponible que sur la ligne de commande et supprime toute sortie de texte inutile du compilateur de
ligne de commande. C' est pratique si vous voulez utiliser le compilateur comme un outil externe à partir d' un autre
éditeur source, par exemple.

PBCompiler MonProgramm.pb /exe "MonProgramm.exe" /quiet

« /ReAsm »
Cette option n' est disponible que sur la ligne de commande et vous permet de réassembler et compiler un fichier
«*.asm » précédemment édité en utilisant le paramètre « /Commented ».

PBCompiler PureBasic.asm /reasm

Si vous utilisez cette commande, vous devez vous assurer que le fichier « *.asm » se trouve dans le dossier
« PureBasic\Compilers », sinon une erreur de compilation va se produire.

« /Resident "NomFichier" »
Cette option n'est disponible que sur la ligne de commande et vous permet de créer un fichier résident à partir d'un
fichier standard « *.pb » . Les fichiers résidents sont généralement utilisés pour prédéfinir les constantes et les
structures.

PBCompiler MonProgramm.pb /resident "MonResident.res"

Le paramètre doit être suivi d'une chaîne de caractères entre guillemets. Définit le nom de fichier du nouveau fichier
résident. Si cette chaîne est manquante ou n'est pas entourée de guillemets, une erreur de compilation se produit.
L'utilisation de cette option du compilateur crée un fichier résident dans le répertoire du code source sous-jacent.

« /Resource "NomFichier" »
Cette option n'est disponible que sous Microsoft Windows et inclut un fichier ressource dans la DLL ou l'exécutable
compilé. L'option « /resource » doit être suivie d'une chaîne de caractères entre guillemets spécifiant le fichier de
ressource à inclure. Un seul fichier de ressources peut être inclus, mais il peut contenir des références à d'autres
fichiers de ressources si nécessaire. Un fichier ASCII avec des références peut être passé à la place d'une ressource
compilée.

PBCompiler MonProgramm.pb /exe "MonProgramm.exe" /resource "MonResource.rc"


200 Au-Delà de l'Essentiel

« /Standby »
Cette option est utilisée par l' IDE pour charger le compilateur en mémoire, où il attend que les commandes lui soient
passées. Cette option n'est généralement pas utilisée par les utilisateurs normaux car l'interface du compilateur chargé
en mémoire est très peu documentée.

« /Subsystem "SubsystemName" »
Cette option de compilateur vous permet de spécifier un sous-système pour compiler votre programme. Une description
des sous-systèmes se trouve plus haut dans ce chapitre, je ne me citerai donc pas ici. Par défaut, il y a déjà quelques
sous-systèmes intégrés dans PureBasic que vous pouvez sélectionner pendant la compilation. Il s'agit de ce qui suit :

Windows:
PBCompiler MonProgramm.pb /exe "MonProgramm.exe" /subsystem "DirectX7"
PBCompiler MonProgramm.pb /exe "MonProgramm.exe" /subsystem "NT4"
PBCompiler MonProgramm.pb /exe "MonProgramm.exe" /subsystem "OpenGL"

Linux:
PBCompiler MonProgramm.pb /exe "MonProgramm.exe" /subsystem "GTK2"

MacOS X:
PBCompiler MonProgramm.pb /exe "MonProgramm.exe" /subsystem "GTK"
PBCompiler MonProgramm.pb /exe "MonProgramm.exe" /subsystem "GTK2"

Comme vous pouvez le voir, après la partie « /sous-système » de l'option compilateur, vous devez spécifier un nom de
sous-système entre guillemets.

« /Thread »
Cette option de compilation active le mode « Threadsafe » pour l'exécutable compilé. Vous devriez activer cette option
pour les programmes qui utilisent des threads. Notez que les programmes qui utilisent le mode'Threadsafe' fonctionnent
un peu plus lentement que les programmes qui n'utilisent pas cette option. Ceci est dû à l'administration interne plus
élevée requise pour une utilisation sûre des filetages.

PBCompiler MonProgramm.pb /exe "MonProgramm.exe" /thread

Vous trouverez plus d'informations sur les fils de discussion plus loin dans ce chapitre.

« /Unicode »
Cette option de compilation active le support Unicode pour l'exécutable compilé. Unicode est un schéma d'encodage de
caractères qui utilise 16 bits (2 octets) par caractère. Il est ainsi possible de stocker tous les caractères des langues
importantes du monde (vivants et morts) dans un seul jeu de caractères. L'utilisation de cette option de compilation
garantit que toutes les commandes PureBasic utilisées ainsi que la gestion interne des chaînes de caractères sont
entièrement compatibles Unicode.

PBCompiler MonProgramm.pb /exe "MonProgramm.exe" /unicode

« /Version »
Cette option de compilation n'est disponible que sur la ligne de commande. La seule fonction est d' afficher la version
du compilateur dans la fenêtre de ligne de commande. Cette option remplace toutes les autres options de la même
instruction de ligne de commande.

PBCompiler /version

« /XP »
Cette option de compilation n' est disponible que sous Microsoft Windows. Il active la prise en charge de l' habillage
Windows XP pour votre exécutable. Ceci affichera tous les gadgets que vous utilisez dans le style de thème Windows
XP si le thème Windows XP est activé pour l'utilisateur.

PBCompiler MonProgramm.pb /exe "MonProgramm.exe" /xp


Au-Delà de l'Essentiel 201

Evaluation des Paramètres de la Ligne de Commande


Vous souhaitez peut-être créer un outil en ligne de commande avec PureBasic, auquel vous pouvez passer différents
paramètres lorsque vous appelez. Le compilateur PureBasic fonctionne de la même manière. Le programme est lancé
et les paramètres lui sont transmis lorsqu'il est appelé. Les valeurs de ces paramètres déterminent la fonction exécutée
par le programme. Dans cette section, je vais vous montrer comment évaluer et traiter les paramètres transmis à votre
programme.

Que sont les Paramètres ?


Lorsque vous passez des paramètres (parfois appelés arguments) à un programme en ligne de commande, vous
devez faire attention comment vous les passez et comment ils sont utilisés. Par exemple, si nous regardons cet
exemple de compilateur du chapitre précédent :

PBCompiler MonProgramm.pb /exe "MonProgramm.exe"

Cette commande demande au système d'exploitation de démarrer le programme « PBCompiler » et lui passe trois
paramètres (MonProgram.pb /exe "MonProgram.exe''). Même si nous n'utilisons qu'une seule option de compilation
après le nom de fichier « *.pb » (le premier paramètre), cette option contient toujours deux paramètres.

Quand nous passons des paramètres à un programme de cette façon, le programme prend la décision sur le nombre de
paramètres basés sur les espaces qui se produisent dans le paramètre String. Si vous voulez passer des espaces dans
un seul paramètre, vous devez mettre ce paramètre entre guillemets. Par exemple, toutes ces commandes de ligne de
commande passeraient deux paramètres au programme « MonProgram » :

MonProgramm /a 105
MonProgramm /jeux /maintenant
MonProgramm /jeux "je joue avec mon ombre"
MonProgramm "remet le en" "place"

Comme vous pouvez le voir dans ces exemples, les paramètres peuvent être constitués de nombres ou de chaînes
de caractères. Cependant, lorsqu'ils sont passés au programme, ils sont automatiquement convertis en chaînes de
caractères. Si vous passez des paramètres entre guillemets (en particulier pour les paramètres qui contiennent des
espaces), ces guillemets sont tronqués avant d'être passés. Cela signifie que seule la chaîne intermédiaire est passée,
pas les guillemets.

Lecture des Paramètres Transférés dans votre Programme


Lorsque les paramètres sont transmis d'un appel en ligne de commande à votre programme, ils sont stockés en
interne pour vous, prêts à être récupérés quand vous en avez besoin. En appelant la commande « ProgramParameter()
» vous pouvez récupérer un paramètre à la fois dans cette liste interne. Lorsque vous avez récupéré tous les
paramètres avec cette commande, elle retourne une chaîne vide. Voici un exemple de programme qui liste tous les
paramètres passés au programme :

NumberOfParameters.l = CountProgramParameters()
Text.s = "Liste des paramètres passés :" + #LF$
+ #LF$
If NumberOfParameters > 0
For x.l = 1 To NumberOfParameters
Text.s + ProgramParameter() + #LF$
Next x
Else
Text.s + "Non"
EndIf
MessageRequester("Info", Text)

La première ligne de cet exemple utilise la fonction « CountProgramParameters() ». Ceci retourne le nombre exact
de paramètres valides passés. Après avoir appelé cette fonction, j'utilise une boucle « For » dans laquelle
j'appelle la fonction « ProgramParameter() » à chaque passage de boucle. J'obtiens donc tous les paramètres valides.
Quand je compile cet exemple dans un exécutable nommé « ListeParameter.exe », je peux passer des paramètres à ce
programme sur la ligne de commande, comme ici :

ListeParameter /un /deux /trois


202 Au-Delà de l'Essentiel

Je n'ai donné ces paramètres qu'à titre d'exemple, bien sûr vous pouvez spécifier tous les paramètres arbitraires.
J'ai utilisé une barre oblique « / » comme préfixe pour mes paramètres, parce que c'est presque une norme et est
attendu par de nombreux programmes de console. Si la ligne de commande a été saisie ainsi, alors la variable
« NumberParameter » contient la valeur « 3 » et chaque fois que le programme appelle la fonction
« ProgramParameter() », chacun de ces paramètres est retrouvé dans la séquence. La première fois qu' il est utilisé.
« ProgramParameter() » renvoie « /one », le deuxième appel renvoie « /two » et le troisième appel renvoie
« /three ». Si j'ai appelé la fonction ProgramParameter() une quatrième fois, la valeur retournée serait une chaîne vide.

Test des Paramètres de Ligne de Commande dans l'IDE

Si vous développez une application dans l'IDE qui accepte les paramètres de ligne de commande, vous ne
voudrez peut-être pas compiler l'application à chaque fois et l'appeler depuis la ligne de commande pour la tester.
l'IDE PureBasic vous débarrasse de cette longue procédure en fournissant un champ de saisie dans lequel vous
pouvez entrer les paramètres de ligne de commande à transmettre au moment de la compilation. Ce champ se
trouve dans la boîte de dialogue « Options du compilateur », accessible via le menu « Compilateur ». Si vous
sélectionnez l'onglet « Compiler/Démarrer » dans cette boîte de dialogue, vous trouverez un champ de saisie au
milieu avec l'étiquette « Ligne de commande exécutable: ». Dans ce champ, vous entrez les paramètres que vous
voulez passer au démarrage du programme avec la commande « Compiler/Exécuter » Saisissez ici quelques
paramètres afin de pouvoir tester les exemples de cette section.

Prise de Décision Basée sur des Paramètres Passés


Si vous utilisez des paramètres de ligne de commande pour contrôler la fonctionnalité ou la sortie de votre programme,
vous en aurez besoin pour effectuer différentes actions en fonction des valeurs de ces paramètres passés. Parfois, vous
aurez besoin de votre programme pour faire quelque chose de complètement différent si un paramètre particulier est
passé. Il n'est pas aussi difficile que vous le pensez de prendre des décisions basées sur les paramètres qui ont été
transmis, vous n'avez qu'à utiliser les énoncés réguliers « If » et « Select » pour tester les valeurs des paramètres.

L'exemple suivant illustre cette approche, en vérifiant si un ou plusieurs des paramètres passés sont « souris » , « chat
» ou « chien » Essayez de passer un ou deux de ces paramètres à ce programme pour voir la sortie :

;Paramètres de comptage
NumberOfParameters.l = CountProgramParameters()

;Ajouter tous les paramètres de la ligne de commande à une NewList.


Global NewList Parameters.s()
If NumberOfParameters > 0
For x.l = 1 To NumberOfParameters
AddElement(Parameters())
Parameters() = UCase(ProgramParameter())
Next x
EndIf

;Vérifier si un paramètre particulier a été passé.


Procedure ParameterPassed(Parameter.s)
ForEach Parameters()
If Parameter = Parameters()
ProcedureReturn #True
EndIf
Next
ProcedureReturn #False
EndProcedure

;Vérifier si le paramètre'Souris' a été passé.


If ParameterPassed("MOUSE")
MessageRequester("Info", "'Souris' a été spécifié comme paramètre.")
EndIf
;Vérifier si le paramètre'Cat' a été passé en paramètre'Chat'.
If ParameterPassed("CHAT")
MessageRequester("Info", "'Chat' a été spécifié comme paramètre.")
EndIf
;Vérifier si le paramètre'Chien' a été passé en paramètre'Chien'. If
ParameterPassed("CHIEN")
MessageRequester("Info", "'Chien' a été spécifié comme paramètre.")
EndIf
Au-Delà de l'Essentiel 203

Si vous regardez attentivement cet exemple, j'utilise la commande « UCase() » (fichier d'aide : Manuel de référence
Bibliothèques générales->Chaîne->UCase) pour convertir tous les paramètres passés en lettres majuscules. Ceci afin
que je puisse effectuer des comparaisons de chaines sur les paramètres sans me soucier de la case. Si vous le faites
dans vos programmes, alors vous pouvez simplement utiliser des comparaisons de chaînes de caractères majuscules,
comme indiqué dans les instructions « If ». C'est une bonne pratique car peu importe la façon dont l'utilisateur saisit les
paramètres (majuscules, minuscules, case mixte), ils seront toujours convertis en majuscules avant la comparaison« If »

Donner à vos programmes un support en ligne de commande en utilisant des paramètres de cette façon peut sembler
une façon démodée de faire les choses, et pour être honnête, c'est le cas. Cependant, donner à vos utilisateurs la
possibilité d'utiliser votre application ou votre outil à partir de la ligne de commande permettra à plus de personnes de
l'utiliser et donnera plus de polyvalence au programme. C'est certainement quelque chose à prendre en compte lors de
la création d'un logiciel.

Un Examen plus Approfondi des Types de Données Numériques


Les types de données numériques vous permettent de stocker des nombres dans différents formats et chaque type
vous permet d'utiliser des quantités de mémoire légèrement différentes pour stocker ces nombres. Cela n'a pas l'air si
important, mais la quantité de mémoire qu'un type numérique utilise définit strictement sa limite numérique. Si vous
regardez en arrière dans le chapitre 2 de la Fig.2, vous verrez un diagramme détaillant toutes les limites de type
numérique de PureBasic. Ces limites sont imposées par le nombre fini de bits contenus dans la mémoire que ces types
de données allouent. Par exemple, si vous regardez le type de données d'octet « .b » vous verrez qu'il utilise un octet de
mémoire, qui se compose de huit chiffres binaires ou « bits ». Ces bits ne peuvent être manipulés que d'une quantité
limitée de façons d'exprimer les nombres. En fait, huit bits ne peuvent être ordonnés qu'en deux cent cinquante-six «
256 » motifs uniques, chaque bit étant'1' ou'0'. Cela signifie que seuls deux cent cinquante-six nombres uniques peuvent
être exprimés par un nombre binaire de huit bits « 1 octet.

Dans cette section, je vais vous expliquer comment les nombres sont stockés en mémoire et comment les nombres
binaires sont réellement calculés. Espérons que cela vous donnera un peu plus d'informations sur le fonctionnement
interne non seulement de PureBasic mais aussi des ordinateurs en général.

Lorsque l'on traite des nombres dans les langages informatiques, il faut faire une distinction claire entre les nombres
entiers et les nombres à virgule flottante. Les nombres entiers sont des nombres qui peuvent être positifs ou négatifs
mais qui ne contiennent pas de point décimal. Les nombres à virgule flottante, par contre, peuvent être positifs ou
négatifs mais contiennent toujours une virgule décimale. Cela a été expliqué plus tôt dans ce livre, mais j'ai pensé vous
rafraîchir la mémoire ici.

Qu'est-ce que le Binaire ?


La notation binaire, ou base-deux comme on l'appelle parfois, est un système numérique où les chiffres d'un nombre
binaire ne peuvent avoir qu'une seule des deux valeurs, « 1 » ou « 0 ». Semblable au système décimal (qui est parfois
appelé base-dix) chaque position d'un chiffre binaire représente une autre grandeur.

Permettez-moi d'expliquer ce concept un peu plus en détail. Voici un exemple de nombre décimal :

542

Dans cet exemple, le chiffre « 2 » est dans la position associée à la quantité « 1 », le chiffre « 4 » est dans la position
associée à la quantité « 10 » et le chiffre « 5 » est dans la position associée à la quantité « 100 ». Chaque quantité
associée est dix fois plus grande que la quantité à sa droite. Pour connaître le nombre que cela représente, il suffit de
multiplier la valeur de chaque chiffre par la quantité associée à la valeur de ce chiffre. et additionnez ensuite ces
résultats ensemble, c'est-à-dire « 5 » x cent) + (« 4 » x dix) + (« 2 » x un) = « 542 » (cinq cent quarante-deux).

C'est également ainsi que les nombres binaires (base-deux) fonctionnent lorsqu'il s'agit d'entiers. La position de chaque
chiffre d'un nombre binaire est également associée à une quantité, sauf que la quantité associée à chaque position est
le double de celle de la position à sa droite, c'est-à-dire la base deux après tout. Bien que cela puisse sembler une
bouchée, c'est étonnamment facile à comprendre à l'aide d'un diagramme. Regardez la Fig.44.
204 Au-Delà de l'Essentiel

Octet non signé

Chiffres Binaires(Bits) 0 1 0 0 1 1 0 1 = 77

Valeurs Attribuées 128 64 32 16 8 4 2 1

Nombre de 8 bits
(1 octet)

Plage numérique: « 0 » à « 255 ». Fig. 44

Pour extraire la valeur représentée par ce nombre binaire, on suit la même procédure qu'en décimal (base-dix). On
multiplie la valeur de chaque chiffre par la quantité associée à sa position puis on additionne les résultats. Par exemple,
la valeur représentée par « 0100110101 », comme le montre la figure 44, est « 77 ». Puisque la notation binaire n'utilise
que les chiffres « 0 » et « 1 ». ce processus de'multiplication et d'addition' démontré précédemment avec des nombres
de base - dix, réduit à l'addition des quantités associées aux positions occupées par une valeur binaire de « 1 ». Ainsi,
si vous regardez la Fig.44 et additionnez les quantités où une valeur binaire de« 1 » apparaît, vous obtenez : « 64 + 8 +
4 + 4 + 1 = 77 ».

Vous pouvez probablement voir maintenant à partir de la Fig.44 que seule une quantité finie de nombres peut être
représentée en binaire en utilisant seulement ce nombre de bits. C'est pourquoi certains types ont certaines limites, ils
sont simplement à court de bits à utiliser. Les plus gros types fonctionnent exactement de la même manière, ils ont juste
plus de bits à calculer.

Nombres Entiers Signés et non Signés


Plus tôt dans la Fig.2, vous pouvez voir que de nombreux types d'entiers de PureBasic vont des nombres négatifs aux
nombres positifs. Ceux-ci sont connus sous le nom de types de nombres signés, car leurs valeurs peuvent
potentiellement contenir un signe négatif. Les types non signés, d'autre part, se réfèrent aux types entiers qui ont une
limite numérique qui va de zéro à un nombre positif plus grand. Le type de caractère PureBasic est un exemple d'un
type entier non signé et qui est également illustré à la figure 2. Parce qu'il n'y a qu'un nombre fini de bits alloués par ces
types de données, il y a deux méthodes nécessaires pour interpréter ces nombres binaires selon qu'ils doivent être lus
comme signés ou non signés.

Si vous jetez un coup d'oeil à la Fig.45, chaque type de données entières a deux façons d'être lu. L'octet par exemple,
peut être à la fois signé et non signé, et les deux saveurs peuvent contenir une valeur prise dans une plage de deux
cent cinquante-six « 256 » nombres possibles, dont zéro...oui, zéro est un

Type de Données Plage de valeurs numériques

octet signé -128 bis 127

octet non signé 0 bis 255

word signé -32768 bis 32767

word non signé 0 bis 65535

Long signé -2147483648 bis 2147483647

*Long non signé 0 bis 4294967295

* Ce type de données n'est pas disponible dans PureBasic (peut-être dans une version ultérieure ?) Fig. 45

Lecture de Nombres Entiers Non Signés à l'Aide d'une Notation Binaire


Un nombre non signé est facile à représenter en binaire comme nous l'avons vu sur la Fig.44. Il suffit de continuer à
tourner les bits à « 1 » et d'additionner les valeurs associées où un « 1 » apparaît. Par exemple, la valeur maximale d'un
octet non signé exprimé en binaire est « 1111111111 » (« 255 »), où tous les bits sont mis « 1 ». C'est simple et
agréable.
Au-Delà de l'Essentiel 205

Lecture de Nombres Entiers Signés à l'Aide d'une Notation Binaire


Un entier signé suit des règles légèrement différentes pour s'exprimer en binaire. PureBasic utilise un système appelé
"Two's" Complement pour exprimer des entiers signés. Dans la forme du complément de deux, le bit le plus à gauche
d'un nombre binaire signé (parfois appelé bit le plus significatif) « MSB » indique si le signe réel (-) est présent dans
l'entier. Si le bit « MSB » le plus à gauche est « 0 », l'entier exprimé par les bits est un entier positif et peut être lu en
utilisant la méthode binaire non signée expliquée précédemment. Si le bit « MSB » le plus à gauche est « 1 », l'entier
exprimé est négatif et doit être lu en utilisant la forme du complément de deux, comme expliqué ci-dessous.

Parce que le bit « MSB » signe le plus à gauche est réservé pour indiquer si un signe est présent ou non, il ne vous
reste plus que le reste des bits pour exprimer le reste de l'entier. Prenons encore un octet comme exemple, si nous
laissons le bit de signe'0' pour exprimer un nombre positif qui ne nous laisse que sept bits restants pour en faire un
nombre, alors nous allons les transformer tous en « 1 », comme ceci : « 01111111 ». Ceci exprime maintenant le
nombre entier positif maximum qu'un octet signé peut contenir, qui dans ce cas est « 127 ».

Si nous voulons exprimer un entier négatif en binaire, nous devons le faire d'une manière légèrement différente.
Regardons d'abord la représentation binaire non signée du nombre « 9 », qui est « 00001001 ». Le bit « MSB » le plus
à gauche est « 0 », donc nous savons qu'il s'agit d'un entier positif. Pour convertir ceci en la forme de complément de
deux et l'exprimer comme un entier négatif, nous devons d'abord inverser les bits et ensuite nous ajoutons un « 1 » au
nombre binaire inversé. Le chiffre « -9 » ressemble donc à ceci : « 11110111 ». Quand je parle d'inverser les bits, ce
que je veux dire c'est que si un bit est « 0 » alors changez-le en « 1 », et si un bit est « 1 » alors changez-le en « 0 » et
faites ceci pour tous les bits contenus dans ce type. Comme vous pouvez le voir, le bit le plus à gauche est maintenant «
1 » indiquant que ce nombre binaire représente un entier négatif (signé). Inverser les bits et ajouter « 1 » à un entier
positif est la méthode complémentaire des deux pour exprimer la forme négative de cet entier.

Pour convertir cet entier négatif en sa forme positive, vous suivez exactement la même procédure. Après avoir inversé
« -9 » « 11110111 », le nombre binaire ressemble maintenant à ceci : « 00001000 ». nous ajoutons alors un « 1 » à ce
nombre et il devient: « 00001001 », ce qui nous donne un « 9 » positif quand on utilise la méthode binaire normale non
signée. La Fig.46 montre un octet signé contenant visuellement la valeur « -9 ».

Octet signé
Signé (-) Bit

Chiffres Binaires (Bits) 1 1 1 1 0 1 1 1 = -9

Valeurs Attribuées 64 32 16 8 4 2 1

Nombre de8 Bit


(1 octet)

Plage Numérique : « -128 » bis «127» Fig. 46

Même si j'ai utilisé le type d'octet dans ces dernières sections pour décrire comment lire binaire, ces méthodes sont
universelles pour tout type d'entier numérique, quelle que soit sa taille. Dans tous les types d'entiers, les grandeurs
associées à chaque position binaire augmentent d'une puissance de « 2 » lorsque vous vous déplacez vers la gauche
dans le nombre binaire. Dans les nombres binaires signés, le bit le plus à gauche est toujours le bit de signe.

Nombres à Virgule Flottante et Notation Binaire


Un nombre à virgule flottante est un nombre qui contient un point décimal et peut être positif ou négatif. De tels nombres
sont mémorisés de manière à ce que la virgule décimale du nombre puisse se déplacer, de sorte qu'il est possible de
mémoriser des nombres très grands ou très petits. L'utilisation d'une telle méthode de stockage permet d'avoir une
grande variété de numéros qui peuvent être stockés, mais au prix de la précision numérique. Même si les nombres à
virgule flottante sont extrêmement polyvalents, vous devez tenir compte du fait qu'une certaine précision peut être
perdue si vous stockez un grand nombre de décimales.
206 Au-Delà de l'Essentiel

PureBasic supporte actuellement deux types de données pour gérer les nombres à virgule flottante, ce sont le type de
flottant normal et le type double. La différence entre ces deux types est la quantité de bits qu'ils utilisent pour stocker le
nombre de virgule flottante. Un flottant utilise 32 bits (4 octets) et un double utilise 64 bits (8 octets), donc évidemment
les doubles sont beaucoup plus précis pour contenir de grands nombres. Alors pourquoi ne pas utiliser des doubles tout
le temps, au lieu de flottants ? Eh bien, la vitesse pour une personne. Les flottants peuvent être beaucoup plus rapides à
lire à partir de la mémoire, en particulier lors de l'utilisation de grands tableaux de flottants. Ceci est dû au fait que vous
ne récupérez que la moitié du nombre d'octets de la mémoire que vous ne le feriez avec les doubles. Habituellement, les
programmes tels que les jeux ont tendance à utiliser des Flottants tandis que les programmes qui nécessitent plus de
précision ont tendance à utiliser des Doubles.

Stockage de Valeurs en VirguleFlottante en Notation Binaire


En raison de la nature particulière des valeurs en virgule flottante, qui doivent stocker un point décimal avec un grand
nombre à gauche, à droite ou des deux côtés du point décimal, une autre forme de codage binaire est utilisée. Cette
méthode est assez compliquée et est décrite dans la norme « IEEE 754 » pour le codage binaire en virgule flottante. Je
vais essayer de la décrire aussi simplement que possible.

Tout d'abord, toutes les valeurs en virgule flottante sont stockées en trois parties binaires. Ces parties sont le signe,
l'exposant et la mantisse. Ces trois parties sont toutes comprises dans le nombre de bits disponibles pour le type, que
vous utilisiez Flottant ou Double. Se reporter à la Figure 47.

32 Bit Flottant
Bit Signé

Exposant Mantisse
(8 Bit) (23 Bit)

0 10 000 000 10 010 010 000 111 111 011 011

31 30 23 22 Bit Index 0

64 Bit Double ( Précision de Flottant)

Exposant Mantisse
(11 Bit) (52 Bit)
Bit Signé

0 1 001 00 000 00 10 010 01 000 011 11 110 11 011 100 10 010 000 11 111 101 10 110 11 011

63 62 52 51 Bit Index 0

Fig. 47

Ici, vous pouvez voir comment le type est divisé en interne pour supporter chacune des trois sections. Maintenant, tout
ce que nous avons besoin de comprendre, c'est comment un nombre à virgule flottante est encodé pour s'insérer dans
ces sections. Le bit de signe est probablement la section la plus facile à expliquer. Si le nombre à coder est positif, le bit
de signe sera « 0 » et si le nombre est négatif, le bit de signe sera « 1 ». Commençons par un numéro d'exemple et je
vais montrer comment il est encodé dans un Flottant 32 bits. Prenons le numéro: «10,625 ».

Première Etape, Coder le Nombre en Notation Binaire


Pour coder le nombre de façon à ce qu'il corresponde aux plages binaires du type flottant, nous avons besoin d'effectuer
plusieurs étapes. La première est de convertir les deux côtés du point décimal en notation binaire, comme ici :

10,625 = 1010.101

Cela semble un peu étrange parce que vous n'avez probablement jamais vu un point décimal (ou plus précisément un
point radian) dans un nombre binaire. Ne vous inquiétez pas, cette orthographe ne sert qu'à visualiser le nombre à ce
stade. Le codage binaire d'un nombre comme celui-ci est un peu différent de ce que j'ai expliqué avant, parce que nous
avons affaire à un entier d'un côté et une fraction de l'autre côté du point radian. La partie entière est rapidement
convertie car elle suit le codage standard pour les nombres binaires que j'ai expliqué dans la Fig. 44, par exemple,
correspond à Décimale «10» = Binaire « 1010 » La fraction de l'autre côté utilise une méthode similaire, cependant, les
bits individuels dans la notation binaire représentent des valeurs différentes, ce sont même des fractions au lieu de
nombres entiers. De plus, nous ne remplissons pas ces chiffres avec des zéros inutiles.
Au-Delà de l'Essentiel 207

Dans le codage binaire non signé standard, les valeurs assignées aux bits commencent par «1» et augmentent vers la
gauche avec le facteur « 2 ». Avec la représentation des fractions en notation binaire, les valeurs assignées
commencent par « 0,5 », puis deviennent plus petites du facteur « 2 » lorsque vous vous déplacez vers la droite.
Regardez la Fig. 48.

Codage d'une Fraction Décimale en Notation Binaire

Nombre Origine: 10,625


Le nombre entier peut être encodé comme ceci :

Ciffres Binaires (Bits) 1 0 1 0 (8+2) = 10

Valeurs Attribuées 8 4 2 1

Point radian

La fraction est codée comme suit :

Chiffres Binaires (Bits) 1 0 1 (0.5 + 0.125) = .625

Valeurs Attribuées 0.5 0.25 0.125

Point radian

Fig. 48

Ici, vous pouvez voir que les valeurs assignées de la fraction binaire commencent par « 0,5 » et deviennent plus petites
par le facteur « 2 » à chaque endroit se déplaçant vers la droite, c'est pourquoi elles sont calculées de cette façon : «
0.5 »,« 0.25 »,« 0.125 », etc. Plus vous allez vers la droite, plus plus un nombre fractionnaire peut contenir de précision.
Puisque notre nombre contient la fraction « .625 » il est facilement représenté par « 0.5 » + « 0.125 ». c'est là que les
binaires « 1 » apparaissent.

Savoir comment un nombre fractionnaire est représenté en binaire ne vous aide pas nécessairement à l'encoder, surtout
quand il s'agit de fractions décimales énormes. Heureusement, il existe un moyen facile d'encoder ces numéros en
utilisant l'astuce du « doublement ».

Tout d'abord, nous prenons notre fraction de départ '.625' eet nous doublons cette somme. Ensuite, nous vérifions si le
résultat est supérieur ou égal à « 1.0 ». Si c'est le cas, nous marquons un « 1 » binaire. Nous prenons alors la partie
fractionnaire de la dernière somme, la doublons et la testons à nouveau. Si, à un moment quelconque, le doublement ne
produit pas un nombre égal ou supérieur à « 1,0 », nous marquons un « 0 » binaire. Voici comment cela fonctionne en
pratique :

.625 * 2 = 1.25 - Le résultat est supérieur ou égal à « 1 »,c'est pourquoi on note un binaire « 1 »
.25 * 2 = 0.5 - Le résultat est inférieur à « 1 », c'est pourquoi nous notons un binaire « 0 »
.5 * 2 = 1.0 - Le résultat est supérieur ou égal à « 1 », c'est pourquoi nous notons un binaire « 1 »

S'il ne reste plus de fractions ou si les positions binaires disponibles sont épuisées, arrêter le calcul. Si vous regardez
maintenant le résultat binaire de ce calcul de haut en bas, vous verrez la combinaison binaire « 101 », exactement ce que
nous attendions pour « .625 ».

Maintenant que nous savons comment coder un nombre décimal fractionnaire en binaire, je peux continuer à expliquer
comment ces nombres sont codés en 32 bits Flottant. Donc, la première étape était d'abord de coder notre numéro dans
une forme binaire, comme ceci :

10.625 = 1010.101
208 Au-Delà de l'Essentiel

Deuxième étape : Déplacement du Point Radian et Calcul de l'Exposant


Dans cette étape, nous devons déplacer le point radian, car il n'est pas inclus dans le nombre binaire fini. Puisque le
point radian définit où se trouve le point décimal dans la version décimale de ce nombre, nous n'avons en fait qu'à nous
rappeler où il se trouvait et nous pouvons ensuite le décoder à la position originale. Pour ce faire, nous déplaçons le
point radiiant du nombre binaire jusqu'à ce qu'il ne reste plus qu'un «1» de ce point. Les autres zéros à gauche du
dernier peuvent être ignorés, mais leur position doit être comptée lorsque le point de radian les dépasse. Regardez cet
exemple :

1010.101 (Original)
1.010101 (Point de radian décalé de 3 chiffres vers la
gauche)

Si vous déplacez le point radian, nous devons noter le nombre d'endroits où nous le déplaçons. Ici, je l' ai déplacé de
« 3 » vers la gauche pour garder un « 1 » en tête sur son côté gauche, donc le nombre de mouvements est un nombre
place. Par exemple, si le nombre original avait la valeur « 0.000110101 » alors je devrais déplacer le point radian vers la
droite jusqu'à ce qu'il soit un « 1 » à sa gauche (sans tenir compte des zéros). Il en résulte une valeur de mouvement
radian négative de « -4 ». (J'expliquerai la raison pour laquelle le « 1 » est toujours à gauche).

Le nombre de chiffres par lequel vous devez déplacer le point radian jusqu'à ce qu'il ne reste plus qu'un « 1 » à sa
gauche s'appelle un exposant. Cet exposant est ensuite ajouté à un nombre prédéfini (selon la taille du type de virgule
flottante que vous utilisez) pour s'assurer que le nombre codé n'est pas signé. Par exemple, si vous utilisez un type de
flottant 32 bits, vous devez ajouter la valeur « 127 », si vous utilisez un double type 64 bits, vous devez ajouter « 1023 »
ces valeurs sont appelées biais exposant.

Dans notre exemple original, nous avons déplacé le point radian « 3 » vers la gauche (ce qui est un 3 positif), donc nous
ajoutons « 127 » à ce « 3 » et obtenons « 130 ». Ce nombre est ensuite codé en binaire à l'aide de la méthode standard
non signée décrite à la Fig.44, qui serait « 10000010 ». Celle-ci est ensuite sauvegardée dans la section exposant à
l'intérieur du flottant 32 bits comme illustré à la Fig. 47. Comme nous enregistrons le nombre d'endroits où le point
radian s'est déplacé, cela signifie que le nombre de bits de la section de l'exposant impose en fait une limite à la
distance à laquelle nous pouvons enregistrer le déplacement du point radian. Cette limite est « 127 » chiffres à gauche
et « (-)126 » chiffres à droite. Si la valeur est supérieure à « 127 », le nombre est interprété comme « infini » i la valeur
est inférieure à « -126 », le nombre est appelé « dénormalisé », ce qui constitue un cas particulier où l'exposant est
maintenu à « -126 » et le premier « 1 » est remplacé par un « 0 ». Dans la limite inférieure, le nombre est interprété
comme « 0 ».

Troisième Etape, le Calcul de la Mantisse


La mantisse est la partie du nombre flottant qui contient la partie significative du nombre. En fait, c'est là que le nombre
réel est stocké, l'exposant indique seulement où le point radian est relatif à la mantisse. Après avoir déplacé le point
radian à l'étape 2, notre nombre devrait maintenant ressembler à ceci: « 1.01010101 ».

Pour calculer la mantisse, nous ignorons d'abord le premier « 1 » du nombre binaire. Ce « 1 » n'a pas besoin d'être
codé, car il est toujours présent. Chaque nombre que nous codons pour un type de virgule flottante a toujours ce « 1 ».
C'est pourquoi il est absolument correct si nous omettons ce numéro lors du codage, nous devons seulement nous
rappeler de l'insérer à nouveau lors du décodage. L'omission de ce nombre nous donne un peu plus dans la mantisse et
nous aide à stocker le nombre décimal original plus précisément. N'oubliez pas que plus nous avons de bits disponibles,
plus le nombre original peut être stocké avec précision.

Après avoir ignoré le « 1 » devant le nombre binaire, le point radian n'a plus aucun sens, donc on peut s'en débarrasser
aussi. Maintenant le nombre binaire ressemble à ceci: « 01010101 ». C'est maintenant notre mantisse. Si la mantisse
est plus petite que 23 bits (ce qui est le cas dans notre exemple), alors nous devons remplir la mantisse jusqu'à une
longueur de 23 bits avec des zéros. Les zéros doivent être à droite, comme ici : « 01010100000000000000000
». C'est maintenant la mantisse complète stockée dans la zone de la mantisse du numéro flottant 32 bits (voir Fig. 47).

Ainsi, le nombre « 10,625 » en notation binaire ressemble à ceci :


« 0 10000010 01010100000000000000000 »
Au-Delà de l'Essentiel 209

Limites des Valeurs en Virgule Flottante


Même si les nombres en virgule flottante sont très polyvalents, ils sont également inexacts par nature en raison de la
façon dont le nombre est stocké en binaire. Ne soyez pas choqué de voir un numéro lu à partir d'un Flottant qui était
différent de ce qui lui avait été assigné à l'origine. Seuls 7 chiffres décimaux environ sont représentés correctement dans
les Flottants de précision simple et 16 dans les Flottants doubles. La précision des nombres décimaux peut également
être perdue lorsque l'on effectue des calculs arithmétiques avec des nombres à virgule flottante, ce qui réduit à nouveau
la précision globale. C'est toujours quelque chose à garder à l'esprit lors de l'utilisation des flottants et des doubles.

Utilisation Directe des Nombres Binaires dans PureBasic


Les nombres binaires peuvent être assignés directement aux variables en utilisant le préfixe « % ». Il ne faut pas
confondre l'utilisation du signe pourcentage avec l'opérateur modulo du chapitre 3 (Introduction aux opérateurs), même
s'ils utilisent le même symbole. PureBasic reconnaît ceci comme une affectation binaire parce qu'il n'y a pas
d'expression à sa gauche et qu'il n'y a pas d'espace à sa droite. En voici un exemple :

BinaryVariable.b = %01101101
Debug BinaryVariable

Vous pouvez assigner des valeurs à tous les types numériques de PureBasic de cette manière binaire.

Pointers
Je pense qu'il est juste de vous dire que les pointeurs dans les programmes informatiques font peur à beaucoup de
gens. Je ne peux pas expliquer pourquoi, parce que les pointeurs peuvent donner un pouvoir immense pour traiter
certains problèmes de programmation. C'est peut-être la peur de l'inconnu qui fait que les gens les évitent ? Je ne sais
pas, mais ce que je sais, c'est que lorsqu'on explique correctement les pointeurs aux gens, ils se demandent toujours
pourquoi ils les ont évités après avoir recu une explication de manière compréhensible. Cette section suivante traite des
pointeurs, de la façon dont PureBasic les crée et les utilise, et des avantages qu'ils nous apportent en tant que
programmeurs.

C'est quoi un pointeur ? Eh bien, tout simplement, un pointeur dans PureBasic est une variable qui contient une adresse
numérique d'une certaine zone mémoire. C'est aussi simple que ça ! Pensez à tous les octets en mémoire, chacun étant
lié à un numéro unique, comme si nous étions dans un énorme tableau. Chaque octet en mémoire peut être consulté via
son numéro (adresse). Puisque les ordinateurs modernes contiennent des milliards d'octets, ces adresses numériques
sont généralement constituées de très grands nombres.

Détermination d'une Adresse Mémoire


Maintenant nous savons qu'un pointeur n'est qu'une variable contenant une adresse mémoire. Maintenant nous avons
juste besoin de savoir comment obtenir l'adresse mémoire de quelque chose d'utile. Pour cela, nous utilisons des
fonctions spéciales à un caractère qui renvoient l'adresse de cet objet comme préfixe avant le nom de l'objet de données
correspondant.

Fonctions d'Adresses de Mémoire

Objet Données Fonction Exemple d'Application


Variables @ @VariablenNom
Arrays (Tableau) @ @ArrayNom()
Procedures @ @ProcedureNom()
Labels ? ?LabelNom
Fig. 49
Dans la Fig. 49, vous pouvez voir les deux fonctions d'adresses mémoire spéciales et les objets de données avec
lesquels elles peuvent être utilisées. La fonction « @ » est la plus polyvalente des deux car elle fonctionne avec des
variables, des tableaux et des procédures. Le « ? » est réservée aux étiquettes de saut. Voici un exemple simple de la
façon d'obtenir l'adresse mémoire d'une variable octet :

MaByteVar.b = 100
Debug MaByteVar
Debug @MaByteVar
210 Au-Delà de l'Essentiel

Dans cet exemple, j'ai créé une variable octet appelé « MaByteVariable » à laquelle j'ai attribué la valeur « 100 » , ce qui
est assez simple. Dans la dernière ligne de l'exemple je récupère l' adresse mémoire de cette variable en mettant le
« @ » avant le nom de la variable. Si j'utilise le « @ » de cette façon j'obtiens l'adresse mémoire de « MaByteVariable »
comme valeur de retour, que j'affiche ensuite dans la fenêtre Debug. Si vous exécutez l'exemple ci-dessus regardez la
fenêtre Debug, vous verrez que la valeur originale est «100» et en dessous que l'adresse de la variable sera affichée.
L'adresse est généralement un grand nombre, généralement de sept ou huit chiffres, et l'adresse peut changer sa valeur
en fonction de l'ordinateur sur lequel vous démarrez le programme. Ceci est dû au type partiellement différent de
réservation de mémoire pour la variable.Quand je démarre le programme sur mon ordinateur, j'obtiens l'affichage suivant
dans la fenêtre Debug :

100
4389540

Cela me dit que la variable octet que j'ai utilisée pour stocker la valeur « 100 » se trouve à l'adresse mémoire « 4389540
» . A l'aide de ces fonctions spéciales d'adresse mémoire, il est possible de déterminer les adresses de tous les types de
variables, tableaux, procédures et étiquettes de saut, ce qui peut être très utile. Voici un exemple qui serait tout à fait
inutile dans le monde normal, mais il montre comment déterminer les adresses mémoire de tous ces objets de données
et les sortir dans la fenêtre Debug:

MaVariableByte.b = 1
MaVariableWord.w = 2
MaVariableLong.l = 3
MaVariableQuad.q = 4
MaVariableFloat.f = 5
MaVariableDouble.d = 6
MaVariableString.s = "Seven"
Dim MaLongArray.l(8)
Procedure MaProcedure(Tester.l)
Debug "Tester ma procédure."
EndProcedure

Debug "Adresse de la variable octet : " + Str(@MaVariableByte)


Debug "Adresse de la variable Word : " + Str(@MaVariableWord)
Debug "Adresse de la variable Long : " + Str(@MaVariableLong)
Debug "Adresse de la variable Quad : " + Str(@MaVariableQuad)
Debug "Adresse de la variable Float: " + Str(@MaVariableFloat)
Debug "Adresse de la variable Double: " + Str(@MaVariableDouble)
Debug "Adresse de la variable String: " + Str(@MaVariableString)
Debug "Adresse du (Tableau) Array: " + Str(@MaLongArray())
Debug "Adresse de la Procedure: " + Str(@MaProcedure())
Debug "Adresse du Label: " + Str(?Label)

DataSection
Label:
Data.s "Tester"
EndDataSection

Notez que lorsque vous obtenez l'adresse des tableaux, des procédures et des étiquettes de saut, aucune « autre
information », comme les identificateurs de type, les dimensions des tableaux, les paramètres, etc. ne doit être ajoutée,
même si le tableau a été défini de cette façon dans l'exemple ci-dessus :

...
Dim MaLongArray.l(8) ...

Pour déterminer son adresse mémoire, il suffit d'utiliser son nom et les parenthèses à la fin, comme ici :

@MaLongArray()

De la même manière que vous déterminez l'adresse de début d'une procédure, vous n'avez besoin que du nom et des
parenthèses à la fin :
Au-Delà de l'Essentiel 211

@MaProcedure()

Aucun type ou paramètre n'est requis. Il en va de même pour les marqueurs. Même s'ils sont définis avec deux points
à la fin, ce deux-points est ignoré lorsqu'on utilise une fonction d'adresse mémoire, comme ici :

?étiquette

L'obtention de l'adresse mémoire de tous ces différents objets de données est facile grâce à la manière simple dont les
fonctions d'adresse mémoire fonctionnent. Pour commencer, et pour des raisons de clarté, je recommanderais que
toutes les adresses de mémoire récupérées soient gardées dans des variables, pour garder le code propre et lisible, en
n'oubliant jamais de leur donner de bons noms significatifs.

Créer et Nommer des Pointeurs


Comme je l'ai dit au début, un pointeur est une variable qui contient une adresse numérique d'un emplacement de
mémoire, mais ce que je n'ai pas dit est qu'un pointeur est un type particulier de variable qui suit quelques règles. Pour
commencer, les pointeurs dans PureBasic sont créés en utilisant un astérisque « * », comme premier caractère dans
son nom. Comme ceci :

* Pointer

Deuxièmement, les pointeurs sont un type numérique qui peut changer de taille selon l'architecture de l'ordinateur qui
compile le programme. Par exemple, sur un système 32 bits, un pointeur utilisera 4 octets de mémoire pour stocker un
numéro, alors que sur un système 64 bits, un pointeur utilisera 8 octets pour stocker un numéro.

De même, un pointeur dans PureBasic n'est associé à aucun type particulier. Cela signifie que si vous définissez un
pointeur à l'aide d'un astérisque avec l'un des types numériques intégrés, le type intégré est supprimé pour s'assurer
que le pointeur a la bonne taille pour votre architecture informatique particulière. Ainsi, si vous avez défini un pointeur
comme celui-ci, en utilisant un type d'octet :

*Pointer.b = @Variable

Le type d'octet est ignoré et le pointeur utilise 4 octets sur un système 32 bits et 8 octets sur un système 64 bits.

L'astérisque est utilisé comme partie du nom du pointeur, c'est donc un caractère permanent. Une fois que vous avez
défini un pointeur avec l'astérisque, vous devez toujours le spécifier comme partie du nom lorsque vous utilisez le
pointeur. Par exemple, ces deux variables n'ont aucune relation l'une avec l'autre, ce sont deux variables complètement
différentes :

MaVariable.i
*MaVariable.i

Bien que la seule différence entre ces variables soit l'astérisque, la première variable est une variable de type Long,
tandis que la seconde est un pointeur (défini par l'astérisque). Dans d'autres langues, un astérisque préfixe les variables
pour retourner sa valeur ou son adresse mémoire de façon interchangeable, il est donc important de comprendre que
PureBasic ne possède pas cette fonctionnalité étendue. Ils sont traités comme deux variables entièrement différentes.

L'utilisation d'astérisques pour créer des variables pointeur est un moyen efficace de les différencier des autres types
dans PureBasic et de vous donner une bonne indication visuelle des données qu'elles peuvent contenir. Dans le fichier
d'aide, tous les exemples de syntaxe qui traitent de la mémoire utilisent également cette convention pour aider les
programmeurs à savoir où les pointeurs sont nécessaires. Jetez un coup d'oeil à quelques exemples de syntaxe des
commandes de mémoire dans l'aide (fichier d'aide : Manuel de référence → Bibliothèques générales → Mémoire), vous
y trouverez des astérisques partout.

Si nous utilisons cette convention, nous pouvons réécrire le premier exemple comme ceci :

MaVariableByte.b = 100
*MemoryAddress = @MaVariableByte
Debug MaVariableByte
Debug *MemoryAddress

Reconnaissez-vous l'astérisque devant le nom du pointeur ? Cela vous permet de distinguer facilement les pointeurs
des autres variables.
212 Au-Delà de l'Essentiel

Accès Structuré à la Mémoire à l'Aide d'un Pointeur


Dans l'exemple suivant, je vais vous montrer comment utiliser un pointeur pour agir comme une variable structurée. Ce
pointeur a la même taille que n'importe quel autre pointeur, mais nous pouvons accéder à la zone de mémoire vers
laquelle il pointe d'une manière plus structurée.

Structure DETAILS
Age.l
Poids.l
EndStructure

Moi.DETAILS
Moi\Age = 32
Moi\Poids = 168

*Pointer.DETAILS = @Moi
Debug *Pointer\Age
Debug *Pointer\Poids

Ici, vous pouvez voir que j'ai défini une structure appelée « DETAILS » qui contient deux champs de type Long.
Immédiatement après, j'ai créé une variable nommée « Moi » qui utilise cette structure comme type et attribue une
valeur à chaque champ. C'est ici que la fonction spéciale de l'astérisque peut être utile pour créer un pointeur. Si nous
créons un pointeur de variable structuré à l'aide d'un astérisque, nous pouvons définir sa valeur en lui assignant une
adresse mémoire, comme ceci :

*Pointer.DETAILS = @Moi

Ceci crée un pointeur nommé « *Pointer » et définit sa valeur comme étant l'adresse mémoire de la variable structurée
« Moi ». Puisque nous avons utilisé une structure comme type lors de la création de la variable « *Pointer », nous
pouvons aussi accéder à l'adresse mémoire qu'elle désigne.

Par conséquent, ces deux lignes affichent des données dans la fenêtre Debug :

Debug *Pointer\Age
Debug *Pointer\Poids

Nous donne accès aux données contenues dans la variable structurée « Moi ». nous ne faisons que récupérer ces
données à l'aide de notre pointeur nouvellement créé. Encore une fois, le pointeur créé ici n'est qu'une variable
contenant une adresse mémoire numérique, aucune donnée n'est dupliquée. La figure 50 montre comment ce
processus fonctionne en mémoire.

La Variable Structurée « Moi.DETAILS » en Mémoire


Moi.DETAILS

Moi\Age Moi\Poids

Nombre d'Octets 1 2 3 4 5 6 7 8

*Pointer\Alter *Pointer\Poids

Mémoire Allouée
(8 Octet)

Fig. 50

Alors à quoi cela sert-il ? Eh bien, il pourrait être utilisé pour retourner plus d'une valeur d'une procédure. Par exemple,
vous pouvez créer une variable structurée « Statique » dans une procédure et lui affecter des valeurs. Renvoyez ensuite
l'adresse mémoire de la procédure. Cette adresse mémoire peut ensuite être utilisée pour créer un pointeur de variable
structurée vous donnant accès aux données qui ont été affectées dans la procédure. Un peu comme ça :
Au-Delà de l'Essentiel 213

Structure REPAS
Dejeuner.s
Diner.s
Tea.s
EndStructure
Procedure.l GetRepas()
Static Gary.REPAS
Gary\dejeuner = "Cornflakes"
Gary\Diner = "Sandwichs au fromage"
Gary\Tea = "Spaghetti bolognaise"
ProcedureReturn @Gary
EndProcedure
*Gary.REPAS = GetRepas()
Debug *Gary\dejeuner
Debug *Gary\Diner
Debug *Gary\Tea

Nous utilisons ici le mot-clé « Static » pour préserver les données dans la variable structurée « Gary » lorsque la
procédure revient, sinon elle sera détruite. L'adresse mémoire renvoyée par cette procédure est ensuite affectée au
pointeur de la variable structurée appelée « *Gary » (notez l'astérisque). Nous pouvons alors accéder à cette mémoire
à l'aide de la structure « REPAS ». Comme vous pouvez le voir, très pratique en effet.

Pour plus de flexibilité, vous pouvez assigner l'adresse de n'importe quel type de variable à un pointeur de
variable structuré en utilisant n'importe quel type intégré dans PureBasic. En voici un exemple :
Structure ECRANCOORDS
x.w
y.w
EndStructure

Coordonnees.l = %00000011000000000000010000000000
*Ecran.ECRANCOORDS = @Coordonnees

Debug *Ecran\x
Debug *Ecran\y

Ici, je définis une variable longue de type 32 bits en binaire et l'appelle « Coordonnees » Ensuite, j'assigne son adresse
mémoire à un pointeur de variable structuré nouvellement créé appelé « *Ecran ». Parce que la structure que j'ai
utilisée pour le pointeur contient deux mots de 16 bits, la valeur de 32 bits pointée ne rentrera pas dans un seul des
champs mais se chevauchera sur les deux, séparés au milieu. Cela me permet de retourner deux valeurs de cette
variable, vous donnant les deux valeurs « x » et « y ».

Passage d'une Variable Structurée à une Procédure à l'Aide d'un Pointeur


Toute variable structurée peut être passée dans une procédure comme un pointeur pour permettre à cette procédure de
la manipuler. C'est la seule façon dans PureBasic de passer une variable structurée dans une procédure. Lorsque vous
passez des variables structurées comme celle-ci, vous les passez en fait « Par référence », très similaire aux tableaux et
aux listes liées. Cela signifie que les valeurs ne sont en fait « copiées » dans aucun paramètre. Au lieu de cela, un
pointeur est passé à la procédure et ceci est utilisé pour manipuler la variable structurée originale. Une des principales
choses que vous devez prendre en compte lorsque vous utilisez cette méthode est que lorsque vous passez une
variable structurée dans une procédure, le nom du paramètre de cette procédure peut ne pas avoir le même nom que la
variable structurée que vous passez, mais quel que soit le nom que vous donnez au paramètre, vous manipulez toujours
la variable structurée originale passée. En voici un exemple :
Structure COORDONNEES
x.l
y.l
EndStructure
Point.COORDONNEES

Procedure IncrementeValeurs(*Var.COORDONNEES)
*Var\x + 10
*Var\y + 10
EndProcedure

Point\x = 100
Point\y = 100
IncrementeValeurs(@Point)
Debug Point\x
Debug Point\y
214 Au-Delà de l'Essentiel

Ici, j'ai défini une structure appelée « COORDONNÉES » et créé une variable structurée à partir de celle-ci appelée
« Point ». Lorsque toutes les valeurs de champ ont été assignées à cette variable, je passe ensuite son adresse
mémoire à la variable Procédure « IncreaseValues() ».

Dans la définition de la procédure « IncreaseValues() », j'ai défini un paramètre du nom de « *Var.COORDONNÉES »


« *Var.COORDONNÉES ». Un paramètre défini comme celui-ci indique à la procédure d'attendre un pointeur d'un fichier
variable structurée qui a été créée à partir de la structure « COORDONNÉES ». Le nom « *Var » peut être tout ce que
vous voulez (tant qu'il est précédé d'un astérisque), c'est simplement utilisé comme un moyen amical de manipuler le
pointeur passé. Donc, quand je fais cela dans la procédure ci-dessus :

...
*Variable\x + 10
*Variable\y + 10
...

Ce que je fais vraiment, c'est ceci :

Point\x + 10
Point\y + 10

car la procédure manipule les données stockées à l'adresse mémoire d'origine.

L'utilisation de cette méthode pour transmettre des variables structurées à des procédures peut s'avérer très pratique
dans les situations où vous voulez transmettre un grand nombre d'informations bien regroupées. Par exemple, les
détails d'adresse, les détails de configuration ou tout autre paramètre ou valeur spécifiquement groupés. Cette méthode
permet également de transmettre moins de paramètres aux procédures, car vous pouvez tous les transmettre dans une
seule variable structurée. Comme exemple d'utilisation dans le monde réel, j'ai écrit il y a quelques années une
procédure de courrier électronique, à laquelle je pouvais passer une variable structurée contenant les détails du compte
de courrier électronique ainsi que le destinataire, le sujet et le message, etc... Cela rend les choses un peu plus lisibles
et gérables.

Lecture et Ecriture de Valeurs à l'Aide de Pointeurs


Si vous déterminez une adresse de stockage, vous avez la possibilité de l'utiliser de différentes manières. Sans aucun
doute, la manière habituelle est de lire les valeurs de la zone de mémoire correspondante ou d'enregistrer les données
à ce stade. Ce processus s'appelle « regarder » et jeter un coup d'oeil . Vous pouvez utiliser une commande « Peek »
pour lire les données d'un emplacement mémoire, et une commande « Poke » pour écrire des données dans un
emplacement mémoire

Dans PureBasic il y a onze commandes « Peek » et onze commandes « Poke » pour supporter tous les types de
données intégrés. Toutes les commandes ont approximativement les mêmes noms, elles ne diffèrent que par la
dernière lettre de la commande. Cette lettre est toujours la désignation de type respective que vous utilisez également
lorsque vous affectez des types à des variables. Par exemple, si vous voulez lire un octet d'une adresse mémoire
spécifique, vous devez utiliser la fonction « PeekB() ». Comme le « B » dans le nom le suggère, un octet est lu à partir
de cette adresse mémoire. De la même manière, vous écrirez une chaîne de caractères à une adresse mémoire
spécifique, auquel cas vous utiliserez la fonction « PokeS() ». Pour plus d'informations sur ces vingt-deux commandes,
consultez l'aide de PureBasic (fichier d'aide : Manuel de référence → Bibliothèques générales → Mémoire).

Consultation des Valeurs Situées à des Emplacements de Mémoire Spécifiques


L'utilisation d'une commande « Peek » est assez simple, vous lui passez un emplacement de mémoire (peut-être en
cours de tenue à l'intérieur d'un pointeur) et la commande « Peek » retournera les données qui s'y trouvent. Pour
retourner un fichier vous devez utiliser la commande « Peek » associée. Voici un exemple de lecture d'un octet à partir
d'un fichier en utilisant la commande « PeekB() »:
Au-Delà de l'Essentiel 215

Poids.b = 30
*Poids = @Poids
ReadValue.b = PeekB(*Poids)
Debug ReadValue~

Ici j'assigne la valeur « 30 » à une variable octet avec le nom « Poids ». Dans la ligne suivante j'assigne l'adresse
mémoire de cette variable à un pointeur nommé « *Poids » (notez l' astérisque). La ligne suivante contient la fonction
« PeekB() », qui lit et renvoie la valeur réelle de l'octet de l'adresse mémoire du pointeur. Vous n'êtes pas obligé d'entrer
un pointeur pour le paramètre adresse (bien qu'il soit recommandé pour plus de clarté), nous pouvons également écrire
l'exemple comme suit :

Poids.b = 30
ReadValue.b = PeekB(@Poids)
Debug ReadValue

Ici, j'utilise la variable de Type Bit « .b » avec la fonction d'adresse mémoire directement, en supprimant complètement
le pointeur. Je suppose que ça dépend de ce avec quoi tu es le plus à l'aise. A la fin de la journée, toutes les
commandes « Peek » ont besoin d'un emplacement mémoire comme paramètre, qui peut finalement être fourni par un
pointeur défini ou (plus directement) par la valeur de retour d'une fonction adresse mémoire.

« Poke » Placer des Valeurs dans Certaines Zones de Mémoire


« Poke » Place des valeurs dans les emplacements de mémoire est aussi simple que d'utiliser une commande « Peek
». Pour « Poke » cependant, vous devez fournir une nouvelle valeur ainsi que l'adresse mémoire de l'endroit où la
mettre. Voici un exemple d'insérer une nouvelle valeur Long dans l'emplacement mémoire d'une variable Long
existante :

Poids.l = 1024
*Poids = @Poids
PokeL(*Poids, 333)
Debug Poids

Ici, nous commençons par la valeur initiale « 1024 » que nous avons affectée à la variable « Poids ». Puis j'ai créé un
pointeur nommé « *Poids » qui contient l'adresse mémoire de « Poids ». Puis j'ai utilisé la fonction « PokeL() » pour
écrire la valeur « 333 » à l'emplacement spécifié dans le premier paramètre. La nouvelle valeur de « Poids » est alors
affichée dans la fenêtre Debug.

Un mot d'avertissement quand vous ajoutez de nouvelles valeurs avec « Poke »


Faites très attention à l'endroit où vous introduisez de nouvelles valeurs. L'utilisation des commandes mémoire de
PureBasic peut être très dangereuse si vous ne savez pas ce que vous faites. Par exemple, les commandes « Poke »
n'ont pas de vérification interne pour vous dire si vous pouvez ou non entrer une valeur dans une adresse mémoire
particulière. Vous pouvez passer un nombre aléatoire à n'importe quelle commande « Poke » en tant qu'adresse
mémoire et elle y ajoutera volontiers une valeur. Il s'agit d'une épée à double tranchant, car vous avez parfois besoin de
ce pouvoir pour réorganiser les valeurs en mémoire, mais cela peut entraîner des problèmes. Si vous vous trompez,
vous risquez d'endommager un emplacement mémoire qu'un programme essentiel pourrait avoir besoin de lire.
Conduire à un plantage du programme ou quelque chose de plus dommageable, comme un plantage du système
d'exploitation.

Pour entrer des valeurs dans la mémoire en toute sécurité, vous devez entrer dans la mémoire d'une variable ou d'un
tableau existant. ou « Poke » dans la mémoire allouée en utilisant la commande « AllocateMemory() », (Fichier d'aide:
Guide de référence → bibliothèques générales->Mémoire->AllocationMémoire). S'assurer que toutes les valeurs qui y
ont été introduites les zones de mémoire ne dépassent pas l'espace alloué. Par exemple, ce serait une mauvaise
pratique que d'inserer un Long dans l'emplacement mémoire d'une variable octet, parce que vous tapez 3 octets de
données de plus que vous ne le faites.devrait l'être. Cela fonctionnerait en fait, car il n'y a pas de vérification d'erreur,
mais vous pourriez écraser 3 octets de données potentiellement essentielles, corrompant tout ce qui s'y trouvait.

Utilisation d'une Adresse Mémoire comme Index de Départ.


Si vous voulez lire des valeurs dans des blocs de mémoire contigus ou y écrire des valeurs il est possible d'utiliser
l'adresse de l'octet de départ comme index de départ pour le reste du bloc.à utiliser. Ceci est particulièrement utile si
vous utilisez un pointeur vers un tableau. Regardez cet exemple :
216 Au-Delà de l'Essentiel

Dim Numbers.l(2)

Numbers(0) = 100
Numbers(1) = 200
Numbers(2) = 300

*ArrayPointer = @Numbers()

Debug PeekL(*ArrayPointer)
Debug PeekL(*ArrayPointer + 4)
Debug PeekL(*ArrayPointer + 8)

Après avoir créé le tableau « Numbers » avec des variables de type Long, j'attribue une valeur numérique
comprise entre « 100 » et « 300 » à chaque index. Ensuite, je crée un pointeur de tableau avec le
nom « *ArrayPointer » qui contient l'adresse de stockage du tableau.

Lorsque vous créez un tableau de cette façon, tous les index sont stockés dans un bloc de mémoire contigus afin que
toutes les données soient stockées les unes derrière les autres. L'adresse retournée de la fonction adresses mémoire
est l'adresse du premier index. En effet, le pointeur nommé « *ArrayPointer » contient l'adresse de stockage de l'index
du tableau « Numbers(0) »

Si nous utilisons alors la ligne de code suivante

...
Debug PeekL(*ArrayPointer)
...

Nous sommes en train d'examiner la valeur de l'emplacement mémoire du premier index. Vous pouvez voir que c'est
vr