Page 1 sur 1

StringGadget décimal (Windows) & UseMask()

Publié : lun. 08/déc./2014 2:04
par falsam
Bien que récurrent, le sujet est tendance : La saisie d'un champ décimal manque à Pure Basic.

-Si vous écrivez des programmes de gestion, il est pratique de pouvoir saisir des montants décimales en précisant le nombre de décimales maximal.

Ce code n'a qu'une valeur didacticiel que je ne met pas dans la section Trucs et Astuces car mon code n'est pas vraiment une astuce ou un truc. De même je ne pense pas qu'il ne mérite pas d'être dans la section Informations et tutoriaux car il existe différentes méthodes pour arriver au même résultat et que de plus je ne lancerais pas dans des explications détaillées.

Assez blablater il est temps de parler un peu de ce code.

■ La procédure UseMask() permet d'afficher un nombre formaté suivant un masque précis (nombre de décimales, groupement des chiffres) J'utilise l'API GetNumberFormat_ (Windows) pour formater un nombre conjointement avec la structure NUMBERFMT (Windows) pour définir le masque d'affichage.

NUMBERFMT est défini dans le compilateur et vous trouverez ci-dessous quelques explications sur chacun des membres de cette structure.

-NumDigits : Nombre de chiffres à afficher après la virgule.
-LeadingZero : Si zéro, complète les chiffres après la virgule avec le nombre de zéros spécifié dans NumDigits.
-Grouping : Nombre de chiffres à inclure dans chaque groupe pour les chiffres avant la virgule. (Défaut : 3).
-lpDecimalSep : Caractère à utiliser comme séparateur décimal. (Défaut : ".").
-lpThousandSep : Caractère à utiliser comme séparateur de groupe (Défaut " ").
-NegativeOrder : Valeur représentant l'affichage d'un nombre négatif. Exemple avec le nombre -123.99 :
        0 donne (123,99)
        1 donne -123,99
        2 donne - 123,99
        3 donne 123,99-
        4 donne 123,99 -

■ Plus classique, la procédure OnEventGadget() gère les différents événement sur un StringGadget()

■ Et enfin pour terminer, la procédure Open_MainForm() comme son nom l'indique, va ouvrir une fenêtre avec deux montants à saisir afin de tester le code. C'est dans cette procédure qu'on va définir une expression régulière contrôlant la saisie décimale.

■ Le code

Code : Tout sélectionner

EnableExplicit

Enumeration Windows
  #Mainform
EndEnumeration

Enumeration Gadgets
  #Montant1
  #Montant2
EndEnumeration

Enumeration RegularExpression
  #Numeric
EndEnumeration

Global WindowStyle.i=#PB_Window_MinimizeGadget|#PB_Window_MaximizeGadget|#PB_Window_ScreenCentered|#PB_Window_SizeGadget
Global PreviousText.s, CurrentText.s

