Đố vui về VBA!

Liên hệ QC

anhtuan1066

Thành viên gạo cội
Tham gia
10/3/07
Bài viết
5,802
Được thích
6,905
Nhằm cũng cố kiến thức về VBA cho các bạn mới bắt đầu và cả những bạn đang ứng dụng mà chưa hiểu nhiều về nó, tôi mở topic này với mong mõi qua những câu hỏi vui, các bạn sẽ nhận định lại sự hiểu biết cũa mình... (Kễ cã chính tôi cũng đang tập tành nên có rất nhiều cái chưa biết)
Mong rằng topic sẽ mang đến cho các bạn những khám phá thú vị với những cái tưỡng chừng như đã biết
Mong nhận dc bài viết về câu đố cũa các cao thủ! Còn các bạn mới thì đừng ngại khi đưa ra ý kiến cũa mình.. Có sai có sữa sẽ hoàn thiện!
Tôi xin mỡ màn trước bằng 1 câu hỏi đơn giãn
ANH TUẤN

CÂU HỎI 1: Tại sao biến K ko hoạt động?
Tôi muốn khi nhấn vào 1 button thì cell A1 sẽ tăng lên 1 đơn vị... Tôi đã làm như sau:
-Tạo 1 Command Button (nút nhấn thuộc thanh Control Toolbox), click phải chuột lên nút nhấn, chọn View code, rồi gõ vào đoạn code sau:
PHP:
Private Sub CommandButton1_Click()
   K = K + 1
   Range("A1").Value = K
End Sub
Ban đầu K chưa có gì, xem như =0, nhấn nút lần thứ nhất thì K dc tăng thêm 1, vậy K hiện tại sẽ bằng 1, và gán K vào cell A1 thì đương nhiên A1 sẽ =1... Nhấn nút lần 2, K lại dc tăng thêm 1 nên hiện tại K sẽ =2 và cell A1 cũng sẽ =2... vân vân.. từ đó diễn tiến tiếp...
Hi.. hi.. Điều này nghe qua có vẽ rất hợp lý, ấy thế mà khi nhấn nút nó chỉ hoạt động dc duy nhất 1 lần (A1 = 1) rồi thôi ko nhút nhít nữa...
Các bạn có thể giãi thích tại sao lại như thế ko? Tại sao những lần nhấn nút sau đó K lại ko tăng thêm tí nào (vì thực tế A1 vẫn cứ = 1 hoài) ?
ANH TUẤN
 
Tôi có đoạn code như sau:
PHP:
For i = 1 to erowNX
    if true then erowNX=erowNX + 1
next
msgbox "Gia tri hien tai cua i la " & i & chr(13) & "Gia tri hien tai cua erownx la " & erownx

Vấn đề là sau khi biến erowNX tăng, vòng lặp vẫn chạy theo giá trị ban đầu của erowNX. Dễ dàng kiểm tra điều này qua câu lệnh msgbox...

Nhờ các bạn giải thich lý do vì sao và xin hỏi có cách nào giải quyết tình huống này không?

Thân.
Ý bạn muốn "đố vui" hay là nhờ tìm giải pháp?
Nếu là tìm giải pháp thì bạn phải đưa nguyên file (có code này) lên đây, nói rõ yêu cầu và những trục trặc bạn đang gặp phải
Mặc khác, nếu là nhờ tìm giải pháp thì bài của bạn lý ra không nên đăng ở đây
Nếu là "đố vui" là code này dường như hơi thiếu gì đó ---> Giả định vòng lập có thể chạy theo biến erowNX mới thì... chạy đến bao giờ?
 
Upvote 0
Cám ơn Bác NDU đã nhắc nhở.
ndu96081631 đã viết:
Ý bạn muốn "đố vui" hay là nhờ tìm giải pháp?
Tất nhiên là "đố vui" rồi, vì đây là chủ đề của mục này mà.
ndu96081631 đã viết:
Nếu là "đố vui" là code này dường như hơi thiếu gì đó
Chịu sư phụ luôn. Đúng là erowNX phải nhận giá trị trước khi chạy vòng lặp For...Next.

