Chuyên đề giải đáp những thắc mắc về code VBA

Liên hệ QC

maytinhvp01

Thành viên thường trực
Tham gia
27/7/13
Bài viết
390
Được thích
179
Mình muốn nhờ giải thich câu lệnh " If Ran.Cells(d, c) > max Then max = Ran.Cells(d, c) "
trong ví du:
Public Function LonNhat(Ran As Range)
Dim max As Double, v As Integer, d As Integer, c As Integer
max = Ran.Cells(1, 1)
For d = 1 To Ran.Rows.Count
For c = 1 To Ran.Columns.Count
If Ran.Cells(d, c) > max Then max = Ran.Cells(d, c)
Next c
Next d
v = Tim(max, Ran)
LonNhat = max
End Function
-------------------------------------------------------
[INFO1]Thông báo:
Vì topic này:
http://www.giaiphapexcel.com/forum/...ải-thích-các-code-đề-nghị-các-bạn-gửi-vào-đây
đã quá dài nên BQT đóng lại.
Nay tôi mở topic mới với cùng chủ đề: GIẢI THÍCH NHỮNG THẮC MẮC VỀ CODE
Các bạn nếu có nhu cầu giải thích code, vui lòng post tại đây nhé
NDU96081631

[/INFO1]
 
Chỉnh sửa lần cuối bởi điều hành viên:
Bạn thử:
PHP:
arr = Array("aaa", "bbb", "ccc", "...")
    For i = 1 To Sheets.Count
        '------------------------
    Next i

Hoặc:
PHP:
        For Each i In Array("aaa", "bbb", "ccc", "...")
            '----------------
        Next
Câu trả lời của bạn chỉ giải quyết vấn đề bằng cách khác, chứ không trực tiếp theo chiều hướng người hỏi.

để các Sheet trong Array được không? và code sửa như thế nào
For Each Sh In Array(Sheets("aaa"), Sheets("bbb"), ...)
...
Next Sh
 
Upvote 0
Em mới tập tành VBA nên không biết xử lý vấn đề này sao. Các anh, chị biết xử lý giúp e nha. E nghiên cứu mãi mà không được. Các anh, chị chỉnh sửa dùm e nha.
PHP:
Private Sub UserForm_Activate()
Me.Caption = "KE HOACH CONG VIEC DEN NGAY " & Format(Now(), "dd/mm/yyyy")
Sheets("Weekend Plan").Select
Dim AsOFDate, AsOfWeek As String, MaxARRow, MaxARColumn, ListQuaHanRow, ListDenHanRow As Integer
AsOFDate = Format(Now(), "mm/DD/yyyy")      'AsOFDate = Format(Now(), "dd/mm/yyyy") '
AsOfWeek = Format(Now() + 7, "mm/DD/yyyy")  'AsOfWeek = Format(Now() + 7, "dd/mm/yyyy") '
MaxARRow = Range("MaxARRow")
MaxARColumn = Range("MaxARColumn")
ListQuaHanRow = 0:                              ListDenHanRow = 0
Me.ListQuaHan.Clear:                            Me.ListDenHan.Clear
'Loc Phát Sinh Quá Han  '
Me.MultiPage1.Value = 0
For i = 2 To MaxARRow
    If Format(Cells(i, 5), "mm/DD/yyyy") < AsOFDate Then
        Me.ListQuaHan.AddItem (Cells(i, 1))
        Me.ListQuaHan.List(ListQuaHanRow, 1) = Cells(i, 2)
        Me.ListQuaHan.List(ListQuaHanRow, 2) = Cells(i, 3)
        Me.ListQuaHan.List(ListQuaHanRow, 3) = Format(Cells(i, 4), "#,###,###")
        Me.ListQuaHan.List(ListQuaHanRow, 4) = Cells(i, 5)
        Me.ListQuaHan.List(ListQuaHanRow, 5) = Cells(i, 6)
        ListQuaHanRow = ListQuaHanRow + 1
    End If
Next i
'Loc Phát Sinh Dén Han: '
Me.MultiPage1.Value = 1
For j = 2 To MaxARRow
    If Format(Cells(j, 5), "mm/DD/yyyy") >= AsOFDate And Format(Cells(j, 5), "mm/DD/yyyy") <= AsOfWeek Then '** '
        Me.ListDenHan.AddItem (Cells(j, 1))
        Me.ListDenHan.List(ListDenHanRow, 1) = Cells(j, 2)
        Me.ListDenHan.List(ListDenHanRow, 2) = Cells(j, 3)
        Me.ListDenHan.List(ListDenHanRow, 3) = Format(Cells(j, 4), "#,###,###")
        Me.ListDenHan.List(ListDenHanRow, 4) = Cells(j, 5)
        Me.ListDenHan.List(ListDenHanRow, 5) = Cells(j, 6)
        ListDenHanRow = ListDenHanRow + 1
    End If
Next j
End Sub
 
