Gambas France BETA

Connexion

Pas de compte ? Incription

Révisions :

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 :



====================