Quand, je suis en manque d'inspiration pour un projet à faire en Gambas, je reprends un de mes vieux programmes et là je pleure (je ne suis pas professionnel de la programmation) car je mesure le chemin parcouru.
Et celui qui reste pour avancer est encore bien long (tant mieux).
Sans avoir, à tout réécrire, réorganiser son ancien projet en un nouveau, est un processus intéressant, permettant de mesurer ses propres progrès et continuer à s'améliorer.
Je vous donne, mes propres pistes empruntées :gambas@gambas:$
- Créer un répertoire d'accueil, genre "DÉVELOPPEMENT", pour mes différents projets, chacun dans un répertoire dédié.
- Toujours regarder ce que l'IDE a fait pour moi, en lisant les fichiers qu'il produit ; comment les a t il écrit?
- Réorganiser mes documents inclus, par type, les déplacer dans des sous répertoires par type.
- Dans un formulaire, essayer de ne conserver que des variables et procédures Private.
- Déplacer les variables et procédures, nécessairement Public, dans un module, genre "MVar" pour les variables, "MProc" pour les procédures.
- Créer un module pour les appels à des procédures Public, spécifiques, du style Settings, Sons, autres, genre "MSettings", "MSons", ...
- Déplacer l'ouverture et la clôture du programme dans un module, souvent, le même, genre "MPrinc" pour module principal, s'il n'y a qu'un formulaire principal (pas obligatoire, mais...).
- Les formulaires sont le centre, la raison de l'IDE mais on peut essayer de s'en affranchir, sans réinventer la roue.
- Mais on peut mesurer le travail fait par celui-ci, et la facilitation obtenue, ainsi.
- M'astreindre, dans tous les cas, à bien nommer mes variables, en fonction de leur type et de leur statut, globales Private, globales Public, locales.
- Les regrouper, dans la déclaration, par type, séparés par une ligne vide (visuellement, c'est mieux).
- Jouer avec les mots Static Public, Static Private, Create Static ; de toute façon l'IDE va m'envoyer sur les roses si je fais quelque chose qu'il n'apprécie pas.
- Et, je vais pouvoir essayer, d'en apprendre, le pourquoi, pour me familiariser avec ces mots, et leurs implications.
- Reprendre mes commentaires, les aligner après 60 caractères "-" ou tiret du six. Cela prends tout son sens si on réduit chaque procédure.
- Lors de l'instanciation d'un objet, toujours s'astreindre à attacher un évènement à cet objet (Object.Attach).
- Toujours, générer une archive des sources, avant de changer de version de mon projet, car l'IDE va effacer l'avant dernière version.
- Que je range dans un répertoire d'archive de mes sources, genre "SOURCES", projet par projet.
- ...
gambas@gambas:$ Toute cette gymnastique, pour espérer que mes nouveaux projets soient, ainsi organisés, d’emblée.
Pour illustrer mon propos, voici une ossature de projet vide qui ne constitue pas, en aucune manière, un modèle, mais simplement, un chemin de réflexion que j'ai emprunté.
Ossature de Projet :
Il s'agit d'un projet traduisible avec un splash screen simple, modifiable, un menu réduit à alimenter en fonction de ses besoins.
Tout est dans la structure proposée.
Dans l'IDE :- Des
répertoires pour Modules, Formulaires, Tâches, Classes, et autres objets dont on pourrait avoir besoin.
- Des
répertoires pour chaque type de données nécessaires au bon fonctionnement de notre application.
Les Classes, regroupées, elles, aussi, dans un endroit pour elles :
CObjetNecessaire, tous les objets nécessaires à votre application seront regroupés, là.
Rappelons qu'un objet est simplement une instance d'une classe.
Les formulaires prêts à l'emploi :
FAide, à construire selon ses envies.
FChoixPolice, pour choisir et modifier la police employée au niveau des formulaires.
FSplash, le splash screen, pour faire pro.
FMain, le formulaire principal de votre application, à développer.
Les Modules :
- Un
module de début qui lance le programme et le termine.
- Un
module par type d'action : sons, settings, langues, variables globales au projet, connexion à une base de données, éventuelle.
Genre : MSon, MSettings, MVar, MConn, ...
Task :
Un
répertoire, enfin pour les TASKS dont nous pourrions avoir besoin :
CTaskNecessaire, c'est un fichier classe mais on le met à part pour bien le différencier.
Car tout est, ici dans la présentation et l'organisation de notre projet, en résumé dans sa structuration
Nous retrouvons l'ensemble de ces objets sur l'image suivante :

Qu'y a t il de particulier à procéder ainsi?
La structuration de notre projet doit nous permettre de bien structurer notre pensée et par là même notre réflexion par rapport au besoin que nous voulons exprimer dans notre application.
Un exemple, pour illustrer cette nécessité de structure,
-1-Le déport des variables globales au projet dans un module :
Quel est l'intérêt :Nous regroupons les variables dans un seul endroit. Deux façons de procéder peuvent s'entrechoquer :
- regrouper les variables par provenance
- regrouper les variables par type
- ou même une troisième, par provenance et puis par type
Au début on aura tendance à les regrouper par provenance puis très vite on les regroupera par type, en s'apercevant que c'est plus intéressant, car leur type est plus important que leur provenance.
Petit rappel, un module est une région particulière, qui est Static et Public, ce qui protège vos variables car elles ne sont pas accessibles autrement que par des appels de votre application que vous aurez programmés.(voir les différences entre static et dynamic,
sur le site.)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| PUBLIC iTemp AS INTEGER '<---------------------------------' durée du splash
PUBLIC sFCValue AS STRING '<------------------------------' police à utiliser PUBLIC sNomApplication AS STRING '<-----------------------' si vous traduisez le nom du projet '-1- PUBLIC nomBase AS STRING = "LaBase" '<-------------------' la base elle même, vous pouvez changer le nom PUBLIC repBdD AS STRING '<---------------------------------' répertoire d'installation PUBLIC T2 AS STRING '<------------------------------------' adresse de la base sur la machine
'<---------------------------------------------------------' Début objets qu'il faudra penser à détruire, à la clôture du programme PUBLIC hLock AS Stream '<----------------------------------' fichier de verrouillage du démarrage PUBLIC hConn AS NEW Connection '<------------------------' la connexion générique à la base PUBLIC hResult AS Result '<------------------------------' résultat générique de requête sur la base, voir avec MVar PUBLIC hTable AS Table '<---------------------------------' Table générique de la base de données '<---------------------------------------------------------' Fin objets à détruire
PUBLIC bShowPreView AS BOOLEAN '<--------------------------' valeurs boolean pour le FontChooser des polices PUBLIC bShowStyle AS BOOLEAN '<---------------------------' Idem PUBLIC bFixedOnly AS BOOLEAN '<---------------------------' Idem PUBLIC bShowRelative AS BOOLEAN '<-------------------------' Idem PUBLIC bSortie AS BOOLEAN '<------------------------------' sortie du programme PUBLIC bSon AS BOOLEAN '<----------------------------------' balise booléenne du son, oui ou non
'-- lieu où enregistrer les variables globales au projet --'
|
Il est vrai qu'il faudra ajouter "MVar." devant le nom de la variable quand il faudra l'appeler de n'importe où dans le projet.
Un mot sur cette procédure particulière : -2-L'application de la langue sélectionnée par l'utilisateur.
Bien suivre, les mentions entourées d'étoiles, elles expliquent que le changement de langue ne peut se faire que par le redémarrage de l'application.
Quand, on effectue ses tests dans l'IDE, la première ligne doit être dé-commentée et la suivante commentée.
Quand on veut effectuer la compilation de son projet, au contraire on commente la première et dé-commente la seconde.
Cette ligne :
1
| SHELL "kill -9 " & Application.id
|
fonctionne, aussi, mais ne quitte pas proprement l'application, et il reste plein de choses de l'application, en mémoire.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| PRIVATE SUB AppliLangues() '<-----------------------------' application du choix de langue par redémarrage auto
Message.Title = ("La langue choisie sera appliquée après le redémarrage."
IF Message.Question(("Voulez-vous quitter ?") & gb.CrLf & ("La langue choisie sera appliquée après le redémarrage du programme."("Oui"), ("Non")) = 2 THEN LangueConf() '<------------------------------------' on continue avec la langue enregistrée dans settings MSon.son("shade") ELSE MSon.son("power-plug") Settings["General/LangInit"] = MLangue.sLangue '<---' choix de la langue Settings.Save '<------------------------------------' la langue choisie est inscrite dans settings '[b]* ATTENTION ligne suivante à Décommenté lors du travail dans l'IDE et à commenter avant de générer l'executable [/b]* SHELL "gbx3 " & Application.Path '<------------------' uniquement dans l'IDE ' Shell "kill -9 " & Application.id '<-------------' pas propre mais fonctionnel si un seul formulaire ME.Close() '<---------------------------------------' possible car quitter par module '[b]* ATTENTION ligne suivante à décommenter avant de générer l'executable [/b]* ' Exec [Application.Path & "/" & Application.Name]'<-' Pour générer l'exécutable, pas pendant le débugage dans l'IDE ENDIF
END
|
-3-Voici l'ensemble des procédures nécessaires à l'application des langues
dont nous aurons préalablement préparées les traductions.
Configuration de la langue enregistrée et du menu :1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| '--------- Début Zone Application des langues ----------'
PRIVATE SUB LangueConf() '<------------------------------' check du menu en fonction langue enregistrée dans settings
MLangue.sLangue = Settings["General/LangInit"]
SELECT CASE MLangue.sLangue CASE "fr" mnFrancais.Checked = TRUE '<---------------------' selon le nom donné aux menus de langues CASE "en" mnAnglais.Checked = TRUE CASE "es" mnEspagnol.Checked = TRUE CASE "pt" mnPortugais.Checked = TRUE CASE "de" mnAllemand.Checked = TRUE CASE "it" mnItalien.Checked = TRUE END SELECT
END
|
Le menu Langue sélectionné :1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| PUBLIC SUB MenuLangues_Click() '<--------------------------' choix de la langue et affichage du menu checked
MSon.son("camera1")
IF mnFrancais.Checked = TRUE THEN MLangue.sLangue = "fr" IF mnAnglais.Checked = TRUE THEN MLangue.sLangue = "en" IF mnEspagnol.Checked = TRUE THEN MLangue.sLangue = "es" IF mnPortugais.checked = TRUE THEN MLangue.sLangue = "pt" IF mnAllemand.Checked = TRUE THEN MLangue.sLangue = "de" IF mnItalien.checked = TRUE THEN MLangue.sLangue = "it"
IF MSettings.AppSettings["General" &/ "LangInit"] <> MLangue.sLangue THEN AppliLangues() ELSE MSon.son("beep") RETURN ENDIF
END
|
Application de la langue choisie :1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| PRIVATE SUB AppliLangues() '<-----------------------------' application du choix de langue par redémarrage auto
Message.Title = ("La langue choisie sera appliquée après le redémarrage."
IF Message.Question(("Voulez-vous quitter ?") & gb.CrLf & ("La langue choisie sera appliquée après le redémarrage du programme."("Oui"), ("Non")) = 2 THEN LangueConf() '<------------------------------------' on continue avec la langue enregistrée dans settings MSon.son("shade") ELSE MSon.son("power-plug") Settings["General/LangInit"] = MLangue.sLangue '<---' choix de la langue Settings.Save '<------------------------------------' la langue choisie est inscrite dans settings '[b]* ATTENTION ligne suivante à dé-commenter lors du travail dans l'IDE et à commenter avant de générer l'exécutable [/b]* SHELL "gbx3 " & Application.Path '<------------------' uniquement dans l'IDE ' Shell "kill -9 " & Application.id '<-------------' pas propre mais fonctionnel si un seul formulaire ME.Close() '<---------------------------------------' possible car quitter par module '[b]* ATTENTION ligne suivante à dé-commenter avant de générer l'exécutable [/b]* ' Exec [Application.Path & "/" & Application.Name]'<-' Pour générer l'exécutable, pas pendant le débugage dans l'IDE ENDIF
END '----------- Fin Zone Application des langues -------------'
|
Une image du menu permettant de sélectionner la langue désirée :

Le Module de démarrage :
Le module de démarrage, MDebut en deux procédures, ouverture et fermeture.
Ouverture :1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
| PUBLIC SUB Main() '<---------------------------------------------' réglages et initialisations nécessaires au fonctionnement
' MVar.sNomApplication = "NomPourProjet" '<------------------' si vous traduisez le nom du projet pour éviter le changement de nom du stream MVar.sNomApplication = Application.Title '<------------------' si vous ne traduisez pas le nom du projet, (- ou tiret du six, dans traductions) MVar.iTemp = 3000 '<---------------------------------------' initialisation durée du splash 1000 = 1 seconde selon le delay du timer
TRY MVar.hLock = LOCK User.home & "/." & MVar.sNomApplication & "-" & Application.Version & "-lock" '<----' stream locked
IF ERROR THEN Message.Title = ("Attention!") Message(("Une seule instance du Programme est possible.")) QUIT '<---------------------------------------------' on peut car aucun formulaire n'est encore lancé ENDIF
'---- Début ensemble des initialisations à réaliser ----' ' ' MSettings.InitDefaultPath() '<------------------------' initialisation des settings, à commenter si pas utilisation de MSettings MLangue.langues() '<------------------------------------' Application de la langue au démarrage
IF NOT MSettings.AppSettings.Exist("Police" &/ "pFont") THEN '<------' première fois MVar.sFCValue = "Default" MSettings.StorePolice() ENDIF
IF NOT Settings.Exist("General" &/ "bSon") THEN '<------' première fois MVar.bSon = TRUE Settings["General/bSon"] = MVar.bSon Settings.Save ENDIF
MVar.bSon = Settings["General/bSon"] '<---------------' récupération du son ou non MSettings.RestorePolice() '<---------------------------' police selon settings 'MConn.main() '<-----------------------------------------' si utilisation d'une base de données SQlite3, adapter le module ' '<-----------------------------------------------------' penser à alimenter les différentes variables public nécessaires dans MVar ' ' '----- Fin ensemble des initialisations à réaliser -----'
FSplash.ShowModal() '<---------------------------------' lancement du splash screen FMain.Show() '<---------------------------------------' lancement Formulaire principal
END
|
Fermeture :1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| PUBLIC SUB Quitter() '<------------------------------------' sortie avec fermeture de tout ce qui doit l'être
IF NOT IsNull(MVar.hLock) THEN TRY UNLOCK MVar.hLock '<----------------------------' libération du fichier avant sortie TRY KILL User.home & "/." & MVar.sNomApplication & "-" & Application.Version & "-lock" '<---------' on tue le stream, voilà pourquoi le nom ne doit pas être traduit. ENDIF
Settings.Save() 'liste des Formulaires à tuer, pour garantir la clôture, à remplir IF NOT IsNull(FChoixPolice) THEN FChoixPolice.Delete()
'liste des objets à tuer, pour garantir la clôture propre, à remplir (voir les objets de MVar) IsNull(MVar.hLock) IsNull(MVar.hConn) IsNull(MVar.hResult) IsNull(MVar.hTable)
'splash screen FMain.Hide MVar.bSortie = TRUE '<---------------------------------' on indique au splasform qu'on est en sortie FSplash.ShowModal() '<---------------------------------' splashform de sortie
END
|
Bien sûr un module de démarrage et de fin n'est pas obligatoire, mais il oblige à bien penser ses initialisations et instanciations et lors de la clôture, il rassemble les objets dont il faut s'occuper pour réaliser une fermeture propre de l'application.
Le Splash Screen :
Le Splash Screen, n'est qu'une cerise sur le gâteau, un plaisir supplémentaire qui ne devrait se justifier que dans le cas où "beaucoup" de choses devraient être lancées avant que l'application ne démarre, pour faire patienter l'utilisateur. Ici, il ne s'agit que d'une "tricherie".
Déclarations minimales :1
2
3
4
5
6
7
8
| PRIVATE $iCount AS INTEGER PRIVATE $cSentence AS String[] = [(" de la Configuration Générale " (" du Répertoire "), (" de la Base de Données ", (" de la Recherche "), (" de l'Initialisation Générale " (" des Réglages du Son "), (" des Réglages de l'Affichage ", (" de la Configuration Sauvegardée "), (" de la Préparation à la Lecture " (" de l'Affichage du Formulaire ")] '<------------' dix commentaires pour être en phase avec calcul de ind du Timer
|
L'ouverture du formulaire :1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| PUBLIC SUB Form_Open()
$iCount = 0
IF MVar.bSortie THEN Label1.Caption = (" Patientez, arrêt en cours... " ProgressBar1.Direction = 2 '<------------------------' droite à gauche ELSE Label1.Caption = (" Patientez, chargement en cours... ") ProgressBar1.Direction = 1 '<------------------------' gauche à droite ENDIF
Label3.Text = "[ " & MVar.sNomApplication & " | " & ("Version") & " " & Application.Version & " ]" Timer1.Start
END
|
Le travail du Timer :1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
| PUBLIC SUB Timer1_Timer()
DIM enPremier1 AS STRING DIM enSuite1 AS STRING DIM ind AS INTEGER
ProgressBar1.Visible = TRUE
INC $iCount ProgressBar1.value = $iCount / MVar.iTemp ind = CInt(ProgressBar1.Value * 10) '<------------------' 1 donne 10, le nombre de commentaires à afficher
IF NOT MVar.bSortie THEN IF ind <= $cSentence.Max THEN Label2.Text = ("Ouverture") & " " & $cSentence[ind]'<-------------------' affichage dans l'ordre croissant ENDIF ELSE IF ind <= $cSentence.Max THEN Label2.Text = ("Fermeture") & " " & $cSentence[$cSentence.Max - ind]'<--' affichage dans l'ordre décroissant ENDIF ENDIF
IF $iCount MOD 100 = 0 THEN '<--------------------------' quand la division est juste (reste = 0) enPremier1 = Left(Label1.Text, 1) '<-----------------' on fait défiler le texte enSuite1 = Right(Label1.Text, Len(Label1.Text) - 1) Label1.text = enSuite1 & enPremier1 ENDIF
IF $iCount = MVar.iTemp THEN MSon.son("beep") WAIT 0.25 '<-----------------------------' durée exacte du son ME.Close() ENDIF
END
|
La fermeture du formulaire :1
2
3
4
5
6
7
8
9
10
| PUBLIC SUB Form_Close()
Timer1.Stop WAIT 0.01 Timer1 = NULL ProgressBar1 = NULL
FSplash.Delete()
END
|
Cette ossature de projet vide ne constitue pas, encore une fois, un modèle, mais simplement, un chemin de réflexion que j'ai emprunté et tenais à partager.
Endroit de téléchargement sur la forge de ce projet :
https://gambas-fr.org/code-279-ossaturedeprojet.html====================
Navigation :
<-- Liens du Wiki : <--<-- Accueil du WIKI : <-- <-- Création de Projets <--<-- Étapes de Développement <--====================
La Documentation :
====================