gõ 6 số ra ngày tháng năm trong textbox (1 người xem)

Liên hệ QC

Người dùng đang xem chủ đề này

NguyenthiH

Thành viên mới đăng ký
Tham gia
11/12/16
Bài viết
965
Được thích
175
Giới tính
Nữ
Chào các anh chị. Em có textbox ngày trong Userform, em muốn chỉ gõ 6 số và enter là ra ngày tháng năm được không ạ.
Ví dụ như em gõ:
310719 enter thì ra ngày 31/07/2019
030819 enter thì ra ngày 03/08/2019.
Mong các anh chị chỉ giáo ạ.
 
Sub ChuanNgay(ctl As Control)
Dim v As String
v = ctl.Text
Select Case Len(v)
Case 10 ' chuẩn rồi khỏi sửa
Exit Sub
Case 8
ctl.Text = Left(v, 2) & "/" & Mid(v, 3, 2) & "/" & Right(v, 4)
Case 6
ctl.Text = Left(v, 2) & "/" & Mid(v, 3, 2) & "/20" & Right(v, 2)
Case Else
ctl.Text = "Sai rồi bạn ơi"
End Select
End Sub

Trong mấy cái Sub event, ví dụ TextBox1.Exit, thêm dòng này
ChuanNgay TextBox1
 
Lần chỉnh sửa cuối:
Upvote 0
Nhớ không nhầm có người làm cho rồi.

 
Upvote 0
À,anh @VetMini ơi sao em thử gõ 300219 thì không báo lỗi anh ơi!
 
Upvote 0
Bạn chỉ hỏi cách đổi dạng thôi chứ đâu có hỏi cách xét mức độ xài được của nó đâu.
Muốn xét mức độ xài được thì phải thêm một hàm xét.
 
Upvote 0
Chào các anh chị. Em có textbox ngày trong Userform, em muốn chỉ gõ 6 số và enter là ra ngày tháng năm được không ạ.
Ví dụ như em gõ:
310719 enter thì ra ngày 31/07/2019
030819 enter thì ra ngày 03/08/2019.
Mong các anh chị chỉ giáo ạ.
Thử Code
Mã:
Sub Ngay_ddmmyy()
  Dim Ngay As String, tmp As String
  Ngay = TextBoxl.Text
  If Len(Ngay) = 6 Then
    If IsDate("20" & Mid(Ngay, 5, 2) & "/" & Mid(Ngay, 3, 2) & "/" & Mid(Ngay, 1, 2)) Then
      TextBoxl.Text = Mid(Ngay, 1, 2) & "/" & Mid(Ngay, 3, 2) & "/" & "20" & Mid(Ngay, 5, 2)
      Exit Sub
    End If
  End If
  MsgBox ("Du Lieu Ngay Thang Sai Bet !")
End Sub
 
Upvote 0
Thử Code
Mã:
Sub Ngay_ddmmyy()
  Dim Ngay As String, tmp As String
  Ngay = TextBoxl.Text
  If Len(Ngay) = 6 Then
    If IsDate("20" & Mid(Ngay, 5, 2) & "/" & Mid(Ngay, 3, 2) & "/" & Mid(Ngay, 1, 2)) Then
      TextBoxl.Text = Mid(Ngay, 1, 2) & "/" & Mid(Ngay, 3, 2) & "/" & "20" & Mid(Ngay, 5, 2)
      Exit Sub
    End If
  End If
  MsgBox ("Du Lieu Ngay Thang Sai Bet !")
End Sub
Lỡ tôi gõ 04/08/2019 ; toi sẽ được dịp vò đầu bứt tai "ngày của tôi sai chỗ nào?"
 
Upvote 0
Lỡ tôi gõ 04/08/2019 ; toi sẽ được dịp vò đầu bứt tai "ngày của tôi sai chỗ nào?"
Thêm hướng dẫn
Mã:
Sub Ngay_ddmmyy()
  Dim Ngay As String
  Ngay = TextBoxl.Text
  If Len(Ngay) = 6 Then
    If IsDate("20" & Mid(Ngay, 5, 2) & "/" & Mid(Ngay, 3, 2) & "/" & Mid(Ngay, 1, 2)) Then
      TextBoxl.Text = Mid(Ngay, 1, 2) & "/" & Mid(Ngay, 3, 2) & "/" & "20" & Mid(Ngay, 5, 2)
      Exit Sub
    End If
  End If
  TextBoxl.Text = ""
 Ngay= MsgBox ("Nhap Lai theo dang: ddmmyy", 0, "Du Lieu Ngay Thang Sai Bet !")
End Sub
 
