Université Jean Monnet, Saint Etienne
CRENAM (Centre de Recherche sur  l’ENvironnement et l’AMénagement)
CNRS UMR 5600 « Environnement-Ville-Société »
Une  application Visual Basic pour la gestion des réseaux d’assainissement collectif.

    I   Une application VISUAL BASIC dédiée à la gestion des réseaux  d’assainissement collectif

Les objectifs du stage sont multiples. Dans un premier temps, il convient de prendre connaissance du métier de l’assainissement (suivi d’une campagne de terrain, interrogation des acteurs du métiers). Ce premier contact, destiné à évaluer les besoins logiciels du métier, doit aussi permettre de mettre en place un modèle de Base de Données (Modèle Conceptuel et Logique des Données).

Une seconde étape consiste à retranscrire les principales fonctionnalités de l’application. La conception des différentes interfaces graphiques doit aussi faire partie de la réflexion étant donnée l’importance portée à la présentation de l’A.P.I. Ensuite la conception des différents algorithmes par phases permet le développement de ces fonctionnalités.

Dans une étape supérieure, lorsque l’application atteint un niveau d’exploitation intéressant, il apparaît important de réaliser  l’empaquetage et le déploiement de celle-ci sur un certain nombre de sites test. Pour un test sur application orientée base de données, la saisie successive est capitale pour analyser le comportement du programme (réaction en temps, succession des événements…). C’est la raison pour laquelle la maintenance  (sur site ou via F.T.P) des bases de données créées au cours du développement  se révèle nécessaire (ajout de table, d’index et de clés manuellement ou par code). Hormis cette mise à jour, le déboguage est aussi importante, sans compter la réflexion qui permet d’optimiser et d’ajouter de nouvelles fonctionnalités à une application.

Outre ces étapes bien définies lors de la conception de l’application, il apparaît impossible de quantifier le temps qu’il est nécessaire d’accorder au déboguage, à l’installation (empaquetage et déploiement en Visual Basic 6) et à la mise à jour des versions sur poste, ainsi qu’à la maintenance des bases de données créées au cours du développement. Pour cette raison, il est important de prévoir une marge de temps supplémentaire dans un projet informatique tout en pensant les possibilités d’extension de fonctions de l’application.

    II  Une application Visual Basic pour la gestion des réseaux d’assainissement collectif

II-1 Introduction
Développée sous Visual Basic, l’application permet une gestion complète des données relatives aux réseaux d’assainissement et donc une organisation des missions de récolement ainsi que leur suivi dans le temps. La compatibilité de l’interface utilisateur avec les outils Microsoft (Excel, Access, Microsoft World...) rend possible l’édition de rapports et de fiches ainsi que le tracé automatique des réseaux d’assainissement.

Au cœur du projet, ce chapitre consacré à l’application permettra de prendre connaissance d'une partie de code associé aux fenêtres et donc aux différentes interactions entre le logiciel de développement Visual Basic et les solutions logicielles Microsoft Jet pour l’enregistrement, l’affichage et la recherche, Microsoft Excel pour l’impression, Autodesk World pour le tracé des réseaux d’assainissement.

II-2 Développement du code associé à l’interface graphique
L’objet de cette section n’est pas de retranscrire intégralement le code lié à l’interface de l’application mais de présenter certaines fonctionnalités dont l’intérêt est démontré par la réutilisabilité des fonctions et des procédures au cours du développement. La présentation suivante a aussi pour but de mettre en exergue la diversité des propriétés et méthodes employées sur objets Visual Basic ou issus des logiciels utilisant la technologie OLE-Automation.
II-2-1 Fonctionnalités classiques sur fichier base de données
Le code suivant présente la chaîne complète depuis le dialogue avec l’utilisateur jusqu’à l’ouverture ou la fermeture d’une base de données. La procédure ci-dessous est le code associé au menu ouvrir du menu principal.

Private Sub MenuOuvrirBase_Click()

If  bBaseOuverte  Then ‘ Drapeau à  1 si base déjà ouverte
Msg$ = « Voulez-vous ouvrir une autre base «  + Chr$(10)
Msg$ = Msg$ + « et fermer la base actuellement ouverte. »
Msbreponse = MsgBox(Msg$, 4 + 32, nompg)
     If Msbreponse = 7 Then
         Exit Sub
     Else
          FermerBase ‘ Procédure de ferneture de la base de données actuellement ouverte
          bBaseOuverte = False     ‘ Remise à False spécifiant qu’aucun fichier n’est déjà ouvert
          CacheMenu ‘ Procédure de masque sur les menus
     End If
End If
cmd1.DialogTitle = « Ouvrir une Base »
cmd1.filename = ficusr
cmd1.Filter = « Base de données|*.mdb|Tous|*.* »
cmd1.FilterIndex = 1
cmd1.Flags = &H1000& + &H4& + &H800&

On Error Resume Next
cmd1.ShowOpen
If Err.Number <> 0 Then
 MsgBox « La tentative d’ouverture de la Base sélectionnée a échouée »

Exit Sub
End if
If Left$(cmd1.FileTitle, 1) = « * » Or cmd1.FileTitle = «  » Then Exit Sub