Upvote 0
Em mới tập tành VBA nên không biết xử lý vấn đề này sao. Các anh, chị biết xử lý giúp e nha. E nghiên cứu mãi mà không được. Các anh, chị chỉnh sửa dùm e nha. Cám ơn các anh, chị nhiều.
Sai vì trong UserForm_Activate bạn so sánh chuỗi mà chuỗi lại không chuẩn.
Lấy vd.
Mã:
For i = 2 To MaxARRow
    If Format(Cells(i, 5), "dd/mm/yyyy") < AsOFDate Then
'    ...
    End If
Next i

Với i = 38 thì Cells(i, 5) là ngày 1 tháng 11 năm 2019. AsOFDate là 6 tháng 10 năm 2019 (ta chạy code ngày hôm nay)
Format(Cells(i, 5), "dd/mm/yyyy") = "01/11/2019"
AsOFDate = "06/10/2019".

Qui tắc so sánh chuỗi cùng chiều dài:
So sánh ký tự 1. Nếu không bằng nhau thì kết thúc và chuỗi có ký tự nhỏ hơn thì nhỏ hơn. Nếu bằng nhau thì so sánh ký tự 2. Tương tự nếu không bằng nhau thì kết thúc và chuỗi có ký tự nhỏ hơn thì nhỏ hơn. Nếu bằng nhau thì so sánh ký tự 3 v...v Nếu tất cả các ký tự bằng nhau thì 2 chuỗi bằng nhau.

Với qui tắc trên thì khi so sánh chuỗi "01/11/2019" và "06/10/2019" thì ở ký tự 2 ta có 1 < 6, vậy chuỗi "01/11/2019" < chuỗi "06/10/2019". Tức điều kiện cho IF thỏa và dòng 38 (STT = 37) được thêm vào ListBox. Tương tự với STT = 38-41, 67-71.

Cách khắc phục:
1. So sánh số.
Ngày tháng trong Excel là số nên so sánh số thôi. Tại sao phải biến thành chuỗi rồi so sánh chuỗi?
Mã:
Private Sub UserForm_Activate()
...
Dim AsOFDate As Long, AsOfWeek As Long, MaxARRow As Long, MaxARColumn As Long, ListQuaHanRow As Long, ListDenHanRow As Long
AsOFDate = Date
AsOfWeek = Date + 7
'    ...
For i = 2 To MaxARRow
    If Cells(i, 5) < AsOFDate Then
'    ...
    End If
Next i
...
For j = 2 To MaxARRow
    If Cells(j, 5) >= AsOFDate And Cells(j, 5) <= AsOfWeek Then
'    ...
    End If
Next j
End Sub

2. So sánh chuỗi (không khuyến cáo). Nếu thế thì dùng dạng "yyy/mm/dd". Dùng dạng này thì đúng.
Với vd. ở trên thì:
Format(Cells(i, 5), "dd/mm/yyyy") = "2019/11/01"
AsOFDate = "2019/10/06".
Và khi so sánh thì có "2019/11/01" > "2019/10/06" (so sánh kết thúc ở ký tự 7: 1 > 0)
Do vậy điều kiện không thỏa và dòng 38 (STT = 37) không được thêm vào ListBox
Mã:
Private Sub UserForm_Activate()
'    ...
Dim AsOFDate As String, AsOfWeek As String, MaxARRow As Long, MaxARColumn As Long, ListQuaHanRow As Long, ListDenHanRow As Long
AsOFDate = Format(Now(), "yyyy/mm/dd")
AsOfWeek = Format(Now() + 7, "yyyy/mm/dd")
'    ...
For i = 2 To MaxARRow
    If Format(Cells(i, 5), "yyyy/mm/dd") < AsOFDate Then
'    ...
    End If
Next i
...

For j = 2 To MaxARRow
    If Format(Cells(j, 5), "yyyy/mm/dd") >= AsOFDate And Format(Cells(j, 5), "yyyy/mm/dd") <= AsOfWeek Then
'    ...
    End If
Next j
End Sub
 
Upvote 0
PHP:
Private Sub UserForm_Activate()
Me.Caption = "KE HOACH CONG VIEC DEN NGAY " & Format(Now(), "dd/mm/yyyy")
Sheets("Weekend Plan").Select
Dim AsOFDate, AsOfWeek As String, MaxARRow, MaxARColumn, ListQuaHanRow, ListDenHanRow As Integer
AsOFDate = Format(Now(), "mm/DD/yyyy")      'AsOFDate = Format(Now(), "dd/mm/yyyy") '
AsOfWeek = Format(Now() + 7, "mm/DD/yyyy")  'AsOfWeek = Format(Now() + 7, "dd/mm/yyyy") '
MaxARRow = Range("MaxARRow")
MaxARColumn = Range("MaxARColumn")
ListQuaHanRow = 0:                              ListDenHanRow = 0
Me.ListQuaHan.Clear:                            Me.ListDenHan.Clear
'Loc Phát Sinh Quá Han  '
Me.MultiPage1.Value = 0
For i = 2 To MaxARRow
    If Format(Cells(i, 5), "mm/DD/yyyy") < AsOFDate Then
        Me.ListQuaHan.AddItem (Cells(i, 1))
        Me.ListQuaHan.List(ListQuaHanRow, 1) = Cells(i, 2)
        Me.ListQuaHan.List(ListQuaHanRow, 2) = Cells(i, 3)
        Me.ListQuaHan.List(ListQuaHanRow, 3) = Format(Cells(i, 4), "#,###,###")
        Me.ListQuaHan.List(ListQuaHanRow, 4) = Cells(i, 5)
        Me.ListQuaHan.List(ListQuaHanRow, 5) = Cells(i, 6)
        ListQuaHanRow = ListQuaHanRow + 1
    End If