Upvote 0
Thiệt ra khi thớt hỏi cái vụ 310719 --> 31/07/2019 vì không có kinh nghiệm về gõ dữ liệu (data entry) cho nên đã suy nghĩ quá đơn giản.
Sau phi gõ, Textbox bị đổi từ 310719 sang 31/07/2019. Nhưng nếu người gõ quay trở lại thì sao? Hiển nhiên là lúc ấy Textbox đang chứa 31/07/2019.
Vì vậy, hàm chuyển đổi phải có khả năng chấp nhận 310719, 31072019, và 31/07/2019 là 3 dạng tối thiểu. Nếu tử tế thì thêm dạng 31/07/19.

Người làm việc với giao diện người dùng (user interface) đáng lẽ nên nghĩ thêm về những phản ứng phụ trong nhu cầu của mình trước khi đưa chúng lên thành yêu cầu.
 
Upvote 0
Theo tôi đây chỉ là những trò nhí nhố. Người ta gõ 310719 thì code biến thành 31/07/2019. Nếu tôi gõ sai vì ngày lẽ ra là 21 thì tôi phải bôi đen toàn bộ và gõ lại tất cả từ đầu.
Việc gõ trong TextBox trên Form đâu có là việc làm mỗi ngày hàng nghìn lần đâu mà phải tiết kiệm từng ký tự.

Mà tại sao lại cứ phải đổi cứng nhắc thành dạng ngày/tháng/năm thế nhỉ. Có lẽ một hòn đảo, một mình ta chăng. Không làm việc nhóm, không có đối tác nước ngoài?

Nếu tôi là đối tác của chủ thớt thì tôi không làm việc được với tập tin của chủ thớt. Nơi tôi ở chuẩn thiết lập là yyyy-mm-dd. Nếu tôi nhập và code biến thành dd/mm/yyyy thì:

Giả sử trong TextBox1 đang có 31/07/2019. Nếu tôi muốn nhập xuống sheet thì
Mã:
Range("B3").Value = TextBox1.Value

Tôi sẽ có text 31/07/2019. Đây không là ngày tháng theo cách hiểu của Excel.

Nếu tôi có code khác
Mã:
Range("B3").Value = CDate(TextBox1.Value)

thì ở B3 tôi có ngày tháng chuẩn 2019-07-31.

Nhưng nếu trong TextBox1 tôi có 12/07/2019 thì dù dùng code nào tôi cũng có 2019-12-07. Tuy cả 2 đều là ngày tháng nhưng là ngày tháng sai. Phải là ngày trong tháng 7 mới là dụng ý của tôi.

Như vậy nếu dùng dạng cứng nhắc thì khi tôi có lúc này 31/07/2019 lúc khác có 12/07/2019, và cả 2 tôi đều nhập xuống sheet thì chỉ trong 1 cell có ngày tháng chính xác.
 
Upvote 0
Thiệt ra hồi thời chưa có máy tính PC, màn hình là dạng điển hình 80 ký tự x 24 dòng (hoàn toàn ký tự, không có graphic) thì chúng tôi thiết kế gõ nhập ngày dạng đại khái như DDMMYY. Do những yếu tố sau đây:
1. Lúc ấy, dân làm văn phòng là dân chuyên nghiệp gõ, hằng 100 từ/phút, không có loại ỏng ẹo 10 từ/phút như bây giờ.
2. Lúc ấy, người ta được huấn luyện nhập dữ liệu số theo dạng batch. Cuối ngày người ta gộp các chứng từ lại, và tuần tự nhập, cứ mỗi chứng từ là 1 phát sinh (transaction) và được gõ thành 1 dòng.
3. Gõ bằng cái bàn phím số. Và gõ theo đúng format được thiết kế.
Ví dụ nhập 100 đồng phát sinh thì người ta nhập:
100.111.222.310180<Return (hết dòng, qua dòng kế)>
4. Phần mềm sẽ dịch ra là số tiền 100, nợ tài khoản 111, có tài khoản 222, ngày 31/01/1980, và ghi vào CSDL.
Chú i: nếu tính bằng đô la thì con số 100 đô được nhập là 10000, tức là kèm 2 chữ số cho xu
Chú ii: những phát sinh có ghi chú thì hơi cực hơn 1 chút, nhưng chủ yếu vẫn là mỗi phát sinh thì nhập bằng 1 dòng
Chú iii: hồi xưa ngừoi ta chỉ trữ số năm bằng 2 chữ số, 1980 thì trữ là 80 (bạn có nhớ câu chuyện Y2K meltdown?)

Nhưng đấy là chuyện của thế kỷ 20, của thời đại mainframe.

Bây giờ là thời đại của máy tính con nối mạng, của dân kéo chuột và màn hình graphic, giao diện cửa sổ. Dữ liệu được nhập qua form và controls.
Và quan trọng hơn cả là kỹ năng nhập số bằng bàn phím số, mắt không rời chồng chứng từ (tức là mắt không nhìn màn hình) đã trở thành huyền thoại.