scheminfichier = cmd1.filename
sfichier = cmd1.FileTitle
bBaseOuverte = True
OuvrirBase(scheminfichier) ‘ Procédure d’ouverture de la base de donnée sélectionnée
AfficheMenu  ‘ Procédure de masque inverse sur les menus

End sub

La première partie du code donne le choix à l’utilisateur entre ouvrir ou pas une autre base grâce à l’objet boîte de message (Msgbox), dans le cas ou une autre base de données serait déjà ouverte. Une réponse négative entraîne une sortie immédiate de la procédure événement. Lors de l’ouverture, les propriétés de la boite de dialogue (cmd1 déclarée CommonDialog) sont utilisées pour , spécifier un chemin accès par défaut (filename), créer un filtre sur les fichiers (Filter) et fixer des règles sur la sélection des fichiers (Flags).

La suite du code permet de contrôler le fichier sélectionner ainsi que la récupération des chemins l'accès complet et le répertoire actif avant de lancer la procédure d’ouverture de la base de donnée sélectionnée. Un procédé de gestion des erreurs grâce à la table err, permet non seulement d’identifier le type d’erreur grâce au numéro d’identification, mais permet surtout de gérer les éventuels problèmes dont il ne peut se douter (Base de données détériorée par exemple). Le drapeau bBaseOuverte indique qu’une base est déjà ouverte.

Sub OuvrirBase(schemfic as string)

Set db = DBEngine.OpenDatabase(schemfic)
Set affaire = db.OpenRecordset(« affaire », dbOpenTable)
« Ouverture des autres tables de la base de donnée »

End Sub

La première ligne de la procédure permet l’ouverture de la base de donnée grâce au moteur MS Jet (Objet  DBEngine) et ceci en spécifiant le chemin d’accés « schemfic ». La suite n’est qu’une manipulation des objets disponibles à partir de l’objet db, à savoir les différentes tables de la base de données. La syntaxe utilisée permet l’ouverture avec modifications possibles des données (option dbOpenTable) mais il est toujours possible de récupérer une partie des données (grâce aux instructions sql) ou encore de récupérer l’ensemble des données en lecture seule (option dbOpenSnapshot).

Sub FermerBase()

affaire.Close
Set affaire = Nothing
«  Fermeture des autres tables et désallocation mémoire »

db.Close
Set db = Nothing

bBaseOuverte = False

Exit Sub

La procédure de fermeture revient simplement à énumérer les tables ouvertes en leur spécifiant la méthode .close. Afin de libérer la mémoire utilisée, la remise à null des pointeurs est aussi importante pour garantir l’optimisation des ressources systèmes.

Pour ce qui est de la création d’une nouvelle base, on retiendra qu’elle fait intervenir les objets, les propriétés et certaines méthodes vus précédemment et qu’elle ne diffère que par son  concept. En effet cette procédure demande à l’utilisateur de choisir une nouvelle base (boîte de dialogue ouvrir),  le prévient si le fichier existe déjà, recopie l’ensemble des données d’un fichier source (fichier base de donnée original contenant les tables vides) vers le fichier créé et procède à l’ouverture de chacune des tables. La sauvegarde d’une base est une fonction permettant la recopie intégrale de la base actuellement ouverte vers un nouveau fichier.

Pour les fonctionnalités de même « famille », il suffit d’utiliser des objets VB similaires (ou presque) avec des concepts légèrement variants. L’exemple précédant employé la boite de dialogue d’ouverture d’un fichier pour l’ouverture (classique), la création et la sauvegarde d’un fichier. En fait, cela montre combien il devient intéressant de pouvoir modulé le code afin d’en réaliser une utilisation multiple et optimiser les ressources du système.

II-2-2 Manipulation des bases de données (pilotage du moteur de base de données Jet).
Le choix porté sur la description de certaines fonctions n’est pas sans intérêt. En illustration, la procédure suivante d’exportation d’une base de donnée met en avant l’ensemble des concepts de base de donnée qui seront utilisés tout au long du développement de l’application. Cette procédure propose la création d’une base de donnée, l’utilisation de requêtes sur plusieurs tables et l’enregistrement des résultats. On remarquera la syntaxe utilisée lors de la création des bases de données, loin de ressembler au SQL standard, elle est la propriété des objets D.A.O.

Private Sub BtExport_Click()

Dim dbsour As Database
Dim dbdest As Database
Dim sSQLREC As String
Dim recor As Recordset
Dim rs As Recordset
Dim td As TableDef
Dim fd As Field
Dim datpar As Recordset
Dim datparrgd As Recordset

' Initialisation : ouverture du fichier source et des tables objet de la transaction : param, parrgd
Screen.MousePointer = vbHourglass
lblmsg = « Initialisation de la base »

DoEvents

‘  Initialisation des variables source et destination aux chemins d’accés aux fichiers choisis

source = Trim$(txtfic1)
destination = Trim$(txtfic2)

‘ Ouverture de la base de données source
Set dbsour = DBEngine.OpenDatabase(source)

‘ Ouverture de chacune des tables
Set datpar = dbsour.OpenRecordset(« param », dbOpenTable)
Set datparrgd = dbsour.OpenRecordset(« parrgd », dbOpenTable)