Next i
'Loc Phát Sinh Dén Han: '
Me.MultiPage1.Value = 1
For j = 2 To MaxARRow
    If Format(Cells(j, 5), "mm/DD/yyyy") >= AsOFDate And Format(Cells(j, 5), "mm/DD/yyyy") <= AsOfWeek Then '** '
        Me.ListDenHan.AddItem (Cells(j, 1))
        Me.ListDenHan.List(ListDenHanRow, 1) = Cells(j, 2)
        Me.ListDenHan.List(ListDenHanRow, 2) = Cells(j, 3)
        Me.ListDenHan.List(ListDenHanRow, 3) = Format(Cells(j, 4), "#,###,###")
        Me.ListDenHan.List(ListDenHanRow, 4) = Cells(j, 5)
        Me.ListDenHan.List(ListDenHanRow, 5) = Cells(j, 6)
        ListDenHanRow = ListDenHanRow + 1
    End If
Next j
End Sub

Được rồi nè. e cám ơn anh nhiều nha.
Bài đã được tự động gộp:

Sai vì trong UserForm_Activate bạn so sánh chuỗi mà chuỗi lại không chuẩn.
Lấy vd.
Mã:
For i = 2 To MaxARRow
    If Format(Cells(i, 5), "dd/mm/yyyy") < AsOFDate Then
'    ...
    End If
Next i

Với i = 38 thì Cells(i, 5) là ngày 1 tháng 11 năm 2019. AsOFDate là 6 tháng 10 năm 2019 (ta chạy code ngày hôm nay)
Format(Cells(i, 5), "dd/mm/yyyy") = "01/11/2019"
AsOFDate = "06/10/2019".

Qui tắc so sánh chuỗi cùng chiều dài:
So sánh ký tự 1. Nếu không bằng nhau thì kết thúc và chuỗi có ký tự nhỏ hơn thì nhỏ hơn. Nếu bằng nhau thì so sánh ký tự 2. Tương tự nếu không bằng nhau thì kết thúc và chuỗi có ký tự nhỏ hơn thì nhỏ hơn. Nếu bằng nhau thì so sánh ký tự 3 v...v Nếu tất cả các ký tự bằng nhau thì 2 chuỗi bằng nhau.

Với qui tắc trên thì khi so sánh chuỗi "01/11/2019" và "06/10/2019" thì ở ký tự 2 ta có 1 < 6, vậy chuỗi "01/11/2019" < chuỗi "06/10/2019". Tức điều kiện cho IF thỏa và dòng 38 (STT = 37) được thêm vào ListBox. Tương tự với STT = 38-41, 67-71.

Cách khắc phục:
1. So sánh số.
Ngày tháng trong Excel là số nên so sánh số thôi. Tại sao phải biến thành chuỗi rồi so sánh chuỗi?
Mã:
Private Sub UserForm_Activate()
...
Dim AsOFDate As Long, AsOfWeek As Long, MaxARRow As Long, MaxARColumn As Long, ListQuaHanRow As Long, ListDenHanRow As Long
AsOFDate = Date
AsOfWeek = Date + 7
'    ...
For i = 2 To MaxARRow
    If Cells(i, 5) < AsOFDate Then
'    ...
    End If
Next i
...
For j = 2 To MaxARRow
    If Cells(j, 5) >= AsOFDate And Cells(j, 5) <= AsOfWeek Then
'    ...
    End If
Next j
End Sub

2. So sánh chuỗi (không khuyến cáo). Nếu thế thì dùng dạng "yyy/mm/dd". Dùng dạng này thì đúng.
Với vd. ở trên thì:
Format(Cells(i, 5), "dd/mm/yyyy") = "2019/11/01"
AsOFDate = "2019/10/06".
Và khi so sánh thì có "2019/11/01" > "2019/10/06" (so sánh kết thúc ở ký tự 7: 1 > 0)
Do vậy điều kiện không thỏa và dòng 38 (STT = 37) không được thêm vào ListBox
Mã:
Private Sub UserForm_Activate()
'    ...
Dim AsOFDate As String, AsOfWeek As String, MaxARRow As Long, MaxARColumn As Long, ListQuaHanRow As Long, ListDenHanRow As Long
AsOFDate = Format(Now(), "yyyy/mm/dd")
AsOfWeek = Format(Now() + 7, "yyyy/mm/dd")
'    ...
For i = 2 To MaxARRow
    If Format(Cells(i, 5), "yyyy/mm/dd") < AsOFDate Then