Cách thiết kế input ngày nay khác hoàn toàn. Mỗi công ty, mỗi môi trường có một cách nhìn dữ liệu ngày tháng năm, tuỳ theo đường lối riêng của họ.

Chú: với máy móc hiện đại hơn, người ta ngỡ rằng năng suất và hiệu quả của một chuyên viên nhập liệu sẽ cao hơn ngày xưa. Thực tế không như vậy. Tốc dộ nhập liệu ngày nay thấp hơn, và tỷ lệ sai nhiều hơn xưa.
(mỗi lần ôi thấy một bạn đăng bài lên với câu "làm thủ công chắc em chết quá" là tôi cười thầm trong bụng - mấy bạn này chưa biết "thủ công" là gì)
 
Upvote 0
Anh Hiếu ơi, trong code anh em muốn khi báo lỗi nhập sai ngày tháng năm thì TextBox1 được Focus.
Trong form của em có thêm TextBox2 nữa, em chọn TabIndex của TextBox1 là 1 và TexBox2 là 2, Em có chèn thêm code như sau:
Mã:
Sub Ngay_ddmmyy()
  Dim Ngay As String
  Ngay = TextBoxl.Text
  If Len(Ngay) = 6 Then
    If IsDate("20" & Mid(Ngay, 5, 2) & "/" & Mid(Ngay, 3, 2) & "/" & Mid(Ngay, 1, 2)) Then
      TextBoxl.Text = Mid(Ngay, 1, 2) & "/" & Mid(Ngay, 3, 2) & "/" & "20" & Mid(Ngay, 5, 2)
      Exit Sub
    End If
  End If
  TextBoxl.Text = ""
 Ngay= MsgBox ("Nhap Lai theo dang: ddmmyy", 0, "Du Lieu Ngay Thang Sai Bet !")
 TextBox1.SetFocus <-----chen them
End Sub
nhưng khi báo lỗi xong, nhấn Enter thì TextBox2 lại Focus.
 
Upvote 0
Sub GiDo(theTextbx As Control)
' xét ngày trong theTextBox và chỉnh dạng
Dim ngay As String
ngay = ChinhDDMMYYYY(theTextBox.Text)
If ChuanNgay(ngay) Then
theTextBox.Text = ngay
Else
MsgBox "báo lỗi gì đó"
theTextBox.SetFocus
End If
End Sub

Private Function ChinhDDMMYYYY(s As String) As String
' chỉnh 1 string từ dạng DDMMYY thành dạng DD/MM/YYYY
Select Case Len(s)
Case 10 ' hy vọng chuẩn rồi khỏi sửa
ChinhDDMMYYYY = s
Case 8 ' dạng ddmmyyyy
ChinhDDMMYYYY = Left(s, 2) & "/" & Mid(s, 3, 2) & "/" & Right(s, 4)
Case 6 ' dạng ddmmyy
ChinhDDMMYYYY = Left(s, 2) & "/" & Mid(s, 3, 2) & "/20" & Right(s, 2)
Case Else
ChinhDDMMYYYY = ""
End Select
End Function

Private Function ChuanNgay(s As String) As Boolean
Dim d as Variant, ng As Integer, th As Integer, nm As Integer
If s Like "[0-3][0-9]/[0-1][0-9]/20[0-9][0-9]" Then ' xét dạng dd/mm/yyyy
ng = CInt(Left(s, 2))
th = CInt(Mid(s, 4, 2))
nm = CInt(Right(s, 4))
' xét độ hợp lý của ngày
d = DateSerial(nm, th, ng)
' hàm dateserial có khả năng đôn ngày cho nên phải xem lại nó có đôn hay không
If Day(d) = ng And Month(d) = th And Year(d) = nm Then ChuanNgay = True
End If
End Function
 
Lần chỉnh sửa cuối:
Upvote 0
Dạ em cám ơn anh @VetMini nhiều, em sẽ Test thử ạ.
 
Upvote 0
Sao em bê nguyên code của anh @VetMini và sửa "thetextbox" thành "ngay1" theo tên textbox ngày của em, và thêm GiDo vào sub ngay1_AfteUpdate () thì lỗi tại GiDo anh @VetMini ơi.
 
Upvote 0
Bạn đã sửa thế nào mà không viết rõ lên đây?

Sub ngay1_AfteUpdate ()
' xét ngày trong ngay1 và chỉnh dạng
Dim ngay As String
ngay = ChinhDDMMYYYY(ngay1.Text)
If ChuanNgay(ngay) Then
ngay1.Text = ngay
Else
MsgBox "báo lỗi gì đó"
ngay1.SetFocus
End If
End Sub

???
 
Upvote 0
Cám ơn Thầy @batman1, em chỉnh theo Thầy thì không lỗi nữa, nhưng ý em khi có msgBox báo lỗi ->enter -> textbox ngay1 được focus, để gõ lại ạ.
Code của anh Hiếu, và anh Vetmini khi báo lỗi lại nhảy qua textbox khác.
 