‘ ----------------------------------------------------------------------------------------------------------------------------------
‘ Création du fichier destination, des tables et des champs  équivalents aux objets du fichier source.
‘ -----------------------------------------------------------------------------------------------------------------------------------lblmsg = « Création de la base »
DoEvents

‘  Création d’une base de donnée destination, fermeture puis réouverture pour test
Set dbdest = defaultworkspace.CreateDatabase(destination, dbLangGeneral)
dbdest.Close
Set dbdest = OpenDatabase(destination)

‘ Création de la table Liste des regards équivalente à la table regard de la base source
Set td = dbdest.CreateTableDef(« Liste_des_regards »)

‘ Création des champs associés à la table
Set fd = td.CreateField(« Code_Regard », dbText, 50)
td.Fields.Append fd

dbdest.TableDefs.Append td
«  Création de l’ensemble des tables et des champs associés »

‘ ----------------------------------------------------------------------------------------------------------------------------
‘ Requêtes sur l’ensemble de la base source pour renseignement des tables de la nouvelle base
‘ -----------------------------------------------------------------------------------------------------------------------------

lblmsg = « Enregistrement de la nouvelle base »
DoEvents

‘ Récupération de l’ensemble du jeu d’enregistrement de la table source dbsour
sSQLREC = « select * from regard »
Set recor = dbsour.OpenRecordset(sSQLREC, dbOpenDynaset)
 

‘  Initialisation de la base destination
Set rs = dbdest.OpenRecordset(« Liste des regards », dbOpenTable)
If Not recor.NoMatch Then ‘ Les enregistrements existent
    recor.MoveFirst ‘ Positionnement sur le premier enregistrement
 

Do Until recor.EOF  ‘ Procédure jusqu’au dernier enregistrement
        rs.AddNew  ‘ Ajout d’un enregistrement
 ‘ ------------ Traitement des données directement récupérables de champ à champ ----------------
        If recor(« cod ») <> « 0 » Then rs(« Code_regard ») = recor(« cod »)   ‘Enregistrement direct
       « Enregistrement des autres données dans chacun des champs appropriés »

‘ ------------ Traitement des données spécifiques : recherche du libellé correspondant aux valeurs
‘ numériques de la table source et enregistrement multiple dans un même champ -------------------
‘ Initialisation des champs et de la chaîne de concaténation
rs(« Tampon_Anomalie ») = «  «
«  Initialisation des autres champs »

libw$ = «  »
datparrgd.Index = « RGD » ‘ Index du champ COD pour tri et recherche

datparrgd.Seek « >= », Trim$(recor(« COD »)) ‘ Recherche des enregistrements affiliés au regard COD

‘  1) Recherche des enregistrements correspondant au regard (COD)  dans la table parrgd
‘  2) Récupération des valeurs du champ NUM pour lequel il convient de rechercher le libellé
‘  3) Recherche du libellé par la fonction libel dont les arguments sont la base de donnée source
       (contenant la table param) et le numéro NUM correspondant au libellé
‘  4) Attribution du libellé au champ correspondant au type de donnée : on comprend mieux la
        possibilité d’obtention de plusieurs valeurs pour un même champ

Do Until Trim$(datparrgd(« RGD »)) <> Trim$(recor(« COD »))      ‘ 1)
            libw$ = libel(dbsour, CDbl(datparrgd(« NUM »))) + «  | «  ‘ 2) et 3)
            Select Case datparrgd(« TYP »)    ‘ 4)
                Case 23
                  rs(« Temps ») = rs(« Temps ») + libw$
                Case 72
                    rs(« Type_réseau ») = rs(« Type_réseau ») + libw$
                    …
                 Case Else
                    ‘MsgBox « param regard inconnu » + Str$(datparrgd(« NUM »)), 16, nompg
            End Select
             datparrgd.MoveNext ‘ Progression pour accéder à un nouvel enregistrement
             If datparrgd.EOF Then Exit Do
      rs.Update
      recor.MoveNext
 Loop
End If
 

«  Fermeture de l’ensemble des bases de données et désallocation mémoire «

lblmsg = « Exportation terminée »
DoEvents
 

Screen.MousePointer = vbDefault

End Sub

II-2-3 Initialisation des contrôles d’une feuille de saisie (formulaire)
L’initialisation est différente suivant les contrôles. En effet, si un champ de type textbox est simplement renseigné par attribution d’une chaîne de caractère dans sa propriété caption, il en est autrement pour les contrôles de type  combobox (boîte de dialogue) dans le cadre de l’application développée.  Préalablement à l’affichage d’une donnée dans le champ d’une combobox, la liste de ce contrôle doit être renseignée par l’ensemble des paramètres lui correspondant (chargement des données PVC, Béton… dans la liste d’une combobox CbMatériaux par exemple).