Procedure.s UseMask(Number.s, NumDigit.l=2, LeadingZero.l=0, Grouping.l=3, lpDecimalSep.s=".", lpThousandSep.s=" ", NegativeOrder.i=0)
  Protected Buffer.s, NF.NUMBERFMT
  
  Buffer.s=Space(255)
     
  NF\NumDigits = NumDigit
  NF\LeadingZero=LeadingZero
  NF\Grouping=Grouping
  NF\lpDecimalSep=@lpDecimalSep
  NF\lpThousandSep=@lpThousandSep
  NF\NegativeOrder=NegativeOrder
  
  GetNumberFormat_(#LOCALE_SYSTEM_DEFAULT, 0, Number, NF, @Buffer, Len(Buffer))
  
  If StringField(Buffer, 1, ".") = ""
    ProcedureReturn "0"+Buffer
  Else
    ProcedureReturn Buffer
  EndIf
  
EndProcedure


Procedure OnEventGadget()
  Protected Gadget = EventGadget()
  Protected EndPos
  Protected Buffer.s
  
  Select EventType()
    Case #PB_EventType_Focus
      SetGadgetColor(Gadget, #PB_Gadget_BackColor, RGB(255, 248, 220))
      PreviousText = GetGadgetText(Gadget)
      Buffer = ReplaceString(PreviousText, " ","") : PreviousText = Buffer
      Buffer = ReplaceString(PreviousText, "(","-") : PreviousText = Buffer
      Buffer = RemoveString(PreviousText, ")") : PreviousText = Buffer
      SetGadgetText(Gadget, PreviousText) 
      
    Case #PB_EventType_Change
      CurrentText = GetGadgetText(Gadget)
      If MatchRegularExpression(#Numeric, CurrentText) = 0
        SendMessage_(GadgetID(Gadget), #EM_GETSEL, 0, @endpos)
        endpos - 1 
        SetGadgetText(Gadget, PreviousText)
        SendMessage_(GadgetID(Gadget), #EM_SETSEL, endpos, endpos)
      Else
        PreviousText = CurrentText  
      EndIf
      
    Case #PB_EventType_LostFocus
      SetGadgetText(Gadget, UseMask(PreviousText, 2))
      SetGadgetColor(Gadget, #PB_Gadget_BackColor, RGB(255, 255, 255))
      PreviousText = ""

  EndSelect
  
EndProcedure

Procedure Open_MainForm()
  Protected Decimal = 2 ;Nombre de décimales
  
  CreateRegularExpression(#Numeric, "^\-{0,1}\d*$|^\-{0,1}\d+\.\d{0,"+Str(Decimal)+"}$|^$")
  
  SetGadgetFont(#PB_Default, FontID(LoadFont(#PB_Any ,"", 11)))
  
  OpenWindow(#Mainform, 0, 0, 500, 400, "IsNumeric", WindowStyle)
  
  TextGadget(#PB_Any, 20, 20, 80, 20, "Montant1")
  StringGadget(#Montant1, 100, 20, 100, 20, "0.00", #ES_RIGHT)
  
  TextGadget(#PB_Any, 20, 50, 80, 20, "Montant2")
  StringGadget(#Montant2, 100, 50, 100, 20, "0.00", #ES_RIGHT)
  
  BindGadgetEvent(#Montant1, @OnEventGadget())
  BindGadgetEvent(#Montant2, @OnEventGadget())  
  
  Repeat : Until WaitWindowEvent(10) = #PB_Event_CloseWindow
EndProcedure

Open_MainForm()
Tester la saisie classique d'un nombre, mais aussi la saisie d'un nombre négatif et regarder l'affichage quand vous quitter le champs de saisie : Exemple le nombre -123.99 donnera (123.99) les comptables adorent ce system d'affichage.

Remplacez

Code : Tout sélectionner

Protected Decimal = 2 ;Nombre de décimales
par

Code : Tout sélectionner

 Protected Decimal = 3 ;Nombre de décimales
Tester maintenant l'arrondi des décimales : (Exemple 100.123 deviendra 100.12 Mais 100.127 deviendra 100.13)

■ A la question Est on obligé de saisir la partie décimale quand elle est égale à 0 ? La réponse est non.
   Exemple : 123 affichera 123.00

Re: StringGadget décimal (Windows)

Publié : lun. 08/déc./2014 10:40
par PAPIPP
Merci Falsam

Je pense que les saisies des nombres décimaux sont pour les plus courantes résolues ici.
avec l'aide de l'API (GetNumberFormat)

A+

Re: StringGadget décimal (Windows)

Publié : lun. 08/déc./2014 11:28
par Lord Nelson
Salut,

Pas mal, mais ya un bug qui arrive quand tu entre pas mal de chiffres et que tu va a tour de rôle dans les champs.
Exemple: Entre -> 145623.25 ensuite: -> va dans le second champs, reviens, fais ça deux fois et vois ensuite :wink:
Le champs ou ta entrer 145623.25 devient pleins d’espace !

Bon travail :wink:

Re: StringGadget décimal (Windows)

Publié : lun. 08/déc./2014 11:50
par falsam
Merci Lord. Code corrigé. J'avais oublié de tester les grands nombres. La prochaine fois je n'oublierais pas de mettre par écrit mon protocole de test. :)

Correction : J'ai retiré deux variables qui ne servaient à rien (LastGadget, CurrentGadget)

Re: StringGadget décimal (Windows)

Publié : lun. 08/déc./2014 12:16
par Micoute
La première version était mieux, car quand on passait d'un champ à un autre le nombre de décimales restait à 2 et maintenant, il passe à 3 ! (Procedure OnEventGadget())

Re: StringGadget décimal (Windows)

Publié : lun. 08/déc./2014 12:19
par falsam
@Micoute: Tu dois avoir

Code : Tout sélectionner

Protected Decimal = 3
Remplace cette valeur par 2

Recherche aussi l'affichage des montants

Code : Tout sélectionner

    Case #PB_EventType_LostFocus
      SetGadgetText(Gadget, UseMask(PreviousText, 3))
et remplace 3 par 2.

Re: StringGadget décimal (Windows)

Publié : lun. 08/déc./2014 12:47
par Lord Nelson
Très bon travail Falsam :)
Merci à toi ;)

Re: StringGadget décimal (Windows)

Publié : lun. 08/déc./2014 21:23
par Micoute
falsam a écrit :@Micoute: Tu dois avoir

Code : Tout sélectionner

Protected Decimal = 3
Remplace cette valeur par 2

Recherche aussi l'affichage des montants

Code : Tout sélectionner

    Case #PB_EventType_LostFocus
      SetGadgetText(Gadget, UseMask(PreviousText, 3))
et remplace 3 par 2.
C'est ce que j'ai fait aussitôt !

Re: StringGadget décimal (Windows) & UseMask()

Publié : lun. 31/août/2015 22:36
par falsam
Le code que j'ai présenté, ne fonctionnant plus avec la version 5.40 LTS, je l'ai modifié afin qu'il fonctionne avec les versions précédentes de PureBasic ainsi que cette nouvelle version 5.40 LTS.

J'ai remplacé

Code : Tout sélectionner

GetNumberFormat_(#LOCALE_SYSTEM_DEFAULT, 0, Number, NF, @Buffer, Len(Buffer))
par

Code : Tout sélectionner

GetNumberFormat_(#LOCALE_SYSTEM_DEFAULT, 0, @Number, NF, @Buffer, Len(Buffer))
Suite au message de fred (Voir plus loin), ne pas tenir compte de cette modification.

Re: StringGadget décimal (Windows) & UseMask()

Publié : mar. 01/sept./2015 9:32
par Fred
Tu devrais attendre la version finale avant de modifier tes codes, car ca va plus marcher avec la beta 2 :)

Re: StringGadget décimal (Windows) & UseMask()

Publié : mar. 01/sept./2015 9:35
par falsam
Fred a écrit :Tu devrais attendre la version finale avant de modifier tes codes, car ca va plus marcher avec la beta 2 :)
Bonjour Fred. J'ai vu ta réponse ce matin sur le forum anglais et je vais remettre le code en l'état et attendre la fin de la période de beta test pour faire les modifications nécessaires si il y a lieu.