'    ...
    End If
Next i
...

For j = 2 To MaxARRow
    If Format(Cells(j, 5), "yyyy/mm/dd") >= AsOFDate And Format(Cells(j, 5), "yyyy/mm/dd") <= AsOfWeek Then
'    ...
    End If
Next j
End Sub
Cám ơn anh nhiều nha, e đã xử lý được rồi nè.
 
Upvote 0
PHP:
Private Sub UserForm_Activate()
Me.Caption = "KE HOACH CONG VIEC DEN NGAY " & Format(Now(), "dd/mm/yyyy")
Sheets("Weekend Plan").Select
Dim AsOFDate, AsOfWeek As String, MaxARRow, MaxARColumn, ListQuaHanRow, ListDenHanRow As Integer
AsOFDate = Format(Now(), "mm/DD/yyyy")      'AsOFDate = Format(Now(), "dd/mm/yyyy") '
AsOfWeek = Format(Now() + 7, "mm/DD/yyyy")  'AsOfWeek = Format(Now() + 7, "dd/mm/yyyy") '
MaxARRow = Range("MaxARRow")
MaxARColumn = Range("MaxARColumn")
ListQuaHanRow = 0:                              ListDenHanRow = 0
Me.ListQuaHan.Clear:                            Me.ListDenHan.Clear
'Loc Phát Sinh Quá Han  '
Me.MultiPage1.Value = 0
For i = 2 To MaxARRow
    If Format(Cells(i, 5), "mm/DD/yyyy") < AsOFDate Then
        Me.ListQuaHan.AddItem (Cells(i, 1))
        Me.ListQuaHan.List(ListQuaHanRow, 1) = Cells(i, 2)
        Me.ListQuaHan.List(ListQuaHanRow, 2) = Cells(i, 3)
        Me.ListQuaHan.List(ListQuaHanRow, 3) = Format(Cells(i, 4), "#,###,###")
        Me.ListQuaHan.List(ListQuaHanRow, 4) = Cells(i, 5)
        Me.ListQuaHan.List(ListQuaHanRow, 5) = Cells(i, 6)
        ListQuaHanRow = ListQuaHanRow + 1
    End If
Next i
'Loc Phát Sinh Dén Han: '
Me.MultiPage1.Value = 1
For j = 2 To MaxARRow
    If Format(Cells(j, 5), "mm/DD/yyyy") >= AsOFDate And Format(Cells(j, 5), "mm/DD/yyyy") <= AsOfWeek Then '** '
        Me.ListDenHan.AddItem (Cells(j, 1))
        Me.ListDenHan.List(ListDenHanRow, 1) = Cells(j, 2)
        Me.ListDenHan.List(ListDenHanRow, 2) = Cells(j, 3)
        Me.ListDenHan.List(ListDenHanRow, 3) = Format(Cells(j, 4), "#,###,###")
        Me.ListDenHan.List(ListDenHanRow, 4) = Cells(j, 5)
        Me.ListDenHan.List(ListDenHanRow, 5) = Cells(j, 6)
        ListDenHanRow = ListDenHanRow + 1
    End If
Next j
End Sub
Code chắc chắn sai.
Với code như thế thì AsOFDate = "10/06/2019"
Nếu vd. Cells(i, 5) = 6 tháng 1 năm 2020 thì Format(Cells(i, 5), "mm/DD/yyyy") = "01/06/2020
Lúc này thì
Format(Cells(i, 5), "mm/DD/yyyy") = "01/06/2020 < "10/06/2019" = AsOFDate

Tức dữ liệu cho Cells(i, 5) được thêm vào ListBox. Nhưng rõ ràng là ngày "6 tháng 1 năm 2020" là trong tương lai nên chưa hoàn thành vậy không thể thêm vào ListBox.

Nếu đã so sánh chuỗi thì phải tạo nó theo dạng "năm/tháng/ngày"
Bài đã được tự động gộp:

Được rồi nè. e cám ơn anh nhiều nha.
Chắc chắn chứ? Bạn thử thay E2 = "ngày 6 tháng 1 năm 2020" xem. Lúc đó dòng 2 được nhập vào ListBox trong khi ngày E2 là trong tương lai.
 
Upvote 0
Code chắc chắn sai.
Với code như thế thì AsOFDate = "10/06/2019"
Nếu vd. Cells(i, 5) = 6 tháng 1 năm 2020 thì Format(Cells(i, 5), "mm/DD/yyyy") = "01/06/2020
Lúc này thì
Format(Cells(i, 5), "mm/DD/yyyy") = "01/06/2020 < "10/06/2019" = AsOFDate