Upvote 0
Sao em bê nguyên code của anh @VetMini và sửa "thetextbox" thành "ngay1" theo tên textbox ngày của em, và thêm GiDo vào sub ngay1_AfteUpdate () thì lỗi tại GiDo anh @VetMini ơi.
Sub GiDo được viết theo kiểu chẳng cần phải sửa chỗ nào cả
(ngoại trừ lúc đầu có 1 chỗ tôi gõ nhầm theTextBox thành meTextBox, nhưng sau đó tôi đã chỉnh lại)
Bạn chỉ cần nạp tên cái TextBox làm tham cbo nó thôi.

Sub ngay1_AfterUpdate()
GiDo ngay1
' nếu có vài textbox thì thêm:
GiDo ngay2
GiDo ngay3
End Sub

Chú: xin lỗi, tôi mới nhìn ra cái tham tôi gõ thiếu ký tự 'o', đáng lẽ phải là theTextBox thay vì theTextBx
Sub GiDo(theTextbx As Control)
cần chỉnh thành
Sub GiDo(theTextBox As Control)
 
Upvote 0
Xin các anh chỉnh code để khi hiện msgbox lỗi do gõ ngày sai thì textbox ngay1 được focus ạ.
 

File đính kèm

Upvote 0
Cám ơn Thầy @batman1, em chỉnh theo Thầy thì không lỗi nữa, nhưng ý em khi có msgBox báo lỗi ->enter -> textbox ngay1 được focus, để gõ lại ạ.
Code của anh Hiếu, và anh Vetmini khi báo lỗi lại nhảy qua textbox khác.
Trong tất cả các bài mà người khác giúp bạn đã có rất nhiều lần người ta đã làm cái SetFocus này theo ý bạn. Ít ra là tôi đã từng đưa ra. Nhưng bạn không chịu nhớ, không chịu ghi lại mà mỗi lần cần đến lại nhờ người khác giúp. Vì bạn có bao giờ tự viết đâu, toàn người khác nhọc công. Đã không chịu học để tự làm thì ít ra phải ghi lại những cái người ta làm hộ. Ai lại nhờđi nhờ lại cái người ta đã giúp mình?

Bạn hãy rà soát lại tất cả các tập tin cũ của mình. Có đúng là có rất nhiều tập tin có kiểu SetFocus cho chính TextBox hiện hành không? Tôi nhớ thì chả lý gì bạn lại không nhớ các tập tin của mình. Thậm chí nếu không ghi lại và không nhớ rõ cách làm thì chỉ cần mở lại các tập tin cũ. Trong 99,99% tập tin bạn có kiểu SetFocus cho TextBox hiện hành. Tôi biết vì đây là món "tủ" của bạn. Nhưng tìm lại mất công đúng không? Thà người khác mất công chứ bạn không muốn mất công trong chính vấn đề của mình.

Vài viên "thuốc đắng", hi vọng chữa khỏi bệnh.

Gợi ý: Cho code vào ngay1_KeyDown thay cho ngay1_AfteUpdate. Kiểm tra nếu thấy KeyCode = 13 thì làm việc. Nếu có lỗi thì KeyCode = 0 rồi SetFocus.
 
Lần chỉnh sửa cuối:
Upvote 0
Em chỉ làm được nếu có Msgbox thì enter và ngay1 focus, nhưng không có báo lỗi thì textbox sp1 chưa focus ạ, mong Thầy chỉ giáo. Em "Ngu lâu khó đào tạo" lắm Thầy ơi.
Mã:
Private Sub ngay1_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
  If KeyCode = 13 Then
    GiDo ngay1
    KeyCode = 0
End If
End Sub
 
Upvote 0
Em chỉ làm được nếu có Msgbox thì enter và ngay1 focus, nhưng không có báo lỗi thì textbox sp1 chưa focus ạ, mong Thầy chỉ giáo. Em "Ngu lâu khó đào tạo" lắm Thầy ơi.
Mã:
Private Sub ngay1_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
  If KeyCode = 13 Then
    GiDo ngay1
    KeyCode = 0
