StringGadget décimal (Windows) & UseMask()

Vous débutez et vous avez besoin d'aide ? N'hésitez pas à poser vos questions
Avatar de l’utilisateur
falsam
Messages : 7324
Inscription : dim. 22/août/2010 15:24
Localisation : IDF (Yvelines)
Contact :

StringGadget décimal (Windows) & UseMask()

Message 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
Dernière modification par falsam le mar. 01/sept./2015 9:36, modifié 9 fois.
Configuration : Windows 11 Famille 64-bit - PB 6.20 x64 - AMD Ryzen 7 - 16 GO RAM
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%
PAPIPP
Messages : 534
Inscription : sam. 23/févr./2008 17:58

Re: StringGadget décimal (Windows)

Message 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+
Il est fort peu probable que les mêmes causes ne produisent pas les mêmes effets.(Einstein)
Et en logique positive cela donne.
Il est très fortement probable que les mêmes causes produisent les mêmes effets.
Lord Nelson
Messages : 355
Inscription : dim. 01/déc./2013 15:29

Re: StringGadget décimal (Windows)

Message 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:
Avatar de l’utilisateur
falsam
Messages : 7324
Inscription : dim. 22/août/2010 15:24
Localisation : IDF (Yvelines)
Contact :

Re: StringGadget décimal (Windows)

Message 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)
Configuration : Windows 11 Famille 64-bit - PB 6.20 x64 - AMD Ryzen 7 - 16 GO RAM
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%
Avatar de l’utilisateur
Micoute
Messages : 2584
Inscription : dim. 02/oct./2011 16:17
Localisation : 35520 La Mézière

Re: StringGadget décimal (Windows)

Message 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())
Microsoft Windows 10 Famille 64 bits : Carte mère : ASRock 970 Extreme3 R2.0 : Carte Graphique NVIDIA GeForce RTX 3080 : Processeur AMD FX 6300 6 cœurs 12 threads 3,50 GHz PB 6.20 LTS (x64)
Un homme doit être poli, mais il doit aussi être libre !
Avatar de l’utilisateur
falsam
Messages : 7324
Inscription : dim. 22/août/2010 15:24
Localisation : IDF (Yvelines)
Contact :

Re: StringGadget décimal (Windows)

Message 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.
Configuration : Windows 11 Famille 64-bit - PB 6.20 x64 - AMD Ryzen 7 - 16 GO RAM
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%
Lord Nelson
Messages : 355
Inscription : dim. 01/déc./2013 15:29

Re: StringGadget décimal (Windows)

Message par Lord Nelson »

Très bon travail Falsam :)
Merci à toi ;)
Avatar de l’utilisateur
Micoute
Messages : 2584
Inscription : dim. 02/oct./2011 16:17
Localisation : 35520 La Mézière

Re: StringGadget décimal (Windows)

Message 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 !
Microsoft Windows 10 Famille 64 bits : Carte mère : ASRock 970 Extreme3 R2.0 : Carte Graphique NVIDIA GeForce RTX 3080 : Processeur AMD FX 6300 6 cœurs 12 threads 3,50 GHz PB 6.20 LTS (x64)
Un homme doit être poli, mais il doit aussi être libre !
Avatar de l’utilisateur
falsam
Messages : 7324
Inscription : dim. 22/août/2010 15:24
Localisation : IDF (Yvelines)
Contact :

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

Message 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.
Dernière modification par falsam le mar. 01/sept./2015 9:37, modifié 1 fois.
Configuration : Windows 11 Famille 64-bit - PB 6.20 x64 - AMD Ryzen 7 - 16 GO RAM
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%
Fred
Site Admin
Messages : 2808
Inscription : mer. 21/janv./2004 11:03

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

Message par Fred »

Tu devrais attendre la version finale avant de modifier tes codes, car ca va plus marcher avec la beta 2 :)
Avatar de l’utilisateur
falsam
Messages : 7324
Inscription : dim. 22/août/2010 15:24
Localisation : IDF (Yvelines)
Contact :

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

Message 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.
Configuration : Windows 11 Famille 64-bit - PB 6.20 x64 - AMD Ryzen 7 - 16 GO RAM
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%
Répondre