Tức dữ liệu cho Cells(i, 5) được thêm vào ListBox. Nhưng rõ ràng là ngày "6 tháng 1 năm 2020" là trong tương lai nên chưa hoàn thành vậy không thể thêm vào ListBox.

Nếu đã so sánh chuỗi thì phải tạo nó theo dạng "năm/tháng/ngày"
Bài đã được tự động gộp:


Chắc chắn chứ? Bạn thử thay E2 = "ngày 6 tháng 1 năm 2020" xem. Lúc đó dòng 2 được nhập vào ListBox trong khi ngày E2 là trong tương lai.
Vâng, được rồi a. Giờ chỉ vướng chỗ như comment trong hình nữa a (trong excel hiện còn 1 ngày, trong bảng hiện ra chỉ số 1), a có cách nào ko a.

1570355659861.png
 
Lần chỉnh sửa cuối:
Upvote 0
Có nghĩa là tôi sai? Tức bạn vẫn cho là code của bạn SA_DQ đúng?
Lúc trước là "Được rồi nè", bây giờ là "Vâng, được rồi a". Tức bạn vẫn cho là không có gì sai cả? Viết thì nên viết rõ, tránh để hiểu lầm.
Giờ chỉ vướng chỗ như comment trong hình nữa a, a có cách nào ko a.
Sai đúng đều như nhau cả thì mất công làm để mà làm gì.
 
Upvote 0
Có nghĩa là tôi sai? Tức bạn vẫn cho là code của bạn SA_DQ đúng?
Lúc trước là "Được rồi nè", bây giờ là "Vâng, được rồi a". Tức bạn vẫn cho là không có gì sai cả? Viết thì nên viết rõ, tránh để hiểu lầm.

Sai đúng đều như nhau cả thì mất công làm để mà làm gì.
Ý em là sau khi tiếp nhận và chỉnh sửa theo ý của a, code đã hoạt động theo đúng nội dung e muốn hiển thị. cám ơn a nhiều.
 
Upvote 0
Upvote 0
Tại sao khi mở file (file đã lưu vào thư mục) thì có file hỏi "Enable Macro", có file thì không hỏi?
Em đang sử dụng Win 7 và Office 2010
Em cũng đã vào Trust Center để kiểm tra nhưng không thấy sự khác biệt
Nhờ anh/chị giải thích. Em cảm ơn.
 
Upvote 0
Nhờ các a/c sửa giúp e đoạn code này với ạ. Vấn đề chính là khi e ấn nút SAVE thì nó chỉ lưu có câu lệnh đầu tiên.z1572670508164_06c4ba1810a931a9447c5907b2ca0994.pngz1572669801550_ff15dbd98890ea20cedd914f46ad216a.png
 

File đính kèm

Upvote 0
Anh chị xem giúp nếu muốn thay cột A trong sheet nhập thành cột C thì chỉnh code như thế nào ạ
Em cảm ơn!
 

File đính kèm

Upvote 0
Nhờ các a/c sửa giúp e đoạn code này với ạ. Vấn đề chính là khi e ấn nút SAVE thì nó chỉ lưu có câu lệnh đầu tiên.View attachment 226500View attachment 226499
Lý thuyết:
Nếu ListBox có nguồn được định nghĩa ListBox.RowSource là ... thì:
1. Nếu click vào một mục bất kỳ trong ListBox hoặc thay đổi ListBox.ListIndex bằng code thì:
- trước hết code của ListBox_Change được thực hiện nếu có.
- tiếp theo code của ListBox_Click được thực hiện nếu có.

2. Khi vùng RowSource trên sheet (là nguồn của ListBox) thay đổi thì ListBox được làm mới.
Khi ListBox được làm mới thì:
- nếu hiện hành không có mục nào được chọn (ListIndex = -1) thì không có code nào được thực hiện thêm.
- nếu hiện hành có mục nào đó được chọn (ListIndex > -1) thì của ListBox_Change được thực hiện nếu có, tiếp theo code của ListBox_Click được thực hiện nếu có.
-----
Trước hết xét code
Mã:
Private Sub lb_dulieu_Click()
    With Me
        If .lb_dulieu.ListIndex >= 0 Then _
            .txt_sanpham_2.Value = .lb_dulieu.List(lb_dulieu.ListIndex, 1)
            ....
            .txt_sotien_2.Value = .lb_dulieu.List(lb_dulieu.ListIndex, 16)
        End With
End Sub
Theo lôgíc thì tất cả các dòng chứ không chỉ dòng đầu tiên đều phải nằm trong IF ... END IF.

Tức bỏ ký tự "_" sau Then và thêm "End If" trước "End With"
------
Vùng dữ liệu nguồn cho lb_dulieu được bạn thiết lập là data_sp (lb_dulieu.RowSource = data_sp).

