image gauche logo Clairinfo image droite

Version du : 28/01/2007

TUTORIAL PARADOX POUR WINDOWS

Leçon 6 - La fiche client, le modèle relationnel

Introduction :

Les leçons précédentes nous ont permis de définir un schéma des données à gérer, nous avons construit les tables dans Paradox puis nous avons construit notre première fiche Paradox pour constituer le menu de notre application. Il convient maintenant de construire les fiches d'accès aux données de nos différentes tables.

Créer une nouvelle fiche Client.fsl :

Nous connaissons maintenant la démarche :

- Menu Fichier / Nouveau / Fiche et nous demandons une fiche vierge (non non...pas d'assistant !)
- Nous l'enregistrons par Menu Fichier / Enregistrer et nous choisissons Client comme nom de fichier. Ce nom doit correspondre au code que nous avons tapé dans notre bouton d'appel de notre fiche Menu évidemment.
- Nous réglons les différents paramètres déjà évoqués pour la fiche Menu comme les dimensions de notre fiche. Toutes nos fiches auront la même dimension sauf peut-être certaines petites fiches modales. (un dialogue qui doit être validé par l'utilisateur pour pouvoir continuer) . Le choix de la couleur de fond etc... (cf la partie 3 du tutorial). Il est évidemment possible de copier une fiche déjà réalisée (la sélectionner dans la fenêtre projet, bouton droit de la souris et demander Copier...) pour repartir sur les même bases. Quand les fiches sont similaires c'est très productif.

Mettre un titre clair pour notre fiche :

Il faut arriver à cliquer sur la barre de titre de la fenêtre (donc elle ne doit pas être maximisée !) puis bouton droit de la souris et demander Style de fenêtre. Là vous allez trouver la zone Titre. Mettons : Gestion des clients

C'est également sur cet écran que se règlent des paramètres utiles comme l'affichage des ascenseurs ou le caractère modale d'une fenêtre. Ici nul besoin de modifier les paramètres standards.

Régler le code d'ouverture de la fiche :

Nous voulons un comportement standard pour toutes nos fiches et nous avons pris soin de centraliser en bibliothèque notre routine d'ouverture donc nous accédons à la méthode open de la fiche (attention de la fiche pas de la page) comme vu à la leçon 3 :

method open(var eventInfo Event)

if eventInfo.isPreFilter() then
;// This code executes for each object on the form

else
;// This code executes only for the form

Lib.open(":App:Lib")
Lib.OpenForm()
Lib.close()

endIf

endMethod

Ceci nous assure que notre fiche affichera notre menu standard , sera maximisée etc...

Rappel : Comme vu à la leçon 3, il convient de définir une variable Lib de type library au niveau fiche et de définir la clause use de la fiche pour intégrer notre méthode externe OpenForm. Sinon cela ne compile pas...

Définir le modèle relationnel de la fiche :

Ce terme un peu étrange désigne simplement l'emplacement où vous aller pouvoir spécifier les tables nécessaires à la fiche et éventuellement par quelles liaisons vous voulez les rapprocher. Pour notre fiche client seule la table Client.db sera nécessaire. Nous verrons par la suite avec la fiche facture ou au niveau des éditions comment utiliser cette formidable fonctionnalité qu'aucun autre produit n'offre aussi simplement !...

- Menu Format / Modèle relationnel (dans les versions plus anciennes c'est dans le menu fiche)
- La liste des tables de notre répertoire de travail s'affiche, on choisit Client.db en double-cliquant dessus.
- On valide par Ok. La fiche sait maintenant quelles tables nous proposer...

Positionner de simples champs de consultation / saisie :

Nous voulons pour notre fiche client voir un enregistrement par page pour pouvoir bien visualiser toutes les informations du client.

- S'assurer que la barre d'outils est visible. Si tel n'est pas le cas, demandez Menu Vue / Barre d'outils et cochez Objets de conception (Pour la version 5 il faut demander Menu Propriété/Bureau et décocher la case Barre d'outils : cachée)

- Réglez la cas échéant la couleur de fond de page et éventuellement placez un objet "boite" sur la page (Outil rectangle dans la barre d'outils). Ceci permet de regrouper les différents éléments que nous allons placer et de jouer sur un changement de couleur intéressant (voir l'image écran plus bas). Appliquez votre couleur à la boite et choisissez le type d'encadrement souhaité (onglet cadre des propriétés et choix du style de cadre)

- Sélectionnez l'outil champ dans la barre d'outils (celui qui est à droite du bouton) et faites un cliqué-glissé sur votre boite en forme de rectangle. Au relachement de la souris un premier champ est créé. Ce champ est pour l'instant "non défini" car il n'est pas encore rattaché au champ réel d'une table. Pour le définir, le champ étant sélectionné (des poignées apparaisssent sur son pourtour), demander bouton droit de la souris, définir le champ. Réapparait notre modèle relationnel (défini auparavant) et donc notre table Client.db

- Dans la liste déroulante de la table Client.db, choisissez le champ CodeClient et validez par Ok. Avant de répéter la manipulation pour les autres champs, nous allons définir les propriétés de style que nous désirons pour nos champs.

Mémoriser un style dans une feuille de style :

Afin d'éviter de préciser manuellement pour chaque objet de conception les propriétés de style attendues il y a plusieurs possibilités :

- Recopier un objet de même nature déjà stylisé (attention dans ce cas on recopie également le code éventuel !)
- Mémoriser dans la barre d'outils le style préféré (valable le temps d'une session Paradox)

   -> sélectionner un objet de conception à votre goût
   -> bouton droit de la souris / Copier dans barre d'outils

A partir de là tout nouvel objet de conception, du type sélectionné, récupérera le style défini, jusqu'au prochain redémarrage de Paradox. Pour mémoriser ce style durablement il faut simplement compléter la manipulation précédente en sauvegardant le tout dans une nouvelle feuille de style.

- Menu Format / Feuille de style / Sauvegarder en... et préciser votre nom de fichier

Ce menu Format / Feuille de stype permet donc de choisir pour une nouvelle fiche quelle feuille de style appliquer.

Construire une barre d'outils pour notre application :

Il est très facile de construire rapidement une petite barre d'outils réutilisable de fiche en fiche et de projet en projet.
Une barre d'outils se constitue simplement d'un objet boite et de quelques objets images pour nos boutons d'action.
Nous vous engageons à créer la votre en dessinant ou en récupérant des images adaptées. Le code OPAL sera placé sur chaque image dans la méthode mouseclick associée. Voici un exemple du résultat auquel vous pourriez arriver :

Remarque concernant le champ Notes : Par défaut Paradox n'affiche le contenu que lors de l'entrée dans la zone afin d'économiser les ressources. Si vous souhaitez forcer l'affichage du blob systématiquement il faut sélectionner la zone et dans le menu propriété / Exécution demander l'affichage complet.

Les boutons de la barre d'outils présentée ici permettront respectivement de :

- Aller au premier enregistrement
- Aller à l'enregistrement précédent
- Aller à l'enregistrement suivant
- Aller au dernier enregistrement
- Entrer et quitter le mode édition (pour pouvoir modifier nos données)
- Rechercher à partir du début de table
- Rechercher suivant sur même critère
- Ajouter un enregistrement
- Supprimer un enregistrement
- Quitter l'écran

Coder nos "boutons" (images) de la barre d'outils :

Il existe comme toujours plusieurs manières de coder une application. Nous avons choisi ici de définir localement pour chaque image l'action souhaitée et de transmettre les actions claviers équivalentes aux images concernées.

Remarque : Nous verrons ainsi les 2 grands types de codes possibles offerts par le complexe modèle évènementiel de Paradox : code au plus près des objet pour nos images et code centralisé au niveau fiche pour l'interception des touches claviers.

- Nous souhaitons pouvoir déclancher le code des images en réponse à une frappe clavier donc il nous faut définir précisément le nom de chacune d'elles. Donnez à ces images les noms respectifs suivants :

imPremier , imPrecedent, imSuivant, imDernier , imEdition, imRech, imRechS, imInser, imSupp, imExit.

- Implantez le code respectif suivant pour chacune des images (événement MouseClick) :

method mouseClick(var eventInfo MouseEvent)
active.action(DataBegin)
endmethod


method mouseClick(var eventInfo MouseEvent)
active.action(DataPriorRecord)
endmethod


method mouseClick(var eventInfo MouseEvent)
active.action(DataNextRecord)
endmethod


method mouseClick(var eventInfo MouseEvent)
active.action(DataEnd)
endmethod


method mouseClick(var eventInfo MouseEvent)
if isEdit() then
 action(DataEndEdit)
else
 action(DataBeginEdit)
endif
endmethod


method mouseClick(var eventInfo MouseEvent)
active.action(DataSearch)
endmethod


method mouseClick(var eventInfo MouseEvent)
active.action(DataSearchNext)
endmethod


method mouseClick(var eventInfo MouseEvent)
if not isEdit() then
 action(DataBeginEdit)
endif
active.action(DataInsertRecord)
CodeClient.MoveTo()
endmethod


method mouseClick(var eventInfo MouseEvent)
Var
 P TCursor
EndVar

if MsgQuestion("Confirmation :","Vous demandez l'effacement du client.\n\n"
+"On continue ?")<>"Yes" then
 return
endif

;// Vérifier que le client n'a pas de facture

P.open(":App:Fact")

if P.Locate("CodeClient",CodeClient) then
 MsgStop("Suppression refusée !","Ce client a des factures.")
 P.close()
 return
endif

P.close()

if not isEdit() then
 action (DataBeginEdit)
endif

active.action(DataDeleteRecord)

endmethod


method mouseClick(var eventInfo MouseEvent)
close()
endmethod

Explications : Les 4 premières méthodes font un simple appel à une constante d'action de type DataCommand proposée par Paradox. Le mot cléf "active" , ici facultatif car il n'y a un qu'une table active, est intéressant car il nous assure que l'instruction sera exécutée sur l'ensemble de donnée actif. Nous verrons cela notamment sur la fiche Facture qui comportera plusieurs tables. La méthode suivante demande le simple basculement entre mode édition et fin d'édition. Puis la recherche, la recherche suivant, l'insertion, la suppression (avec une étape de confirmation suivi d'un test pour empêcher de supprimer un client qui aurait une facture) et enfin la sortie de la fiche.

Traiter au niveau fiche les touches claviers correspondantes :

Notre code est d'ores et déjà opérationnel mais que se passerait-il si l'utilisateur au lieu d'utiliser notre belle barre d'outils s'amusait à essayer un des raccourcis standard de Paradox comme <CTRL> <SUPP> pour supprimer un client ? Et bien rien de bon ... Paradox effectuerait l'action sans lancer notre code de confirmation ou de vérification !

Il convient donc d'empêcher cela. Le seul endroit adequat pour intercepter toutes les touches claviers est la fiche elle-même qui voit passer tous les événements avant de le dispatcher à tous les objets concernés :

- Sélectionnez la fiche (attention pas la page...) et accédez à sa méthode keyphysical (touches enfonçées)
- Tapez le code suivant :

method keyPhysical(var eventInfo KeyEvent)
Var
 sChar String
EndVar

if eventInfo.isPreFilter() then
;// Ce code s'exécute pour chaque objet de la fiche :

sChar=eventInfo.vChar()

switch

case sChar="VK_INSERT" :

disableDefault
imInser.MouseClick()

Case sChar="VK_DELETE" and eventInfo.isControlKeyDown() :

disableDefault
imSupp.MouseClick()

case sChar="VK_ESCAPE" :

disableDefault
imExit.MouseClick()

case sChar="VK_F1" or sChar="VK_F2" or sChar="VK_F3" or sChar="VK_F4" :

disabledefault

case sChar="VK_F5" :

disableDefault
imRech.MouseClick()

case sChar="VK_F6" :

disableDefault
imRechS.MouseClick()

case sChar="VK_F7" or sChar="VK_F9" :

disabledefault

case sChar="VK_F10" :

disableDefault
if isEdit() then
 active.action(DataCancelRecord)
endif

case sChar="VK_F11" or sChar="VK_F12" :

disabledefault

endSwitch

else
;// Ce code s'exécute seulement pour la fiche :

endif

endmethod

Pour certaines nous désactivons le fonctionnement par défaut, pour d'autres nous les orientons vers notre propre code en leur demandant d'exécuter la méthode mouseclick de telle ou telle image de notre barre d'outil. Nous avons laissé passer la touche F8 qui permet de basculer entre la conception de fiche et son exécution pour son côté pratique ! Remarquez l'importance du mot clé "disabledefault" qui permet de bloquer le comportement par défaut.

Interdire toute modification de la zone CodeClient et contrôler doublon :

Précaution très importante, ne pas laisser les utilisateurs modifier les clés (à moins d'être sûr du système d'intégrité référentielle (IR) mis en place, système qui souvenez-vous est limité à un seul niveau sous Paradox...)
Notre application pourrait fournir un utilitaire dédié permettant de changer un CodeClient.

Concrètement nous allons empêcher toute modification de la zone CodeClient une fois celui-ci attribué. En outre quitte à coder autant ajouter un petit contrôle pour prévenir l'utilisateur en cas de saisi d'un doublon. Cela évitera l'apparition d'un message "Violation de clé" par toujours très clair pour l'utilisateur...

- Sélectionnez la zone CodeClient et accédez à sa méthode ChangeValue
- Tapez le code suivant :

method changeValue(var eventInfo ValueEvent)
Var
 P TCursor
EndVar

if Self<>"" then
 
 disabledefault
 msgStop("Attention !","Vous ne devez pas modifier ce champ...")  

else

 P.Attach(CodeClient)
 if P.locate("CodeClient",eventInfo.Newvalue()) then
  disabledefault
  msgInfo("Message :","Ce client existe déjà !\n\n"+eventInfo.Newvalue()+" : "+P.Nom)
  P.close()
  return
 endif
 P.close()

 Dodefault

endif
endmethod

Comme annoncé, si la zone n'est pas vierge nous bloquons le fonctionnement par défaut et nous envoyons un message à l'utilisateur. Dans le cas contraire nous cherchons un doublon éventuel. Cas particulier de l'événement Changevalue , la valeur entrée par l'utilisateur n'est pas celle du champ tant que Dodefault n'a pas été exécuté. Pour obtenir cette valeur entrée sans lancer le code par défaut lié à Dodefault nous interrogeons la méthode Newvalue du paquet d'événement reçu en entrée. La présence des "\n\n" dans les messages permet de sauter des lignes, ici 2 lignes.

Interdire la création non contrôlée d'un nouvel enregistrement :

Autre précaution à prendre : Il faut désactiver dans le modele relationnel la création automatique d'enregistrement lors du déplacement en fin de table. Faites l'essai , positionnez-vous en fin de table , passez en mode édition et effectuez un déplacement supplémentaire en avant. Cela crée par défaut un nouvel enregistrement sans passer par notre routine d'insertion... Pour éviter cela :

- Menu Format / Modèle relationnel
- Bouton droit de la souris sur la table souhaitée, ici Client.db
- Décocher Ajout automatique et valider

Voilà notre fiche est maintenant prête pour des tests intensifs... Beaucoup de choses pourraient encore être améliorées mais cette fiche devrait être robuste et parfaitement fonctionnelle.

A titre d'exercice je vous laisse construire la fiche Produit qui offrira le même type de fonctionnalités. Idéalement on duplique la fiche et l'on ne modifie que ce qui change mais évidemment si le but est d'apprendre il vaut mieux tout recréer de zéro.

Haut de page    Précédent    Suivant

© Copyright 2000-2007 , Clairinfo ® , http://www.clairinfo.fr