End If
End Sub
[
Kiểm tra nếu thấy KeyCode = 13 thì làm việc. Nếu có lỗi thì KeyCode = 0 rồi SetFocus.

Làm việc ám chỉ toàn bộ cái tôi ghi trong AfteUpdate chứ không phải gọi GiDo. Cái tôi hỏi bạn, tức cái ghi trong AfteUpdate, làm gì có gọi GiDo??? Tôi có dùng GiDo bao giờ đâu? Tùy trả lời ai mà dùng chính xác nhé.

Nếu có lỗi thì KeyCode = 0 có nghĩa là chỉ sau hoặc trước MsgBox mới có KeyCode = 0.

Nếu cố tình dùng GiDo thì chỉ cần suy nghĩ lôgíc. Tôi không nói là cứ nhấn Enter là phải KeyCode = 0. Enter chỉ là đk thực hiện code. Còn khi thực hiện code mà phát hiện ra lỗi thì mới KeyCode = 0.

Nói ngắn gọn thì thiết lập KeyCode = 0 khi và chỉ khi muốn giữ Focus ở lại TextBox hiện hành.

Tôi đã ghi rất chính xác. Chỉ cần suy nghĩ lôgíc.
 
Lần chỉnh sửa cuối:
Upvote 0
Em vẫn không hiểu ý Thầy.
Mò hoài không làm được. Không hiểu lo6gic làm sao.
Thầy chỉ em với.
Bài đã được tự động gộp:

Thì trong Sub ngay1_AfterUpdate () thì chạy GiDo ngay1 mà Thầy.
 
Upvote 0
Giải quyết bài toán Setfocus, em sửa cái hàm GiDo của anh Vetmini lại chút rồi dùng ở sự kiện On Exit.

- Sửa Sub thành Function và trả về giá trị True/False

Mã:
Function GiDo(theTextbox As Control) As Boolean
' xét ngày trong theTextBox và ch?nh d?ng
    Dim ngay As String
    ngay = ChinhDDMMYYYY(theTextbox.Text)
    If ChuanNgay(ngay) Then
        theTextbox.Text = ngay
        GiDo = True
    Else
        MsgBox "báo l?i gì dó"
        GiDo = False
        'theTextbox.SetFocus
    End If
End Function

- Gọi trong event Exit:

Mã:
Private Sub ngay1_Exit(ByVal Cancel As MSForms.ReturnBoolean)
    If GiDo(ngay1) = False Then
        Cancel = True
    End If
End Sub

Em test lại xem.
 
Upvote 0
Em vẫn không hiểu ý Thầy.
Mò hoài không làm được. Không hiểu lo6gic làm sao.
Thầy chỉ em với.
Bài đã được tự động gộp:

Thì trong Sub ngay1_AfterUpdate () thì chạy GiDo ngay1 mà Thầy.
Chạy code lấy từ GiDo và chạy - gọi GiDo là 2 vấn đề khác nhau
Mã:
Sub ngay1_AfteUpdate ()
' xét ngày trong ngay1 và chỉnh dạng
Dim ngay As String
ngay = ChinhDDMMYYYY(ngay1.Text)
If ChuanNgay(ngay) Then
ngay1.Text = ngay
Else
MsgBox "báo lỗi gì đó"
ngay1.SetFocus
End If
End Sub

Bạn nhìn code trên có chỗ nào có GiDo không?

Chuyển sang KeyDown + KeyCode = 0 thì là

Mã:
Private Sub ngay1_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
Dim ngay As String
    If KeyCode = 13 Then
        ngay = ChinhDDMMYYYY(ngay1.Text)
        If ChuanNgay(ngay) Then
            ngay1.Text = ngay
        Else
            MsgBox "báo lỗi gì đó"
            KeyCode = 0
        End If
    End If
End Sub

Thực ra tôi viết quá đà. Chỉ cần KeyCode = 0 mà không SetFocus gì cả. KeyCode = 0 tức "rút lại", xí xóa, coi như phím "nọ" đã không được nhấn, tức trở lại trạng thái trước khi nhấn phím "nọ". Tức focus đang ở TextBox hiện hành thì nó vẫn ở TextBox hiện hành. Thế thôi. Cần gì SetFocus nữa.
 
Upvote 0
Dùng Keycode = 0 cũng được em phải suy nghĩ logic như anh batman1 đã nói rồi.

Mã:
Private Sub ngay1_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
    If KeyCode = 13 Then
        If GiDo(ngay1) = False Then
            KeyCode = 0
        End If
    End If
End Sub

(Viết được vài câu thì anh batman1 đã trả lời rồi nên thôi... :) )
 
Lần chỉnh sửa cuối:
Upvote 0
Cám ơn Thầy @batman1 nhiều ạ, thông cảm em "ngu" quá.
 
Upvote 0
Bạn thử đoạn code của tôi xem có giúp gì được bạn không

Cách gõ:
- Nếu gõ ký tự đầu mà lớn hơn 3 thì sẽ chuyển sang gõ tháng
- Nếu gõ ký tự đầu mà bằng 3 thì chỉ có thể gõ thêm 0 đến 1
- Nếu gõ 3 và x số lớn hơn 1 gõ 2 lần thì sẽ thành 03/0x/20
- Tương tự gõ tháng cũng ràng buộc theo giới hạn tháng
- Nếu gõ xong tháng thì sẽ tự động điền thêm 2 ký tự YY trong YYYY, nếu muốn điền số khác thì gõ Backspace gõ lại tháng, rồi tiếp tục gõ đủ năm YYYY. (Dự phòng cho trường hợp gõ tháng bị sai)
- Nếu gõ Delete thì xóa tất cả ký tự.