Ta xét một ví dụ cụ thể để có thể giải thích cụ thể. Giả sử bạn chọn trong lb_dulieu dòng có STT = 4, ứng với dòng 6 trên sheet SP. Code của lb_dulieu_Click sẽ được thực hiện, hậu quả là các giá trị của dòng được chọn sẽ được nhập vào các textbox trên Form. Bây giờ giả sử bạn chỉnh sửa các giá trị trong các textbox bằng cách thêm hậu tố " mới". Tiếp theo bạn nhấn nút SAVE thì code của btnchange_Click sẽ được thực hiện
Mã:
Private Sub btnchange_Click()
Dim dong_sua As Long
    dong_sua = Sheets("SP").Range("A" & lb_dulieu.ListIndex + 2).Row
        With Worksheets("SP")
            .Cells(dong_sua, 2).Value = Dulieu_SP.txt_sanpham_2
            .Cells(dong_sua, 3).Value = Dulieu_SP.combo_ma_KH_2
            .Cells(dong_sua, 4).Value = Dulieu_SP.combo_nhucau_2
            .Cells(dong_sua, 5).Value = Dulieu_SP.combo_mucdogap_2
            .Cells(dong_sua, 6).Value = txt_add_2
            .Cells(dong_sua, 7).Value = txt_duan_2
            .Cells(dong_sua, 8).Value = txt_solo_2
            .Cells(dong_sua, 9).Value = txt_sothua_2
            .Cells(dong_sua, 10).Value = txt_soto_2
            .Cells(dong_sua, 11).Value = txt_dientich_2
            .Cells(dong_sua, 12).Value = txt_loaidat_2
            .Cells(dong_sua, 13).Value = txt_huong_2
            .Cells(dong_sua, 14).Value = txt_kichthuoc_2
            .Cells(dong_sua, 15).Value = txt_congtrinh_2
            .Cells(dong_sua, 16).Value = combo_cachtinh_2
            .Cells(dong_sua, 17).Value = txt_sotien_2
            .Cells(dong_sua, 18).Value = .Cells(dong_sua, 18).Value & "Edit by:" & Sheets("menu").Range("F2").Text & "; Edit Time: " & Now()
          End With
End Sub
Sau khi thực hiện dòng đầu tiên
Mã:
.Cells(dong_sua, 2).Value = Dulieu_SP.txt_sanpham_2
Thì trên sheet ô B6 sẽ có giá trị B6 = "THU.NT-4 mới".
Do dữ liệu trong vùng dữ liệu nguồn data_sp thay đổi (B6) nên theo lý thuyết thì code của lb_dulieu_Click sẽ được thực hiện. Đó chính là code ở trên. Bạn nhìn kỹ thì sẽ thấy là giá trị của các textbox mà bạn vừa bỏ nhiều công sức để thêm " mới" đã bị thay thế bằng các giá trị của lb_dulieu, tức lấy từ nguồn data_sp trên sheet do lb_dulieu được làm mới khi data_sp thay đổi Mà trên sheet mới chỉ có B6 thay đổi thôi, còn các giá trị khác chưa có " mới". Tức sau khi thực hiện lb_dulieu_Click thì chỉ có txt_sanpham_2 là có hậu tố " mới" do lấy từ cột 2 hàng 5 (ứng với B6 trên sheet) của lb_dulieu. Các textbox khác không có hậu tố " mới". Chúng có các giá trị y như sau khi chọn dòng STT = 4 và trước khi chỉnh sửa. Vì thế khi code thực thi các dòng còn lại bắt đầu từ dòng
Mã:
.Cells(dong_sua, 3).Value = Dulieu_SP.combo_ma_KH_2
tới cuối thì do các textbox không chứa các hậu tố " mới" mà chỉ chứa các giá trị y như trên sheet nên hiển nhiên là các giá trị trên sheet được thay bằng chính chúng nên không thể có hậu tố " mới" được.

Nếu có nhu cầu chỉnh sửa trên sheet thì không được phép chỉnh sửa trong vùng RowSource của ListBox. Nếu cần chỉnh sửa trong một vùng mà vùng đó đồng thời là dữ liệu nguồn cho ListBox thì phải cẩn thận khi dùng ListBox_Change và ListBox_Click. Nếu trong ListBox_Click code thay đổi giá trị của các textbox như của bạn, tức chúng được thay đổi - lấy từ vùng nguồn của ListBox, thì công lao chỉnh sửa các textbox trước đó đổ xuống sông xuống biển. Tôi hiểu là code Click phải thế để lấy các giá trị của dòng được chọn trong ListBox vào các textbox. Vậy thì phải từ bỏ dùng RowSource và dùng List để nhập dữ liệu vào ListBox.

Tóm lại:
0. Thêm End If vào lb_dulieu_Click
1. Xóa lb_dulieu.RowSource.
2. Thêm code vào Form
Mã:
Private Sub UserForm_Initialize()
    lb_dulieu.List = Worksheets("SP").Range("data_sp").Value
