Page 1 sur 3

Saisie numérique dans un string gadget avec 1 à n décimales

Publié : sam. 02/oct./2010 18:58
par falsam
N'ayant pas trouver de fonction ou include (qui fonctionnent) me permettant de saisir des montants avec décimales, je vous présente ce que j'ai fait.

- Un fichier include StrMaskDec.pbi

Code : Tout sélectionner

; StrMaskDec - V1.00
;
;Using : StrMaskDec(Gadget,IntegerLenght,DecimalLenght)
;
;Compatibility : Windows 
;
Procedure StrMaskDec(Gadget,IntegerLenght,DecimalLenght)
  ValText.s  ;String Value 
  ValASCII.b ;ASCII Value
  PartEnt.s   ;Integer Value
  PartDec.s  ;Décimal Value
  x.b           ;Longueur de la chaine en cours de saisie
  y.b           ;Position du point decimal
  
  ValText=GetGadgetText(gadget)
  
  Select EventType()
    Case #PB_EventType_Focus 
      ;Le texte de l'edit control est selectionné totalement
      SendMessage_(GadgetID(Gadget), #EM_SETSEL, 0, -1)  
      
    Case #PB_EventType_LostFocus
      ;Il est temps de mettre en forme le résultat
      
      x = Len(ValText) 
      y = FindString(ValText,".",1)
      
      If y<>0
        PartEnt=Left(ValText,y-1)
        If PartEnt=""
          PartEnt="0"
        EndIf
        PartDec=Right(ValText,x-y)
        SetGadgetText(Gadget,PartEnt+"."+LSet(PartDec,Len(PartDec)+(DecimalLenght-Len(PartDec)),"0"))
      Else
        SetGadgetText(Gadget,ValText+"."+LSet("0",DecimalLenght,"0"))
      EndIf
  
    Case #PB_EventType_Change 
      ;Il y a du changement dans notre string 
      x=Len(ValText)
      y = FindString(ValText,".",1)
      
      ;Seul les caractéres de 0 à 9 ainsi que le point décimal sont autorisés
      ValASCII = Asc(Right(GetGadgetText(Gadget),1))  
      
      Select ValASCII 
        Case 46
          ;Un point est saisi. On teste qu'il y en a bien qu'un seul
          If CountString(GetGadgetText(Gadget),".")>1
             keybd_event_(#VK_BACK,0,0,0)
          EndIf
            
        Case 48 To 57 
          ; Chiffres de 0 à 9
          ;Il y a t'il un point decimal et en quelle position
          y = FindString(ValText,".",1)
                    
          If y>0
              ;La taille de la partie entiére ne doit etre > à celle autorisée (IntegerLenght)
              If Len(Left(ValText,y-1))>IntegerLenght
                keybd_event_(#VK_BACK,0,0,0)
              EndIf
              
              ;La taille de la partie décimale ne doit etre > à celle autorisée (DecimalLenght)
              If Len(Right(ValText,x-y))>DecimalLenght
                keybd_event_(#VK_BACK,0,0,0)
              EndIf
              
            Else
      
              ;Pas de partie decimale pour le moment dans notre saisie
              ;La taille de la partie entiére ne doit etre > à celle autorisée (IntegerLenght)
              If Len(ValText)>IntegerLenght
                keybd_event_(#VK_BACK,0,0,0)
              EndIf      
          EndIf
            
        Default 
            ;Ce n'est pas des chiffres 
            keybd_event_(#VK_BACK,0,0,0)
              
        EndSelect
  EndSelect
EndProcedure
- Un exemple d'utilisation. (Calcul m'un montant ttc à partir d'un montant ht

Code : Tout sélectionner

XIncludeFile "StrMaskDec.pbi"

Enumeration
  #MainForm
  #MntHt
  #MntTtc
EndEnumeration

Procedure MainFormShow()
  If OpenWindow(#MainForm,0,0,400,150,"Nouvelle application",#PB_Window_ScreenCentered |#PB_Window_SizeGadget | #PB_Window_SystemMenu)
  
  TextGadget(#PB_Any,10,23,80,23,"Montant Ht")
  StringGadget(#MntHt,100,20,80,23,"0.00",#ES_RIGHT) 
  
  TextGadget(#PB_Any,10,43,80,23,"Montant Ttc")
  StringGadget(#MntTtc,100,40,80,23,"0.00",#PB_String_ReadOnly | #ES_RIGHT)
  SetGadgetColor(#MntTtc,#PB_Gadget_BackColor,$F9F9F9)
  TextGadget(#PB_Any,200,43,80,23,"Taux 19,60%")
  
  SetActiveGadget(#MntHt)
  EndIf
EndProcedure

Procedure CalculTTC()
  MntHt.f=ValF(GetGadgetText(#MntHt))
  MntTtc.f=MntHt*(1.196)
  SetGadgetText(#MntTtc,StrD(MntTtc,2))
EndProcedure

MainFormShow()

Repeat
  Select WaitWindowEvent()
    Case #PB_Event_CloseWindow
      End
      
    Case #PB_Event_Gadget
      If EventGadget() = #MntHt
        StrMaskDec(#MntHt,5,2)
        CalculTTC()
      EndIf
    
  EndSelect
ForEver
Découvrant PB que depuis un peu plus d'un mois, ce code n'est peut être pas "académique". :p

La prochaine étape constituera à mettre en place un masque d'affichage du genre ### ###.## (Ex : 12555.15 affichera 12 555.15)

Re: Saisie numérique dans un string gadget avec 1 à n décima

Publié : sam. 02/oct./2010 19:07
par nico

Code : Tout sélectionner

keybd_event_(#VK_BACK,0,0,0) 
Pourquoi ne pas utiliser Getgadgettext, Setgadgettext plutôt?

Re: Saisie numérique dans un string gadget avec 1 à n décima

Publié : sam. 02/oct./2010 21:17
par falsam
Cela évite la manipulation de chaines.

Re: Saisie numérique dans un string gadget avec 1 à n décima

Publié : sam. 02/oct./2010 21:44
par nico
Je serais toi, j'éviterais ce genre d'instruction.

Sinon, il aurait été plus judicieux de faire un Subclassing de l'Edit ; ainsi tu gère l'affichage des caractères avant que celles-ci s'affichent.

Re: Saisie numérique dans un string gadget avec 1 à n décima

Publié : sam. 02/oct./2010 21:52
par falsam
nico a écrit :... il aurait été plus judicieux de faire un Subclassing de l'Edit ....
Je ne sais pas ce que c'est.

Re: Saisie numérique dans un string gadget avec 1 à n décima

Publié : sam. 02/oct./2010 21:54
par falsam
Apres une courte recherche ....
Le SubClassing est une technique de programmation qui permet l’interception des messages Windows, en remplaçant les processus par défaut de Windows par vos propres procédures.
A chaque fois que l’utilisateur fait quelque chose, déplace la souris, appuie sur une touche

je ne vois ce que ça change.

Re: Saisie numérique dans un string gadget avec 1 à n décima

Publié : sam. 02/oct./2010 21:55
par PAPIPP
Bonjour à tous
et comme cela ce n'est pas plus simple
a$=InputRequester("Saisie avec décimale","Donnez votre valeur avec . point ou , virgule","")
a$=ReplaceString(a$,",",".")
VD.D=ValD(a$)
Debug "A$="+A$+" Vd="+StrD(vd)
A+

Re: Saisie numérique dans un string gadget avec 1 à n décima

Publié : sam. 02/oct./2010 22:35
par nico
je ne vois ce que ça change.
Subclassing=controle total du Gadget

Re: Saisie numérique dans un string gadget avec 1 à n décima

Publié : sam. 02/oct./2010 22:54
par falsam
@PAPIPP : Ton exemple ne permet pas de contrôler la longueur de la partie entiere ainsi que de la partie décimale. Prends la peine de tester mon code au cas ou ça ne serait pas fait, afin de voir ce que ça donne.
Nico a écrit :Subclassing=controle total du Gadget
Nico ça ne me dit toujours pas comment faire pour mettre en oeuvre tes savantes explications :)

Re: Saisie numérique dans un string gadget avec 1 à n décima

Publié : dim. 03/oct./2010 8:51
par Backup
falsam a écrit : La prochaine étape constituera à mettre en place un masque d'affichage du genre ### ###.## (Ex : 12555.15 affichera 12 555.15)

ton code me parait pas mal :)

pour ce qui est des mask cela a deja ete abordé ici :
http://www.purebasic.fr/french/viewtopi ... ask+%23%23

;)

ps : inutile d'utiliser : XIncludeFile "StrMaskDec.pbi"
alors que tu fourni la procedure StrMaskDec
puisque celle ci est dans le code , et non plus a l'exterieur ...

les pbi ne sont pas une obligation !!
perso , je ne les utilises jamais ! :)

Re: Saisie numérique dans un string gadget avec 1 à n décima

Publié : dim. 03/oct./2010 10:49
par PAPIPP
OK ici avec contrôle type : [+ -]nnnn[.]nnn
et on peut changer sans pb tous les termes mais c'est toujours aussi simple

Code : Tout sélectionner

Procedure.s  remplace_pv(term1.s)
    Static flag.b,hld0,hld1 ;; recherche [+ -]nnnn[.]nnn
  Dim resultat$(0)
  If flag=0
    hld0=CreateRegularExpression(#PB_Any," ") ;suppression de tous LES Blancs
    hld1=CreateRegularExpression(#PB_Any,",") ;remplacement , par .
    flag=1
  EndIf
    term2.s=ReplaceRegularExpression(hld0,term1,"")
    term2  =ReplaceRegularExpression(hld1,term2,".")
    ProcedureReturn term2
  EndProcedure

  Procedure ISNUM(TERM1.S)
  Static flag.b,hld0,hld1,hld2 ;; 
  Dim resultat$(0)
  If flag=0
    hld0=CreateRegularExpression(#PB_Any,"^[\+-]{0,1}[\d]{1,6}\.[\d]{1,2}$")  ; structure [+-]n[nnnnn].n[n] C'est ici que l'on peut changer les différents termes
    flag=1
  EndIf
  M2= MatchRegularExpression(hld0,Term1) ;+" chr("+Str(i)+")"+_s(Chr(i))
  ProcedureReturn m2

EndProcedure

RE:
a$=InputRequester("Saisie avec décimale","valeur "+mes$,a$)
a$=remplace_pv(a$) ; suppression des blancs et remplacement de la virgule par un point
If isnum(a$)=0 
  mes$="non comforme à [+-]n[nnnnn].n[n]"
  Goto re
EndIf 
Debug a$
A+

A propos de CreateRegularExpression

Publié : dim. 03/oct./2010 15:31
par falsam
C'est super déroutant, mais qu'est ce que c'est biennnn !!!

CreateRegularExpression(#ExpressionReguliere, Motif$ [, Options])

J'ai eu du mal à comprendre que ce tout petit bout de code était la base pour chercher, extraire ou remplacer du texte ou un caractère par un autre.

Pour mon exemple, je voulais examiner un string et remplacer tout les espace par rien.

je commence par créer mon expression régulière pour dire que je vais traiter le caractére Espace

Code : Tout sélectionner

Enumeration
  #NoSpace
EndEnumeration

CreateRegularExpression(#NoSpace," ")


je vais maintenant demander à mon programme de remplacer les espaces par rien du tout.
Pour cela je vais utiliser ReplaceRegularExpression(#RegularExpression, Texte$, TexteRemplace$)

Code : Tout sélectionner

Debug ReplaceRegularExpression(#NoSpace,"1 235.25","")
Tout simplement génial :)

Re: A propos de CreateRegularExpression

Publié : dim. 03/oct./2010 15:43
par Backup
falsam a écrit :
Pour mon exemple, je voulais examiner un string et remplacer tout les espace par rien.
pour un truc aussi simple tu peux utiliser
String$ = ReplaceString(Chaine$, ChaineCherchee$, ChaineRemplacee$ [, Mode [, PositionDepart]])
par exemple :


toto$= "1 3456.45"
toto$ = replacestring (toto$, " " , "" )
debug toto$
:)

Re: Saisie numérique dans un string gadget avec 1 à n décima

Publié : dim. 03/oct./2010 16:04
par falsam
Voila qui confirme la signature de mon profil !!!

Initialement c'est bien cette fonction que j'avais utilisé (ReplaceString). Je viens juste de voir la façon dont j'ai codé ma procédure et je comprends mieux pourquoi je n'avais pas de résultat.

Dobro ....... merci :)

Re: Saisie numérique dans un string gadget avec 1 à n décima

Publié : dim. 03/oct./2010 22:39
par falsam
Comme dit précédemment, j'ai inclus le masque de saisie dans la fonction StrMaskDec

Rappel :
Le gadget StringGaget permet à l'utilisateur de saisir directement une information.

Je souhaitais pouvoir saisir des valeurs numériques (Monétaire, poids, taille, surface, etc ......) en contrôlant la taille de la partie entière ainsi que la taille de la partie décimale.

Il est assez facile de cadrer à droite les valeurs saisies.

Code : Tout sélectionner

Exemple : StringGadget(#MntHt,100,20,80,23,"0.00",#ES_RIGHT) 
Il me restait à codifier quelques procédures de contrôles que j'ai regroupé dans un fichier include (.pbi)

3 Procédures sont disponibles.

StrMaskDec

But
Appliquer un masque d'édition sur un String gadget

Syntaxe
StrMaskDec(Gadget.l ,IntegerLenght.b, DecimalLenght.b, UsingMask.s)
Gadget : Handle du gadget concerné
IntegerLenght : Longueur de la partie entiére
DecimalLenght : Longueur de la partie décimale
Usingmask : Format d'edition sous la forme d'une chaine composée uniquement du caractere #

Exemple
StrMaskDec(#MntHt,5,2,"### ###.## €")


StrFormat

But
Obtenir une chaine de caractere formatée en fonction du masque décrit

Syntaxe
Result=StrFormat(String.s,Mask.s)
String : Nombre en entrée sous forme de chaine
Mask : Format d'edition sous la forme d'une chaine composée uniquement du caractere # (Voir exemple)
Result : Est une chaine de caractere

Exemple
StrFormat("123455", "### ###.##") donnera "1 234.55"
StrFormat("123455", "### ###.## €") donnera "1 234.55 €"
StrFormat("03102010","##-##-####") donnera "03-10-2010"



StrToNumStr

But
Obtenir une chaine de caractere correspondant au nombre passé en paramétre
débarassé de son masque d'edition

Syntaxe
Result=StrToNumStrt(String.s)
String : Est une chaine de cartactere qui contient le nombre à "De-Formater"
Result : Est une chaine de caractere débarassée de son masque d'edition

Exemple
StrToNumStr("1 234,55") donnera "1234.55"


Ci dessous vous trouverez :
- Le code correspondant aux trois procédures ci-dessus et que j'ai regroupé
dans un fichier que j'ai nommé StrMaskDec.pbi

- Un code exemple regroupant l'utilisation de ces trois procédures.

Code correspondant à l'include StrMaskDec.pbi

Code : Tout sélectionner

; 
StrMaskDec - V1.01
;
;Contributor : Falsam; Thyphoon
;
;Compatibility : Windows 
;

;StrFormat 
;
;But
; Obtenir une chaine de caractere formatée en fonction du masque décrit
; 
;Syntaxe 
; Result=StrFormat(String.s,Mask.s)
;     String : Nombre en entrée sous forme de chaine
;     Mask  : Format d'edition sous la forme d'une chaine composée uniquement du caractere # (Voir exemple)
;     Result : Est une chaine de caractere
;
;Exemple
; StrFormat("123455", "### ###.##") donnera "1 234.55"
; StrFormat("123455", "### ###.## €") donnera "1 234.55 €"
; StrFormat("03102010","##-##-####") donnera "03-10-2010"

Procedure.s StrFormat(String.s, Mask.s)
  Result.s=""
  
  String=ReplaceString(String,".","")
  String=ReplaceString(String,",","")
  
  lt.b=Len(String)+1
  lm.b=Len(Mask)+1
  
  Repeat
    c.s=Mid(Mask,lm,1)
    If c="#" And lt>0
      Result=Mid(String,lt,1)+Result
      lt=lt-1
      lm=lm-1
    ElseIf c <> "" And lm>0
      Result=c+Result
      lm=lm-1
    Else
          lt=lt-1
      lm=lm-1
    EndIf
    Until  lt<1
    ProcedureReturn Result
EndProcedure

;StrToNumStr
;
;But
; Obtenir une chaine de caractere correspondant au nombre passé en paramétre 
; débarassé de son masque d'edition 
; 
;Syntaxe 
; Result=StrToNumStrt(String.s)
;     String : Est une chaine de cartactere qui contient le nombre à "De-Formater"
;     Result : Est une chaine de caractere débarassée de son masque d'edition
;
;Exemple
; StrToNumStr("1 234,55") donnera "123455"

Procedure.s StrToNumStr(String.s)
  Result.s
  Result=ReplaceString(String, ",",".") 
  Result=ReplaceString(String," ", "")
  ProcedureReturn Result
EndProcedure
;StrMaskDec
;
;But
; Appliquer un masque d'édition sur un String gadget
; 
;Syntaxe 
; StrMaskDec(Gadget.l ,IntegerLenght.b, DecimalLenght.b, UsingMask.s)
;     Gadget              : Handle du gadget concerné
;     IntegerLenght    : Longueur de la partie entiére
;     DecimalLenght   : Longueur de la partie décimale
;     Usingmask         : Format d'edition sous la forme d'une chaine composée uniquement du caractere # (Voir exemple)
;
;   
;Exemple
; StrMaskDec(#MntHt,5,2,"### ###.## €")

Procedure StrMaskDec(Gadget.l ,IntegerLenght.b, DecimalLenght.b, UsingMask.s)
  ValText.s  ;String Value 
  ValASCII.b ;ASCII Value
  PartEnt.s   ;Integer Value
  PartDec.s  ;Décimal Value
  x.b           ;Longueur de la chaine en cours de saisie
  y.b           ;Position du point decimal
  
  ValText=GetGadgetText(gadget)
  
  Select EventType()
    Case #PB_EventType_Focus 
      ;Le texte de l'edit control est selectionné totalement
      SendMessage_(GadgetID(Gadget), #EM_SETSEL, 0, -1)  
      
    Case #PB_EventType_LostFocus
      ;Il est temps de mettre en forme le résultat
      
      x = Len(ValText) 
      y = FindString(ValText,".",1)
      
      If y<>0
        PartEnt=Left(ValText,y-1)
        If PartEnt=""
          PartEnt="0"
        EndIf
        PartDec=Right(ValText,x-y)
        SetGadgetText(Gadget,StrFormat(PartEnt+LSet(PartDec,Len(PartDec)+(DecimalLenght-Len(PartDec)),"0"),UsingMask))
      Else
        SetGadgetText(Gadget,StrFormat(ValText+LSet("0",DecimalLenght,"0"),UsingMask))
      EndIf
      
    Case #PB_EventType_Change 
      ;Il y a du changement dans notre string 
      x=Len(ValText)
      y=FindString(ValText,".",1)
      
      ;Seul les caractéres de 0 à 9 ainsi que le point décimal sont autorisés
      ValASCII = Asc(Right(GetGadgetText(Gadget),1))  
      
      Select ValASCII 
        Case 46
          ;Un point est saisi. On teste qu'il y en a bien qu'un seul
          If CountString(GetGadgetText(Gadget),".")>1
             keybd_event_(#VK_BACK,0,0,0)
          EndIf
            
        Case 48 To 57 
          ; Chiffres de 0 à 9
          ;Il y a t'il un point decimal et en quelle position
          y = FindString(ValText,".",1)
                    
          If y>0
              ;La taille de la partie entiére ne doit etre > à celle autorisée (IntegerLenght)
              If Len(Left(ValText,y-1))>IntegerLenght
                keybd_event_(#VK_BACK,0,0,0)
              EndIf
              
              ;La taille de la partie décimale ne doit etre > à celle autorisée (DecimalLenght)
              If Len(Right(ValText,x-y))>DecimalLenght
                keybd_event_(#VK_BACK,0,0,0)
              EndIf
              
            Else
      
              ;Pas de partie decimale pour le moment dans notre saisie
              ;La taille de la partie entiére ne doit etre > à celle autorisée (IntegerLenght)
              If Len(ValText)>IntegerLenght
                keybd_event_(#VK_BACK,0,0,0)
              EndIf      
          EndIf
            
        Default 
            ;Ce n'est pas des chiffres 
            keybd_event_(#VK_BACK,0,0,0)
              
        EndSelect
  EndSelect
EndProcedure

Notre code exemple :)

Code : Tout sélectionner

IncludeFile "StrMaskDec.pbi"

Enumeration
  #MainForm
  #MntHt
  #MntTtc
EndEnumeration

Procedure MainFormShow()
  If OpenWindow(#MainForm,0,0,400,150,"Saisie monétaire",#PB_Window_ScreenCentered |#PB_Window_SizeGadget | #PB_Window_SystemMenu)
  
  TextGadget(#PB_Any,10,23,80,23,"Montant Ht")
  StringGadget(#MntHt,100,20,80,23,"0.00",#ES_RIGHT) 
  
  TextGadget(#PB_Any,10,43,80,23,"Montant Ttc")
  StringGadget(#MntTtc,100,40,80,23,"0.00 €",#PB_String_ReadOnly | #ES_RIGHT)
  SetGadgetColor(#MntTtc,#PB_Gadget_BackColor,$F9F9F9)
  TextGadget(#PB_Any,200,43,80,23,"Taux 19,60%")
  
  SetActiveGadget(#MntHt)
  EndIf
EndProcedure

Procedure CalculTTC()
  ;Convertissons la chaîne en une valeur numérique de type Float.
  ;Ici nous utilisons la fonction StrToNumStr pour nous debarasser du format d'edition
  MntHt.f=ValF(StrToNumStr(GetGadgetText(#MntHt)))
  
  MntTtc.f=MntHt*(1.196)
  

  SetGadgetText(#MntTtc,StrFormat(StrF(MntTtc,2),"### ###.## €"))
EndProcedure

MainFormShow()

Repeat
  Select WaitWindowEvent()
    Case #PB_Event_CloseWindow
      End 
      
    Case #PB_Event_Gadget
      If EventGadget() = #MntHt
          ; C'est ici qu'on applique le format d'edition 
          StrMaskDec(#MntHt,5,2,"### ###.## €")
          
          Select EventType()
            Case #PB_EventType_LostFocus
              ;Calcul de du montant Ttc
              CalculTTC()
          EndSelect
      EndIf    
  EndSelect
ForEver