Dans le cadre du chapitre II (Organisation de la base de données), nous avons pu présenter la méthode employée pour associé un contrôles Visual Basic de type combobox à des données d’une base (2-4 Relations entre les contrôles Visual Basic et la base de donnée Access : protocole de gestion des données), le code suivant présente donc la séquence d’initialisation de l’ensemble des contrôles combobox d’une feuille. Il suffit qu’un seule contrôle combobox n’ai pas de type correspondant dans la table param pour que la fonction renvoie la valeur faux. En effet, tout les contrôles de type combobox de l’application doivent être préchargés pour permettre la sélection d’une des données de la liste par l’utilisateur. IL suffit de se rappeler que chaque contrôle Combobox correspond à un type (Forme de cheminée par exemple) dans la base données et que chaque type possède des sous-types (Circulaire, Rond par exemple) qui doivent être préchargés. A ses sous-types correspond un numéro d’identification aussi préchargé.

Function ChargCombobox (frmw as form) as boolean
‘ Passage en argument de la feuille contenant les contrôles

For i = 0 To frmw.Controls.Count - 1    ‘  Recherche des combobox dans la collection …
    If TypeOf frmw.Controls(i) Is ComboBox Then  ‘  …Controls de la feuille de travail frmw
 numpar = frmw.Controls(i).Tag  ‘    Variable d’identification du type à rechercher dans la B.D
 frmw.Controls(i).Clear
 param.Index = « CLEX »  ‘ Recherche et trie sur le champ TYPE d’index CLEX
       param.Seek « >= », numpar, «  » ‘ Recherche des types correspondants à numpar dans la table param
        If param.NoMatch Then
            Msgbox « Aucun type n’a été trouvé pour le contrôle : «  & controls(i).Name
 ChargCombobox = False
        Else
 ‘ Tant que le type de la table param correspond au tag du contrôle

             While param( « TYP ») = numpar
 ‘ Ajout de la chaîne du champ LIB de la table param
                    frmw.Controls(i).AddItem Trim$(UCase(param(« LIB »)))
 ‘ Affectation de l’ensemble des numéros (sous-types NUM, valeurs numériques
 équivalentes à LIB) d’un type
                   frmw.Controls(i).ItemData(frmw.Controls(i).NewIndex) = param(« NUM »)
                   param.MoveNext    ‘   Déplacement sur le prochain enregistrement
 Wend
        End If
     End If

Next i  ‘  Recherche axée sur un nouveau contrôle
ChargCombobox = True

End Function

La fonction de chargement précédante souligne l’intérêt que peut avoir le développeur à être le plus abstrait possible lorsqu’il s’agit de manipuler des contrôles. L’appel à un nom de contrôle n’a jamais été effectué et seule le passage à la fonction du nom de la forme contenant les contrôles a permis de réaliser le chargement. Mais cette affirmation n’aurait pas été possible sans la richesse des fonctions/procédures et des méthodes/ propriétés  proposées par Visual Basic (Méthode .count sur collection controls, fonction TypeOf sur controls(i), propriété .tag de controls(i)…).

II-2-4 Enregistrement dans la base de données et l’affichage des formulaires
L’étape d’enregistrement des valeurs d’un formulaire vers la base de données passe d’abord par une vérification des données renseignées dans les champs. L’interdiction d’enregistrement de valeurs incompatibles ou le renseignement de champs obligatoires constituent le gage d’une bonne exploitation de la base de donnée.

Plusieurs méthodes d’enregistrement sont possibles, notamment l’édition des enregistrements et la modification des valeurs correspondantes ou bien la destruction simple des enregistrements,  la création et l’initialisation d’un nouvel enregistrement  avant sa mise à jour. Pour l’application, la deuxième solution a été retenue afin de s’assurer de la bonne initialisation des champs. Les procédures mise en place pour l’occasion font ressortir plusieurs types d’enregistrement dans la base en fonction de la nature des données saisies (chaînes de caractères, valeurs numériques) mais aussi en fonction des contrôles du formulaire.

Enregistrements liés à la table Regard :

Private Sub AjoutTableRegard()


‘ Ajout d’un nouvel enregistrement dans la table regard
rsRegard.AddNew
«  Initialisation des champs «

‘   Enregistrement direct d’une chaîne de caractère constituant la clé primaire de la table
rsRegard (« COD ») = Trim$(frmsaisie1.Textcod)


‘   Enregistrement après conversion du type chaîne de caractère en Réel Double
If Trim$(frmsaisie2.Textdim1) <> «  » Then
rsRegard (« DIM1 ») = CDbl(Trim$(frmsaisie2.Textdim1))
End If

‘  Enregistrement de la valeur de tag correspondant à l’élément coché de la collection OptionBox
For i = 0 To frmsaisie1.collecteur().Count - 1
    If frmsaisie1.collecteur(i).Value = True Then
  rsRegard (« TYPRES ») = frmsaisie1.collecteur(i).Tag
        Exit For
    End If
Next i


‘   Mise à jour des enregistrements précédents
rsRegard.Update

End Sub

Enregistrements liés à la table Parrgd :

Private Sub AjoutTableParrgd()


