PureBasic - Beginners Guide - French
PureBasic - Beginners Guide - French
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:
[Link]
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
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
[Link]
Auteur
Gary Willoughby
Impréssion
Disponible 1 Juli 2006
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: [Link].
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
Les exemples de codes contenus dans ce livre peuvent être téléchargés gratuitement à partir de la page suivante
[Link] (englisch)
[Link] (deutsch)
Table de Matières
Avant-Propos................................................................................................................................................... 9
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
3. Operateurs............................................................................................................................................... 24
Introduction aux Opérateurs .................................................................................................................... 24
Priorités des Opérateurs .............................. ........................................................................................... 35
Règles de Calcul pour les Expressions ..................................................................................................... 36
V. Appendix.............................................................................................................................................. .......234
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.
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.
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 à [Link] .
12 Nous Commençons
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.
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.
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.
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.
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
[Link] 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.
Barre de menu
Barre d'outils
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.
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
Dans l'IDE:
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é « [Link] » 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 « [Link] »). 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'[Link] 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.
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.
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.
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 :
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 :
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.
* 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 :
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 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
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.
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 [Link] 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 :
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 ».
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 :
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 :
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:
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
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 :
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
#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
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.
« = » ( 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
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 :
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 :
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
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.
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.
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 ».
False
False
True
True
True
True
True
Valeure Binaire 54 0 0 1 1 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 « | »
0 0 0
0 1 1
1 0 1
1 1 1
Fig. 7
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 « ! »:
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
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).
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.
Valeur Binaire 50 0 0 1 1 0 0 1 0
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.
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
Valeur Binaire 50 0 0 1 1 0 0 1 0
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
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
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
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
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 ».
NumberOne.l = 0
NumberTwo.l = 1
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
NumberOne.l = 2
NumberTwo.l = 1
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
<> (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
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
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:
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
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 :
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.
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.
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
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:
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 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.
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.
#True
#False
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 ».
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.
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
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 ».
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 ».
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.
If OpenConsole()
PrintN("1. Official PureBasic Home")
PrintN("2. Official PureBasic Forums")
PrintN("3. [Link]")
PrintN("")
PrintN("Enter un nombre de 1 à 3 et appuyer sur Return:")
Destination.s = Input()
Select Destination
Case "1"
RunProgram("[Link]
Case "2"
RunProgram("[Link]
Case "3"
RunProgram("[Link]
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
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 ».
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
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
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
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.
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.
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
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:
[Link]é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).
Structure Coordonnées
Prénom.s
Nom.s
Maison.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"
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 UNIONSTRUCTURE
StructureUnion
un.l
deux.l
trois.l
EndStructureUnion
Debug SizeOf(UNIONSTRUCTURE)
[Link]
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
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)
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.
index valeur
0 L'un est pas
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)
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.
index 0 1 2
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:
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.
index 0 1 2
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.
Structure Poissons
Gentil.s
Poids.s
Couleur.s
EndStructure
Dim [Link](2)
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:
Décomposons cela en morceaux faciles à comprendre. Le premier est le nom du tableau, dans ce cas-ci il s’agit de, «
[Link] ». 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
« [Link] ». 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 « [Link] ». 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 « [Link] » et pour mieux comprendre les choses voir la figure Fig 19,
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
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é.
index 0 1 2
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:
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. ,.
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é.
Dim Dogs.s(2)
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)
For x.l = 0 To 2
Debug Dogs(x)
Next x
Debug ""
ReDim Dogs.s(4)
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.
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.
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
[Link]
Family\pere = "Peter"
Family\Mere = "Sarah"
Family\ enfant[0] = "John"
Family\ enfant[1] = "Jane"
Family\Surnom = "Smith"
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.
Famille\enfant[0] = "John"
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 !
Structure EMPLOYEES
EmployeNom.s
EmployeNombreheure.l
EmployeAdresse.s
EmployeNuméroTel.l[2]
EndStructure
Dim [Link](9)
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.
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
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
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 »).
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 [Link]()
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
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
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.
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
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 :
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 [Link](2)
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 ».
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
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 [Link]()
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"
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
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
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.
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
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é.
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()
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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 ».
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.
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.
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
[Link] 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.
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:
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.
Dim Pays.s(3, 1)
Pays(0,0) = "Angleterre"
Pays(0,1) = "57,000,000"
76 Procédures et sous-routines
Pays(2, 0) = "Ecosse"
Pays(2,1) = "5,200,000"
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())
Structure Pays
Nom.s
Population.s
EndStructure
Dim [Link](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"
VoirArray(Europe())
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 [Link](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.
NewList Nombres.i()
AddElement(Nombres())
Nombres() = 25
AddElement(Nombres())
Nombres() = 50
AddElement(Nombres())
Nombres() = 75
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.
Structure Drapeau
Pays.s
Drapeau.s
EndStructure
NewList [Link]()
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"
VoirList(info())
Comme vous pouvez le voir dans l'exemple ci-dessus, le paramètre de la procédure ressemble à ceci:
List [Link]())
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.
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.
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
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 :
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 :
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.
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.
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.
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 :
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, "[Link]")
SaveImage(1, "[Link]", #PB_ImagePlugin_JPEG)
SaveImage(1, "[Link]", #PB_ImagePlugin_JPEG, 10)
Le premier exemple enregistrera une image appelée « [Link] » 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
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.
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.
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)
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.
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
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() » :
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.
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.
« 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
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() »
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() »
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() »
Exemple de syntaxe:
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 ».
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)
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() »
;Possible drapeau:
#PB_MessageRequester_Yes
#PB_MessageRequester_YesNo
#PB_MessageRequester_ YesNoCancel
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"
If Resultat = #PB_MessageRequester_YesNo
Debug "Vous avez appuyé sur 'Oui'"
Else
Debug "Vous avez appuyé sur 'Non'"
EndIf
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() »
Exemple de syntaxe:
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 :
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() »
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 »
Exemple de syntaxe:
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.
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
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.
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.
#FILE_RHYME = 1
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.
« 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 [Link] », 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 :
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
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.
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.
NewList Contenu_Fichier.s()
If ReadFile(#FICHIER_RAPPORT, "[Link]")
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
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
[Link] les « 4 » octets plus en avant, prêt à être utilisé[Link] prochaine commande de lecture..
Àide pour les commandes intégrées 93
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.
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.
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
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.
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.
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
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.
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.
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 :
Procedure.f Pi ()
ProcedureReturn 4 * (4 * ATan(1/5) - ATan(1/239))
EndProcedure
Diametre_Circle.i = 150
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 :
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 :
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.
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.
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:
« 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 :
If NombreDecimales <0
NombreDecimales = 0
EndIf
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.
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é.
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é « [Link] » 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 "[Link]"
Ceci a pour effet de prendre toutes les lignes de code du fichier « [Link] » 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 "[Link]"
La ligne « XIncludeFile » inclura le code du fichier « [Link] » , 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
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.
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, "[Link]")
Debug ReadString(#TEXTFILE)
CloseFile(#TEXTFILE)
Else
MessageRequester("Erreur", "Impossible d'ouvrir le fichier: '[Link]'.")
EndIf
Ici, je teste pour m'assurer que je peux lire le fichier « [Link] » 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
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.
ReadFile(#TEXTFILE, "[Link]")
Si le fichier « [Link] » 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 :
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
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
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
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.
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.
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:
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é:
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
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 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
Dans l'exemple ci-dessus, si le fichier « [Link] » 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
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.
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.
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("")
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
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.
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()
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
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.
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.
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
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
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
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.
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.
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é.
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.
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.
Enumeration
#WIN_MAIN
#TEXT_INPUT
#STRING_INPUT
#BUTTON_INTERACT
#BUTTON_CLOSE
EndEnumeration
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.
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
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.
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.
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.
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.
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
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.
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
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.
Enumeration
#WINDOW_MAIN
#MENU_MAIN
#MENU_QUIT
#MENU_APROPOS
#TEXT_INPUT
#STRING_INPUT
#LIST_INPUT
#BUTTON_INTERACT
#BUTTON_CLOSE
EndEnumeration
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.
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.
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
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.
#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.
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, "[Link]")
...
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 [Link]. 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,
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
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 "[Link]"
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 "[Link]"
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 « [Link] ». 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 « [Link] ».
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).
« 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 "[Link]"
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.
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
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.
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.
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.
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
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.
#WINDOW_MAIN = 1
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.
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.
...
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 :
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.
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
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.
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.
Enumeration
#WINDOW_MAIN
#IMAGE_GADGET
#IMAGE_MAIN
#FONT_MAIN
EndEnumeration
Procedure.l MyRandom(Maximum.l)
Repeat
Number.l = Random(Maximum)
Until (Number % 10) = 0
ProcedureReturn Number
EndProcedure
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.
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() »
Enumeration
#WINDOW_MAIN
#IMAGE_GADGET
#IMAGE_SMALL
#IMAGE_MAIN
#FONT_MAIN
EndEnumeration
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.
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 :
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:
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).
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.
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, "[Link]")
...
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
« #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).
« 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).
SaveImage(#IMAGE_MAIN, "[Link]")
Ce premier exemple enregistrera une image appelée « [Link] » 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, "[Link]", #PB_ImagePlugin_JPEG)
Le deuxième exemple enregistrera une image appelée « [Link] » 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, "[Link]", #PB_ImagePlugin_JPEG, 10)
Ce troisième exemple enregistrera une image appelée « [Link] » 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, "[Link]", #PB_ImagePlugin_PNG)
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.
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.
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
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)
...
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.
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() ».
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.
#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
;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)
;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.
Structure STAR
xPos.f
yPos.f
xStep.f
Color.l
EndStructure
;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
;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 [Link] 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
#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.
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.
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
#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, "[Link]")
« DisplaySprite3D() »
Sans canal alpha
CreateSprite (#PB_NOMBRE, width.i, height.i, #PB_Sprite_Texture)
LoadSprite (#PB_NOMBRE, "[Link]", #PB_Sprite_Texture)
Graphiques 2D 155
« 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, "[Link]", #PB_Sprite_Memory)
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.
StartSpecialFX()
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
#SPRITE_MAIN = 1
#NUMBER_OF_BALLS = 500
Structure BALL
x.f
y.f
XOrigin.l
YOrigin.l
Radius.l
Angle.f
Speed.f
EndStructure
;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
;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.
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 [Link](#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
;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,"[Link]",#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é.")
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 « [Link] » , 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)
« #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.
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)
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.
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.
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
« 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
;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, "[Link]"), "Impossible de charger mesh")
HandleError(LoadTexture(#TEX, "[Link]"), "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.
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 : « [Link] » ([Link]) « 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.
« #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, "[Link]")
...
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 «
[Link] » 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\[Link]")
LoadTexture(#TEX, "Textures\[Link]")
...
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, "[Link]")
LoadTexture(#TEX, "[Link]")
...
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("[Link]", #PB_3DArchive_Zip)
LoadMesh(#MESH, "Meshes\[Link]")
LoadTexture(#TEX, "Texturen\[Link]")
...
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.
1. 2.
Chargement de 3.
la mesh
Chargement de
la texture
4.
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, "[Link]"), "Impossible de charger la mesh")
GestionErreur(LoadTexture(#TEX, "[Link]"), "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
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.
...
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.
...
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.
...
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 ».
/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)
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 :(
;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, "[Link]"), "Impossible de charger texture")
HandleError(LoadTexture(#TEXTURE_DETAIL, "[Link]"), "Impossible de charger texture")
CreateMaterial(#MATERIAL_TERRAIN, TextureID(#TEXTURE_GLOBAL))
AddMaterialLayer(#MATERIAL_TERRAIN,TextureID(#TEXTURE_DETAIL),#PB_Material_Add)
CreateTerrain("[Link]", 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)
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.
...
HandleError(LoadTexture(#TEXTURE_GLOBAL, "[Link]"), "Impossible de charger texture")
HandleError(LoadTexture(#TEXTURE_DETAIL, "[Link]"), "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, « [Link] », 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, « [Link] », 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("[Link]", 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.
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
« 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
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.
Enumeration
#MESH
#TEXTURE
#MATERIAL
#ENTITY
#CAMERA_ONE
#LIGHT_ONE
#LIGHT_TWO
#PARTICLE_ONE
EndEnumeration
;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, "[Link]"), #PB_Material_None)
LoadTexture(#TEXTURE, "[Link]")
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 « [Link] »:
material Statue
{
technique
{
pass
{
texture_unit
{
texture [Link]
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 « [Link] »
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, "[Link]"), #PB_Material_None)
...
Ceci charge le fichier « [Link] » 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.
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 « [Link] » 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)
...
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).
...
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.
#SOUND_FILE = 1
If InitSound()
LoadSound(#SOUND_FILE, "[Link]")
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é.
#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 "[Link]"
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() ».
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
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
« 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 :
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, "[Link]")
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() ».
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() ».
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
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
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.
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.
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.
#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 :
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 :
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
CompilerElse
;Code de version complète:
Procédure.d MyPI()
ProcédureRetour ACos(-1)
EndProcedure
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é.
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.
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.
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 :
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.
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 :
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.
PBCompiler [Link]
Si votre variable d'environnement « PATH » est correctement configurée, cela lancera le compilateur PureBasic et
passera le fichier « [Link] ». 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 :
Cette instruction compile le fichier « [Link] » et crée un programme exécutable à partir de celui-ci. Cet
exécutable compilé reçoit le nom « [Link] » 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 :
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.
« /? »
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é « [Link] » 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 :
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 ».
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 :
« /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 « [Link] ». Vous pouvez renommer ce fichier comme vous le
souhaitez. Comme sous-produit de la création de DLL, une bibliothèque statique nommée « [Link] » et un
fichier exporté nommé « [Link] » sont créés dans le même dossier.
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.
« /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.
« /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 :
« /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.
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.
« /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 ».
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.
« /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.
« /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 ».
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.
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.
« /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 [Link] /exe "[Link]" /subsystem "DirectX7"
PBCompiler [Link] /exe "[Link]" /subsystem "NT4"
PBCompiler [Link] /exe "[Link]" /subsystem "OpenGL"
Linux:
PBCompiler [Link] /exe "[Link]" /subsystem "GTK2"
MacOS X:
PBCompiler [Link] /exe "[Link]" /subsystem "GTK"
PBCompiler [Link] /exe "[Link]" /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.
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.
« /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.
Cette commande demande au système d'exploitation de démarrer le programme « PBCompiler » et lui passe trois
paramètres ([Link] /exe "[Link]''). 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.
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é « [Link] », je peux passer des paramètres à ce
programme sur la ligne de commande, comme ici :
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.
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.
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()
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.
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.
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
Chiffres Binaires(Bits) 0 1 0 0 1 1 0 1 = 77
Nombre de 8 bits
(1 octet)
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.
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
* Ce type de données n'est pas disponible dans PureBasic (peut-être dans une version ultérieure ?) Fig. 45
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
Valeurs Attribuées 64 32 16 8 4 2 1
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.
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.
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)
31 30 23 22 Bit Index 0
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 ».
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.
Valeurs Attribuées 8 4 2 1
Point radian
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
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 ».
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).
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.
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 [Link] 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
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.
* 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
Structure DETAILS
Age.l
Poids.l
EndStructure
[Link]
Moi\Age = 32
Moi\Poids = 168
*[Link] = @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 :
*[Link] = @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.
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 [Link]
Gary\dejeuner = "Cornflakes"
Gary\Diner = "Sandwichs au fromage"
Gary\Tea = "Spaghetti bolognaise"
ProcedureReturn @Gary
EndProcedure
*[Link] = 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
*[Link] = @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 ».
Procedure IncrementeValeurs(*[Link])
*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() ».
...
*Variable\x + 10
*Variable\y + 10
...
Point\x + 10
Point\y + 10
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.
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).
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.
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.
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 [Link] 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.
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) »
...
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
vrai par la première valeur répercutée dans la fenêtre Debug . Pour jeter un coup d'oeil à d'autres valeurs du tableau,
nous devons utiliser ce pointeur comme position de départ et y ajouter le nombre d'octets que nous souhaitons déplacer
dans la mémoire. Nous savons que les types longs utilisent quatre octets, ce qui permet d'augmenter le pointeur de « 4
» pour récupérer la prochaine valeur Longue contenue dans la mémoire qui est allouée à ce tableau. Les lignes de code
suivantes, tirées de l'exemple ci-dessus, ne font que cela, elles regardent les valeurs plus loin dans la mémoire du
tableau en utilisant le pointeur du tableau comme point de départ.
...
Debug PeekL(*ArrayPointer + 4) ;Affiche la deuxième valeur longue : 200'
Debug PeekL(*ArrayPointer + 8) ;Affiche la troisième valeur longue : '300'
Je l'ai montré visuellement à la Fig.51. Si j'utilisais un tableau d'octets alors bien sûr, je devrais augmenter le
pointeur du tableau de « 1 » pour regarder le deuxième octet et de « 2 » pour regarder le troisième, etc. De même,
si j'utilisais des types Word, alors le pointeur devrait être augmenté de « 2 » octets à chaque fois.
Nombre d'octets 35 1 2 3 4 5 6 7 8 9 10 11 12
Fig. 51
Au-Delà de l'Essentiel 217
Threads (Processus)
Un thread est une séquence d'instructions qui sont exécutées dans une tâche séparée (processus indépendant) mais
qui appartiennent toujours au programme original. Chaque programme peut lancer plusieurs threads en parallèle, et
chacun peut effectuer une tâche différente, comme attendre les événements d'une tâche qui prend du temps. Les
discussions sont des ramifications du programme principal qui peuvent fonctionner indépendamment de celui-ci..
Lorsque le programme principal est fermé, tous les threads sont également arrêtés et terminés. Quel programme utilise
alors des threads ? Eh bien, n'importe quel programme peut potentiellement les utiliser, mais ils sont surtout utilisés
dans des programmes qui ont besoin de faire plus d'une chose à la fois. Un exemple serait un programme de recherche
qui recherche des fichiers sur votre disque dur. Vous écrivez ensuite le code de recherche pour lancer un thread. Cela
ne bloquerait pas le redessin de l'interface ou la gestion des événements dans la boucle principale. La recherche peut
être effectuée indépendamment, sans l'effet secondaire que le programme principal ne répond plus aux entrées. Un
autre exemple serait un programme qui traite des fichiers volumineux. Puisque l'édition de ces fichiers prend
habituellement un peu plus de temps, vous pouvez sous-traiter cette édition à un thread, tandis que le programme
principal peut faire d'autres choses entre-temps. Ce sont deux exemples qui illustrent où les threads peuvent être utiles
pour résoudre des problèmes de programmation.
L'Utilisation de Threads
Avant de continuer à vous montrer comment utiliser les threads, je vais vous montrer un programme simple sans
threads pour que vous ayez une comparaison. Ce programme appelle deux fois une procédure pour insérer des
valeurs dans deux « ListViewGadgets » différents. Notez que vous ne pouvez pas déplacer la fenêtre après avoir
appuyé sur le bouton Démarrer, ni afficher le texte actuellement saisi dans le gadget tant que les deux procédures n'ont
pas été effectuées.
Enumeration
#WINDOW_ROOT
#LIST_ONE
#LIST_TWO
#BUTTON_TEST
EndEnumeration
Procedure InsertText(Gadget.l)
For x.l = 1 To 25
AddGadgetItem(Gadget, -1, Str(x))
Delay(100)
Next x
EndProcedure
Vous remarquerez également que les deux appels de procédure de « InsertText() » dans la boucle principale sont
exécutés l'un après l'autre. Cela signifie que la première procédure doit être terminée avant que la deuxième procédure
puisse commencer. C'est exactement ainsi que fonctionnent les programmes procéduraux. Dans ce cas, cela ne nous
concerne pas, car nous ne voyons pas de mise à jour dans les gadgets ListView, ce qui est dû à l'instruction « Delay() »
dans la procédure « InsertText() ».
218 Au-Delà de l'Essentiel
Si ce mode n'est pas activé, et que vous compilez et exécutez votre programme, alors votre exécutable fini n'est
pas 100% « thread-safe ». Puisque tous les « threads » de votre programme accèdent à des données communes
dans votre exécutable, des erreurs peuvent se produire dans ces données en raison des accès simultanés. Ce
problème est particulièrement fréquent lors de l'utilisation de chaînes de caractères. Sans l' option de compilateur
« thread-safe », les chaînes de caractères de votre programme peuvent être écrasées et des résultats inattendus
peuvent être renvoyés.
Cependant, l'utilisation de l'option compilateur « thread-safe » a un petit prix. Grâce au code additionnel
automatiquement intégré dans votre exécutable, la vitesse d'exécution de votre programme est légèrement réduite
par rapport au mode « thread-safe ». La décision d'utiliser des fils doit être bien réfléchie.
Pour tous les débutants de PureBasic, je recommande généralement d'utiliser l'option « Create thread-safe
executable » du compilateur lors de la compilation de programmes qui fonctionnent avec des « threads «
Cette instruction « Delay() » bloque le programme et l'empêche d'exécuter des messages internes, tels que redessiner
l'interface utilisateur ou déplacer la fenêtre. On clique sur le bouton et on doit attendre que les procédures soient
terminées avant de pouvoir travailler à nouveau avec le programme. Imaginez maintenant qu'il s'agit d'un programme de
traitement d'images et que les deux procédures prendraient chacune trente minutes à compléter, quoi qu'elles fassent.
C'est une longue période d'attente avant de pouvoir déplacer la fenêtre ou visualiser la progression sur l'interface
utilisateur. Nous ne serions pas non plus en mesure d'intégrer une barre de progression dans notre programme.
Si nous voulons exécuter ces deux procédures en même temps et complètement indépendantes du programme
principal, alors nous pouvons créer deux « threads » travaillant simultanément à côté du programme principal. Ça
pourrait ressembler à ça :
Enumeration
#WINDOW_ROOT
#LIST_ONE
#LIST_TWO
#BUTTON_TEST
EndEnumeration
Si vous regardez de plus près les deux exemples, vous remarquerez que la seule différence réside dans l'appel des
procédures. Chaque nouveau « thread » dans PureBasic commence sa vie comme une procédure standard, qui est
définie de la manière habituelle dans le code source et contient toujours exactement un paramètre. Pour créer un
« thread » à partir de celui-ci, utilisez la fonction « CreateThread() » (fichier d'aide : Manuel de référence →
Bibliothèques générales → Thread → CreateThread), qui nécessite deux paramètres. Le premier paramètre est
l'adresse de stockage de la procédure que vous voulez démarrer en tant que « thread ». Le second paramètre est un
paramètre obligatoire et peut être de n'importe quel type. Vous devez toujours passer ce paramètre à la procédure,
même si vous n'en avez pas besoin dans la procédure. Je l'ai utilisé ici pour spécifier à quel gadget insérer le texte.
Lors de la création d'un « thread » comme celui-ci, Si « CreateThread() » renvoie une valeur supérieure à zéro quand un
« thread » est créé de cette façon, alors le « thread » a été créé avec succès et sera lancé immédiatement. La valeur
retournée (en cas de succès) est une valeur entière (identificateur de « thread ») et peut être utilisée avec les autres
commandes de la bibliothèque de threads (fichier d'aide : Manuel de référence → Bibliothèques générales → Thread).
Récapitulons donc les règles à suivre lors de la création d'un « thread » à partir d'une procédure :
Lorsque cet exemple de « thread » est lancé, vous verrez des valeurs insérées dans les deux gadgets de la vue en liste
en temps réel. Pendant que ces valeurs sont insérées, vous pouvez également déplacer la fenêtre du programme sur
l'écran et vous remarquerez qu'il est maintenant redessiné et mis à jour normalement. Les deux « threads »
nouvellement créés sont devenus des parties indépendantes du même programme, qui s'exécutent en même temps que
celui-ci. Si le programme principal devait se fermer à tout moment, ces deux « threads » seront terminés
automatiquement.
Si vous remarquez une distorsion du texte dans l'un des gadgets, assurez-vous que l'option « Créer un exécutable
sécurisé » est cochée, comme je l'ai décrit dans la boîte d'information'Compiler des programmes sécurisés par les
threads'.
Dans PureBasic, vous pouvez contourner ce problème avec la fonction « WaitThread() » (fichier d'aide : Manuel de
référence → Bibliothèques générales → Thread → WaitThread). Cette commande s'assure qu'un thread a terminé son
travail avant de continuer avec le programme principal. En voici un exemple :
Procedure DrawNumbers(Unused.l)
For x.l = 1 To 20
PrintN(Str(x))
Delay(75)
Next x
EndProcedure
If OpenConsole()
ThreadID.l = CreateThread(@DrawNumbers(), 0)
WaitThread(ThreadID)
Print("Press Return to quit") : Input()
CloseConsole()
EndIf
End
220 Au-Delà de l'Essentiel
Après la ligne dans laquelle j'ai créé le thread, j'ai utilisé une fonction « WaitThread()». Cela nécessite un paramètre,
c'est l'identifiant du « thread » précédemment créé. Cette commande arrête l'exécution normale du programme jusqu'à
ce que le « thread » passé dans l'identificateur de « thread » soit terminé,ou en d'autres termes, jusqu'à ce que la
procédure utilisée pour créer le fil ait terminé son travail. Vous pouvez passer un second paramètre optionnel à la
fonction « WaitThread() » si nécessaire, il définit une valeur de timeout en millisecondes. Lorsque ce temps est écoulé,
l'exécution du programme continue quel que soit l'état du « thread ». Je n'ai pas utilisé ce deuxième paramètre optionnel
dans mon exemple parce que je voulais m'assurer que le « thread » était terminé avant de vous donner la possibilité de
quitter le programme. Si vous commentez la ligne « WaitThread() » , vous remarquerez que vous pouvez quitter le
programme à tout moment avec la touche Entrée et ainsi « couper » le fil pendant l'exécution. Avec la fonction «
WaitThread() », à tout moment, vous devez attendre que le « thread » termine son travail avant d'appuyer sur la touche
Entrée.
Un « mutex » est un objet de données qui peut être utilisé comme un verrou pour empêcher un « thread » d'utiliser des
données qui sont déjà utilisées par un autre « thread ». Lorsque vous utilisez un « mutex » pour protéger les données
partagées, il empêche un thread d'accéder aux données jusqu'à ce que ce « thread » bloque le « mutex ». Après qu'un
thread ait verrouillé cet objet « mutex », il a libre accès aux données. Si un autre « thread » essaie de verrouiller ce «
mutex » en même temps, alors le second « thread » est arrêté jusqu'à ce que le « mutex » soit relâché par le premier «
thread », c'est-à-dire que le premier « thread » termine l'accès aux données partagées. Voici un exemple où j'utilise un «
mutex » pour contrôler l'accès en écriture à la console :
If OpenConsole()
EnableGraphicalConsole(#True)
Thread0.l = CreateThread(@DrawNumbers(), 0)
Thread1.l = CreateThread(@DrawNumbers(), 1)
Thread2.l = CreateThread(@DrawNumbers(), 2)
WaitThread(Thread0)
WaitThread(Thread1)
WaitThread(Thread2)
ConsoleLocate(0, 23)
Print("Appuyer sur Return pour quitter") : Input()
CloseConsole()
EndIf
End
Quand vous démarrez ce programme, chaque « thread » écrit des nombres dans la console, mais j'ai utilisé un « mutex
» dans la procédure « WriteNumbers() ». Un seul « thread » peut occuper le « mutex » à la fois et écrire des nombres
sur la console.
La première ligne de code crée un nouvel objet « mutex » avec la fonction « CreateMutex() » (fichier d'aide : Manuel de
référence → Bibliothèques générales → Thread → CreateMutex). Cette commande nécessite ne contient pas de
paramètre, mais renvoie l'identifiant de l'objet « mutex » nouvellement créé lorsqu'il est appelé. La valeur retournée est
une valeur entière, donc je l'ai mise dans une variable entière nommée « ConsoleAccess »
Au-Delà de l'Essentiel 221
Après que l'objet « mutex » ait été créé, je dois concevoir mes procédures de sorte qu'elles gardent le statut verrouillé
ou non verrouillé. Pour ce faire, j'ai besoin d'ajouter des commandes de verrouillage et de déverrouillage à toutes les
procédures qui accèdent aux données partagées. Dans mon exemple, je n'ai qu'une seule procédure de « thread » ,
donc je n'ai qu'à ajouter cette fonctionnalité ici. Si j'ajoute d'autres procédures de « thread » qui écrivent sur la console,
alors je dois aussi les éditer pour qu'elles respectent le statut « mutex ».
Pour donner à un « thread » la possibilité de verrouiller un « mutex » , nous utilisons la fonction «LockMutex() » (fichier
d'aide : Manuel de référence → Bibliothèques générales → Thread → LockMutex). Cette commande nécessite un
paramètre, c'est l'identifiant de l'objet « mutex » que nous voulons verrouiller. Si le « mutex » est libre au moment de
l'appel de la commande, la fonction « LockMutex() » verrouille le « mutex » et le « thread » continue à fonctionner
normalement. Mais si le « mutex » est verrouillé par un autre « thread », alors la fonction « LockMutex() » arrête le
thread appelant jusqu'à ce qu'il ait la possibilité de verrouiller le mutex lui-même, ce qui est le cas si l'autre « thread » a
relâché le « mutex » .
Vous pouvez voir ce processus dans mon exemple de « mutex », je verrouille le « mutex »avant d'écrire sur la console
et je le relâche une fois mon travail terminé. Ceci permet à d'autres « threads » de verrouiller à nouveau le « mutex »et
de l'écrire sur la console. Le déverrouillage du « mutex »se fait avec la fonction « UnlockMutex() » (fichier d'aide :
Manuel de référence → Bibliothèques générales → Thread → UnlockMutex), auquel nous passons l'identifiant du «
mutex » à déverrouiller comme paramètre.
Voici un exemple qui utilise trois fils de discussion. Tous essaient de verrouiller l' objet « mutex » avec la fonction
« TryLockMutex() ». Si un « thread » ne réussit pas, il n'attend pas que le mutex soit libéré, mais affiche le temps
d'attente pour le « mutex » dans un « StringGadget ».
Enumeration
#WINDOW_ROOT
#TEXT_ONE
#TEXT_TWO
#TEXT_THREE
#BUTTON_START
EndEnumeration
Global Lock.l = CreateMutex()
Procedure Update(Gadget.l)
StartTime.l = ElapsedMilliseconds()
Repeat
If TryLockMutex(Lock)
For x.l = 1 To 20
SetGadgetText(Gadget, Str(Gadget) + " le mutex est verrouillé. " +
Str(x))
Delay(250)
Next x
UnlockMutex(Lock)
Break
Else
Time.s = "(" + Str((ElapsedMilliseconds() - StartTime) / 1000) + "
Secs)"
SetGadgetText(Gadget, Str(Gadget) + " attendre le mutex. " + Time)
Delay(1)
EndIf
ForEver
SetGadgetText(Gadget, Str(Gadget) + " c'est terminé.")
EndProcedure
#FLAGS = #PB_Window_SystemMenu | #PB_Window_ScreenCentered
If OpenWindow(#WINDOW_ROOT, 0, 0, 290, 130, " Test TryLockMutex() ", #FLAGS)
StringGadget(#TEXT_ONE, 10, 10, 270, 20, "")
StringGadget(#TEXT_TWO, 10, 40, 270, 20, "")
StringGadget(#TEXT_THREE, 10, 70, 270, 20, "")
ButtonGadget(#BUTTON_START, 95, 100, 100, 20, "Départ")
222 Au-Delà de l'Essentiel
Repeat
EventID.l = WaitWindowEvent()
Select EventID
Case #PB_Event_Gadget
Select EventGadget()
Case #BUTTON_START
Thread1.l = CreateThread(@Update(), #TEXT_ONE)
Thread2.l = CreateThread(@Update(), #TEXT_TWO)
Thread2.l = CreateThread(@Update(), #TEXT_THREE)
EndSelect
EndSelect
Until EventID = #PB_Event_CloseWindow
EndIf
End
Ici, vous pouvez voir que dans la procédure de fil, j'ai utilisé une boucle « repeat » pour garder le fil en marche alors qu'il
ne peut pas bloquer le « mutex ». Si le « mutex » peut être verrouillé, alors le « thread » compte jusqu'à vingt et met à
jour le gadget string. Une fois le processus de comptage terminé, le « mutex » est relâché et le mot-clé « Break » est
appelé pour quitter la boucle et terminer le fil. Une instruction « If » vérifie la valeur de retour de la fonction «
TryLockMutex() » et décide ensuite de l'action à effectuer.
Résumé de l'étude
Les filets sont un autre outil utile dans la boîte à outils du programmeur, et comme tout outil il doit être utilisé
correctement. Si vous créez un programme qui utilise des « threads », alors je vous recommande de toujours activer
l'option « Créer un exécutable sûr pour les threads » et d'utiliser aussi peu de « threads » que possible.
Je recommande également de lire la section « Thread » complète de l'aide PureBasic (fichier d'aide : Manuel de
référence → Bibliothèques générales → Thread), car il y a beaucoup d'autres commandes de « Thread » utiles décrites
ici, que je ne pourrais pas lister toutes ici. Avant de travailler avec des « Threads », vous devez être pleinement
conscient de leur utilité et de leurs limites.
Le concept de DLL était autrefois destiné à réduire la taille du programme et la consommation de mémoire en stockant
les bibliothèques sur le disque dur et en ne les rechargeant qu'en cas de besoin. Mais la réalité est souvent différente, et
surtout avec le système d'exploitation Microsoft Windows, cette " maladie " est répandue. Ici vous trouvez souvent les
mêmes DLLs dans des versions différentes, parce qu'elles sont nécessaires à des programmes différents pour des
raisons de compatibilité. Cela signifie que parfois plusieurs versions de la même DLL (mais dans des versions
différentes) sont nécessaires. Cette circonstance a donné à Windows le surnom « DLL Hell » pour indiquer quels
problèmes peuvent en découler.
Mettons de côté les problèmes de système d'exploitation, les DLLs peuvent être très utiles si vous voulez créer un
programme de manière modulaire. Si vous trouvez un code particulier utile pour des programmes futurs, vous pouvez le
compiler dans une DLL et le mettre à la disposition de tout programme.
PureBasic rend l'utilisation des DLLs via la bibliothèque « Library » intégrée (fichier d'aide : manuel de référence →
Bibliothèques générales → Bibliothèque) très facile. Vous pouvez facilement charger et utiliser des DLLs, tandis que le
compilateur PureBasic a une option pour créer votre propre code de programme dans un fichier DLL à compiler. Cela fait
de PureBasic le choix parfait pour l'utilisation des DLLs.
Au-Delà de l'Essentiel 223
Lors de l'écriture du code d'une DLL, assurez-vous qu'il y a quatre noms de procédure spécialement réservés qui sont
automatiquement appelés par Windows une fois la DLL chargée. Ces quatre procédures sont définies comme n'importe
quelle autre procédure DLL, mais si elles sont correctement nommées Windows appelle chacune d'elles lorsqu'une
certaine condition se produit dans la DLL environnante. Je définis personnellement ces quatre fonctions dans toutes les
DLL que je crée, même si je ne les utilise pas. Ceci a la raison suivante, si jamais j'étends cette DLL particulière, alors
les fonctions sont disponibles si nécessaire et prêtes à l'emploi. Voici la liste des quatre noms de procédure réservés et
les conditions qui déclenchent leur exécution automatique :
« AttachProcess(Instance.i) »
Cette procédure est appelée une fois lorsqu'un programme charge la DLL. Cette procédure est le seul endroit de la DLL
où vous pouvez définir des tableaux et des listes. J'utilise également cette procédure pour définir des variables et des
structures. De cette façon, je garde tout ensemble au même endroit et évite de faire des définitions en dehors des
procédures. La seule limitation est qu'aucune procédure d'initialisation DirectX ne peut être écrite dans la procédure
« DetachProcess(Instance.i) »
Cette procédure est appelée lorsque le programme ferme la DLL. Tout code à nettoyer doit se trouver dans cette
procédure, comme le partage des ressources utilisées par la DLL.
« AttachThread(Instance.i) »
Cette procédure est appelée chaque fois qu'un thread est créé dans le programme qui charge cette DLL.
« DetachThread(Instance.i) »
Cette procédure est appelée chaque fois qu'un thread dans le programme qui a chargé cette DLL est fermé
Comme vous pouvez le voir dans la liste, ces procédures ne sont pas difficiles à comprendre et elles ont des noms
simples. Si vous voulez utiliser ces procédures appelées automatiquement dans votre DLL, vous n'avez qu'à définir les
noms de procédure comme décrit ci-dessus. Le paramètre « Instance » que toutes les procédures utilisent est un
gestionnaire d'instance (parfois aussi appelé gestionnaire de module). Ceci peut être très utile pour une programmation
plus avancée. Ce paramètre doit toujours être défini lorsque vous utilisez ces procédures, même si vous n'avez pas
l'intention de traiter le paramètre dans la procédure de votre code.
Vous savez maintenant comment programmer une DLL (tout doit se trouver à l'intérieur des procédures) et
vous connaissez les noms des procédures spéciales réservées. Laissez-moi vous montrer un exemple d'une simple DLL
ProcedureDLL AttachProcess(Instance.l)
Global Message.s = "C'est ma DLL."
EndProcedure
ProcedureDLL ShowAlert()
MessageRequester("Alerte", Message)
EndProcedure
Ici, j'ai l'habitude d'être bref et de ne pas parler de toutes les procédures spéciales réservées. Le seul que j'ai
utilisé dans l'exemple est la procédure « AttachProcess() », dans laquelle j'ai utilisé une procédure Globale avec le nom
« message ». La deuxième procédure de l'exemple a la propriété Nom « ShowAlarm() ». J'appellerai cette procédure
lorsque j'ouvrirai la DLL avec un autre programme. Comme vous pouvez le voir, le demandeur de message utilise la
chaîne de caractères dans la procédure « ShowAlarm() », que j'ai défini dans la procédure « AttachProcess() ».
224 Au-Delà de l'Essentiel
Vous aurez également remarqué que j'ai utilisé un autre mot-clé pour définir les procédures, au lieu de « Procédure »
j'ai utilisé « ProcedureDLL ». Ceci est essentiel si vous souhaitez créer des procédures réservées spéciales ou
des procédures disponibles pour tous les programmes. Vous pouvez utiliser le mot-clé par défaut « Procédure » pour
définir les procédures, mais elles ne seront pas disponibles pour les autres programmes qui chargent votre DLL. Les
procédures normales sont principalement utilisées dans les DLLs pour les calculs internes, etc.
Après avoir programmé notre DLL dans le style ci-dessus, nous devons la tester. Compilons donc l'exemple dans une
DLL d'abord. Puisque les bibliothèques Dynamic Link Libraries diffèrent un peu des programmes normaux, nous devons
informer le compilateur que nous voulons créer une DLL au lieu d'un programme normal. Si vous utilisez le compilateur
sur la ligne de commande, vous pouvez le faire avec l'option « /DLL ». Dans l'IDE, vous pouvez utiliser la boîte de
dialogue « Compiler Options » (Menu : Compilateur → Options du compilateur.... → Options du compilateur → Format
exécutable → DLL partagée). La Figure 52 montre où sélectionner « DLL partagée » dans la boîte de dialogue Options
du compilateur. Après avoir fait ceci vous pouvez sélectionner la commande « Create Executable...» dans le menu «
Compiler » pour créer la DLL actuelle. Vous avez ici la possibilité de définir un nom de fichier et l'emplacement de
stockage pour votre DLL.
Fig. 52
La boîte de dialogue « Options du compilateur » telle qu'elle apparaît sous Microsoft Windows
Après avoir créé votre DLL, vous remarquerez que le compilateur a créé trois fichiers. Par exemple, si nous
avions nommé notre DLL « [Link] », nous aurions trouvé les trois fichiers suivants :
Le premier fichier est bien sûr la DLL compilée, le second est un f ichier d' exportation et le troisième est un fichier
« bibliothèque » statique. PureBasic n'a besoin que de la DLL pour utiliser les commandes qu'elle contient, mais les
autres fichiers peuvent être utiles aux programmeurs d'autres langues. Si vous voulez publier une DLL, je vous
recommande de partager les trois fichiers. Si vous utilisez la DLL uniquement avec PureBasic, vous n'avez besoin que
du fichier DLL, vous pouvez ignorer les deux autres fichiers.
Au-Delà de l'Essentiel 225
#LIBRARY_DEMO = 0
If OpenLibrary(#LIBRARY_DEMO, "[Link]")
CallFunction(#LIBRARY_DEMO, "Afficher l'alerte")
CloseLibrary(#LIBRARY_DEMO)
EndIf
Ouvrez d'abord la bibliothèque avec la fonction « OpenLibrary() ». Ceci nécessite deux paramètres. Le premier est le
numéro PB que vous voulez associer à la bibliothèque nouvellement ouverte et le second est le nom de la DLL que vous
voulez ouvrir. Pour appeler une fonction dans la DLL ouverte, utilisez la fonction « CallFunction() » qui nécessite deux
paramètres obligatoires. Le premier paramètre est le numéro PB de la bibliothèque à partir de laquelle vous voulez
exécuter une fonction et le second paramètre est le nom de la procédure que vous voulez exécuter. Notez que vous
n'insérez pas de paranthèses à la fin lorsque vous saisissez le nom de la procédure. Après ces deux paramètres
obligatoires, la fonction « CallFunction() » peut encore avoir jusqu'à vingt paramètres optionnels passés à la procédure
dans la DLL. Ceci est utile lorsque la procédure dans la DLL nécessite des paramètres. La dernière fonction dans mon
exemple est la fonction « CloseLibrary() », qui ferme la DLL associée au numéro PB attribué
La création et l'utilisation de DLLs peuvent être un peu plus compliquées que ce qui est montré ici, mais les exemples
utilisés ici montrent les grandes lignes de l'ensemble du processus. Toutes les DLLs se composent de procédures, et
pour les utiliser, vous devez ouvrir la bibliothèque et appeler les procédures (peu importe la méthode que vous utilisez),
c'est aussi simple que cela.
Si vous utilisez une DLL de cette façon, vous pourriez être tenté d'ouvrir la DLL, d'utiliser une procédure et de refermer
immédiatement la bibliothèque. C'est très bien si vous appelez occasionnellement une ou deux procédures, mais vous
aurez des problèmes de vitesse si votre programme fait un usage intensif de la DLL. Une meilleure façon est d'ouvrir la
bibliothèque au démarrage du programme et d'utiliser les commandes de la DLL dans votre programme. Si vous quittez
ensuite votre programme, fermez d'abord la bibliothèque DLL. Cela garantit que la DLL n'est ouverte qu'une seule fois,
fermée une seule fois et que les pertes de vitesse pendant les opérations sur fichiers sont éliminées.
Comme vous pouvez le voir la chose est très simple et en dehors du mot-clé « ProcedureDLL », l' ensemble ressemble
à une procédure normale. Compiler le code dans une DLL puis l'appeler avec ce code :
#LIBRARY = 0
If OpenLibrary(#LIBRARY, "[Link]")
ReturnValue.l = CallFunction(#LIBRARY, "Multiplier les valeurs", 22, 33)
Debug ReturnValue
CloseLibrary(#LIBRARY)
EndIf
Ici, j'utilise à nouveau la fonction « CallFunction() » , mais cette fois j'utilise deux des paramètres optionnels pour
passer les valeurs à la procédure « MultiplyValues() » dans la DLL. Je passe les valeurs « 22 » et « 33 » comme
paramètres. Si ceux-ci sont passés à la procédure « MultiplyValues() » dans la DLL, il les utilisent comme paramètres et
les éditent en conséquence. Dans ce cas, les deux valeurs sont multipliées et le résultat est renvoyé. La valeur
retournée est ensuite transmise à la fonction « CallFunction() » et la fonction « CallFunction() » la transmet à notre
programme. J'ai utilisé une variable de type long nommé « Résultat » pour stocker la valeur retournée de la DLL. Je
l'édite ensuite dans la fenêtre Debug.
226 Au-Delà de l'Essentiel
Bien que cette possibilité de retourner des valeurs soit bonne pour la plupart des types d' entiers intégrés (voir
« Limitations sur le travail avec les DLL » ci-dessous), elle fonctionne un peu différemment avec les chaînes. Au début :
Chaque chaîne que vous voulez retourner d'une DLL doit être définie globalement. Ceci préservera la chaîne de
caractères lorsque la procédure DLL sera terminée. De plus, si une chaîne est reçue d'une procédure DLL, alors la
valeur retournée est un pointeur vers cette chaîne, même si le type de retour de la procédure a été défini comme chaîne.
ProcedureDLL AttachProcess(Instance.l)
Global MaChaine.s = "Je veux être dans le programme principal."
EndProcedure
ProcedureDLL.s GetString()
ProcedureReturn MaChaine
EndProcedure
Dans cet exemple, j'ai défini la procédure « GetString() » pour retourner une chaîne, et je me suis assuré que la
variable « MaChaine » est définie globalement. Compiler l'exemple dans une DLL et l'appeler avec ce code :
#LIBRARY = 0
If OpenLibrary(#LIBRARY, "[Link]")
*ReturnValue = CallFunction(#LIBRARY, "GetString")
Debug PeekS(*ReturnValue)
CloseLibrary(#LIBRARY)
EndIf
Vous pouvez voir que la fonction « CallFunction() » renvoie un pointeur, nous devons donc utiliser une variable
pointeur pour stocker la valeur. J'ai donc créé un pointeur avec le nom « *Result » pour enregistrer l'adresse retournée.
Avec la fonction « PeekS() » j'obtiens la chaîne de caractères de cette adresse.
Pour retourner une valeur flottante d'une procédure DLL, il est préférable d'utiliser à nouveau un pointeur et de lire la
valeur réelle dans le programme principal avec la fonction « PeekF() ». Voici un petit exemple de comment retourner
avec succès une valeur flottante d'une procédure DLL. Tout d'abord, voici l'exemple DLL :
ProcedureDLL AttachProcess(Instance.l)
Global MyFloat.f = 3.1415927
EndProcedure
ProcedureDLL.l GetPi()
ProcedureReturn @MyFloat
EndProcedure
Au lieu de retourner la valeur flottante réelle, la procédure DLL « GetPi() » est définie pour retourner une valeur longue.
Cela me permet de passer l'adresse mémoire de la variable flottante. Après la compilation dans une DLL, je peux
appeler la fonction avec le code suivant :
#LIBRARY = 0
If OpenLibrary(#LIBRARY, "[Link]")
*ReturnValue = CallFunction(#LIBRARY, "GetPi")
Debug PeekF(*ReturnValue)
CloseLibrary(#LIBRARY)
EndIf
Au-Delà de l'Essentiel 227
Une fois l'adresse mémoire retournée, elle est assignée au pointeur « *Result ». Puis j'utilise la fonction « PeekF() »
pour lire la valeur flottante de l'emplacement vers lequel pointe le pointeur. Strictement parlant, cette astuce avec le
pointeur peut aussi être utilisée pour les quads ou les doubles, vous pouvez donc dire que PureBasic supporte
effectivement le retour de ces types.
Il n'y a actuellement aucun moyen de passer une valeur Quad ou Double comme paramètre à une procédure DLL en
utilisant les commandes « Library ».
L'utilisation des DLLs est très facile si vous vous intéressez de front à la transmission et au retour des valeurs. Ils
rendent le code réutilisable en le plaçant dans une bibliothèque bien emballée. Il y a quelques limitations à l'utilisation de
certains types intégrés, mais elles peuvent être contournées avec des techniques plus avancées, généralement en
utilisant un pointeur vers les données requises. Les approches plus compliquées, comme les prototypes, sont encore un
peu trop avancées pour le moment, mais vous pouvez toujours en apprendre plus à leur sujet dans l'aide PureBasic
(fichier d'aide : Manuel de référence → Bibliothèques générales → Prototype) et vous familiariser avec elles. Ne soyez
pas choqué si vous ne les comprenez pas la première fois que vous essayez. De plus, je recommande de lire la section
« Bibliothèque » de l'aide de PureBasic (fichier d'aide : Manuel de référence → Bibliothèques générales → Bibliothèque
→) pour en savoir plus sur les commandes qui peuvent être utilisées avec les DLLs. Cela devrait vous donner une
bonne compréhension des possibilités disponibles avant de décider de programmer votre première DLL réelle.
Si nécessaire, la convention d'appel « cdecl » peut être utilisée en utilisant les fonctions « C » complémentaires du
groupe de commandes « Library » de PureBasic. Par exemple, au lieu d'utiliser le mot-clé « ProcedureDLL » pour
créer une procédure DLL « stdcall », vous pouvez utiliser la convention d'appel « cdecl » en utilisant plutôt le mot-
clé « ProcedureCDLL ». Il en va de même pour les procédures d'appel à partir des DLLs. Au lieu d'appeler une
procédure « stdcall » en utilisant la commande « CallFunction() », vous pouvez appeler une procédure « cdecl »
en utilisant la commande « CallFunction() ».
Il existe d'autres fonctions « C » complémentaires qui peuvent être utilisées dans PureBasic, consultez le fichier
d'aide dans la section « Bibliothèque » pour une liste complète.
L'interface de programmation d'application de Windows (habituellement abrégée comme Win32 API) se trouve dans
toutes les nouvelles versions du système d'exploitation Microsoft Windows, c'est une interface de programmation
largement utilisée qui peut être utilisée par tous les programmes informatiques. L'API Win32 est fondamentalement une
grande bibliothèque de commandes qui est distribuée sur de nombreuses DLLs différentes et s'installe automatiquement
sur le disque dur pendant l'installation normale de Windows. L'API elle-même fait partie du système d'exploitation et peut
être utilisée par n'importe quel programme informatique pour exécuter la plupart des fonctions du système d'exploitation,
telles que l'ouverture de fenêtres, la manipulation de chaînes, le dessin de formes, etc.
#LIBRARY = 0
If OpenLibrary(#LIBRARY, "[Link]")
MB_OK = 0
Caption.s = "Test"
TextString.s = "Ceci est un test de l'API Win32"
CallFunction(#LIBRARY, "Message Box A", #Null, @TextString,
@Caption, MB_OK)
CloseLibrary(#LIBRARY)
EndIf
Vous pouvez voir que vous devez d'abord ouvrir la DLL avec la commande requise. Ici c'est la commande
« MessageBoxA » qui se trouve dans la « [Link] ». Après l'avoir ouverte, vous pouvez appeler la commande
requise et lui transmettre les paramètres nécessaires. C'est bien beau, mais c'est aussi un peu compliqué et
fastidieux. Dans PureBasic, vous pouvez appeler la même commande comme suit :
Avez-vous remarqué le trait de soulignement « _ » après le nom de la commande ? Ceci indique clairement qu'il s'agit
d'une commande API et l'appelle automatiquement depuis la DLL correspondante. Je pense que nous sommes d'accord
pour dire que cette approche est beaucoup plus facile et rapide. Nous utilisons les commandes API comme s'il s'agissait
de commandes PureBasic standard.
Le soulignement peut être utilisé pour insérer automatiquement une commande de l'API Win32. Dans l'API Win32, par
exemple, il y a une commande appelée « CharUpper » qui convertit une chaîne en majuscules. En utilisant le trait de
soulignement avant les parenthèses, nous pouvons utiliser cette commande comme une commande PureBasic normale
comme ici :
Selon la documentation de l'API Win32, cette commande nécessite l'adresse mémoire d'une chaîne comme paramètre,
c'est pourquoi je la passe. Si vous démarrez cet exemple et regardez la fenêtre Debug, vous remarquerez que la chaîne
a été convertie en majuscules.
L'utilisation de l'API Win32 de cette façon désamorce les tracas liés à l'ouverture des DLL requises et vous permet
d'utiliser les commandes API dans votre programme quand vous en avez besoin. Si vous utilisez la version Windows de
PureBasic, vous pouvez toujours mélanger les commandes normales avec les commandes API de votre code comme
vous le souhaitez.
Vous pouvez le voir dans la version PureBasic de l'exemple « MessageBox » où j'ai utilisé la constante
« #MB_OK »sans la définir au préalable. Cela fonctionne car la constante « #MB_OK » de l'API Win32 a déjà été définie
en interne. Pour utiliser une constante de l'API Win32 dans PureBasic, il suffit de mettre le hashtag « # » devant le nom
de la constante et elle devrait être utilisable comme si elle avait été définie directement dans votre code source
Il en va de même pour les structures de l'API Win32, quand vous en avez besoin, il suffit de l'utiliser. Vous n'avez pas
besoin de les définir. Regardez cet exemple :
[Link]
DesktopHandle.l = GetDesktopWindow_()
GetClientRect_(DesktopHandle, @DesktopInfo)
Ici, j'utilise la structure de l'API Win32 appelée « RECT » sans l'avoir définie auparavant, puis j'utilise les commandes de
l'API Win32 « GetDesktopWindow » et « GetClientRect » comme si elles étaient des commandes intégrées (voir les
soulignements). Comme vous pouvez le voir dans la structure « RECT » , toutes les structures de l'API Win32 ont été
définies en lettres majuscules dans le nom. C'est le formulaire par défaut lors de la programmation à l'aide de l'API
Win32, et mon orthographe préférée pour les structures comme décrit dans le chapitre 8 (Mon code de conception).
Ces conventions de nommage correspondent exactement à la façon dont les structures ont été définies dans la
référence API Win32. De cette façon, j'évite la confusion lorsque vient le temps de les utiliser.
Par exemple, si la documentation de l'API Win32 indique qu'une commande particulière nécessite une variable de type
« RECT » , vous pouvez utiliser « RECT » directement dans votre code PureBasic comme structure.
Considérez cet exemple de texte de la documentation de l'API Win32 qui décrit la commande API « BeginPaint ».
HDC BeginPaint(
HWND hwnd, // Poignée à fenêtre
PAINTSTRUCT lpPaint // Pointeur sur la structure avec les informations à dessiner);
Paramètre
hwnd
Identificateur de la fenêtre à redessiner.
lpPaint
Pointeur sur la structure PAINTSTRUCT qui reçoit les informations à dessiner.
valeurs de retour
Si la fonction a réussi, alors la valeur de retour est la poignée dans le contexte du
dispositif d'affichage (HDC) de la fenêtre spécifiée. Si la fonction échoue, la valeur de
retour est NULL, indiquant qu'aucun contexte de dispositif d'affichage n'est disponible.
Vous pouvez voir que cette commande nécessite un pointeur (ou adresse mémoire) vers une variable structurée comme
deuxième paramètre, et que cette variable doit être créée avec la structure « PAINTSTRUCT ». Pour créer une telle
variable dans PureBasic, nous procédons comme suit :
[Link]
Et c'est tout. La structure « PAINTSTRUCT » a déjà été définie en interne, nous pouvons donc l'utiliser ici sans notre
propre définition. Un exemple entièrement fonctionnel dans votre programme principal pourrait ressembler à ceci :
...
[Link]
WindowHandle.l = WindowID(#MY_WINDOW)
HDC.l = BeginPaint_(WindowHandle, @PaintVariable)
...
Après l'ouverture du répertoire de structure, une liste de toutes les structures définies en interne s'affiche. Cette liste
peut être recherchée et triée par ordre alphabétique en cliquant sur le champ correspondant. Même si cette liste
n'affiche initialement que des structures, vous pouvez également afficher les interfaces et les constantes en
sélectionnant l'onglet correspondant. Nous n'avons pas discuté des interfaces dans ce livre, mais la liste des constantes
est très utile pour vous, car elle affiche toutes les constantes internes avec leurs valeurs associées. Toutes les
constantes PureBasic intégrées sont également visibles ici.
Pour afficher la définition réelle d'une structure définie en interne, double-cliquez simplement sur le nom de la structure
dans la liste. Une fois que vous avez fait ceci, les boutons « Coller Copier » et « Coller » deviennent actifs. Le bouton
« Insert Copy » insère une copie de la définition de la structure dans votre code source PureBasic, tandis que le
bouton'Insert' insère le code pour l'utilisation réelle de la structure dans votre code source. Ouvrez une nouvelle fenêtre
de source et jouez un peu avec elle pour découvrir comment elle fonctionne.
Filtre alphabétique
bouton Précédent
Insérer une copie
(utilisé pour revenir à
(ajoute le bouton
la liste principale)
définition de structure
dans le code source)
La boîte de dialogue « Structure Directory » telle qu'elle apparaît sous Microsoft Windows
Fig. 53
La plus petite référence que j'utilise est le fichier « [Link] », un fichier d'aide Windows contenant une référence aux
commandes API Win32. Ce fichier d'aide ne fait pas partie du paquet PureBasic, vous devez donc le télécharger et
l'installer vous-même. Vous pouvez trouver ce fichier sur « PureArea », un lien vers ce fichier se trouve à l'annexe A
(Liens Internet utiles). Après avoir chargé le fichier «[Link] » vous devez le copier dans un dossier nommé « Help »
dans le répertoire PureBasic. S'il n'y a pas de dossier « Help » dans votre répertoire PureBasic, vous devez le créer et y
copier le(s) fichier(s) « [Link] ». Parfois, le fichier d'aide est accompagné d'autres fichiers, tels que « [Link] » et
« [Link] », auquel cas vous copiez tous les fichiers ensemble dans ce dossier. Après avoir fait cela, vous pouvez
profiter de l'avantage d'intégrer ce fichier dans l'EDI.
Au-Delà de l'Essentiel 231
Une fois le fichier correctement installé, vous pouvez sélectionner n'importe quelle API Win32 dans l'IDE en déplaçant le
curseur sur la commande et en appuyant sur F1. Le fichier « [Link] » apparaît maintenant à la place de l'aide
PureBasic et affiche la description de la commande API Win32 sélectionnée sur la page correcte. Ce comportement ne
met pas fin à la fonction de l'aide standard PureBasic, seul un autre fichier d'aide est affiché, en fonction de la
commande sélectionnée dans l'EDI.
Essayez-le vous-même, prenez ce code dans un exemple précédent, déplacez le curseur clignotant sur la commande
« GetClientRect » et appuyez sur « F1 ».
[Link]
DesktopHandle.l = GetDesktopWindow_()
GetClientRect_(DesktopHandle, @DesktopInfo)
Vous devriez maintenant voir que le fichier « [Link] » s'ouvre et affiche la page de commande « GetClientRect ».
Rappelez-vous que le fichier « [Link] » est un fichier d'aide Windows standard et qu'il est donc facilement navigable
et entièrement consultable. Ce fichier peut valoir la peine d'être regardé si vous prévoyez de vous impliquer davantage
dans la programmation de l'API Win32.
Un autre inconvénient est que l'API Win32 a été développée à l'origine pour utiliser C et C+++ comme langage de
programmation, et en tant que tel contient beaucoup de références à des types de données avancées qui n'existent tout
simplement pas dans PureBasic. Mais pour la plupart de ces types, vous pouvez utiliser un type PureBasic en
remplacement des types C/C++. La Figure 54 montre un tableau indiquant le type PureBasic que vous pouvez utiliser à
la place du type C/C++ indiqué. Par exemple, si vous voyez dans la description de l'API Win32 d'une commande
particulière qu'elle nécessite une variable de type'DWORD32', vous pouvez voir dans la Figure 54 que vous pouvez
utiliser l'entier de type PureBasic.
Vous aurez remarqué que certains types de la Fig. 54 sont marqués du symbole « † ». Ceci indique que ces
types ne correspondent pas exactement à leurs équivalents PureBasic. La raison de cette confusion est que les types
d'API Win32 marqués sont des types non signés (sauf « TBYTE »), alors que les types de remplacement PureBasic sont
tous signés. Par conséquent, certaines valeurs peuvent déborder lorsqu'elles sont utilisées dans leurs équivalents
PureBasic. La seule exception est le type d'API: « TBYTE », qui est signé, alors que son homologue PureBasic est non
signé. Cela ne pose pas un gros problème pour votre programme, car avec un peu de programmation vous pouvez
facilement convertir les valeurs signées en valeurs non signées et inversement. Voici quelques procédures que vous
pouvez utiliser pour convertir tous ces types de problèmes :
Integer
BOOL HHOOK LANGID LPWORD PSHORT
COLORREF HICON LCID LPWSTR PSTR
DWORD HIMAGELIST LCTYPE LRESULT PTBYTE
DWORD32 HIMC LONG PBOOL PTCHAR
HACCEL HINSTANCE LONG32 PBOOLEAN PTSTR
HANDLE HKEY LPARAM PBYTE PUCHAR
HBITMAP HKL LPBOOL PCHAR PUINT
HBRUSH HLOCAL LPBYTE PCRITICAL_SECTION PULONG
HCONV HMENU LPCOLORREF PCSTR PUSHORT
HCONVLIST HMETAFILE LPCRITICAL_SECTION PCTSTR PVOID
HCURSOR HMODULE LPCSTR PCWCH PWCHAR
HDC HMONITOR LPCTSTR PCWSTR PWORD
HDDEDATA HPALETTE LPCVOID PDWORD PWSTR
HDESK HPEN LPCWSTR PFLOAT SC_HANDLE
HDROP HRGN LPDWORD PHANDLE SC_LOCK
HDWP HRSRC LPHANDLE PHKEY SERVICE_STATUS_HANDLE
HENHMETAFILE HSZ LPINT PINT UINT †
HFILE HWINSTA LPLONG PLCID UINT32 †
HFONT HWND LPSTR PLONG ULONG †
HGDIOBJ INT LPTSTR PLUID ULONG32 †
HGLOBAL INT32 LPVOID POINTER_32 WPARAM
Les types marqués par « † » doivent être lus correctement après un appel de commande. Ces types peuvent Fig. 54
être signés ou non signés contrairement aux types PureBasic que vous utilisez.
Par exemple, si vous utilisez un octet PureBasic (qui est signé) pour stocker une valeur « UCHAR » non signée, vous
ne pouvez lire correctement cette valeur qu'en utilisant la procédure « UCHAR() » , comme ici :
Le seul inconvénient de l'utilisation de ces procédures est que (même si c'est tout à fait correct) les valeurs qu'elles
retournent occupent deux fois plus de mémoire que le type que vous avez passé comme paramètre. Regardez la
procédure « UCHAR() » du dernier exemple. Il accepte un octet comme paramètre « UCHAR » que vous voulez lire,
mais la valeur retournée est de type Word et contient la valeur correcte non signée. C'est deux fois la taille de l'octet
original. Ceci doit être géré de cette façon car presque tous les types PureBasic sont signés. Par conséquent, nous
devons utiliser un type suffisamment grand pour exprimer correctement la valeur non signée afin d'éviter les erreurs de
débordement.
Assigner des valeurs non signées à des types signés est par contre facile. Comme le montre le dernier exemple, vous
pouvez attribuer une valeur non signée à un type signé, mais cette valeur est toujours stockée comme valeur signée.
C'est ainsi que cette ligne de code est stockée :
MonUCHAR.b = 255
Debug MonUCHAR
Mémoriserait en fait « -1 ». Ceci est implémenté dans PureBasic pour faciliter la conversion de l'API Win32.
Voici les types de pointeur de chaîne Win32 API, et plus important encore, comment lire correctement chaque type de
chaîne de caractères de ou l'écrire dans la mémoire :
« LPCSTR »
Un octet par chaîne de caractères (ASCII), même si le programme a été compilé en mode Unicode.
« LPCWSTR »
Deux octets par chaîne de caractères (Unicode), même si le programme n'a pas été compilé en mode Unicode.
PeekS(StringPointer.l, StringLength)
PokeS(StringPointer.l, Text.s, StringLength)
V. Annexe
Cette section contient les annexes du livre. Ce matériel supplémentaire contient diverses informations utiles telles que
des liens Internet utiles, des pages avec des tableaux utiles et un glossaire complet des termes techniques liés à
l'informatique.
Ces pages de conclusion vous donneront un bref aperçu de certains des sujets les plus utiles que vous voudrez peut-
être revoir de temps à autre.
PureBasic Beginners
[Link]
Ce site web appartient à ce livre. La plupart des codes, images et fichiers son utilisés dans les exemples de ce livre
peuvent être téléchargés à partir de ce site Web, ainsi que d'autres outils utiles, dont le fichier « [Link] ».
Ces pages seront, nous l'espérons, l'une de vos premières escales si vous utilisez PureBasic. Tout ce que vous avez à
faire est de vous inscrire, et vous pouvez poser autant de questions que vous le souhaitez. Ce forum en ligne est
également surveillé par l'équipe PureBasic et permet de répondre aux discussions et aux questions concernant
PureBasic. Vous ne devez pas sous-estimer la richesse des informations sur PureBasic sur ces pages. Non seulement
vous avez accès aux connaissances partagées de centaines de programmeurs PureBasic, mais vous avez également la
possibilité de rechercher dans des messages déjà enregistrés. Cela signifie que vous avez un accès instantané à des
années de connaissances PureBasic. Peut-être que votre problème a déjà été résolu par quelqu'un d'autre.
PureArea
[Link]
Cette page contient beaucoup de matériel pertinent de PureBasic, y compris des milliers d'exemples de code PureBasic
dans les « Archives de codes » téléchargeables, des « Bibliothèques d'utilisateurs » téléchargeables et des liens vers des
centaines de shareware et d'outils gratuits créés avec PureBasic. Sur cette page, vous trouverez également une version
en ligne du manuel de référence PureBasic.
Cette page contient les nouvelles et les versions actuelles du concepteur visuel officiel de PureBasic. Tout ce qui
concerne le développement du Visual Designer se trouve sur cette page.
Annexe A : Liens Internet Utiles 235
PureProject
[Link]
Plusieurs extraits de code PureBasic ainsi que des jeux, des applications et de nombreuses « bibliothèques utilisateur »
téléchargeables. Sur cette page il y a aussi une section traitant de l'API Windows.
Pure Vision
[Link]
Un remplacement commercial pour le PureBasic Visual Designer standard. Avec ce concepteur visuel professionnel, il
est également possible de créer des interfaces utilisateur modifiées dont l'apparence diffère de celle du standard
Windows (GUI Skinning).
Page de l'API Windows de Microsoft. Sur cette page, vous trouverez des informations détaillées sur l'interface de
programmation d'applications Windows. Utilisez le champ de recherche du site Web pour trouver rapidement
l'information que vous recherchez.
API-Guide
[Link]
[Link]
Un programme appelé « API-Guide » qui vous permet de lister toutes les commandes API Win32 disponibles. Pour
toutes les commandes, les détails et les paramètres requis sont disponibles ainsi que des exemples pour presque toutes
les commandes. Notez que les exemples ont été développés pour Visual Basic, mais qu'ils sont faciles à convertir en
PureBasic.
OGRE Engine
[Link]
Le site du moteur OGRE 3D. Il est utilisé par PureBasic pour les graphiques 3D.
Ce plugin est utilisé par PureBasic pour lire les modules. Pour plus d'informations, reportez-vous au chapitre 12
(Fichiers du module).
236 Annexe A : Liens Internet Utiles
B. Tables Utiles
Cette annexe contient de nombreux tableaux utiles, dont certains ont déjà paru dans ce livre. Ceux-ci sont montrés
ici encore une fois pour vous aider à trouver plus facilement certaines choses dont vous avez besoin.
+ En plus. Ajoute la valeur de l'expression RVO à la valeur de l'expression LVO et retourne le résultat. Si le résultat de cet opérateur n'est
pas utilisé et qu'il existe une variable LVO, la valeur de l'expression RVO est ajoutée directement à la variable LVO.
- Moins. Soustrait la valeur de l'expression RVO de la valeur de l'expression LVO. S'il n'y a pas d'expression LVO, la valeur de l'expression
RVO aura un signe négatif. Si le résultat de cet opérateur n'est pas utilisé et qu'il existe une variable LVO, la valeur de l'expression RVO
est soustraite directement de la variable LVO. (Cet opérateur ne peut pas être utilisé avec des chaînes de caractères).
* Multiplication. Multiplie la valeur de l'expression LVO par la valeur de l'expression RVO. Si le résultat de cet opérateur n'est pas utilisé et
qu'il y a une variable LVO, alors la valeur de l'expression RVO est multipliée directement dans la variable LVO (cet opérateur ne peut pas
être utilisé avec des chaînes).
/ Division. Divise la valeur de l'expression LVO par la valeur de l'expression RVO. Si le résultat de cet opérateur n'est pas utilisé et qu'il y a
une variable LVO, alors la valeur de la variable LVO est divisée directement par la valeur de l'expression RVO. (Cet opérateur ne peut pas
être utilisé avec des chaînes de caractères).
& Au niveau du bit ET. Vous devriez être familier avec les nombres binaires lorsque vous utilisez 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. Cela se fait petit à petit. Si le résultat de l'opérateur n'est pas
utilisé et qu'il y a une variable LVO, alors le résultat est stocké directement dans cette variable (cet opérateur ne peut pas être utilisé avec
des chaînes).
| Au niveau du bit OU. Vous devriez être familier avec les nombres binaires lorsque vous utilisez cet opérateur. Le résultat de cet opérateur
est la valeur de l'expression LVO OU liée à la valeur de l'expression RVO. Cela se fait petit à petit. Si le résultat de l'opérateur n'est pas
utilisé et qu'il y a une variable LVO, alors le résultat est stocké directement dans cette variable (cet opérateur ne peut pas être utilisé avec
des chaînes).
! Au niveau du bit XOR. Vous devriez être familier avec les nombres binaires lorsque vous utilisez cet opérateur. Le résultat de cet opérateur
est la valeur de l'expression LVO EXCLUSIVE OU liée à la valeur de l'expression RVO. Cela se fait petit à petit. Si le résultat de l'opérateur
n'est pas utilisé et qu'il y a une variable LVO, alors le résultat est enregistré directement dans cette variable. (Cet opérateur ne peut pas
être utilisé avec des chaînes de caractères).
~ Au niveau du bit PAS. Vous devriez être familier avec les nombres binaires lorsque vous utilisez cet opérateur. Le résultat de cet opérateur
est la valeur NON liée de l'expression RVO, c'est-à-dire que les bits du résultat sont inversés par rapport à la valeur de l'expression. (Cet
opérateur ne peut pas être utilisé avec des chaînes de caractères).
< Plus petit que. Permet de comparer les valeurs des termes LVO et RVO. Si la valeur de l'expression LVO est inférieure à la valeur de
l'expression RVO, l'opérateur retourne True, sinon il retourne False.
> Plus grand que ça. Permet de comparer les valeurs des expressions LVO et RVO. Si la valeur de l'expression LVO est supérieure à la
valeur de l'expression RVO, l'opérateur retourne True, sinon il retourne False.
<= Moins ou égal. Permet de comparer les valeurs des expressions LVO et RVO. Si la valeur de l'expression LVO est inférieure ou égale à la
valeur de l'expression RVO, l'opérateur retourne Vrai, sinon il retourne Faux.
>= Plus grand ou égal. Permet de comparer les valeurs des expressions LVO et RVO. Si la valeur de l'expression LVO est supérieure ou égale
à la valeur de l'expression RVO, l'opérateur retourne Vrai, sinon il retourne Faux.
<> Ce n'est pas l'égalité. Permet de comparer les valeurs des expressions LVO et RVO. Si la valeur de l'expression LVO est égale à la valeur
de l'expression RVO, l'opérateur retourne False, sinon il retourne True.
And Logique ET. Permet de comparer les valeurs des expressions LVO et RVO. Si la valeur de l'expression LVO et la valeur de l'expression
RVO sont toutes deux vraies, l'opérateur retourne Vrai, sinon il retourne Faux.
Or Logique OU. Permet de comparer les valeurs des expressions LVO et RVO. Si la valeur de l'expression LVO ou la valeur de l'expression
RVO est vraie, l'opérateur retourne True, sinon il retourne False.
Not Logique NOT. Utilisé pour annuler une valeur booléenne. En d'autres termes, si une expression retourne Vrai, elle est convertie en Faux
par l'opérateur Non. Inversement, si l'expression RVO renvoie False, elle est convertie en True.
XOr XOR logique. Permet de comparer les valeurs des expressions LVO et RVO. Si une seule des expressions LVO ou RVO renvoie Vrai, le
résultat est Vrai. Si les deux expressions sont Vrai ou Faux, l'opérateur XOr retourne Faux.
<< Arithmétique poussant vers la gauche. Déplace chaque bit de la valeur d'expression LVO vers la gauche du nombre de chiffres défini par la
valeur d'expression RVO. Si le résultat de cet opérateur n'est pas utilisé et qu'il y a une variable LVO, alors la valeur de la variable est
décalée du nombre de chiffres RVO. Il est utile que vous ayez compris les nombres binaires lorsque vous utilisez cet opérateur. Chaque
chiffre décalé agit comme une multiplication par 2.
>> Arithmétique poussant vers la droite. Déplace chaque bit de la valeur d'expression LVO vers la droite du nombre de chiffres défini par la
valeur d'expression RVO. Si le résultat de cet opérateur n'est pas utilisé et qu'il y a une variable LVO, alors la valeur de la variable est
décalée du nombre de chiffres RVO. Il est utile que vous ayez compris les nombres binaires lorsque vous utilisez cet opérateur. Chaque
chiffre décalé agit comme une division avec un facteur 2.
( ) Parenthèses. Vous pouvez utiliser des parenthèses pour éditer une partie d'une expression de préférence ou dans un ordre spécifique.
Les expressions entre parenthèses sont éditées avant toute autre partie de l'expression. Entre parenthèses imbriquées, les plus intimes
sont d'abord résolus, puis plus loin.
Integer
BOOL HHOOK LANGID LPWORD PSHORT
COLORREF HICON LCID LPWSTR PSTR
DWORD HIMAGELIST LCTYPE LRESULT PTBYTE
DWORD32 HIMC LONG PBOOL PTCHAR
HACCEL HINSTANCE LONG32 PBOOLEAN PTSTR
HANDLE HKEY LPARAM PBYTE PUCHAR
HBITMAP HKL LPBOOL PCHAR PUINT
HBRUSH HLOCAL LPBYTE PCRITICAL_SECTION PULONG
HCONV HMENU LPCOLORREF PCSTR PUSHORT
HCONVLIST HMETAFILE LPCRITICAL_SECTION PCTSTR PVOID
HCURSOR HMODULE LPCSTR PCWCH PWCHAR
HDC HMONITOR LPCTSTR PCWSTR PWORD
HDDEDATA HPALETTE LPCVOID PDWORD PWSTR
HDESK HPEN LPCWSTR PFLOAT SC_HANDLE
HDROP HRGN LPDWORD PHANDLE SC_LOCK
HDWP HRSRC LPHANDLE PHKEY SERVICE_STATUS_HANDLE
HENHMETAFILE HSZ LPINT PINT UINT †
HFILE HWINSTA LPLONG PLCID UINT32 †
HFONT HWND LPSTR PLONG ULONG †
HGDIOBJ INT LPTSTR PLUID ULONG32 †
HGLOBAL INT32 LPVOID POINTER_32 WPARAM
Les types marqués par « † » doivent être lus correctement après un appel de commande. Ces types peuvent
être signés ou non signés contrairement aux types PureBasic que vous utilisez.
Fig. 54
Fig. 56
242 Annexe B : Tableaux Utiles
Fig. 56
Annexe C : Index des termes 243
Cet index est une collection de termes et d'abréviations que vous pouvez rencontrer dans votre vie quotidienne de
programmation. Dans cette annexe, j'ai essayé de décrire chaque terme de manière aussi détaillée que nécessaire mais
aussi courte que possible pour vous faciliter la vie si vous rencontrez quelque chose que vous ne connaissez pas.
3D Engine
Un moteur 3D est un environnement programmé uniquement dans le but de fournir une construction dans laquelle des
graphiques 3D peuvent être réalisés. Un moteur 3D peut être expliqué comme une couche d'abstraction qui permet aux
artistes ou aux développeurs d'assembler rapidement et facilement des objets 3D. Cela signifie qu'ils n'ont pas à
s'occuper de la programmation au niveau le plus bas. Par exemple, un moteur 3D fournit probablement une
fonction'LoadModel()' qui charge et affiche un modèle 3D, rendant le travail de l'utilisateur beaucoup plus facile. Les
moteurs 3D offrent parfois aussi d'autres fonctions utiles, comme la détection de collisions et un moteur physique.
Absolut
Peut se référer à une valeur ou à un chemin. Une valeur absolue est une valeur autonome qui ne fait pas référence à
une autre valeur. Un chemin absolu est une spécification de chemin complète. Par exemple, toutes les adresses Internet
sont des chemins absolus, comme vous pouvez le voir dans la barre d'adresse de votre navigateur Internet. Des
chemins absolus sont utilisés pour s'assurer clairement qu'un fichier particulier est accessible exactement à cet endroit.
ActiveX
Une spécification Microsoft pour les composants logiciels réutilisables. ActiveX est basé sur COM, qui spécifie comment
un composant interagit et collabore avec les autres. Les contrôles ActiveX peuvent ajouter des fonctionnalités avancées
aux applications en s'attachant à l'interface du programme avec des modules prédéfinis. Les modules peuvent être
échangés, mais apparaissent toujours comme faisant partie du programme original. Sur Internet, les contrôles ActiveX
peuvent être intégrés dans des pages Web qui peuvent être téléchargées et exécutées par un navigateur Web
compatible ActiveX. Les contrôles ActiveX peuvent fournir les mêmes fonctionnalités que n'importe quel autre
programme s'exécutant sur un serveur. Les contrôles ActiveX peuvent avoir un accès complet au système ! Dans la
plupart des cas, cet accès est tout à fait légitime, mais le passé a montré que cet accès était également exploité par
Schad-ActiveX Controls.
Algorithmes
Une procédure explicite étape par étape qui crée une solution à un problème.
Canal Alpha
Les formats d'image qui prennent en charge cette fonction réservent une partie des données de pixels pour
les informations de transparence. Certains formats d'image 32 bits contiennent quatre canaux, trois canaux 8 bits
pour le rouge, le vert et le bleu et un canal alpha 8 bits. Le canal alpha est un masque. Il spécifie la proportion de la
couleur du pixel qui est fusionnée avec une autre couleur de pixel sous-jacente d'une autre image.
Anti-Virus Software
Logiciel qui analyse la mémoire et le disque dur d'un ordinateur à la recherche de virus. S'il a trouvé un virus,
l'application informe l'utilisateur de la découverte et nettoie le fichier infecté par le code malveillant, le met en
quarantaine ou le supprime.
Applet
Une application miniature qui est transportée sur Internet, souvent comme une extension d'une page Web.
244 Annexe C : Index des termes
Array
Une structure de données simple qui stocke des éléments de données de la même taille qui doivent toujours être du
même type. Les éléments individuels sont adressés par un index constitué d'une gamme continue de nombres entiers.
Certains tableaux sont multidimensionnels, c'est-à-dire que l'indice est composé de plusieurs valeurs entières. Les plus
courantes sont les tableaux unidimensionnels et bidimensionnels.
ASCII Art
Dessins créés à l' aide de caractères ASCII. Habituellement, des polices non proportionnelles sont utilisées pour
s'assurer que chaque caractère du graphique a la même largeur.
Assembler
Un programme informatique qui traduit le langage assembleur en code exécutable.
Attribute
Propriétés assignées à tous les fichiers et répertoires. attributs : Lecture seule, archivage, statut caché ou système
uniquement.
Back Door
Une fonction que les programmeurs incorporent dans les programmes qui donnent accès à des privilèges spéciaux qui
sont normalement refusés aux utilisateurs normaux. Les programmeurs utilisent souvent cette technique pour corriger
les erreurs dans leurs programmes. Lorsque des pirates informatiques et d'autres personnes apprennent à utiliser ces
portes dérobées, cette fonctionnalité peut devenir un risque pour la sécurité.
Background Task
Programme exécuté par le système mais invisible pour l'utilisateur. Le système affecte généralement moins de temps
de calcul à ces programmes d'arrière-plan qu'aux programmes en avant-plan. Les programmes malveillants sont
souvent exécutés sur un système en tâche de fond afin que l'utilisateur ne remarque pas les logiciels indésirables, tels
que les virus, logiciels espions, etc.
Backup
Copie de données créée à des fins d'archivage ou pour protéger l'original contre la perte ou l'endommagement.
Fichiers Batch
Fichiers texte contenant une instruction MS-DOS par ligne. Après le démarrage, toutes les lignes sont traitées
consécutivement. Un exemple pour ces fichiers est le fichier « [Link] », qui se trouve toujours sur les
systèmes Windows, et qui est exécuté lorsque l'ordinateur est démarré. Les fichiers ont l'extension « *.bat »
Binaire
Désigne le système de numérotation de base à deux chiffres. Ce système ne contient que deux chiffres,« 0 » et « 1 ».
Boot
Démarrez (démarrage à froid) ou réinitialisez (démarrage à chaud) l'ordinateur pour qu'il soit prêt à exécuter les
programmes utilisateur. Le démarrage de l'ordinateur démarre divers programmes qui vérifient l'ordinateur et le rendent
opérationnel.
Bug
Une erreur involontaire dans un programme qui provoque une fonction dans le programme qui n' est pas prévue par
l'utilisateur.
Bits (Octet)
Un groupe de huit bits (chiffres binaires). En outre, le nom d'un type entier qui peut être exprimé par l'utilisation de huit
bits.
Cache
one de mémoire dans laquelle les données fréquemment utilisées sont temporairement mises en mémoire buffer pour
augmenter la vitesse d'accès.
Child (enfant )
Une fenêtre (ou un objet) qui est basée sur ou étroitement liée à une autre fenêtre (ou objet).
Class (catégorie )
Un modèle de POO qui peut être instancié pour créer des objets avec des définitions, propriétés, méthodes et
comportements communs.
Client
Un système informatique ou une partie d' logiciel qui accède à un service fourni par un autre ordinateur par
l'intermédiaire d'un réseau quelconque. Un navigateur Web est un client d'un serveur Web.
Code
Terme familier désignant le texte source
Coding
Terme familier désignant la programmation informatique.
Compiler (compilateur)
Outil de développement logiciel qui traduit le code source d' un langage de programmation supérieur
en instructions machine (code objet) qui peuvent être comprises et exécutées par une architecture informatique
particulière.
246 Annexe C : Index des termes
Constant (Constante)
Un élément nommé qui retourne une valeur constante pendant l'exécution du programme. Vous pouvez utiliser
des constantes au lieu de valeurs réelles n'importe où dans votre code. Une constante peut être une chaîne de
caractères ou une valeur numérique.
Cookies
Les blocs de texte qui sont stockés dans un fichier sur le disque dur de votre ordinateur. Les pages Web utilisent des
cookies pour identifier un utilisateur lorsque la page est à nouveau visitée. Les cookies peuvent contenir des informations
de connexion telles que le nom d'utilisateur et le mot de passe ou des paramètres définis par l'utilisateur. Si vous
accédez à une page Web déjà visitée, le serveur peut évaluer les données enregistrées dans le cookie et adapter la
page Web aux paramètres correspondants.
Data Elément
Dans la POO, un élément de données est une variable qui est définie dans un objet de classe et y est
encapsulée. Chaque instance d'un objet contient une valeur unique pour chaque élément de données de la classe,
par opposition à une classe qui contient une variable qui divise chaque instance. C'est un autre nom pour une propriété.
Data Type
Caractéristique d'une variable qui décrit si elle peut contenir des valeurs numériques, alphabétiques ou
alphanumériques. Il définit également les valeurs maximales que cette variable peut contenir et la façon dont ces
informations sont stockées dans la mémoire de l'ordinateur.
DirectX
Une collection d'interfaces de programmation d'applications (API) fournies par Microsoft pour créer des applications
multimédia de haute performance. DirectX permet aux programmes d'utiliser les routines 3D haute vitesse intégrées via
des interfaces qui permettent un traitement plus rapide sur la carte graphique. L'API DirectX permet également d'accéder
facilement au matériel de l'ordinateur, comme une carte son, un joystick ou un adaptateur réseau.
Encapsulation
Un schéma POO pour définir les objets. L'encapsulation cache les spécifications internes d'un objet et ne révèle que les
interfaces externes. Cela signifie que les utilisateurs de cet objet n'ont qu'à accéder aux interfaces. L'encapsulation
permet de modifier ou de mettre à jour les données et méthodes internes d'un objet sans que l'utilisateur n'ait à adapter
la manière dont l'objet est utilisé.
Encryption
Le cryptage des données afin qu'elles ne puissent être interprétées sans clé.
Expression
Combinaison de valeurs, de chaînes de caractères, d'opérateurs, de commandes ou de procédures qui sont traitées
selon les règles de priorité et qui retournent ensuite une valeur.
Extension de fichier
Un identificateur de trois ou quatre lettres qui identifie le format de données d'un fichier ou de l'application qui l'a créé.
Fonction
Identique à la procédure
Hexadécimale
Un système de numérotation qui utilise la base 16. Les dix premiers chiffres sont « 0 » à « 9 » et les six suivants sont
« A » à « F ». Cela permet d'afficher de très grands nombres avec seulement quelques caractères. « FF » en
hexadécimal correspond à « 255 » en décimale. Les pages Web utilisent des valeurs hexadécimales pour exprimer des
valeurs de couleur sur 24 bits.
Inheritance (héritage)
Processus dans la POO dans lequel un objet hérite des fonctionnalités et des données d'une classe dérivée.
Integer (entier)
Un nombre sans point décimal. Les valeurs entières peuvent être inférieures, égales ou supérieures à zéro.
248 Annexe C : Index des termes
Internet
Un réseau électronique d'ordinateurs qui relie presque toutes les universités, les gouvernements et les institutions de
recherche dans le monde d'aujourd'hui. L'installation d'origine a été construite en 1969 pour servir d'épine dorsale à la
communication en cas de guerre nucléaire. Depuis le développement de logiciels faciles à utiliser, l'utilisation publique
pour la collecte d'informations et à des fins commerciales a explosé.
Interpreter
Un programme qui exécute des instructions écrites dans un langage de programmation supérieur ligne par ligne
directement à partir du code source. Ceci contraste avec un compilateur qui n'exécute pas le texte source mais le traduit
dans un format exécutable (code objet). Ceci sera lié et exécuté plus tard.
JavaScript
Un langage de script qui peut être exécuté avec un interpréteur approprié, tel qu'un navigateur Web.
Link Time
Le temps pendant la compilation d'un programme dans lequel le code objet est lié à l'exécutable final.
Linker
Un programme qui combine des fichiers de code objet compilés avec d'autres fichiers de données pour créer
un programme exécutable. Un linker peut également avoir d'autres fonctions, comme la création de bibliothèques.
Linken
Le processus de connexion du code objet à l'exécutable final.
Linux
Un système d'exploitation libre et open source basé sur Unix. Linux a été créé à l'origine par Linus Torvalds avec l' aide
de développeurs du monde entier.
Long
Un type entier qui occupe quatre octets en mémoire.
Annexe C : Index des termes 249
Mac OS X
La dernière version de Mac OS, le système d'exploitation utilisé pour les ordinateurs Apple Macintosh. Contrairement
à ses prédécesseurs, Mac OS X est basé sur un noyau Unix et possède une interface utilisateur actualisée.
Malware
Terme générique désignant les logiciels malveillants, tels que Virus, chevaux de Troie, logiciels espions, logiciels
publicitaires, etc.
Member Fonction
Une fonction ou une procédure qui fait partie d' une classe OOP et qui effectue habituellement des calculs sur les
données des membres de la classe. C'est un autre nom pour la méthode
Methode
Une fonction ou une procédure qui fait partie d'une classe OOP et qui effectue habituellement des calculs sur les
données des membres de la classe.
Newsgroup
Un forum électronique où les lecteurs peuvent afficher des articles et des messages de suivi sur un sujet précis. Un
groupe de discussion sur Internet permet aux gens du monde entier de discuter de sujets d'intérêt commun. Chaque
nom de newsgroup donne des informations sur le sujet du newsgroup.
Object
Une instance d'une classe OOP. Cet objet hérite de toutes les fonctionnalités et données programmées dans la classe
originale.
Object Code
La sortie du compilateur et de l'assembleur, ainsi que l'entrée et la sortie de l'éditeur de liens sont des fichiers
contenant du code Object. Il existe plusieurs formats de fichiers objets propriétaires normalisés. Cela signifie que le
code objet d'un environnement de développement peut rarement être lu par un autre environnement de
développement.
250 Annexe C : Index des termes
Parent
Une fenêtre parent ou attachée (ou objet) qui crée et parfois gère des sous-fenêtres (ou objets).
Polymorphisme
Terme de la POO qui signifie avoir la possibilité d'utiliser une définition unique avec différents types de données. Par
exemple, une définition de procédure polymorphe pourrait retourner différents types, pas seulement un, et un opérateur
polymorphe simple pourrait travailler avec des expressions de différents types.
Port
(1) Interface par laquelle les données sont envoyées et reçues. (2) Par « port », on entend l'acte de recodage d'un
(parfois en utilisant un autre langage) pour permettre la compilation ou l'exécution du programme sur
une autre plate-forme informatique.
Procedure
Séquence d'instructions nommée qui est exécutée comme une unité lorsque son nom est appelé. Les procédures
peuvent également passer des paramètres pour charger des données définies par l'utilisateur dans la séquence.
Contrairement aux sous-programmes, les procédures peuvent retourner une valeur calculée. Les procédures peuvent
être appelées plusieurs fois et permettent au programme d'exécuter un code à plusieurs reprises sans avoir à le
programmer à nouveau.
Process
Une instance de programme en cours d'exécution. Un système d'exploitation multitâche passe d'un processus à
l'autre pour donner l'impression d'une exécution simultanée. En réalité, un seul processus peut utiliser le CPU à la fois.
Annexe C : Index des termes 251
Propriété
Dans l'OOP est une propriété pour une variable définie et encapsulée dans un objet de classe. Chaque instance contient
une valeur unique pour chaque propriété de la classe, par opposition à la classe qui a une variable qui est partagée dans
chaque instance.
Protocol
Une description formelle des formats de messages et des règles que deux ordinateurs doivent suivre pour échanger ces
messages.
Quad
Un type entier qui occupe huit octets en mémoire
Point radian
En mathématiques, le point radian désigne le symbole utilisé dans la représentation numérique des nombres pour
séparer la partie entière (à gauche du rayon) de la fraction du nombre (à droite du rayon). Le point radian est
habituellement un petit point (ou virgule) situé sur la ligne de base ou à la moitié de la hauteur d'un chiffre. Dans le
système de base dix, le point radian est aussi appelé point décimal.
Registre
Une base de données interne qui utilise Microsoft Windows pour stocker les informations de configuration matérielle et
logicielle, les paramètres utilisateur et les informations d'installation.
Relative
Peut se référer à une valeur ou à un chemin. Une valeur relative est une valeur dépendante qui se réfère à une autre
valeur. Un chemin relatif est une spécification de chemin qui se réfère à un autre chemin. Les chemins relatifs sont
généralement utilisés lorsque vous spécifiez l'emplacement des ressources de votre programme dans le code source,
qui sont alors relatives à l'exécutable. Par exemple, si vous voulez que votre programme charge une image à partir du
dossier'Images', le chemin relatif est défini comme'\images', puisque ce dossier est situé dans le même répertoire que
l'exécutable et est donc relatif au programme.
Reset
Redémarrez l'ordinateur sans l'éteindre
Serveur
Toute application ou ordinateur qui en fournit un autre. Par exemple, les ordinateurs qui stockent les pages Web sont
appelés serveurs parce qu'ils fournissent des ressources Web aux applications clientes telles qu'un navigateur Web.
252 Annexe C : Index des termes
Service
Un programme qui peut être démarré automatiquement en tant que partie intégrante du système d'exploitation au cours
du processus de démarrage et qui peut ensuite être exécuté en tâche de fond de façon continue.
Shareware
Logiciel offert gratuitement à des fins de test, mais qui nécessite un enregistrement auprès de l'auteur pour obtenir
toutes ses fonctionnalités. Si vous décidez de cesser d'utiliser le logiciel après la période d'essai, supprimez-le
simplement. L'utilisation de shareware au-delà de la période d'essai est considérée comme du piratage de logiciel.
Source Code
Le code qui constitue un programme avant qu'il ne soit compilé. Ce sont les instructions de création originales
du programme qui indiquent au compilateur quelles fonctions le programme doit exécuter à l'état compilé.
Déclaration
Une instruction de programmation qui retourne rarement une valeur et peut contenir d'autres composants tels que des
constantes ou des expressions. Une ou plusieurs instructions sont nécessaires pour créer un programme.
String (Chaine
Une séquence séquentielle de lettres, de chiffres et d'autres caractères inclus entre guillemets (doubles ou simples).
Subroutine (sous-routine)
Une séquence nommée d'instructions exécutées en tant qu'unité lors du saut au début de la séquence, généralement
avec une commande « Goto » ou « GoSub ». Après l'exécution de la séquence, le programme continue au point
d'origine de l'instruction de saut. Le retour se fait généralement par une commande « Retour ». Contrairement aux
procédures, les sous-programmes ne peuvent pas retourner une valeur calculée. Les sous-routines peuvent être
démarrées plusieurs fois et permettent au programme d'utiliser le code qu'elles contiennent à plusieurs reprises sans
avoir à l'écrire plusieurs fois dans le programme.
Syntaxe
Les règles selon lesquelles les mots du code source d'un programme doivent être combinés pour former des
commandes qui sont interprétées comme valides par le compilateur
TCP/IP
Cet ensemble de protocoles Internet est un ensemble de protocoles de communication qui implémentent une pile de
protocoles sur laquelle Internet et la plupart des réseaux commerciaux fonctionnent. Le nom TCP/IP est composé des
deux protocoles les plus importants qu'il contient : le protocole de contrôle de transmission (TCP) et le protocole
Internet (IP), tous deux définis en premier.
Unicode
Un schéma d'encodage de caractères qui utilise 16 bits (2 octets) par caractère pour encapsuler tous les caractères de
l'attribut important pouvoir fusionner les langues du monde (vivantes et mortes) en un seul jeu de caractères. Comme
dans le cas de ASCII, les caractères individuels sont identifiés par des chiffres. Les jeux de caractères Unicode peuvent
être contiennent plus de 65 000 caractères.
Unix
Un système d'exploitation développé en collaboration avec des chercheurs d'AT&T. Unix est bien connu pour son
indépendance matérielle et ses interfaces d'applications portables. Unix est conçu pour une utilisation simultanée par de
nombreuses personnes et possède un support réseau TCP/IP intégré. Unix et ses dérivés (Linux) sont les systèmes
d'exploitation les plus courants pour les serveurs sur Internet
Usenet
Un système informel de babillards électroniques ou de groupes de discussion sur Internet. Usenet a vu le jour avant
Internet, même si la plupart des documents Usenet sont aujourd'hui distribués via Internet.
Virus
Un programme informatique qui a la capacité d'accéder à des lecteurs et à d'autres fichiers, et qui peut se reproduire et
se distribuer. Cela se fait généralement à l'insu et sans le consentement de l'utilisateur. Certains virus infectent les
fichiers, de sorte que ces fichiers démarrent le virus pendant leur exécution. D'autres virus résident dans la mémoire de
l'ordinateur et infectent les fichiers lorsqu'ils sont ouverts, modifiés ou créés. Certains virus présentent des symptômes
et d'autres détruisent des fichiers et des systèmes informatiques, mais ni les symptômes ni la destruction ne sont
importants pour la définition d'un virus. Même un virus non destructeur est un virus.
VM (Virtual Machine)
Logiciel qui simule les propriétés du matériel. Une machine virtuelle est un environnement de travail autonome qui se
comporte comme un ordinateur séparé. Par exemple, les applets Java s'exécutent dans une machine virtuelle Java qui
n'a pas accès au système d'exploitation hôte.
Word
Un type entier qui occupe deux octets en mémoire
Ver
Un programme informatique parasite qui se reproduit mais qui, contrairement aux virus, n'infecte pas l'ordinateur ou
d'autres fichiers. Les vers peuvent faire des copies sur le même ordinateur ou envoyer des copies à d'autres ordinateurs
dans un réseau
Wrapper
Une interface de programmation entre un programme et un code embarqué séparé. Principalement utilisé à des fins de
compilation, si le code incorporé est situé dans une DLL ou a une autre convention d'appel. L'intérêt de tout cela, c'est
que le code intégré n'est accessible que par l'emballage.
ZIP Fichier
Une archive qui contient une collection d'autres fichiers sous forme compressée. Les fichiers ZIP sont très populaires sur
Internet parce que l'utilisateur peut livrer plusieurs fichiers dans un seul conteneur, ce qui économise de l'espace disque
et du temps de téléchargement.
Index 255
Index
C
Cameras . . . . . . . . . . . . . . . . . . . 168-174, 177 DLL . . . . . . . . . . . . . . . . . . . . . . . 198,.222-227
Camera Premier Plan . . . . . . . .170-171, 173,174 DLL Calling Conventions . . . . . . . . . . . . . . . 227
Double Buffered Rendering . . . . . . . . . . . .147-153
CD Audio. . . . . . . . . . . . . . . . . . . . . . . . . 186-189
Double Precision Flottants . . . . . . . . . . . . . . 206
Chaines de Longueur Fixes . . . . . . . . . . . . . . . . . .20
Dessin et ses Commandes. . . . . . . .. . . . . . . . . . . . . .134
Cdecl. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .227
Changement de Modes du Dessin . . . 139,140 Dessiner sur une Fenêtre. . . . . . . . . .135,137
Chr() .............................................................. 85 Dessiner sur une Image . . . . . . . . . . . . . . . . . . .137
Dessiner du Texte. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .141
CLI ............................................................... 196
Dessin avec une Image . . . . . . . . . . . . 141,142
CloseFile() ..................................................... 91
Dynamique Link Libraries..................222-227
Code Format .................................................... 96
Compilateur en Lignes de commandes. . . 196 E
Commandes Lignes Parametres. . . . . 201-202 Écriture dans les fichiers ..................... 104-105
Commandes Invité . . . . . . . .. . . . . . . .. . . . . . . . . .196 ElapsedMilliseconds() ......................................86
Commandes Intégrès. . . . . . . . . . . . . . . . . . . 81 Else ....................................................................39
Commandes Communes. . . . . . . .. . . . . . . . . . . .84 ElseIf ................................................................ 40
Commentaires . . . . . . . . . . . . . . . . . . . . . 95,96 Intégration de Fichiers Wave .............. 179-182
Compliateur Constantes . . . . . . . . . . . 190,191 EnableDebugger.............................................. 103
Compliateur Directives ........................ 191-195 EnableExplicit ....................................................101
Compliateur Functions. . . . . 190,191, 194,195 End (Arrêt du Programme) .......................... 99
CompilerError . . . . . . . . . . . . . . . . . . . 193,194 Entités (Objets) .......................................... 166
CompilerIf . . . . . . . . . . . . . . . . . . . . . .191,192 Enumeration Constantes .............................. 22
CompilerSelect . . . . . . . .. . . . . . . .. . . . . . . . . . 193 Eof() ...................................................................... 93
Console Programme Differences . . . . . . . . .110 Egale (=) ........................................................ 24
Console Programmes. . . . . . . . . . . . . . . . . 108-112 Entiers . . . . . . . . . . . . . . . . . . . . . . . . . . 18,203
Constantes. . . . . . . .. . . . . . . .. . . . . . . .. . . . . 22 Erreurs définies par l'utilisateur. . . . . . . . . . 106
Continue . . . . . . . . . . . . . . . . . . . . . . . . 45,46 Erreur Traitement........................................99
CreateFile(). . . . . . . .. . . . . . . .. . . . . . . .. . . . . . . .. . . . . . . . 90 Erreur Procedure de Traitement . . .. . . .99,100
Etiquettes (Labels) . . . . . . . . . . . . . . . . . . . . . . .64
D Events . . . . . . . . . . . . . . . . . . . . . . . 114,115,122
Data Types . . . . . . . . . . . . . . . . . .10, 203-209 Exécuter un Programme PureBasic............... 15
Data Types Format des Nombres 11, 232,233 Exposants (Flottants)...........................206-208
Data Types Limites Numeriques . 11, 203-205
Debugger . . . . . . . . . . . . . . . . . . . 21, 102-105 F
Debugger Controles. . . . . . . . . . . . . . . 103,104 False. . . . . . . . . . . . . .. . . . . . . . . . . . . . . . . . . . . . .38
Debugger <>Debogueur. . . . . . . . . . . . 21, 102 Fichier Accès avec Pointer. . . . . . . . . . . . . . . . . . . . . 93
Declare .............................................................. 67 Fichier Buffer. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
Define.............................................................. 102 Fichier Chemin. . . . . . . . . . . . . . . . . . . . . . . . 91
Define Default Type . . . . . . . . . . . . . . 20, 102 File Requester. . . . . . . . . . . . . . . . . . . . . . . . . 142
Defined() ......................................................... 195 Fichiers . . . . . . . . . . . . . .. . . . . . . . . . . . . . . . . . . 89-92
Delay() . . . . . . . . . . . . . . . . . . . . . . . . . 85, 111 Fichiers MP3. . . . . . . . . . . . . . . . . . . . . . . . . . . 84-186
Dim (Arrays) (Tableaux). . . . . . . . . . . .49, 54 Fichiers Wave. . . . . . . . . . . . . . . . . . . . . . . . . . . . .179-182
DisableDebugger ......................................... 103 FileSeek().......................................................93
Division (/) .................................................... 26 FindString(). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
Index 257
G
Gadgets . . . . . . . . . . . . . . . . .113-120, 123,124 Modulo (%) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
George Boole .................................................. 38 Multi-Dimension Arrays. . . . . . . . . . . . 51, 56
Global ............................................................... 69 Multi-Commandes sur la même Ligne . . . . .98
Multiplication (*) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .25
Graphique Interfaces Utilisateurs ................127
Mutex . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .221
I N
IDE .....................................................................14 NewLists. . . . . . . . . . . . . . . . . . . . . . . . . . .57,63
IDE Error Log ................................................14 NewLists Utilisation de la Mémoire . . . . . . . . . . . 60
IDE Helpfile Integration ...............................16 NewLists et Parametres . . . . . . . . . . . . . . . . . . . 77-79
IDE Quick Help.............................................. 15 Niveau de Detail .......................................173
If Déclaration ............................................... 38 Nombres . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
Images avec Canal Alpha............................. 143 Nombres Non-Signés . . . . . . . . . . . . .204,205
Include Graphique ................................ 127-131 Nombres Signés . . . . . . . . . . . . . . . . . .204-206
Include Autres Fichiers Sources................... 98 Nombres Virgules Flottante. .18, 203, 206-208
Indentation .......................................................97 Not . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .29,34
Inférieur (<) ................................................... 31 Not Egale à (<>) ........................................... 33
Inférieur ou Egale à (<=) ............................ 32
Interfaces Natives ................................. 113-131 O
OffsetOf() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .61
L OGRE API Identifiants . . . . . . . . . . . . . . . . . . . . .163
Langage Assembleur .....................................13 OGRE Engine . . . . . . . . . . . . . . . . . . . 161,162
Lecture Fichier (ReadFile()).......................... 90 OGRE Mesh Format . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161
Lecture à partir de Fichiers . . . . . . . . . . .91,92 OGRE Texture Format . . . . . . . . . . . . . . . . . . . . . . . . . .161
Lecture des Entrées Utilisateur ............ 109-111 OnErrorGosub() . . . . . . . . . . . . . . . . . .104,105
Len()...................................................................... 86 OnErrorGoto() . . . . . . . . . . . . . . . . . . . 106,107
Libèrer la Mémoire Arrays ............................ 51 OpenFile() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
Loc() ................................................................. 93 Opération Précédente . . . . . . . . . . . . . . . 33,34
Local .................................................................. 67 Opérateurs . . . . . . . . . . . . . . . . . . . . . . . . 24,37
Lof() .................................................................. 93 Opérateur AND (&) . . . . . . . . . . . . . . . .26,33
Logique AND (And) . . . . . . . . . . . . . . . . . 27, 33 Opérateur NOT (~) . . . . . . . . . . . . . . . . . 29,34
Logique NOT (Not) . . . . . . . . . . . . . . . . .29, 34 Opérateur OR (|) . . . . . . . . . . . . . . . . . . 27,34
Logique OR (Or) . . . . . . . . . . . . . . . . . . .28, 34 Opérateur XOR (!) . . . . . . . . . . . . . . . . . 28,34
Logique XOR (XOr) . . . . . . . . . . . . . . . . 28,34 Opérateur Unitaire.......................................25
Lumière . . . . . . . . . . . . . . . . . . . . . . . . .167,177 Options Avancèes du Compilateur. . . 195-200
Options Parametres dans Procedures. . . . . . .74
M Or (Ou) . . . . . . . . . . . . . . . . . . . . . . . . . . 27, 34
Memoire (Adresse) . . . . . . . . . . . . . . . .209,210 OS Identifiants. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .82-84
Menus . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120-126
MessageRequester() . . . . . . . . . . . . . . . . . . . . .87 P
Mid() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88 Particules . . . . . . . . . . . . . . . . . . . .174, 176,177
Moins (-) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 Parenthèses. . . . . . . . . . . . . . . . . . . . . . . . . . . . .33
Modification du Son en Temps Réel. . 180-182 Passer Par Référence . . . . . . . . . . . . . . .78, 213
Module (Fichiers) . . . . . . . . . . . . . . . . .182,183 PB Nombres. . . . . . . . . . . . . . . . . . . . . . . . 82-84
258 Index
A propos de l'auteur
Gary Willoughby est un graphiste, développeur web
et développeur de logiciels professionnel. Pour la
première fois, il s'est arraché les dents avec des
langages de programmation comme PHP, Python et
JavaScript. Vers la fin des années 90, Gary a décidé
d'investir son temps libre dans le développement
d'applications avec des langages compilés.
Extraits du contenu :
Gary Willoughby
Copyright © 2006