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?
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:
- Vous n'avez pas à ne vous inquiétez pas si l'utilisateur entre des informations erronées
- Vous n'avez pas à vous inquiéter de l'utilisateur de coller dans la zone de texte
- Vous n'avez pas à vous inquiéter au sujet de l'écriture majeur de code
- GUI Attractive
- peut être facilement incorporé dans votre application
- 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
- Télécharger
Userform1.frm
etUserform1.frx
ici. - dans votre VBA, importez simplement
Userform1.frm
comme indiqué dans l'image ci-dessous.
importation du formulaire
RUNNING IT
Vous pouvez l'appeler de toute procédure. Par exemple,
Sub Sample()
UserForm1.Show
End Sub
SCREEN SHOTS IN ACTION
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.
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
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
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
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
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:
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 grises25
jusqu'à gris5
ci-dessus). Changer le nom de laLabel
contrôles Label_01,Label_02 et ainsi de suite. Placez les 42 étiquettesTag
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). NomImage_Left
etImage_Right
la mise en page devrait être plus ou moins comme ceci (je laisse la créativité à quiconque l'utilisera).
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_01
Lable_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.
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.
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.
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
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
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.