Code không cần đến MsgBox để thông báo, vì code đã được tối ưu.

PHP:
Option Explicit

Private Const Separetor = "/"
Private DelFirstY As Boolean, k3%, YY$, Y%
'Private Function Separetor()'
'  Separetor = Mid$(Me.Label1.Value, 5, 1)'
'End Function'

Private Sub SetFontFm(TextBox As MSForms.TextBox, Optional b As Boolean)
  With TextBox
    .Font.Strikethrough = Not b
    .ForeColor = IIf(b, vbBlue, vbRed)
  End With
End Sub
Private Function IsDateFM(Text$) As Boolean
  Dim T$(), I%
  IsDateFM = True
  Select Case Len(Text)
    Case 10: IsDateFM = IsDate(Text)
    Case 4 To 6
      T = Split(Text, Separetor)
      If UBound(T) < 1 Then Exit Function
      I = CInt(T(1))
      If I = 0 Then Exit Function
      If CInt(T(0)) = 30 Then
        IsDateFM = Not (I = 2)
      ElseIf CInt(T(0)) = 31 Then
        IsDateFM = Not (I = 2 Or I = 4 Or I = 6 Or I = 9 Or I = 11)
      End If
  End Select
End Function
Private Sub ngay1_KeyUp(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
  Select Case Len(ngay1.Value)
    Case 0: SetFontFm ngay1, True: DelFirstY = False: k3 = 0
    Case 10: SetFontFm ngay1, IsDateFM(ngay1.Value)
  End Select
End Sub
Private Sub ngay1_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
  If KeyCode = 46 Then ngay1.Value = "": SetFontFm ngay1, True: k3 = 0: GoTo Ends
  Dim L%, T$, Text$, Tmp$, I%, M%, F$
  L = Len(ngay1.Value): T = ngay1.Value
  Select Case KeyCode
    Case 13
    Case 48 To 57
      Tmp = ChrW(KeyCode): I = CInt(Tmp)
      If L >= 10 Then KeyCode = 0: GoTo Ends
      Select Case L
        Case 0: F = IIf(I > 3, 0, "") & Tmp & IIf(I > 3, Separetor, ""): DelFirstY = False
        Case 1
          If CInt(T) < 3 Then
            F = T & Tmp & Separetor
          ElseIf CInt(T) = 3 Then
            k3 = k3 + 1
            F = T & IIf(I < 2, Tmp & Separetor, "")
            If k3 > 1 Then k3 = 0: F = 0 & T & Separetor & 0 & Tmp & YY
          End If
        Case 3: F = T & IIf(I > 1, 0, "") & Tmp & IIf(I > 1, YY, "")
        Case 4
          M = CInt(Right$(T, 1))
          F = T & IIf((M = 0 And I > 0) Or (M = 1 And I <= 2), Tmp & IIf(DelFirstY, Separetor, YY), "")
        Case 6: If I <= Y And I >= 1 Then F = T & Tmp
        Case 7: If I <= 2  Or I >= 8 Then F = T & Tmp
        Case Else
          F = T & Tmp
      End Select
      KeyCode = 0
    Case 8
      k3 = 0
      If L = 8 And Not DelFirstY Then
        F = Left$(T, L - 4): KeyCode = 0: DelFirstY = True
      ElseIf Right$(T, 1) = Separetor Then
        F = Left$(T, L - 2): KeyCode = 0
      End If
    Case Else: KeyCode = 0
  End Select

Ends:
  If F <> vbNullString Then
    Dim b As Boolean: b = IsDateFM(F)
    If b Then ngay1.Value = F
    SetFontFm ngay1, b
  End If
End Sub
' Xóa nêu Di Chuyen Con tro ve truoc'
Private Sub ngay1_MouseUp(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
  Dim L%, Lst%
  Lst = ngay1.SelStart: L = Len(ngay1.Value)
  If Lst < L Then ngay1.Value = "": k3 = 0: DelFirstY = False
End Sub
' Khoi Tao Form
Private Sub UserForm_Initialize()
  YY = Separetor & Left$(CStr(Year(Now)), 2)
  Y = CInt(Left$(CStr(Year(Now)), 1))
End Sub
 
Lần chỉnh sửa cuối:
Upvote 0
Em có thử code của anh @HeSanbi thì thấy cũng hay. Nhưng vì chưa có code kiểm tra tháng 2 và tháng chẵn lẻ nên còn lỗi.Ví dụ gõ 290219hay 310619.vv..
 
Upvote 0
Từ đầu tôi đã cố gắng dẫn bạn về cái nguyên tắc code phải là 1 hàm và nhận TexBox vào như một tham.
Lý do:
Một Forrm rất có thể có nhiều ô để gõ ngày tháng. Chả nhẽ mỗi ô phải lặp lại một đống code để dùng riêng cho nó.
 
Upvote 0
Em có thử code của anh @HeSanbi thì thấy cũng hay. Nhưng vì chưa có code kiểm tra tháng 2 và tháng chẵn lẻ nên còn lỗi.Ví dụ gõ 290219hay 310619.vv..
Tôi chỉ giúp bạn loại bỏ lỗi và giữ focus khi cần thiết thôi. Còn chuyện gõ 6 ký tự thì biến thành ngày tháng thì quan điểm của mình tôi đã trình bày. Một khi tôi đã cho là nhí nhố thì tôi sẽ không tham gia viết code.
Vậy tôi dừng ở đây.
 
Upvote 0
Bạn thử lại:

PHP:
Option Explicit

Private Const Separetor = "/"
Private DelFirstY As Boolean, k3%, YY$, Y%
'Private Function Separetor()'
'  Separetor = Mid$(Me.Label1.Value, 5, 1)'
'End Function'

Private Sub SetFontFm(TextBox As MSForms.TextBox, Optional b As Boolean)
  With TextBox
    .Font.Strikethrough = Not b
    .ForeColor = IIf(b, vbBlue, vbRed)
  End With
End Sub
Private Function IsDateFM(Text$) As Boolean
  Dim T$(), I%
  IsDateFM = True
  Select Case Len(Text)
    Case 10: IsDateFM = IsDate(Text)
    Case 4 To 6
      T = Split(Text, Separetor)
      If UBound(T) < 1 Then Exit Function
      I = CInt(T(1))
      If I = 0 Then Exit Function
      If CInt(T(0)) = 30 Then
        IsDateFM = Not (I = 2)
      ElseIf CInt(T(0)) = 31 Then
        IsDateFM = Not (I = 2 Or I = 4 Or I = 6 Or I = 9 Or I = 11)
      End If
  End Select
End Function
Private Sub ngay1_KeyUp(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
  Select Case Len(ngay1.Value)
    Case 0: SetFontFm ngay1, True: DelFirstY = False: k3 = 0
    Case 10: SetFontFm ngay1, IsDateFM(ngay1.Value)
  End Select
End Sub
Private Sub ngay1_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
  If KeyCode = 46 Then ngay1.Value = "": SetFontFm ngay1, True: k3 = 0: GoTo Ends
  Dim L%, T$, Text$, Tmp$, I%, M%, F$
  L = Len(ngay1.Value): T = ngay1.Value
  Select Case KeyCode
    Case 13
    Case 48 To 57
      Tmp = ChrW(KeyCode): I = CInt(Tmp)
      If L >= 10 Then KeyCode = 0: GoTo Ends
      Select Case L
        Case 0: F = IIf(I > 3, 0, "") & Tmp & IIf(I > 3, Separetor, ""): DelFirstY = False
        Case 1
          If CInt(T) < 3 Then
            F = T & Tmp & Separetor
          ElseIf CInt(T) = 3 Then
            k3 = k3 + 1
            F = T & IIf(I < 2, Tmp & Separetor, "")
            If k3 > 1 Then k3 = 0: F = 0 & T & Separetor & 0 & Tmp & YY
          End If
        Case 3: F = T & IIf(I > 1, 0, "") & Tmp & IIf(I > 1, YY, "")
        Case 4
          M = CInt(Right$(T, 1))
          F = T & IIf((M = 0 And I > 0) Or (M = 1 And I <= 2), Tmp & IIf(DelFirstY, Separetor, YY), "")
        Case 6: If I <= Y And I >= 1 Then F = T & Tmp
        Case 7: If I <= 2 Or I >= 8 Then F = T & Tmp
        Case Else
          F = T & Tmp
      End Select
      KeyCode = 0
    Case 8
      k3 = 0
      If L = 8 And Not DelFirstY Then
        F = Left$(T, L - 4): KeyCode = 0: DelFirstY = True
      ElseIf Right$(T, 1) = Separetor Then
        F = Left$(T, L - 2): KeyCode = 0
      End If
    Case Else: KeyCode = 0
  End Select

Ends:
  If F <> vbNullString Then
    Dim b As Boolean: b = IsDateFM(F)
    If b Then ngay1.Value = F
    SetFontFm ngay1, b
  End If
End Sub
' Xóa nêu Di Chuyen Con tro ve truoc'
Private Sub ngay1_MouseUp(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
  Dim L%, Lst%
  Lst = ngay1.SelStart: L = Len(ngay1.Value)
  If Lst < L Then ngay1.Value = "": k3 = 0: DelFirstY = False
End Sub
' Khoi Tao Form
Private Sub UserForm_Initialize()
  YY = Separetor & Left$(CStr(Year(Now)), 2)
  Y = CInt(Left$(CStr(Year(Now)), 1))
End Sub
 
Lần chỉnh sửa cuối:
Upvote 0
Ở bài #15 tôi dùng hàm DateSerial vì nó tiện lợi.
Trong trường hợp không muốn dùng hàm này (ví dụ ngôn ngữ tổng quát) thì cái thuật toán xét xem d,m,y có phải là ngày tháng hay không là một thuật toán căn bản, vỡ lòng của lập trình. Nó gồm một hàm tính xem tháng ấy có bao nhiêu ngày, và xét xem ngày có nằm trong khoảng ấy.

Mã:
Function NumOfDaysInMonth(m As Integer, y As Integer) As Integer
' hàm tính số ngày tối đa trong tháng
' nếu tháng năm ngoài giới hạn 1-12 thì nó trả về 0
Select Case m
  Case 1, 3, 5, 7, 8, 10, 12
    NumOfDaysInMonth = 31
  Case 4, 6, 9, 11
    NumOfDaysInMonth = 30
  Case 2 ' tháng 2 hơi rắc rối
    If y Mod 4 Then
      NumOfDaysInMonth = 28 ' không phải năm nhuần
    Else If y Mod 100 = 0 And y Mod 400 <> 0 Then
      NumOfDaysInMonth = 28 ' năm thế kỷ không phải năm nhuần, trừ năm 4 thế kỷ
    Else
      NumOfDaysInMonth = 29
    End If
  Case Else
    NumOfDaysInMonth = 0 ' không phải đúng tháng
End Select
End Function

Function IsValidDMY(d As Integer, m As Integer, y As Integer) As Boolean
If d < 1 Then Exit Function
If d > NumOfDaysInMonth(m, y) Then Exit Function
NumOfDaysInMonth = True
End Function
 
Upvote 0
Em có thử code của anh @HeSanbi thì thấy cũng hay. Nhưng vì chưa có code kiểm tra tháng 2 và tháng chẵn lẻ nên còn lỗi.Ví dụ gõ 290219hay 310619.vv..

Chút góp ý cho em là nên vẽ ra giấy cái Form xử lý (có các control) và dự kiến tất cả các trường hợp thao tác, bẫy lỗi có thể phát sinh khi người dùng nhập liệu (phải giả thiết là người nhập không biết gì về vi tính chỉ nhìn theo giao diện, ghi chú, hướng dẫn mà thao tác thôi). Sau đó em mới đưa các yêu cầu, điều kiện xử lý đầy đủ hơn và người viết code cho em có cái nhìn tổng thể để đưa vào code xử lý toàn diện, thay vì cứ lắc nhắc sửa code, xử lý từng cái yêu cầu phát sinh.
Ví dụ: đối với textbox [Ngày].
Nếu sau này đó em có cái Form với 2 textbox [Từ Ngày] , [Đến Ngày] và em lại muốn bẫy lỗi: sau khi nhập ngày, phải kiểm tra thêm tính hợp lệ của [Từ Ngày] phải <= [Đến Ngày] --> Khi đó ngoài cái bộ code chuyển đổi ngày tháng bên trên còn phải thêm vô code bẫy lỗi mới này nữa và lại sửa code tiếp.
Túm lại: nên lường trước các yêu cầu, điều kiện có thể có rồi đưa lên một lần để tìm kiếm giải pháp tổng thể hơn.
 
Upvote 0
Em đang muốn chuyển cho giống file Access mà anh làm cho em đó mà, tại file Access của anh em thấy hơi trục trặc trong lúc gõ tìm tên phụ liệu đó anh. Nếu được anh có thể giúp em nhập liệu trên Form Excel mà lấy và nạp dữ liệu vào Access.
 
Upvote 0
Em đang muốn chuyển cho giống file Access mà anh làm cho em đó mà, tại file Access của anh em thấy hơi trục trặc trong lúc gõ tìm tên phụ liệu đó anh. Nếu được anh có thể giúp em nhập liệu trên Form Excel mà lấy và nạp dữ liệu vào Access.

:) Userform Excel và xử lý code kiết bên Excel anh không rành lắm em à. Lâu lâu lọt chọt ý kiến ý cò vô vài cái đơn giản thôi em à.
 
Lần chỉnh sửa cuối:
Upvote 0
Em đang muốn chuyển cho giống file Access mà anh làm cho em đó mà, tại file Access của anh em thấy hơi trục trặc trong lúc gõ tìm tên phụ liệu đó anh. Nếu được anh có thể giúp em nhập liệu trên Form Excel mà lấy và nạp dữ liệu vào Access.
Cái vụ ngày tháng này khó thì không khó, dễ thì không dễ, nếu bạn làm chương trình, thì theo mình nghĩ chỉ có cách bắt người sài nhập ngày tháng năm theo ý đồ của bạn. Vì trong thực tế thì sẽ phát sinh nhiều trường hơp lắm...
 
Upvote 0

Bài viết mới nhất

Back
Top Bottom