End Sub
3. Đễ làm mới lb_dulieu sau khi ghi xuống sheet thì trong Sub btnchange_Click sau dòng End With thì thêm code
Mã:
lb_dulieu.List = Worksheets("SP").Range("data_sp").Value
 
Upvote 0
Lý thuyết:
Nếu ListBox có nguồn được định nghĩa ListBox.RowSource là ... thì:
1. Nếu click vào một mục bất kỳ trong ListBox hoặc thay đổi ListBox.ListIndex bằng code thì:
- trước hết code của ListBox_Change được thực hiện nếu có.
- tiếp theo code của ListBox_Click được thực hiện nếu có.

2. Khi vùng RowSource trên sheet (là nguồn của ListBox) thay đổi thì ListBox được làm mới.
Khi ListBox được làm mới thì:
- nếu hiện hành không có mục nào được chọn (ListIndex = -1) thì không có code nào được thực hiện thêm.
- nếu hiện hành có mục nào đó được chọn (ListIndex > -1) thì của ListBox_Change được thực hiện nếu có, tiếp theo code của ListBox_Click được thực hiện nếu có.
-----
Trước hết xét code
Mã:
Private Sub lb_dulieu_Click()
    With Me
        If .lb_dulieu.ListIndex >= 0 Then _
            .txt_sanpham_2.Value = .lb_dulieu.List(lb_dulieu.ListIndex, 1)
            ....
            .txt_sotien_2.Value = .lb_dulieu.List(lb_dulieu.ListIndex, 16)
        End With
End Sub
Theo lôgíc thì tất cả các dòng chứ không chỉ dòng đầu tiên đều phải nằm trong IF ... END IF.

Tức bỏ ký tự "_" sau Then và thêm "End If" trước "End With"
------
Vùng dữ liệu nguồn cho lb_dulieu được bạn thiết lập là data_sp (lb_dulieu.RowSource = data_sp).

Ta xét một ví dụ cụ thể để có thể giải thích cụ thể. Giả sử bạn chọn trong lb_dulieu dòng có STT = 4, ứng với dòng 6 trên sheet SP. Code của lb_dulieu_Click sẽ được thực hiện, hậu quả là các giá trị của dòng được chọn sẽ được nhập vào các textbox trên Form. Bây giờ giả sử bạn chỉnh sửa các giá trị trong các textbox bằng cách thêm hậu tố " mới". Tiếp theo bạn nhấn nút SAVE thì code của btnchange_Click sẽ được thực hiện
Mã:
Private Sub btnchange_Click()
Dim dong_sua As Long
    dong_sua = Sheets("SP").Range("A" & lb_dulieu.ListIndex + 2).Row
        With Worksheets("SP")
            .Cells(dong_sua, 2).Value = Dulieu_SP.txt_sanpham_2
            .Cells(dong_sua, 3).Value = Dulieu_SP.combo_ma_KH_2
            .Cells(dong_sua, 4).Value = Dulieu_SP.combo_nhucau_2
            .Cells(dong_sua, 5).Value = Dulieu_SP.combo_mucdogap_2
            .Cells(dong_sua, 6).Value = txt_add_2
            .Cells(dong_sua, 7).Value = txt_duan_2
            .Cells(dong_sua, 8).Value = txt_solo_2
            .Cells(dong_sua, 9).Value = txt_sothua_2
            .Cells(dong_sua, 10).Value = txt_soto_2
            .Cells(dong_sua, 11).Value = txt_dientich_2
            .Cells(dong_sua, 12).Value = txt_loaidat_2
            .Cells(dong_sua, 13).Value = txt_huong_2
            .Cells(dong_sua, 14).Value = txt_kichthuoc_2
            .Cells(dong_sua, 15).Value = txt_congtrinh_2
            .Cells(dong_sua, 16).Value = combo_cachtinh_2
            .Cells(dong_sua, 17).Value = txt_sotien_2
            .Cells(dong_sua, 18).Value = .Cells(dong_sua, 18).Value & "Edit by:" & Sheets("menu").Range("F2").Text & "; Edit Time: " & Now()
          End With
End Sub
Sau khi thực hiện dòng đầu tiên
Mã:
.Cells(dong_sua, 2).Value = Dulieu_SP.txt_sanpham_2
Thì trên sheet ô B6 sẽ có giá trị B6 = "THU.NT-4 mới".
Do dữ liệu trong vùng dữ liệu nguồn data_sp thay đổi (B6) nên theo lý thuyết thì code của lb_dulieu_Click sẽ được thực hiện. Đó chính là code ở trên. Bạn nhìn kỹ thì sẽ thấy là giá trị của các textbox mà bạn vừa bỏ nhiều công sức để thêm " mới" đã bị thay thế bằng các giá trị của lb_dulieu, tức lấy từ nguồn data_sp trên sheet do lb_dulieu được làm mới khi data_sp thay đổi Mà trên sheet mới chỉ có B6 thay đổi thôi, còn các giá trị khác chưa có " mới". Tức sau khi thực hiện lb_dulieu_Click thì chỉ có txt_sanpham_2 là có hậu tố " mới" do lấy từ cột 2 hàng 5 (ứng với B6 trên sheet) của lb_dulieu. Các textbox khác không có hậu tố " mới". Chúng có các giá trị y như sau khi chọn dòng STT = 4 và trước khi chỉnh sửa. Vì thế khi code thực thi các dòng còn lại bắt đầu từ dòng
Mã:
.Cells(dong_sua, 3).Value = Dulieu_SP.combo_ma_KH_2
tới cuối thì do các textbox không chứa các hậu tố " mới" mà chỉ chứa các giá trị y như trên sheet nên hiển nhiên là các giá trị trên sheet được thay bằng chính chúng nên không thể có hậu tố " mới" được.