‘  Enregistrement des identifiants TYP et NUM (type temps et sous-type sec par exemple)
For i = 0 To frmsaisie1.temps().Count - 1    ‘   Pour tous les éléments de la collection temps()
    If frmsaisie1.temps(i).Value = True Then
        With rsParrgd     ‘   rsParrgd est un objet de type recordset
            .AddNew
            !RGD = Trim$(frmsaisie1.Textcod)        ‘   Enregistrement du code de regard dans le champ RGD
            !NUM = frmsaisie1.temps(i).Tag      ‘  Enregistrement du sous-type .tag dans le champ NUM
 ‘  Définition d’une requête pour recherche du type correspondant au sous-type .tag
            sqltyp = « select TYP from PARAM where NUM = » & frmsaisie1.temps(i).Tag
            Set rsparrgdtyp = db.OpenRecordset(sqltyp, dbOpenDynaset)
            !TYP = rsparrgdtyp!TYP
            .Update       ‘  Mise à jour de tous les enregistrements précédents
        End With
    End If
Next i

End Sub

Enregistrements liés à la table canal :

Private Sub AjoutTableCanal()


‘ Ajout d’un nouvel enregistrement dans la table canal
rsCanal.AddNew
«  Initialisation des champs «

‘  Enregistrement de l’ItemData (valeur numérique NUM correspondant au libellé actif de la Combobox CbTypres)
If Trim$(CbTypres(i)) <> «  » Then
       rsCanal (« TYPE ») = CbTypres (i).ItemData(CbTypres (i).ListIndex)
End If
rsCanal.Update   ‘  Mise à jour des enregistrements précédents

End Sub

En terme d’enregistrement, il est donc possible de réaliser combien les procédures diffèrent suivant le type d’objet à partir duquel s’effectue la copie des données dans la base. Pour ce qui est de l’affichage, le principe reste le même si ce n’est que l’opération se réalise dans le sens inverse. Les valeurs récupérée dans la base de données pour un regard et une canalisation ont une signification différente suivant le type de contrôle (TextBox, ListBox, ComboBox…) affiliée à la donnée. Néanmoins afin de comprendre le principe de l’enregistrement et l’affichage à partir ou dans un objet ComboBox, voici le code approprié qu’il est intéressant  de comparer à la procédure ci-dessus. (AjoutTableCanal)

Private Sub AffichTableCanal()


‘ Affichage de la chaîne à partir de l’ItemData récupéré dans la base de donnée
For w = 0 To CbTypres (j).ListCount - 1
 If CbTypres (j).ItemData(w) = rsCanal (« TYPE ») Then
  CbTypres (j).ListIndex = w
 Exit For
 End If
Next w

End Sub

II-2-5 Principe de recherche des anomalies sur les objets  regards de visite et canalisations
Deux types caractéristiques de la recherche tampan (Anomalies sur tampon) et chemform (forme de cheminée), représentent le sous-type (NUM) de la table parrgd dans laquelle s’effectue la recherche. Si l’enregistrement (valeur tampan) a été trouvé dans la table, la recherche se poursuit avec les autres valeurs (chemform par exemple) dans le cas de la condition ET pour test. Il suffit pour cette condition qu’un enregistrement n’est pas été trouvé pour que le passage du filtre s’arrête et que le code du regard ne soit pas retenu. Sinon dans le cas de la condition OU un seul enregistrement trouvé conduit à un passage positif du filtre pour un enregistrement du code de regard. La fonction booléenne requetnum  permet de rechercher  un critère et de renvoyer une valeur Vrai si celui-ci a été trouvé.

Public Sub rechaffich ()

Dim cod As String
Dim nbrcod as integer
Dim nbrselect as integer
Dim regsuiv As Label
Dim regou As Label

Dim tampan As Integer
Dim tamras As Integer
Dim chemform As Integer

‘  Type de donnée Tampon Anomalies où figure la mention RAS en coche
tampan = cbTampan(1).ItemData(cbTampan(1).ListIndex)
‘  Cas général
 

If tampan <> 0 And tampan <> 1 Then tamras =_ _rechnumras(cbTampan(1).ItemData(cbTampan(1).ListIndex))
‘   Au moins une anomalie dans ce cas récupération de l’itemdata correspondant à « RAS »
If tampan = 1 Then tamras = recras(cbTampan(1))
‘  Aucune requête
If tampan = 0 Then tamras = 0

‘   Type de donnée Cheminée Forme
chemform = cbchemform(5).ItemData(cbchemform(5).ListIndex)

regard.MoveFirst   ‘  Positionnement au première enregistrement
nbrselect = 0
Do While Not regard.EOF     ‘ Récupération des regards un à un
 cod = regard!cod
 ‘ Passage des arguments à la fonction de recherche de l’enregistrement correspondant à
 ‘  l’argument. Si l’enregistrement a été trouvé alors la fonction booléenne renvoie Vrai pour
 ‘ passage à la ligne suivante dans le cas de la condition ET sinon le renvoi au label regsuiv
 ‘  permet de ne pas sélectionner ce regard et le test se poursuit avec le regard suivant
 If Not requetnum(parrgd, cod, tampan, tamras) Then GoTo regsuiv
 If Not requetnum(parrgd, cod, chemform) Then GoTo regsuiv
 …

 ‘  Passage du filtre réussit pour le regard
 nbrselect = nbrselect + 1
 ‘  Mémorisation du code de regard
 ReDim Preserve reqnum(nun)
 reqnum(nbrselect - 1) = Trim$(cod)

 regsuiv:            ‘  Si non trouvé saut au label pour recherches sur le regard suivant
 regard.MoveNext