Tôi sửa code ví dụ như sau:
Mã:
[FONT=Times New Roman][SIZE=1][COLOR=black]erowNX = 5[/COLOR][/SIZE][/FONT]
[SIZE=1][COLOR=black][FONT=Courier New]For [/FONT][FONT=Courier New]i [/FONT][FONT=Courier New]= [/FONT][FONT=Courier New]1 to erowNX[/FONT][/COLOR][/SIZE]
[SIZE=1][COLOR=black][FONT=Courier New]if [/FONT][FONT=Courier New]true then erowNX[/FONT][FONT=Courier New]=[/FONT][FONT=Courier New]erowNX [/FONT][FONT=Courier New]+ [/FONT][FONT=Courier New]1[/FONT][/COLOR][/SIZE]
[FONT=Courier New][SIZE=1][COLOR=black]next[/COLOR][/SIZE][/FONT]
[SIZE=3][COLOR=black][SIZE=1][FONT=Courier New]msgbox [/FONT][FONT=Courier New]"Gia tri hien tai cua i la " [/FONT][FONT=Courier New]& [/FONT][FONT=Courier New]i [/FONT][FONT=Courier New]& [/FONT][FONT=Courier New]chr[/FONT][FONT=Courier New]([/FONT][FONT=Courier New]13[/FONT][FONT=Courier New]) & [/FONT][FONT=Courier New]"Gia tri hien tai cua erownx la " [/FONT][FONT=Courier New]& [/FONT][/SIZE][/COLOR][FONT=Courier New][SIZE=1][COLOR=black]erownx[/COLOR][/SIZE][COLOR=#0000bb] [/COLOR][/FONT][/SIZE]

Mong nhận được ý kiến trao đổi của các bạn. Tôi nghĩ lỗi này rất hay xảy ra, nhất là với những người còn đang chập chững với VBA (như tôi chẳng hạn).

Trân trọng.
 
Upvote 0
Cám ơn Bác NDU đã nhắc nhở.

Tất nhiên là "đố vui" rồi, vì đây là chủ đề của mục này mà.

Chịu sư phụ luôn. Đúng là erowNX phải nhận giá trị trước khi chạy vòng lặp For...Next.

Tôi sửa code ví dụ như sau:
Mã:
[FONT=Times New Roman][SIZE=1][COLOR=black]erowNX = 5[/COLOR][/SIZE][/FONT]
[SIZE=1][COLOR=black][FONT=Courier New]For [/FONT][FONT=Courier New]i [/FONT][FONT=Courier New]= [/FONT][FONT=Courier New]1 to erowNX[/FONT][/COLOR][/SIZE]
[SIZE=1][COLOR=black][FONT=Courier New]if [/FONT][FONT=Courier New]true then erowNX[/FONT][FONT=Courier New]=[/FONT][FONT=Courier New]erowNX [/FONT][FONT=Courier New]+ [/FONT][FONT=Courier New]1[/FONT][/COLOR][/SIZE]
[FONT=Courier New][SIZE=1][COLOR=black]next[/COLOR][/SIZE][/FONT]
[SIZE=3][COLOR=black][SIZE=1][FONT=Courier New]msgbox [/FONT][FONT=Courier New]"Gia tri hien tai cua i la " [/FONT][FONT=Courier New]& [/FONT][FONT=Courier New]i [/FONT][FONT=Courier New]& [/FONT][FONT=Courier New]chr[/FONT][FONT=Courier New]([/FONT][FONT=Courier New]13[/FONT][FONT=Courier New]) & [/FONT][FONT=Courier New]"Gia tri hien tai cua erownx la " [/FONT][FONT=Courier New]& [/FONT][/SIZE][/COLOR][FONT=Courier New][SIZE=1][COLOR=black]erownx[/COLOR][/SIZE][/FONT][/SIZE]
Mong nhận được ý kiến trao đổi của các bạn. Tôi nghĩ lỗi này rất hay xảy ra, nhất là với những người còn đang chập chững với VBA (như tôi chẳng hạn).

Trân trọng.
Vòng lập For... Next có cú pháp:
PHP:
For counter = start To end
 .....
 .....
Next
Tôi nghĩ ta không thể thay đổi được giá trị end trong quá trình thực thị vòng lập đâu
Ví dụ thế này:
PHP:
Sub Test()
  Dim i As Long, er As Long
  er = 5
  For i = 1 To 5
    er = 7
    MsgBox i
  Next
End Sub
Ban đầu er = 5 và trong vòng lập tôi lại thay đổi er = 7, thế nhưng vòng lập vẫn cứ chạy theo giá trị end ban đầu
Chắc đây thuộc về quy định rồi ---> Còn bạn, bạn giải thích thế nào?
 
Upvote 0
Vòng lập For... Next có cú pháp:
PHP:
For counter = start To end
.....
.....
Next
Tôi nghĩ ta không thể thay đổi được giá trị end trong quá trình thực thị vòng lập đâu
Ví dụ thế này:
PHP:
Sub Test()
Dim i As Long, er As Long
er = 5
For i = 1 To 5
er = 7
MsgBox i
Next
End Sub
Ban đầu er = 5 và trong vòng lập tôi lại thay đổi er = 7, thế nhưng vòng lập vẫn cứ chạy theo giá trị end ban đầu
Chắc đây thuộc về quy định rồi ---> Còn bạn, bạn giải thích thế nào?

Có cách này thay đổi được "giá trị end"
Mã:
Public Sub thu1()
k = 5
j = 1
n:
erownx = k
For i = j To erownx
If True Then erownx = erownx + 1
k = erownx
j = j + 1
If erownx = 100 Then GoTo m
'If i = 100 Then GoTo m
GoTo n
Next
m:
MsgBox "Gia tri hien tai cua i la " & i & Chr(13) & "Gia tri hien tai cua erownx la " & erownx
End Sub
 
Upvote 0
Có cách này thay đổi được "giá trị end"
Mã:
Public Sub thu1()
k = 5
j = 1
n:
erownx = k
For i = j To erownx
If True Then erownx = erownx + 1
k = erownx
j = j + 1
If erownx = 100 Then GoTo m
'If i = 100 Then GoTo m
GoTo n
Next
m:
MsgBox "Gia tri hien tai cua i la " & i & Chr(13) & "Gia tri hien tai cua erownx la " & erownx
End Sub
Trời!
Cái bạn đang dùng mà gọi là "thay đổi giá trị end" uh?
Bạn dùng Goto là quay lại vòng lập ---> Chuyện đó quá bình thường
 
Upvote 0
Tầm thường chớ! nhưng mà chưa có cách nào khác.
Ý tôi muốn nói là vầy: Trong quá trình code chạy, hình như ta không thể thay đổi được giá trị End mà ta đã gán trước đó
(Nói là hình như là vì không chắc có cách hay không, có điều thí nghiệm chứng minh là không thể làm được)
Còn cách bạn nếu chỉ là GIẢI QUYẾT VẤN ĐỀ LÀM SAO CHO erownx ĐẠT ĐƯỢC GIÁ TRỊ NÀO ĐÓ ---> Tôi nghĩ nó chưa đúng với những gì mà bạn tungson_mrcc đã nêu
Tóm lại: Giải pháp mà ta cần tìm là: "Liệu có cách nào thay đổi được giá trị End khi vòng lập đang chạy không?"
Chú ý là: KHI VÒNG LẬP ĐANG CHẠY nha
 
Upvote 0
Cám ơn các bạn đã quan tâm tới vấn đề mình nêu ra.

Theo tôi, cách giải thích của Bác NDU là chí lý.

Vòng lập For... Next có cú pháp:
PHP:
For counter = start To end
.....
.....
Next
Tôi nghĩ ta không thể thay đổi được giá trị end trong quá trình thực thị vòng lập đâu
Chắc đây thuộc về quy định rồi

Vấn đề là khi vòng lặp For... Next đang chạy ta không có cách nào thay đổi giá trị end, trong khi trên thực tế, có rất nhiều bài toán đòi hỏi giá trị end thay đổi trong quá trình cho biến i thay đổi. Ví dụ như ở bài toán Tạo Số Thứ tự nhiều cấp...

Có lẽ vì vậy Bác Bill mới nghĩ ra vòng lặp Do... Loop để giải quyết vấn đề này.

Trong bài toán tạo số thứ tự nhiều cấp, tôi đã dùng cách sau:
Mã:
erow3 = Cells(Rows.Count, "B").End(xlUp).Row
i = 28
Do While i <= erow3
    If Cells(i, "G") <> "" And Cells(i, "G") <> N1 Then
        N1 = Cells(i, "G")
        sttN1 = sttN1 + 1
        sttN2 = 0
        sttN3 = 0
 
        Cells(i, "G").EntireRow.Insert shift:=xlDown
        Cells(i, "A") = Chr(sttN1 + 64) & ". " & N1
        Cells(i, "G") = N1
 
        Range("A" & i & ":B" & i).HorizontalAlignment = xlLeft
        Range("A" & i & ":B" & i).Font.FontStyle = "Bold"
        Range("A" & i & ":F" & i).Interior.ColorIndex = 8 'Mau xanh coban
        erow3 = erow3 + 1
    End If    
    If Cells(i + 1, "G") = N1 Then Cells(i + 1, "G") = ""
    If Cells(i + 1, "H") = N2 Then Cells(i + 1, "H") = ""
    If Cells(i + 1, "I") = N3 Then Cells(i + 1, "I") = ""
 
    i = i + 1
Loop

Như vậy, đáp án của tôi là:
1. Khi vòng lặp For...Next đang chạy theo biến i, dù biến end có thay đổi giá trị thì vòng lặp vẫn cứ chạy với giá trị ban đầu của biến end. Đấy là nhược điểm của For...Next (sinh ra đã là như vậy, không biết có sửa được không?!!!).
2. Gặp bài toán như vậy, cách giải quyết là dùng vòng Do... Loop ( Cám ơn Bác Bill )

Đây chỉ là thiển nghĩ của tôi. Mong các bạn góp ý thêm.

Trân trọng.
 
Lần chỉnh sửa cuối:
Upvote 0
Cám ơn các bạn đã quan tâm tới vấn đề mình nêu ra.

Theo tôi, cách giải thích của Bác NDU là chí lý.



Vấn đề là khi vòng lặp For... Next đang chạy ta không có cách nào thay đổi giá trị end, trong khi trên thực tế, có rất nhiều bài toán đòi hỏi giá trị end thay đổi trong quá trình cho biến i thay đổi. Ví dụ như ở bài toán Tạo Số Thứ tự nhiều cấp...

Có lẽ vì vậy Bác Bill mới nghĩ ra vòng lặp Do... Loop để giải quyết vấn đề này.

Trong bài toán tạo số thứ tự nhiều cấp, tôi đã dùng cách sau:
Mã:
erow3 = Cells(Rows.Count, "B").End(xlUp).Row
i = 28
Do While i <= erow3
    If Cells(i, "G") <> "" And Cells(i, "G") <> N1 Then
        N1 = Cells(i, "G")
        sttN1 = sttN1 + 1
        sttN2 = 0
        sttN3 = 0
 
        Cells(i, "G").EntireRow.Insert shift:=xlDown
        Cells(i, "A") = Chr(sttN1 + 64) & ". " & N1
        Cells(i, "G") = N1
 
        Range("A" & i & ":B" & i).HorizontalAlignment = xlLeft
        Range("A" & i & ":B" & i).Font.FontStyle = "Bold"
        Range("A" & i & ":F" & i).Interior.ColorIndex = 8 'Mau xanh coban
        erow3 = erow3 + 1
    End If    
    If Cells(i + 1, "G") = N1 Then Cells(i + 1, "G") = ""
    If Cells(i + 1, "H") = N2 Then Cells(i + 1, "H") = ""
    If Cells(i + 1, "I") = N3 Then Cells(i + 1, "I") = ""
 
    i = i + 1
Loop

Như vậy, đáp án của tôi là:
1. Khi vòng lặp For...Next đang chạy theo biến i, dù biến end có thay đổi giá trị thì vòng lặp vẫn cứ chạy với giá trị ban đầu của biến end. Đấy là nhược điểm của For...Next (sinh ra đã là như vậy, không biết có sửa được không?!!!).
2. Gặp bài toán như vậy, cách giải quyết là dùng vòng Do... Loop ( Cám ơn Bác Bill )

Đây chỉ là thiển nghĩ của tôi. Mong các bạn góp ý thêm.

Trân trọng.
Có 2 loại vòng lặp là vòng lặp xác định và vòng lặp không xác định. Vòng lặp xác định là vòng lặp mà số vòng lặp đã được xác định từ trước (For ... Next), vòng lặp không xác định là vòng lặp có số vòng lặp không xác định trước (Do ... Loop), người ta đã định ra 2 loại vòng lặp này rồi thì tùy từng trường hợp cụ thể mà sử dụng chứ đừng nghĩ cách thay đổi nó làm gì. Còn thực tế thì với For ... Next thì vai trò của Start và End là như nhau, ở đây mọi người mới chỉ quan tâm tới làm sao để thay đổi End nên nghe thì có vẻ có lý, nhưng hay thử hình dung ta đang đi tìm cách thay đổi Start xem sao, tự dưng sẽ thấy nó vô lý. Ví dụ For i = erowNX to 1 step -1 chẳng hạn, nếu erowNX mà thay đổi được thì thử hình dung vòng lặp sẽ chạy như nào???
 
Upvote 0
Sao lại viết là:
if true then erowNX=erowNX + 1
mà không viết luôn là:
erowNX=erowNX + 1
(luôn thực hiện và mã lệnh ngắn hơn).
Còn về lệnh FOR, nhiều bạn nói khá rõ: không thể thay đổi số lần lặp bằng thay đổi End
Tôi đã chạy thử lệnh:
i=10
FOR i = i-2 to 2*i
...
...
next i
với Start = i - 2 = 8, End = 2*i = 20 thì số lần lặp là 20 - 8 + 1 = 13
Nghĩa là các biểu thức Start, End được tính và lưu riêng khi bắt đầu vòng lặp.
Có thể thoát khỏi vòng lặp bằng các IF...EXIT FOR
hoặc thay đổi biến đếm. Ví dụ lại mã lệnh trên:
i=10
FOR i = i-2 to 2*i
i=i+50
next i

thì chỉ lặp 1 lần.
 
Upvote 0
Kiểm tra xem Dictionary Object có tồn tại hay không

Tôi có đoạn code thế này:
PHP:
Public Dic
Sub Main()
  If Dic Is Nothing Then
    Set Dic = CreateObject("Scripting.Dictionary")
    Dic.Add "a", ""
    Dic.Add "b", ""
    Dic.Add "c", ""
  End If
  MsgBox Join(Dic.Keys, " - ")
End Sub
Ý tôi muốn rằng: Nếu biến Dic không tồn tại thì sẽ làm động tác Add Key Item vào Dic
Tuy nhiên, đoạn code trên báo lỗi. Vậy các bạn sẽ khắc phục như thế nào?
 
Upvote 0
Tôi có đoạn code thế này:
PHP:
Public Dic
Sub Main()
  If Dic Is Nothing Then
    Set Dic = CreateObject("Scripting.Dictionary")
    Dic.Add "a", ""
    Dic.Add "b", ""
    Dic.Add "c", ""
  End If
  MsgBox Join(Dic.Keys, " - ")
End Sub
Ý tôi muốn rằng: Nếu biến Dic không tồn tại thì sẽ làm động tác Add Key Item vào Dic
Tuy nhiên, đoạn code trên báo lỗi. Vậy các bạn sẽ khắc phục như thế nào?
Chả biết thế nào nhưng khi khai báo Dic rành mạch thì nó OK.
Cụ thể như:
PHP:
Public Dic As Object
Sub Main()
  If Dic Is Nothing Then
    Set Dic = CreateObject("Scripting.Dictionary")
    Dic.Add "a", "1"
    Dic.Add "b", "2"
    Dic.Add "c", "3"
  End If
  'MsgBox Join(Dic.Keys, " - ")
  MsgBox Join(Dic.Items, "-")
  Set Dic = Nothing
End Sub
 
Upvote 0
Chả biết thế nào nhưng khi khai báo Dic rành mạch thì nó OK.
Chính xác là thế... Xem kỹ thông báo lỗi sẽ thấy ngay!
(Hầu hết người dùng đều ít khi xem thông báo lỗi, khi có lỗi xuất hiện chỉ biết OK rồi.. la làng... Ẹc.. Ẹc...)
Câu này xem ra quá dễ với ThuNghi nhỉ?
 
Upvote 0
Hôm nay trở lại topic này với 1 câu đố rất dễ nhưng cũng.. vui vui
Như ta đã biết, nếu thiết lập Security ở mức High thì không thể chạy được macro ---> Vậy xin hỏi các bạn liệu có trường hợp ngoại lệ nào không?
(Máy tôi đang đặt security ở mức High nhưng tôi vẫn chạy code được đấy... Hi... Hi...)
 
Upvote 0
Chào anh, không biết có phải là cái này không?

MS đã viết:
When you set security levels to Very High, High, Medium, or Low, the following conditions apply:

* Very High security

VBA macros can run only if the Trust all installed add-ins and templates option is checked and the macros (signed or unsigned) are stored in a specific trusted folder on the user's hard disk. If all these conditions are not met, VBA macros cannot run under Very High security.

* High security

Executables must be signed by an acknowledged trusted source (certificate of trust) in order to run. Otherwise, all executables associated with, or embedded in, documents are automatically disabled without warning the user when the documents are opened. All Office applications are installed with macro security set to High by default.

Le Van Duyet
 
Upvote 0
Chào anh, không biết có phải là cái này không?



Le Van Duyet
Cũng không phức tạp thế đâu Duyệt ơi! Mình làm đơn giản hơn nhiều, gần như là chạy được ngay mà chẳng phải làm gì cả (thế mới gọi là đố vui, hay nói đúng hơn là đố mẹo 1 chút)
Nói thêm: Mình thường dùng cách này để test những code đơn giản trên 1 máy tính có security = High đấy
 
Lần chỉnh sửa cuối:
Upvote 0
...
Nói thêm: Mình thường dùng cách này để test những code đơn giản trên 1 máy tính có security = High đấy
Em thật sự không hiểu, code đơn giản là thế nào. Nhưng theo anh nói em nghĩ nếu có thể chạy code đơn giản thì cũng có thể chạy code phức tạp chứ anh nhỉ.
Hay anh dùng Immediate window à?

Lê Văn Duyệt
 
Upvote 0
Em thật sự không hiểu, code đơn giản là thế nào. Nhưng theo anh nói em nghĩ nếu có thể chạy code đơn giản thì cũng có thể chạy code phức tạp chứ anh nhỉ.
Hay anh dùng Immediate window à?

Lê Văn Duyệt
Cho dù ta có đặt Security cho Excel ở mức nào đi nữa, chỉ cần mở 1 Workbook mới, chèn code vào là nó chạy thôi ---> Nó chỉ "cằn nhằn" khi file ấy đã được lưu rồi mở lại mà thôi!
Ẹc... Ẹc...
 
Upvote 0
Thì em cũng đã test rồi với High Security, và dùng Immediate Window cũng test được mà.

Lê Văn Duyệt
 
Upvote 0
Cũng không phức tạp thế đâu Duyệt ơi! Mình làm đơn giản hơn nhiều, gần như là chạy được ngay mà chẳng phải làm gì cả (thế mới gọi là đố vui, hay nói đúng hơn là đố mẹo 1 chút)
Nói thêm: Mình thường dùng cách này để test những code đơn giản trên 1 máy tính có security = High đấy
Bác anhtuan1066 ơi. các đại cao thủ đang chờ bác giải đáp đấy. Hổng lẻ dùng công cụ hỗ trợ sao?
 
Upvote 0
Web KT
Back
Top Bottom