Formatage MM / JJ / AAAA dates dans l'encadré dans VBA

je cherche un moyen de formater automatiquement la date dans une zone de texte VBA au format MM/JJ/AAAA, et je veux qu'elle soit formatée au fur et à mesure que l'utilisateur la Tape. Par exemple, une fois que l'utilisateur aura tapé le second numéro, le programme Tapera automatiquement un "/". Maintenant, j'ai obtenu ce travail (ainsi que le deuxième tiret) avec le code suivant:

Private Sub txtBoxBDayHim_Change()
    If txtBoxBDayHim.TextLength = 2 or txtBoxBDayHim.TextLength = 5 then
    txtBoxBDayHim.Text = txtBoxBDayHim.Text + "/"
End Sub

maintenant, cela fonctionne très bien en tapant. Toutefois, lorsque vous essayez de supprimer, il entre toujours dans les tirets, de sorte que son impossible pour l'utilisateur de supprimez l'un des tirets (la suppression d'un tiret entraîne une longueur de 2 ou 5, et le sous est alors exécuté de nouveau, en ajoutant un autre tiret). Des suggestions pour une meilleure façon de le faire?

25
demandé sur Siddharth Rout 2012-08-17 23:43:10

9 réponses

Je ne suggère jamais d'utiliser des boîtes de textes ou des boîtes D'entrées pour accepter des dates. Donc, beaucoup de choses peuvent mal se passer. Je ne peux même pas suggérer d'utiliser le calendrier de contrôle ou le capteur de Date comme pour que vous devez enregistrer le mscal.ocx ou mscomct2.ocx et c'est très douloureux car ils ne sont pas librement distribuable fichiers.

Voici ce que je recommande. Vous pouvez utiliser ce calendrier personnalisé pour accepter les dates de l'utilisateur

PROS:

  1. Vous n'avez pas à ne vous inquiétez pas si l'utilisateur entre des informations erronées
  2. Vous n'avez pas à vous inquiéter de l'utilisateur de coller dans la zone de texte
  3. Vous n'avez pas à vous inquiéter au sujet de l'écriture majeur de code
  4. GUI Attractive
  5. peut être facilement incorporé dans votre application
  6. N'utilise aucun contrôle pour lequel vous devez faire référence à des bibliothèques comme mscal.ocx ou mscomct2.ocx

CONS:

Ummm...Ummm... Ne peut pas penser de tout...

COMMENT L'UTILISER

  1. Télécharger Userform1.frm et Userform1.frxici.
  2. dans votre VBA, importez simplement Userform1.frm comme indiqué dans l'image ci-dessous.

importation du formulaire

enter image description here

RUNNING IT

Vous pouvez l'appeler de toute procédure. Par exemple,

Sub Sample()
    UserForm1.Show
End Sub

SCREEN SHOTS IN ACTION

enter image description here

56
répondu Siddharth Rout 2016-07-13 13:09:58

Vous pouvez cliquer sur ce lien pour télécharger le récupérateur de date personnalisé que j'ai créé. Ci-dessous quelques screenshots de la forme en action.

Three example calendars

pour utiliser le picker de date, il suffit d'importer le CalendarForm.fichier frm dans votre VBA projet. Chacun des calendriers ci-dessus peut être obtenu avec un seul appel de fonction. Le résultat ne dépend que des arguments que vous utilisez (tous optionnels), de sorte que vous pouvez personnaliser autant ou aussi peu que vous voulez.

par exemple, le calendrier le plus basique à gauche peut être obtenu par la ligne de code suivante:

MyDateVariable = CalendarForm.GetDate

C'est tout ce qu'il y a à faire. De là, vous incluez juste les arguments que vous voulez obtenir le calendrier que vous voulez. L'appel de la fonction ci-dessous va générer le calendrier vert sur la droite:

MyDateVariable = CalendarForm.GetDate( _
    SelectedDate:=Date, _
    DateFontSize:=11, _
    TodayButton:=True, _
    BackgroundColor:=RGB(242, 248, 238), _
    HeaderColor:=RGB(84, 130, 53), _
    HeaderFontColor:=RGB(255, 255, 255), _
    SubHeaderColor:=RGB(226, 239, 218), _
    SubHeaderFontColor:=RGB(55, 86, 35), _
    DateColor:=RGB(242, 248, 238), _
    DateFontColor:=RGB(55, 86, 35), _
    SaturdayFontColor:=RGB(55, 86, 35), _
    SundayFontColor:=RGB(55, 86, 35), _
    TrailingMonthFontColor:=RGB(106, 163, 67), _
    DateHoverColor:=RGB(198, 224, 180), _
    DateSelectedColor:=RGB(169, 208, 142), _
    TodayFontColor:=RGB(255, 0, 0), _
    DateSpecialEffect:=fmSpecialEffectRaised)

Voici un petit avant-goût de certaines des fonctions qu'il contient. Toutes les options sont entièrement documentées dans le module userform lui-même:

  • Facilité d'utilisation. Le formulaire d'utilisateur est entièrement autonome, et peut être importé dans n'importe quel projet VBA et utilisé sans beaucoup, voire aucun codage supplémentaire.
  • design Simple et attrayant.
  • fonctionnalité entièrement personnalisable, taille et couleur schéma
  • limiter la sélection de l'utilisateur à une plage de dates précise
  • Choisir n'importe quel jour pour le premier jour de la semaine
  • inclure les numéros de semaine, et le soutien à la norme ISO
  • en cliquant sur l'étiquette du mois ou de l'année dans l'en-tête, on obtient des comboboxes sélectionnables
  • Dates qui changent de couleur quand vous passez votre souris au-dessus d'eux
28
répondu Trevor Eyre 2016-10-09 19:47:40

ajouter quelque chose pour suivre la longueur et vous permettre de faire des "vérifications" sur si l'utilisateur ajoute ou soustrait du texte. Ceci n'a pas encore été testé, mais quelque chose de similaire devrait fonctionner (surtout si vous avez un formulaire d'utilisateur).

'add this to your userform or make it a static variable if it is not part of a userform
private oldLength as integer

Private Sub txtBoxBDayHim_Change()
    if ( oldlength > txboxbdayhim.textlength ) then
        oldlength =txtBoxBDayHim.textlength
        exit sub
    end if

    If txtBoxBDayHim.TextLength = 2 or txtBoxBDayHim.TextLength = 5 then
    txtBoxBDayHim.Text = txtBoxBDayHim.Text + "/"
    end if
    oldlength =txtBoxBDayHim.textlength
End Sub
11
répondu Elysian Fields 2012-08-20 00:41:12

juste pour m'amuser, J'ai pris la suggestion de Siddharth de séparer les boîtes de texte et j'ai fait des comboboxes. Si quelqu'un est intéressé, ajouter un formulaire d'utilisateur avec trois comboboxs nommés cboDay, cboMonth et cboyan et les arranger de gauche à droite. Ensuite, collez le code ci-dessous dans le module de code UserForm. Les propriétés combobox requises sont définies dans UserFormInitialization, de sorte qu'aucune PPRE supplémentaire ne devrait être requise.

la partie délicate est de changer le jour où il devient invalide en raison d'un changement dans de l'année ou du mois. Ce code le réinitialise à 01 quand ça arrive et met en valeur cboDay.

Je n'ai pas codé quelque chose comme ça depuis un moment. J'espère que ça intéressera quelqu'un un jour. Sinon, c'est amusant!

Dim Initializing As Boolean

Private Sub UserForm_Initialize()
Dim i As Long
Dim ctl As MSForms.Control
Dim cbo As MSForms.ComboBox

Initializing = True
With Me
    With .cboMonth
        '        .AddItem "month"
        For i = 1 To 12
            .AddItem Format(i, "00")
        Next i
        .Tag = "DateControl"
    End With
    With .cboDay
        '        .AddItem "day"
        For i = 1 To 31
            .AddItem Format(i, "00")
        Next i
        .Tag = "DateControl"
    End With
    With .cboYear
        '        .AddItem "year"
        For i = Year(Now()) To Year(Now()) + 12
            .AddItem i
        Next i
        .Tag = "DateControl"
    End With
    DoEvents
    For Each ctl In Me.Controls
        If ctl.Tag = "DateControl" Then
            Set cbo = ctl
            With cbo
                .ListIndex = 0
                .MatchRequired = True
                .MatchEntry = fmMatchEntryComplete
                .Style = fmStyleDropDownList
            End With
        End If
    Next ctl
End With
Initializing = False
End Sub

Private Sub cboDay_Change()
If Not Initializing Then
    If Not IsValidDate Then
        ResetMonth
    End If
End If
End Sub

Private Sub cboMonth_Change()
If Not Initializing Then
    ResetDayList
    If Not IsValidDate Then
        ResetMonth
    End If
End If
End Sub

Private Sub cboYear_Change()
If Not Initializing Then
    ResetDayList
    If Not IsValidDate Then
        ResetMonth
    End If
End If
End Sub

Function IsValidDate() As Boolean
With Me
    IsValidDate = IsDate(.cboMonth & "/" & .cboDay & "/" & .cboYear)
End With
End Function
Sub ResetDayList()
Dim i As Long
Dim StartDay As String

With Me.cboDay
    StartDay = .Text
    For i = 31 To 29 Step -1
        On Error Resume Next
        .RemoveItem i - 1
        On Error GoTo 0
    Next i
    For i = 29 To 31
        If IsDate(Me.cboMonth & "/" & i & "/" & Me.cboYear) Then
            .AddItem Format(i, "0")
        End If
    Next i
    On Error Resume Next
    .Text = StartDay
    If Err.Number <> 0 Then
        .SetFocus
        .ListIndex = 0
    End If
End With
End Sub

Sub ResetMonth()
Me.cboDay.ListIndex = 0
End Sub
2
répondu Doug Glancy 2012-08-17 21:32:40

Vous pouvez utiliser un masque de saisie sur la zone de texte, trop. Si vous définissez le masque ##/##/#### il sera toujours formaté au fur et à mesure que vous tapez et vous n'avez pas besoin de faire de codage autre que de vérifier si ce qui a été entré était une date vraie.

ce qui juste quelques lignes faciles

txtUserName.SetFocus
If IsDate(txtUserName.text) Then
    Debug.Print Format(CDate(txtUserName.text), "MM/DD/YYYY")
Else
    Debug.Print "Not a real date"
End If
2
répondu Brad 2012-09-05 18:46:16

moi aussi, d'une manière ou d'une autre de tombé sur le même dilemme, pourquoi diable VBA Excel ne dispose pas d'un Date Picker. Grâce à Sid, qui a fait un travail impressionnant pour créer quelque chose pour nous tous.

néanmoins, j'en suis arrivé à un point où j'ai besoin de créer le mien. Et je le poste ici depuis beaucoup de gens je suis sûr atterrit sur ce poste et en tirer profit.

ce que j'ai fait était très simple comme Sid sauf que je n'utilise pas de feuille de travail temporaire. Je pensais que le les calculs sont très simples et simples de sorte qu'il n'est pas nécessaire de le jeter ailleurs. Voici la dernière sortie du calendrier:

enter image description here

Comment le configurer:

  • Créer 42 Label contrôle et nomme le de façon séquentielle et rangé de gauche à droite, de haut en bas (cette étiquette contient des couleurs grises 25 jusqu'à gris 5 ci-dessus). Changer le nom de la Label contrôles Label_01,Label_02 et ainsi de suite. Placez les 42 étiquettes Tag propriété dts.
  • Créer plus 7 Label contrôle de l'en-tête (celui-ci contiendra Di,Lu,Tu...)
  • Créer plus de 2 Label de contrôle, un pour la ligne horizontale (hauteur de la valeur 1) et un pour le mois et année affichage. Nom de l' Label utilisé pour afficher le mois et l'année Label_MthYr
  • Insérer 2 Image contrôles, un pour contenir l'icône de gauche pour faire défiler les mois précédents et un pour faire défiler le mois prochain (je préfère simple gauche et flèche droite icône de tête). Nom Image_Left et Image_Right

la mise en page devrait être plus ou moins comme ceci (je laisse la créativité à quiconque l'utilisera).

enter image description here

Déclaration:

Nous avons besoin d'une variable déclarée au très haut pour tenir le mois en cours sélectionné.

Option Explicit
Private curMonth As Date

Procédure Privée et les Fonctions:

Private Function FirstCalSun(ref_date As Date) As Date
    '/* returns the first Calendar sunday */
    FirstCalSun = DateSerial(Year(ref_date), _
                  Month(ref_date), 1) - (Weekday(ref_date) - 1)
End Function

Private Sub Build_Calendar(first_sunday As Date)
    '/* This builds the calendar and adds formatting to it */
    Dim lDate As MSForms.Label
    Dim i As Integer, a_date As Date

    For i = 1 To 42
        a_date = first_sunday + (i - 1)
        Set lDate = Me.Controls("Label_" & Format(i, "00"))
        lDate.Caption = Day(a_date)
        If Month(a_date) <> Month(curMonth) Then
            lDate.ForeColor = &H80000011
        Else
            If Weekday(a_date) = 1 Then
                lDate.ForeColor = &HC0&
            Else
                lDate.ForeColor = &H80000012
            End If
        End If
    Next
End Sub

Private Sub select_label(msForm_C As MSForms.Control)
    '/* Capture the selected date */
    Dim i As Integer, sel_date As Date
    i = Split(msForm_C.Name, "_")(1) - 1
    sel_date = FirstCalSun(curMonth) + i

    '/* Transfer the date where you want it to go */
    MsgBox sel_date

End Sub

Les Événements De L'Image:

Private Sub Image_Left_Click()

    If Month(curMonth) = 1 Then
        curMonth = DateSerial(Year(curMonth) - 1, 12, 1)
    Else
        curMonth = DateSerial(Year(curMonth), Month(curMonth) - 1, 1)
    End If

    With Me
        .Label_MthYr.Caption = Format(curMonth, "mmmm, yyyy")
        Build_Calendar FirstCalSun(curMonth)
    End With

End Sub

Private Sub Image_Right_Click()

    If Month(curMonth) = 12 Then
        curMonth = DateSerial(Year(curMonth) + 1, 1, 1)
    Else
        curMonth = DateSerial(Year(curMonth), Month(curMonth) + 1, 1)
    End If

    With Me
        .Label_MthYr.Caption = Format(curMonth, "mmmm, yyyy")
        Build_Calendar FirstCalSun(curMonth)
    End With

End Sub

j'ai ajouté ceci pour faire croire que l'utilisateur clique sur l'étiquette et devrait être fait sur le Image_Right trop de contrôle.

Private Sub Image_Left_MouseDown(ByVal Button As Integer, ByVal Shift As Integer, _
                                 ByVal X As Single, ByVal Y As Single)
    Me.Image_Left.BorderStyle = fmBorderStyleSingle
End Sub

Private Sub Image_Left_MouseUp(ByVal Button As Integer, ByVal Shift As Integer, _
                               ByVal X As Single, ByVal Y As Single)
    Me.Image_Left.BorderStyle = fmBorderStyleNone
End Sub

Label Events:

Tout cela devrait être fait pour les 42 étiquettes (Label_01Lable_42)

Astuce: construisez les 10 premiers et utilisez find et replace pour le reste.

Private Sub Label_01_Click()
    select_label Me.Label_01
End Sub

ceci est pour le survol des dates et l'effet de clic.

Private Sub Label_01_MouseDown(ByVal Button As Integer, ByVal Shift As Integer, _
                               ByVal X As Single, ByVal Y As Single)
    Me.Label_01.BorderStyle = fmBorderStyleSingle
End Sub

Private Sub Label_01_MouseMove(ByVal Button As Integer, ByVal Shift As Integer, _
                               ByVal X As Single, ByVal Y As Single)
    Me.Label_01.BackColor = &H8000000B
End Sub

Private Sub Label_01_MouseUp(ByVal Button As Integer, ByVal Shift As Integer, _
                             ByVal X As Single, ByVal Y As Single)
    Me.Label_01.BorderStyle = fmBorderStyleNone
End Sub

Événements De L'Objet UserForm:

Private Sub UserForm_Initialize()
    '/* This is to initialize everything */
    With Me
        curMonth = DateSerial(Year(Date), Month(Date), 1)
        .Label_MthYr = Format(curMonth, "mmmm, yyyy")
        Build_Calendar FirstCalSun(curMonth)
    End With

End Sub

encore une fois, juste pour l'effet sur les dates.

Private Sub UserForm_MouseMove(ByVal Button As Integer, ByVal Shift As Integer, _
                               ByVal X As Single, ByVal Y As Single)

    With Me
        Dim ctl As MSForms.Control, lb As MSForms.Label

        For Each ctl In .Controls
            If ctl.Tag = "dts" Then
                Set lb = ctl: lb.BackColor = &H80000005
            End If
        Next
    End With

End Sub

Et c'est tout. C'est brut et vous pouvez ajouter votre propre twist.

Je l'utilise depuis un certain temps et je n'ai aucun problème (en termes de performance et de fonctionnalité).

Aucun Error Handling mais peut être facilement géré je suppose.

en Fait, sans les effets, le code est trop court.

Vous pouvez gérer vos dates d'aller dans le select_label procédure. HTH.

2
répondu L42 2017-07-15 05:13:32

Pour une solution rapide, j'ai l'habitude de faire comme ça.

Cette approche permettra à l'utilisateur de saisir la date dans le format qu'ils aiment dans la zone de texte, et enfin le format mm/jj/aaaa quand il est terminé. Donc, il est très flexible:

Private Sub TextBox1_Exit(ByVal Cancel As MSForms.ReturnBoolean)
    If TextBox1.Text <> "" Then
        If IsDate(TextBox1.Text) Then
            TextBox1.Text = Format(TextBox1.Text, "mm/dd/yyyy")
        Else
            MsgBox "Please enter a valid date!"
            Cancel = True
        End If
    End If
End Sub

cependant, je pense que ce que Sid a développé est une bien meilleure approche - un contrôle complet date picker.

1
répondu Pradeep Kumar 2012-08-17 23:28:24

bien que je sois d'accord avec ce qui est mentionné dans les réponses ci-dessous, suggérant qu'il s'agit d'une très mauvaise conception pour un formulaire D'utilisateur à moins que de nombreux contrôles d'erreurs ne soient inclus...

pour réaliser ce que vous devez faire, avec un minimum de modifications à votre code, il y a deux approches.

  1. Utiliser KeyUp () événement à la place de l'événement de Changement de la zone de texte. Voici un exemple:

    Private Sub TextBox2_KeyUp(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
    
        Dim TextStr As String
        TextStr = TextBox2.Text
    
        If KeyCode <> 8 Then ' i.e. not a backspace
    
            If (Len(TextStr) = 2 Or Len(TextStr) = 5) Then
                TextStr = TextStr & "/"
            End If
    
        End If
        TextBox2.Text = TextStr
    End Sub
    
  2. en Alternance, si vous avez besoin d'utiliser le Modifier() événement, utilisez le code suivant. Cela modifie le comportement de sorte que l'Utilisateur continue à entrer les nombres, comme

    12072003
    

alors que le résultat quand il tape apparaît comme

    12/07/2003

mais le caractère ' / ' n'apparaît qu'une fois le premier caractère du DD, c'est-à-dire 0 de 07, saisi. Pas idéal, mais sera toujours gérer backspaces.

    Private Sub TextBox1_Change()
        Dim TextStr As String

        TextStr = TextBox1.Text

        If (Len(TextStr) = 3 And Mid(TextStr, 3, 1) <> "/") Then
            TextStr = Left(TextStr, 2) & "/" & Right(TextStr, 1)
        ElseIf (Len(TextStr) = 6 And Mid(TextStr, 6, 1) <> "/") Then
            TextStr = Left(TextStr, 5) & "/" & Right(TextStr, 1)
        End If

        TextBox1.Text = TextStr
    End Sub
1
répondu hnk 2014-06-29 02:47:01
Private Sub txtBoxBDayHim_KeyPress(ByVal KeyAscii As MSForms.ReturnInteger)
If KeyAscii >= 48 And KeyAscii <= 57 Or KeyAscii = 8 Then 'only numbers and backspace
    If KeyAscii = 8 Then 'if backspace, ignores + "/"
    Else
        If txtBoxBDayHim.TextLength = 10 Then 'limit textbox to 10 characters
        KeyAscii = 0
        Else
            If txtBoxBDayHim.TextLength = 2 Or txtBoxBDayHim.TextLength = 5 Then 'adds / automatically
            txtBoxBDayHim.Text = txtBoxBDayHim.Text + "/"
            End If
        End If
    End If
Else
KeyAscii = 0
End If
End Sub

Cela fonctionne pour moi. :)

Votre code m'a beaucoup aidé. Merci!

je suis brésilien et mon anglais est pauvre, désolé pour l'erreur.

1
répondu Lucas 2016-02-03 22:58:34