Loop
Screen.MousePointer = vbDefault
nbrcod = nbrselect - 1
‘  Chargement de la fenêtre d’affichage des résultats
Load frmcod
‘  Passage en argument de la table des regards  et du nombre d’enregistrement pour affichage
frmcod.initlbcod reqnum, nbrcod
‘  Visualisation du résultat
frmcod.Show

End Sub

II-2-6 Tracé automatique des réseaux (pilotage du logiciel S.I.G Autodesk World)
D’un intérêt particulier, cette fonctionnalité de l’application permet de concevoir rapidement la syntaxe employée pour la manipulation des objets d’un logiciel acceptant le protocole OLE-Automation tel qu’Autodesk World. L’organisation du code se fait sous forme de deux modules l’un regroupant toutes les fonctions et procédures d’intérêt général tandis que l’autre est dédiée à l’interaction de VB avec les objets de la collection d’Autodesk World. Dans une autre perspective de manipulation d’un logiciel S.I.G via OLE et Automation, il sera alors possible d’intégrer un module supplémentaire.

La procédure principale du module Drawres est simple, elle fait appel aux procédures nécessaires au
tracé. Ces dernières, si elles appartiennent au module de tracé A_World sont précédées du nom même du module. Cette distinction d’appel n’est pas nécessaire (les procédures de modules étant déclarées globales), néanmoins elle offre l’avantage de différencier l’origine des procédures appelées. On retiendra que le projet modele.apj est un projet paramétré de manière à répondre à toutes les attentes lors du tracé. Ses unités sont définies en mètre et en radiant tandis qu’un dessin (dessin1.dwg) contient les blocs dessins représentants des formes unitaires de cheminée, la direction du Nord, le cartouche et d’autres entités figurant généralement sur plan. Les blocs cheminées seront automatiquement insérés aux coordonnées à l’échelle voulue.

Sub main()

Choosbas ‘ Choix de la base objet des requêtes pour tracé
Openbase ‘ Ouverture de la base de données sélectionnée
A_world.openaworld ‘ Ouverture du projet modele.apf dans lequel va être généré le tracé
A_world.setdraw ‘ Création d’une nouveau dessin dans le projet modele.apf
A_world.insertbloconetime  ‘ Copie des blocs regards du dessin1.dwg vers le nouveau dessin créé
insert_rgd ‘ Insertion du bloc et de l’étiquette associée
insert_canal ‘ Insertion d’une ligne et de l’étiquette associée
A_world.closeaworld ‘ Sauvegarde du nouveau tracé et fermeture du projet modele.apf
End

End sub

La fonction suivante openworld() permet de « capturer » une application (elle même un objet)

actuellement ouverte. Si aucune application n’est ouverte, une nouvelle instance Aworld est créé. Si cette création échoue, c’est que l’application World n’est pas accessible sur site.

Public Sub openaworld()

On Error Resume Next
Set WorldApp = GetObject(, « Aworld.Application ») ‘ Capture d’une instance World ouverte
If Err Then
    Err.Clear
    Set WorldApp = CreateObject(« AWorld.Application »)   ‘ Création d’une instance World
    If Err Then
        Err.Clear
        MsgBox « Pas de connection possible à Autodesk World »
        Exit Sub
    End If
End If
pth = app.path   ‘ Normalisation du chemin d’accés au projet
If Right$(pth, 1) <> « \ » Then pth = pth & « \ »
pth = pth & « modele.apf »

Set oproj = WorldApp.OpenProject(pth)  ‘ Ouverture du projet modele

If oproj Is Nothing Then MsgBox « Impossible d’ouvrir le projet spécifié

End Sub

Les procédures insert_rgd() et insert_canal()  sont certainement les plus intéressantes de cette section et nous retiendrons qu’elles gèrent à la fois :

Néanmoins, afin d’apprécier la syntaxe du langage orienté objet permettant la manipulation des objets Autodesk World, nous nous en tiendrons à une fonction simple mais représentative d’insertion de blocs.

Public Sub insert_bloc_
_(layname As String, numpoint As String, coordX1 As Double, coordY1 As Double, coordZ1 As Double)

‘ Le type de réseau  suivi de la mention RGD comme regard constitue le nom de la couche d’insertion
layname = layname & « _RGD »
For i = 1 To oproj.ActiveDrawing.Layers.Count  ‘ Recherche de l’existence de la couche
   If oproj.ActiveDrawing.Layers(i).name = layname Then
       Set ScalePoint = WorldApp.CreateR3Point(1, 1, 1) ‘ Définition du facteur d’échelle
       Set oPoint = WorldApp.CreateR3Point(coordX1, coordY1, coordZ1) ‘ Définition du point
      ‘ Définition du bloc blo et insertion de l’entité à la collection d’objets de la couche du dessin
       actif du projet
        Set blo = oproj.ActiveDrawing.Layers.Item(i).Entities.CreateBlockEnt(« RGD_RO », oPoint, ScalePoint,0)
        oproj.ActiveDrawing.Layers.Item(i).Entities.Add_
                    _blo, numpoint, oproj.ActiveStyle, WorldApp.ActiveProject.ActiveDrawing.Layers.Item(i), True
        Exit For
    End If
