Đố 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
 
Chi tiết thứ nhất liên quan đến cách hoạt động của vòng lặp For trong VBA (nhấn mạnh, VBA. Có nghĩa là ngôn ngữ khác chưa chắc hoạt động như thế)
Chi tiết thứ hai liên quan đến cách sử dụng biến đếm vòng lặp.
Về triết lý của vòng FOR thì ở ngôn ngữ nào cũng thế. Nhưng về chi tiết thì có thể có khác biệt trong mỗi ngôn ngữ
Vd. như trong Delphi (Object Pascal):
0. Biến điều khiển i phải có kiểu thứ tự. Tức vd. BYTE, WORD (trong VBA là Integer), Integer (trong VBA là Long). Không thể là Double hay Single được. Nếu thế thì không compile project được.
1. Biến điều khiển i phải là biến cục bộ (local variable). Khai báo biến toàn cục (global) thì vẫn compile project được, chạy nhiều khi vẫn ra kết quả. Nhưng khi compile thì sẽ có cảnh báo (Warning). Tức tôi lưu ý, còn anh làm khác đi thì tôi không đảm bảo luôn luôn không có trục trặc.
2. Trong vòng FOR không được phép thay đổi biến điều khiển i (vd. i := i + 1). Nếu thay đổi i trong vòng FOR thì chả có warning gì cả mà là Error và không thể compile được project.
3. Sau khi ra khỏi vòng FOR một cách tự nhiên thì biến điều khiển không xác định (undefined). Dùng biến i sau FOR trong trường hợp này thì vẫn compile project được, chạy nhiều khi vẫn ra kết quả. Nhưng khi compile thì sẽ có cảnh báo (Warning). Tức tôi lưu ý, còn anh làm khác đi thì tôi không đảm bảo biến i luôn đúng, luôn xác định.
Nhưng nếu ra khỏi vòng FOR bằng code (trong VBA là Exit For, trong Delphi là Break) thì sau FOR biến i có giá trị như lúc ra khỏi For.
Trong VBA sau FOR biến i luôn xác định.
 
Upvote 0
Lý thuyết về vòng lặp For của VBA:

Cũng như mọi ngôn ngữ khác, VBA coi vòng lặp như là một cụm code. Biến điều khiển (biến đếm), biến bước (step), và biến giới hạn (to) có thể coi như là tham nạp vào cụm code. Đến đây thì hết giới hạn "cũng như".
Riêng đối với VBA thì biến đếm là tham byRef, và biến bước, biến giới hạn là mọt hình thức đặc biệt giữa byVal và byRef.
ByRef có nghĩa là hoàn toàn có thể thay đổi, khong cần giới thiệu thêm. Còn hình thức đặc biệt giữa byVal và byRef ra sao mới là chỗ quan trọng:
Khi bạn khai báo câu For bienDem = khoiDau to ketThuc step buoc (nếu không có step thì bước được hiểu ngầm là 1) thì VBA làm các bước TUẦN TỰ sau:
Lưu ý rằng chỉ có bienDem mới bắt buộc là biến, ba cái còn lại có thể là một hằng, 1 biến hay một biểu thức
- Tính giá trị của biểu thức khoiDau, và gán kết quả cho bienDem
- Tính giá trị của biểu thức ketThuc và gán vào 1 biến tạm, kể từ phút này, biến tạm là mọt HẰNG số xác định điểm cuối mà bienDem cần so sánh, ketThuc hết nhiệm vụ của nó. Nếu là một biến thì nó toàn quyền thay đổi mà không hề ảnh hưởng đến hằng kia.
- Tính giá trị của biểu thức buoc và gán vào 1 biến tạm, kể từ phút này, biến tạm là mọt HẰNG số xác định bước tăng của bienDem, tương tự như ketThuc, buoc hết nhiệm vụ của nó
- VBA bắt đầu xét xem có thể tiến vào vòng lặp, tức là bienDem <= trị hằng copied từ ketThuc (nếu trị của buoc là âm thì ngược lại) ở trên

Từ hằng được viết hoa ở trên để nhấn mạnh rằng chúng khong thay đổi nữa. Bên trong vòng lặp, bạn có thay đổi ketThuc hay buoc thì vẫn không ảnh hưởng gì đến vòng lặp. Ví dụ khởi đầu bạn đặt ketThuc là 10, bên trong vòng lặp sửa lại thành 5 thì vòng lặp vẫn chạy đủ đến 10. Tuy nhiên, thay đổi bienDem thì có ảnh hưởng. Tính chất này rất quan trọng để tôi giải thích sự khác nhau của hai đoạn code nhỏ trong câu đố.

Cái khác nhau thứ nhất của 2 đoạn code trên là khi diều kiện thoả; với code 1, vòng lặp CHẮC CHẮN thoát; với code 2, vòng lặp CHƯA CHẮC thoát, vì bên trong vòng lặp, tôi có thể đã sửa ketThuc nhỏ hơn giá trị ban đầu của nó!

Thực hành vòng lặp For của VBA:

Thực hành căn bản thì bạn nào cũng học qua rồi. Khong cần phải nhắc lại. Tôi chỉ nói ra đây mọt vài ứng dụng đặc biệt.

