L'évènement ChangeValue: ajouter vos contrôles et vos traitements

Quand se produit l'évènement ChangeValue:

L'évènement ChangeValue est déclenché en deux circonstances:

- lorsque l'utilisateur tente de quitter un champ dont il a modifié la valeur (modification manuelle)

- ou bien, lorsqu'une assignation par ObjetPal a été faite au champ (modification par programmation).

 

Cet évènement est utile pour:

- vérifier la nouvelle valeur, par exemple demander une confirmation si la valeur est supérieure à un seuil donné;

- déclencher un traitement après acceptation de la valeur, par exemple, calculer une date d'échéance à partir des conditions de paiement.

 

Pour illustrer notre programmation, nous allons prendre comme exemple le calcul d'une date d'échéance à partir de la date de facture et d'un délai de paiement exprimé en nombre de jours.

 

Comportement par défaut de l'évènement ChangeValue, ajout d'un traitement après acceptation de la valeur

Paradox fait comme toujours une partie du travail à la place du développeur en intégrant dans son comportement par défaut un certain nombre de contrôles physiques:

1. Il vérifie le type de données du champ de la table (contrôle qu'il s'agit d'une date valide pour un champ date, contrôle que la valeur est inférieure à 32762 s'il s'agit d'un entier court, ...)

2. Il vérifie que la valeur saisie respecte les contrôles de validité (modèle de sdaisie, plage de valeurs, table de référence, ...), ce, aussi bien pour les champs définis (liés à un champ d'une table) que pour les champs non définis (on peut placer un modèle de saisie sur un champ non défini).

 

Le comportement par défaut est exécuté implicitement en fin de la méthode ChangeValue (c'est à dire lorsque la méthode renvoie le contrôle à Paradox, soit par Return, soit par EndMethod).

 

Il est cependant possible de forcer Paradox à exécuter ses contrôles internes à un instant donné par l'intermédiaire de l'instruction:

 

DODEFAULT

 

Vous pouvez ainsi intervenir après les contrôles Paradox pour effectuer un traitement spécifique. Bien sûr, vous souhaitez conditionner ce traitement par l'acceptation par Paradox de la valeur saisie . Il est alors nécessaire de tester si une erreur a été détectée par Paradox. Ceci peut être fait en vérifiant la présence d'un éventuel code erreur grâce à la méthode errorCode() :

 


Method ChangeValue (var EventInfo valueEvent)   notre champ est DelaiPaiement

DODEFAULT;on force le traitement par défaut de Paradox
IF eventinfo.errorCode() = 0 THEN;on teste si Paradox a accepté la valeur
DateEcheance.Value = DateFacture.Value + self.Value   traitement après l'acceptation de la nouvelle valeur
ENDIF
EndMethod

Ajout d'un contrôle avant le traitement par défaut par Paradox

Souvent, il est nécessaire de compléter les contrôles faits par Paradox. Dans notre cas, nous voulons que toute valeur saisie supérieure à 60 jours donne lieu à une confirmation. Nous avons mis une plage de valeurs dans notre table de sorte à limiter la saisie à des délais compris entre 0 et 90 jours.

 

Le contrôle s'effectue en plaçant notre programmation avant l'instruction DODEFAULT. Nous avons accès à la valeur candidate par l'intermédiaire de la méthode NewValue() (dans self.Value, on a encore l'ancienne valeur).

 


Method ChangeValue (var EventInfo valueEvent)   notre champ est DelaiPaiement
;demande de confirmation pour des délais > 60 jours
IF eventinfo.NewValue() > 60 THEN
iF msgQuestion("Demande de confirmation","Le délai saisi est supérieur à 60 jours, veuillez confirmer svp") = "No" then
DISABLEDEFAULT    ne pas acccepter la valeur
EventInfo.setErrorCode(canNotDepart) ; rester sur le champ
RETURN
ENDIF
ENDIF
DODEFAULT
IF eventinfo.errorCode() = 0 THEN
DateEcheance.Value = DateFacture.Value + self.Value
ENDIF
EndMethod

La commande DISABLEDEFAULT refuse la valeur saisie et rétablit la valeur précédente mais n'enmpêche pas le déroulement du Dodefault et l'exécution de la suite du programme. DISABLEDEFAUT n'empêche pas en particulier le déplacement vers le prochain champ. Pour interdire le départ, il faut initialiser un code erreur dans le paquet d'informations eventinfo grâce à la méthode: setErrorCode(..). L'instruction RETURN est utile pour abandonner le flux du programme dans le cas où du code ObjectPal se trouve après le test de la nouvelle valeur.

 

cas particulier: il est possible de modifier la nouvelle valeur avant sa prise en compte par Paradox. Dans notre cas, on veut, si l'utilisateur efface la valeur, on veut mettre un délai à 45 jours. Cette modification de valeur peut être faite en utilisant la méthode SetNewValue().


IF isblank(eventInfo.newValue()) THEN
eventInfo.setNewValue(45)
ENDIF
 DODEFAULT   les contrôles de Paradox se font alors sur 45

Cas particulier: déclenchement croisé de 2 évènements changeValue

 

Dans notre exemple, l'utilisateur peut au choix saisir le délai (et la date d'échéance est calculée automatiquement) ou saisir la date d'échéance et le délai est alors calculé. Si on programme la méthode ChangeValue du champ DateEcheance comme on a fait si dessus pour le champ Delai, on va renconter un petit (et même un gros) problème lors de l'exécution. En effet, la saisie dans le champ Delai provoque le calcul de la dat d'échéance et l'affectation dans le champ correspondant de la nouvelle valeur (notre instruction DateEcheance.Value = self.value + DateFacture.Value). Cette affectation déclenche à son tour la méthode ChangeValue du champ DateEcheance qui contient une instrcution Delai.Value = self.Value - DateFacture.Value, instruction qui a son tour va déclencher la méthode ChangeValue du champ Delai, etc ... Autrefois on parlait d'un serpent qui se mord la queue. Paradox parle plutôt d'un débordement de pile. Le résultat est que Paradox tourne en rond entre deux affectations.

 