Next i

End Sub

II-2-7 Intégration du composant ActiveX DWGX pour la visualisation des plans
La suite d’instructions suivante est destinée à présenter la partie de code qui permet le chargement et la visualisation d’un format DWG par simple manipulation des propriétés du composant DwgX1 de la feuille d’affichage. Une fois le fichier intégré visuellement au composant, les fonctions classiques de zoom, visualisation par couche…sont disponibles.

Private Sub dwgsrc(ficdwg as String)  ‘  Passage du chemin d’accès au fichier, en paramètre..

Dim FileType As String
If Trim$(ficdwg) <> «  »  Then
    FileType = Right(ficdwg, 3)   ‘  Mémorisation de l’extension du fichier
    If (StrComp(FileType, « red », 1) = 0) Then   ‘  Si le fichier est d’extension red. Résultat 0…
       srgdao1.DwgX1.RedlineSrc = ficdwg              ‘  …alors chargé le fichier via la propriété RedlineSrc
    Else
       srgdao1.DwgX1.Src = ficdwg    ‘  Sinon utiliser la propriété Src de l’objet
       srgdao1.Caption = « Fichier : «  & ficdwg
    End If
End If
srgdao1.Show   ‘  Visualisation de la feuille contenant le contrôle Dwg.OCX chargé

End Sub

II-2-8 Gestion des impressions (objet presse papier et pilotage du logiciel bureautique MS Excel)
Encore une fois destinée à illustrer la puissance des outils Microsoft lorsqu’il s’agit d’interagir avec des logiciels compatibles OLE, la gestion des impressions se fonde sur ce principe puisqu’à partir de l’application, les fiches de regard (modèle de terrain) et les fenêtres de saisie sont identiques à la fiche de sortie d’un regard. Pour mettre en place le code, il convient de préciser trois points importants : Public Sub fcimpr(RGDCOD As String)

If Not ExcelNoexist Then
    initsheet
    checksheet (RGDCOD)
    clpbrd
    printsheet
Else
    MsgBox «  Le logiciel Excel n’est pas disponible sur votre poste »
End if

End Sub

La procédure fcimpr() pour l’impression des fiches se base sur le code de regard dont la fiche Excel doit être renseignée. Pour ce faire, une initialisation de la feuille Excel (appelée xlsheet) est systématiquement réalisée. Cette procédure utilise les syntaxes suivantes pour l’initialisation : xlsheet.Range(cell).Value = False dans le cas d’une coche et xlsheet.Range(cell).Value = «  » dans le cas d’une textbox. Ensuite, la procédure checksheet permet de rechercher les caractéristiques relatives au code de regard afin d’en assurer l’édition (basé sur la même syntaxe que précédemment) grâce aux tables et aux champs de la base de donnée destinés à la correspondance données-cellule. La procédure clpbrd est spécialement conçue pour assurer le copier-collé du schéma de regard (fig.17 p33) du clipboard (presse papier) vers la feuille Excel avant le lancement de l’impression par la procédure printsheet qui utilise les propriétés : de configuration de l’impression pour l’objet xlsheet (PaperSize, CenterHorizontally…), et d’envoi de la feuille à l’imprimante (PrintOut).
 

II-3 Installation, maintenance de l’application et des bases de données.
II-3-1 Empaquetage, déploiement et maintenance de l’application
L’assistant d’empaquetage et déploiement de Visual Basic est une aide à la création d’un fichier paquet d’extension .cab destiné à la réinstallation sur site. Ce fichier est en fait un répertoire qui regroupe l’ensemble des  fichiers nécessaires à l’exécution normal du programme, ainsi que les chemins d'accès aux fichiers déjà installés sur poste (.dll, .exe,…). La création d’un tel fichier se réalise étape par étape afin d’assister l’opérateur concernant : A la fin de l’empaquetage, un fichier setup d’installation permet de lancer l’exécution pour le déploiement sur site des fichiers issus du répertoire .cab et l’inscription dans la base de registre des chemins d’accès.

Pour ce qui est de la réinstallation complète sur poste, elle n’est utile que si un composant Visual Basic (ActiveX, contrôles internes…) a été ajouter au cours du développement. En effet, il s’agit d’indiquer à l’exécutable une nouvelle référence à un objet. Sinon, le simple remplacement de l’exécutable par un fichier plus récent suffit à proposer de nouvelles fonctionnalités aux utilisateurs.

II-3-2 Impératifs du développement orienté bases de données
En matière de règles d’application générales, un nombre surprenant de programmes ont été créés avec l’idée qu’ils « se concevront d’eux-mêmes » au cours de leur développement. Au fur et à mesure de l’ajout de nouvelles fonctionnalités au programme, le code est réécrit et modifié jusqu’à ce que qu’il n’ait qu’une vague ressemblance avec son concept d’origine. Le pire est qu’une mauvaise conception (ou pas de conception du tout) entraîne souvent le développeur à s’encombrer avec la gestion d’un " fouillis " inextricable de code qu’il lui est difficile de comprendre, même s’il en est l’auteur. De nombreux problèmes de programmation sont la conséquence d’une conception médiocre due à une réflexion insuffisante du projet du début à la fin.