Ứng dụng đặc biệt nhất là khi bạn có sử dụng Exit For.
Hầu hết mọi trường hợp, bạn Exit For khi có một điều kiện nào đó. Vậy thì sau khi thoát khỏi vòng lặp, bạn muốn biét có phải do điều kiện ấy thì sao? Dễ dàng, bạn chỉ viẹc xét lại. Nhưng nếu điều kiện ấy rất rắc rối, là mọt hàm chẳng hạn, thì sao? Dễ dàng, bạn dùng một biến Boolean để chứa trị. Tuy nhiên, cách gọn hơn nữa là xét xem bienDem có vượt quá ketThuc hay không.

Ứng dụng này nói lên cái khác nhau thứ hai của hai đoạn code nhỏ trong câu đố: nếu dùng đoạn code 2 thì không thể dùng biến đếm để thử xem vòng lặp có thoát sớm hay không.

Qua phần thứ nhì của câu đố, tôi hỏi "khi nào dùng code 2"? Câu trả lời là rất hiếm khi. Nhưng tôi đã từng làm rồi (*). Là khi trong code trước đó (cũng trong vòng lặp, nhưng trước phần gán = ketThuc) tôi có một điều kiện khác để Exit For. Và tôi muốn xem lại điều kiện này sau vòng lặp. Thoát bằng Exit For thì luôn luôn biến đếm nằm trong giới hạn. Thoát bằng đièu kiện vòng lặp thì luôn luôn biến đếm vượt ngoài điều kiện ban đầu của vòng lặp (lưu ý, tôi dùng từ ban đầu để phân biệt rằng nếu bên trong vòng lặp bạn thay đổi biến giới hạn thì bạn không thể dùng nó để so sánh được nữa)

(*) code như vậy là trái với luật chuyên nghiệp. Nhưng đôi khi ngộ biến phải tùng quyền.
 
Upvote 0
Em làm thử như anh @huuthang_bd , chọn luôn từ A1 đến A10 vẫn được:
[A1:A10].copy [C1]

Cái này mình copy 1 ô vẫn dũng kiểu đó, công thức gọn hè. Cảm ơn anh nhiều nhé!

Code trên sẽ chép công thức. Ví dụ ô A2 của bạn là công thức A2 = B1 thì tại C2 là công thức C2=D1.
Chú ý là yêu cầu chép value.
 
Upvote 0
Code trên sẽ chép công thức. Ví dụ ô A2 của bạn là công thức A2 = B1 thì tại C2 là công thức C2=D1.
Chú ý là yêu cầu chép value.
Cảm ơn @haonlh, mình thử lại nhé:
code [A1,A2:A10].Copy [C1] : nếu range [A1:A10] tô vàng thì sẽ sao chép vừa giá trị, vừa màu tô vàng.
code [C1:C10] = [A1:A10].Value: chỉ copy giá trị.
 
Upvote 0
Không phải cái tên của nó đã nói lên tất cả ý nghĩa rồi sao? Hay bạn muốn so sánh nó với ActiveWorkbook?
Tên của nó thì cũng có phần sát nghĩa, nhưng em hỏi là dưới góc nhìn của một VBAer thì nó là gì?
Ps: Nó phức tạp hơn mọi người từng nghĩ về nó.
 
Upvote 0
Trong vba, ThisWorkbook là cái gì?
Mình chả biết nó là cái gì cả trong ví dụ sau:
PHP:
Sub GPE()
 Dim ThisWorkbook As Object, WF As Object

 Set ThisWorkbook = Application.WorksheetFunction
 Set WF = Range("A9:A2")
 MsgBox ThisWorkbook.Sum(WF), , "0"
 MsgBox ThisWorkbook.Sum(Range("A2:A9")), , "1"
End Sub
 
Upvote 0
Mình chả biết nó là cái gì cả trong ví dụ sau:
PHP:
Sub GPE()
 Dim ThisWorkbook As Object, WF As Object

 Set ThisWorkbook = Application.WorksheetFunction
 Set WF = Range("A9:A2")
 MsgBox ThisWorkbook.Sum(WF), , "0"
 MsgBox ThisWorkbook.Sum(Range("A2:A9")), , "1"
End Sub
Đoạn code trên thì tính làm gì, nó là một biến thuộc kiểu object thôi anh. Nếu ta định nghĩa sờ sờ thế kia thì không tính. Ví dụ có mỗi một modul mà ta nhập chẳng hạn.

sub Thu()
msgbox thisworkbook.path
end sub
 
Upvote 0
Hiểu kiểu nông dân là vầy : ThisWorkbook là Cha là Mẹ của cái File Excel đó .............. Nếu ko có Nó là File Excel đó Tèo Téo Teo .............. Xong đơn Giản ko phải nghĩ_)()(-,,,,,,,
 
Upvote 0
Upvote 0
Mới nghiên cứu cái này thấy hay hay nên mang lên đây đố luôn :D
Câu hỏi: Làm sao lấy được Công thức thực tế áp dụng cho Conditional Formatting của một ô.
 

File đính kèm

  • FormatConditionFormula.xlsm
    14.7 KB · Đọc: 12
Upvote 0
Web KT
Back
Top Bottom