La première solution consiste à appliquer la formule de calcul présente dans le changeValue uniquement si l'utilisateur se trouve dans le champ courant. On évitera ainsi la propagation. Ceci peut être effectué de la façon suivante:


Method ChangeValue(VAR eventInfo ValueEvent)  
IF not  self.arrivedTHEN
RETRUN
ENDIF
......

ainsi on évite la propagation du changeValue.

 

La seconde solution consiste à utiliser la méthode dmPut() qui permet d'écrire dans un champ d'une table du modèle raltionnel sans déclencher le modèle évènementiel.

 


Method ChangeValue (var EventInfo valueEvent)
;contrôles spécifiques
DODEFAULT
IF eventinfo.errorCode() = 0 THEN
dmput("MaTable","DateEcheance", DateFacture.Value + self.Value)
ENDIF
EndMethod

Piège: On pourrait être tenté d'utiliser un tcursor attaché à l'enregistrement courant afin de mettre à jour le champ concerné. Dans ce cas on ne déclencherait évidemment pas l'évènement ChangeValue (qui ne concerne que les modifications efffectuées par l'interface). C'est une mauvaise solution car la tentative de mise à jour par l'intermédiaire du Tcurso serait bloquée par le verrou d'enregistrement posé dans l'interface. Vous pouvez vérifier ceci avec le code suivant:


var
tc tcursor
endvar
dodefault
if eventinfo.Errorcode()=0 then
tc.dmattach(self.TableName)
tc.edit()
if not tc.lockRecord() then
errorshow()
       msginfo("Echec","Vous êtes bloqué, l'enregistrement est déjà verrouillé")
       endif
     tc.fieldValue("DateEcheance"self.Value+DateFacture.Value) ; ce que vous auriez bien voulu faire
    if not tc.unlockRecord() then
       errorshow()
       endif
   endif
endif

Résumé: Structure générale de la programmation de ChangeValue

Method changeValue (VAR eventInfo ValueEvent)
; programmation des contrôles avant le traitement de la nouvelle valeur par Paradox vos contrôles
IF Not (contrôles satisfaits) then
DISABLEDEFAULT on rétablit l'ancienne situation
eventInfo.setErrorCode(canNotDepart) on empêche le départ du champ
RETURN on arrête le traitement de la méthode
ENDIF
DODEFAULT Paradox traite la valeur saisie
IF eventInfo.errroCode() = 0 then Paradox a accepté la valeur
;traitement X après acceptation de la valeur

ENDIF
Endmethod

Rappel: La commande RETURN n'inhibe pas le comportement par défaut , c'est-à-dire que dans notre exemple ci-dessus, si le champ est défini sur un champ de type date d'une table, nous aurons d'une part notre premier message puis le message paradox (dans la ligne statut) comme quoi le format est incorrect. En revanche, la suite du traitement se situant après le Return ne s'exécutera pas.