En matière de base de données, le problème est autrement compliqué puisque la structure d’une base de données, si elle est modifiée, contraint à la révision de l’interface graphique, jusqu’au code. En effet, l’installation de l’application sur poste pour test et utilisation (on ne saisie pas complètement des données dans une base pour test, surtout quand le nombre d’enregistrement est important) à demandé ensuite un temps considérable à consacrer à la mise à jour des bases. L’évolution du modèle de base de données à partir duquel sont créés les projets oblige la tenue à jour des anciennes bases crées à partir d’un modèle antérieur. Dans ce cas, la mise à jour s’effectue soit manuellement, c’est à dire en créant les nouveaux éléments (tables, index, clés…) dans les anciennes bases, soit automatiquement par développement de procédures de création d’éléments ne figurant pas dans les bases de données antérieures. Cette seconde solution a été adoptée après constatation qu’il deviendrait trop embarrassant de remettre à jour l’ensemble des bases existantes sur site ou via le protocole de transfert de fichier F.T.P. Néanmoins, il est intéressant de prévoir à long terme, l’élimination de ces procédures. Lorsque la totalité des anciennes bases auront été ouverte via l’application (recherche et mise à jour à l’ouverture des bases de données), il sera inutile de conserver le code correspondant à la recherche d’éléments déjà présents dans la base. Il est correct dans ce cas, de procéder à l’effacement du code au bout de 3-4 mois environ. Une part du travail consiste aussi à mettre les enregistrements à jour des bases de données par requêtes spécifiques.

Outre ces difficultés dues à une installation prématurée de l’application, il est toujours difficile d’avoir la vision métier pour développer une interface et des fonctionnalités complètement adaptées à l’utilisateur. Les discussions peuvent parfois ne jamais aboutir et le compromis est indispensable. Dans tous les cas, les standards en matière de logiciel et d’application est utopique (encore plus dans le domaine des applications orientées bases de données et S.I.G). La performance se mesure à la capacité à réadapter son application (les objets d’une fenêtre et bien évidemment le code sous-jacent) suivant les besoins d’un autre utilisateur voire aux besoins d’un autre développeur. A mon sens, si un terme était à retenir actuellement pour une application performante outre rapidité, facilité d’utilisation et fiabilité, se serait modularité qui permet de prévoir en temps et en chiffre, les conséquences de la réadaptation d’une application à des besoins différents. Bien évidemment, il ne s’agit pas de passer un temps trop important à développer des classes d’objet réutilisables, mais le développement par module a déjà fait ses preuves et Visual Basic offre la possibilité d’optimiser son code de cette manière.

Si la rigueur algorithmique et une vision macroscopique sont de mise pour développer des applications actuellement, il reste toujours à comprendre les méthodes et propriétés des nouveaux objets insérés dans un projet. Si l’utilisation des composants ActiveX évite la création d’objets au développeur, elle ne l’abstient pas du temps qu’il doit passer à la compréhension des propriétés et des méthodes associées aux objets, lorsque la documentation est absente.

II-4 Outils d’aide au développement
Une grande part des résultats du développement est conditionnée par le temps consacré à la recherche. Il est donc important de décrire les différentes sources d’aide au développement, qu’elles soient internes ou externes à l’environnement de développement.
II-4-1 Documentation numérique externe
Pour obtenir des sources intéressantes voire propres à résoudre certains problèmes de développement, Internet se place en bonne position, tant la communauté des développeurs Visual Basic est importante. Voici deux des sites fréquemment utilisés :


La demande en documentation des développeurs Microsoft a conduit à la création d’une bibliothèque presque exhaustive des fonctions et autres concepts liés à la conduite de projets : La Microsoft Developer Network Library (M.S.D.N) 97 et 6 qui constituent une excellente référence pour Visual Basic, Interdev, C++.

II-4-2 Documentation numérique de Visual Basic.
Outre ces aides « externes » à Visual Basic, l’explorateur d’objet donne accès à l’ensemble des objets, des propriétés et des méthodes pour une approche rapide. L’aide en ligne constitue bien sur la référence indispensable parce que source de recherche simple et rapide.
II-4-3 Ouvrages techniques consacrés.
Parce que l’utilisation des environnements de développement s’est intensifiée, on ne compte plus les ouvrages consacrés à des applications spécifiques. A ce titre, il n’a pas été difficile de s’appuyer sur des « pavés » dédiés aux bases de données, à Visual Basic et aux produits Microsoft pour la programmation Visual Basic Application.
 
Pour une description complète des règles stylistiques de programmation, on se reportera à l’ouvrage « Atelier Microsoft Visual Basic 5 » de J.C. Craig et J. Webb. Pour la mise au point et l’optimisation d’une application, on se référera à l’ouvrage « Visual Basic, ressources d’experts » de R. Thayer. Tandis que pour un développement d'applications orientées bases de données, on s'appuiera sur « Accés aux bases de données avec Visual Basic 6 » de J. Connell.