Nếu có nhu cầu chỉnh sửa trên sheet thì không được phép chỉnh sửa trong vùng RowSource của ListBox. Nếu cần chỉnh sửa trong một vùng mà vùng đó đồng thời là dữ liệu nguồn cho ListBox thì phải cẩn thận khi dùng ListBox_Change và ListBox_Click. Nếu trong ListBox_Click code thay đổi giá trị của các textbox như của bạn, tức chúng được thay đổi - lấy từ vùng nguồn của ListBox, thì công lao chỉnh sửa các textbox trước đó đổ xuống sông xuống biển. Tôi hiểu là code Click phải thế để lấy các giá trị của dòng được chọn trong ListBox vào các textbox. Vậy thì phải từ bỏ dùng RowSource và dùng List để nhập dữ liệu vào ListBox.

Tóm lại:
0. Thêm End If vào lb_dulieu_Click
1. Xóa lb_dulieu.RowSource.
2. Thêm code vào Form
Mã:
Private Sub UserForm_Initialize()
    lb_dulieu.List = Worksheets("SP").Range("data_sp").Value
End Sub
3. Đễ làm mới lb_dulieu sau khi ghi xuống sheet thì trong Sub btnchange_Click sau dòng End With thì thêm code
Mã:
lb_dulieu.List = Worksheets("SP").Range("data_sp").Value

Cảm ơn a Batman1 rất nhiều. đúng cái e cần luôn. Vấn đề chính của e là dùng RowSource nên sửa được 1 ô là nó cập nhật lại luôn.
 
Upvote 0
Cảm ơn a Batman1 rất nhiều. đúng cái e cần luôn. Vấn đề chính của e là dùng RowSource nên sửa được 1 ô là nó cập nhật lại luôn.
Nếu vẫn muốn dùng RowSource thì phải thay lb_dulieu_Click bằng lb_dulieu_DblClick. Lúc đó trong quá trình ghi xuống sheet thì ListBox vẫn được làm mới liên tục nhưng do DblClick không được gọi (chỉ cọ Click được gọi) nên các textbox không bị chuyển về các giá trị cũ lấy từ ListBox (lấy từ sheet).
Nhưng tôi không thích cái đỏ đỏ. Dùng List và khi nào cần làm mới ListBox thì mới gọi code làm mới thôi.
 
Upvote 0
Các anh/ chị cho e hỏi, có cách nào chỉnh được như comment trong hình ko vậy anh/chị?
Em mới tập tành VBA nên cũng ko rõ lắm. Cám ơn anh/chị trước nhé.


1571406723722.png
 

File đính kèm

Upvote 0
Các anh/ chị cho e hỏi, có cách nào chỉnh được như comment trong hình ko vậy anh/chị?
Em mới tập tành VBA nên cũng ko rõ lắm. Cám ơn anh/chị trước nhé.


View attachment 226867
Mình nghĩ ra 2 cách bạn xem dùng được thì dùng:
Cách 1: Thay đổi công thức ở cột C thành: =+IF(-TODAY()+E2<0;"Hoàn thành";IF(-TODAY()+E2=0;"Đến hạn";"Còn "&E2-TODAY()&" ngày"));
Cách 2: thay đoạn code:
'Loc Phát Sinh Dén Han: '
...
Me.ListDenHan.List(ListDenHanRow, 2) = Cells(j, 3)
....
Thành code:
If Cells(j, 3) = ChrW(272) & ChrW(7871) & "n h" & ChrW(7841) & "n" Then
Me.ListDenHan.List(ListDenHanRow, 2) = Cells(j, 3)
Else: Me.ListDenHan.List(ListDenHanRow, 2) = "Còn " & Cells(j, 3) & "ngày"
End If

Bổ sung cách 3 ngắn và đơn giản nhất:
thay code:
'Loc Phát Sinh Dén Han: '
...
Me.ListDenHan.List(ListDenHanRow, 2) = Cells(j, 3)
....
Thành code:
'Loc Phát Sinh Dén Han: '
...
Me.ListDenHan.List(ListDenHanRow, 2) = Cells(j, 3).text
....
 
Lần chỉnh sửa cuối:
Upvote 0
Web KT

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

Back
Top Bottom