Đố 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
 
Em cũng tham gia tí :
Anh muốn biến K tăng thì Anh cần khai báo biến Public. Ví dụ :
PHP:
Public K As Integer 
Private Sub CommandButton1_Click()
   K = K + 1
   Range("A1").Value = K
End Sub
hoặc anh dùng cách sau (có khác đôi chút)
PHP:
Private Sub CommandButton1_Click()
   Range("A1").Value = Range("A1").Value + 1
End Sub
TDN
</span></span>
 
Upvote 0
CÂU HỎI 2: Sub và Private Sub?
Sau khi hoàn tất câu hõi 1, giờ tôi sữa code 1 chút, đặt code vào 1 module rồi dùng Command Button đễ gọi Sub thông qua lệnh Call
PHP:
Sub Add()
     Cho code vào đây!
End Sub
Private Sub CommandButton1_Click()
     Call Add
End Sub
Hoàn toàn ko có vấn đề gì về cách viết này.. và các bạn cũng thấy các cao thủ đã từng viết kiểu như vậy!
Cho hỏi: Cách viết trong câu hỏi 1 là gọi trực tiếp code bằng Button, còn cách viết thứ 2 này thì gọi code thông qua lệnh Call... Vậy có gì khác nhau giữa 2 cách viết và tại sao đôi khi ta lại cần làm như vậy? Sao ko cho code trực tiếp vào mà lại thông qua Call Add chi cho mất công thế?
ANH TUẤN
 
Upvote 0
Nào, các bạn mới! Tham gia đi.
Hoặc chưa biết làm thì thử 2 cách của tedaynui, rồi cho ý kiến đúng sai.
Lần sau biết làm.
Nghĩa là tham gia theo khả năng của mình. Không ai cười đâu. Ai cũng bắt đầu như thế cả!
Mại dzô! Cuối năm miễn phí!
 
Upvote 0
anhtuan1066 đã viết:
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
ANH TUẤN

Theo em đoạn này thiếu Sub cộng với việc ta phải khai báo biến K.
Tuy nhiên em đang đọc tai liệu thì khai báo là Dim ...
Chứ còn private ... thi chưa hiểu (đừng cười nhé.... còn ngu quá)
hì... Không biết đúng không???
 
Lần chỉnh sửa cuối:
Upvote 0
Đúng và chưa đúng.
Có rồi đấy chứ
ta phải khai báo biến K.
Đúng nhưng chưa phải nguyên nhân.
bạn cố lên tí nữa!

Giải thích thêm:
- Khai báo Private cho cả biến và sub:
biến chỉ dùng trong 1 sub nơi nó được khai báo, Sub chỉ dùng riêng trong sheet nơi nó được khai báo.
- Muốn biến dùng chung cho cả work book (và sub cũng vậy), khai báo Public
- Muốn biến dùng chung cho nhiều work book (đang mở), khai báo Global
Cấu trúc:
Private/Public/Global Sub()/<tenbien>
Riêng biến và sub dùng chung phải khai báo trong Module - General - Declarations
(Nhờ các cao thủ xem dùm đúng hông nha)
 
Upvote 0
anhtuan1066 đã viết:
CÂU HỎI 2: Sub và Private Sub?
Sau khi hoàn tất câu hõi 1, giờ tôi sữa code 1 chút, đặt code vào 1 module rồi dùng Command Button đễ gọi Sub thông qua lệnh Call
PHP:
Sub Add()
     Cho code vào đây!
End Sub
Private Sub CommandButton1_Click()
     Call Add
End Sub
Hoàn toàn ko có vấn đề gì về cách viết này.. và các bạn cũng thấy các cao thủ đã từng viết kiểu như vậy!
Cho hỏi: Cách viết trong câu hỏi 1 là gọi trực tiếp code bằng Button, còn cách viết thứ 2 này thì gọi code thông qua lệnh Call... Vậy có gì khác nhau giữa 2 cách viết và tại sao đôi khi ta lại cần làm như vậy? Sao ko cho code trực tiếp vào mà lại thông qua Call Add chi cho mất công thế?
ANH TUẤN
Cách giải thích của em !
Cách gọi code thông qua lệnh call nhằm mục đích bố trí sắp xếp và quản lý chương trình cho khoa học hơn, nhất là đối với những chương trình lớn và phức tạp, có nhiều lệnh phải thực hiện nhiều lần, khi chúng ta cần đến một nhiệm vụ chúng ta không cần phải viết lại cả đoạn code thực hiện nhiệm vụ đó nữa, chỉ cần dùng lệnh call...
 
Upvote 0
anhtuan1066 đã viết:
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

Mình hôg phải lập trình viên, nên cũng hiểu tạm thế này thôi :D
K là biến cục bộ, khi thoát khỏi sub thì k sẽ trả về giá trị ban đầu, tức là 0, vì thể nếu nút command n lần thì cũng chỉ là 1 mà thôi,
nếu muốn range("A1").value tăng lên thì khai báo thêm
Mã:
 Dim k as integer
trước sub. Hôg biết vậy có đúng hôg nữa,hic
 
Upvote 0
vumian đã viết:
Mình hôg phải lập trình viên, nên cũng hiểu tạm thế này thôi :D
K là biến cục bộ, khi thoát khỏi sub thì k sẽ trả về giá trị ban đầu, tức là 0, vì thể nếu nút command n lần thì cũng chỉ là 1 mà thôi,
nếu muốn range("A1").value tăng lên thì khai báo thêm

Đúng rùi,
NHƯNG còn giải pháp sửa thì chưa cụ thể "khai báo thêm" trước sub (?) là ở đâu nhỉ (???) và tại sao làm thế (???).
Thử suy nghĩ xem sao
 
Upvote 0
Tức là vậy nè
Mã:
Dim k as integer
[COLOR=#000000][COLOR=#0000bb][/COLOR][COLOR=#007700]Private [/COLOR][COLOR=#0000bb]Sub CommandButton1_Click[/COLOR][COLOR=#007700]()
[/COLOR][COLOR=#0000bb]K [/COLOR][COLOR=#007700]= [/COLOR][COLOR=#0000bb]K [/COLOR][COLOR=#007700]+ [/COLOR][COLOR=#0000bb]1
Range[/COLOR][COLOR=#007700]([/COLOR][COLOR=#dd0000]"A1"[/COLOR][COLOR=#007700]).[/COLOR][COLOR=#0000bb]Value [/COLOR][COLOR=#007700]= [/COLOR][COLOR=#0000bb]K
End Sub [/COLOR][/COLOR]
[COLOR=#000000][COLOR=#0000bb][/COLOR][/COLOR] 
[COLOR=#000000][COLOR=#0000bb]Để cho nó thành biến toàn cục, thoát khỏi sub này, biến vẫn giữ nguyên giá trị đang có, sub khác mà gọi k thì là k có giá trị n lần click[/COLOR][/COLOR]
 
Upvote 0
Tôi có thễ nói nôm na theo cách hiễu của tôi về câu hõi 1 như sau:
-Biến K lúc đầu chưa có gì xem như = 0 thì đúng rồi...
-Khi chạy code, K sẽ tăng lên =1, đúng luôn
Nhưng khi chạy tiếp lần nữa thì mọi chuyện lại trở về từ đầu... Tức là K sẽ lại từ 0 chuyễn thành 1 mà ko hề biết rằng lần trước nó đã từng =1
Đễ ý xem trong này đâu có chỗ nào gọi là "nhớ" lại giá trị chạy lần trước... hi.. hi... Và nếu như thế thì khi chạy code lần thứ bao nhiêu biến K vẫn xem như còn "trinh nguyên".. từ 0 lại biến lên 1 mà ko bao giờ tăng dc lên 2, 3...
Chuyện khai báo biến là cần thiết nhưng chưa đũ trong trường hợp này... (khai tại đâu? Khai thế nào?).. Chính vì lẽ đó mà sẽ làm theo cách:
-Public K... hoặc Dim nằm trên cùng cũa Sub tạm xem như động tác cho nó "nhớ" giá trị lần trước... và nếu làm như cách này thì K có thể dùng cho những Sub khác
-Cells(1,1).Value = Cells(1,1).Value + 1 ... vùng nhớ chính là cell A1 luôn
--------------------------------
Câu 2:
Sub và Private Sub tôi có thễ hình dung nó giống như cái toilet của tôi và cái Toilet công cộng... he...he...
Cái Toilet công cộng thì ai cũng dùng dc, và ai cũng nhìn thấy nó nếu đi ngang qua... Ko tin cứ bấm Alt + F8 sẽ thấy ngay nó trong danh sách các macro...
Cái toilet cũa tôi là cũa riêng tôi... ai muốn dùng thì phãi vào nhà tôi mới thấy dc... Tôi đây chính là CommandButton1_Click... Và muốn dùng nó đương nhiên phãi thông qua tôi đễ vào nhà... Còn đi ngang qua cũng đương nhiên là sẽ ko thễ nhìn thấy... (Bấm Alt + F8 chã thấy nó tồn tại).. Chã thế mà nó ghi tên gọi Private đó sao? Ha.. ha..
Chính vì lẽ đó mà tùy theo từng trường hợp cụ thễ sẽ xài công cộng hay cá nhân... Nếu như tôi muốn xài lại em macro khi đạt 1 d/k nào đó thì hãy xài kiễu công cộng (Sub).. Lúc cần thì.. Call...
--------------------------
Tôi hiểu đến đây thì giãi thích đến đây!... Mong các cao thủ đóng góp ý kiến
ANH TUẤN

Anh Tuấn ơi, có thể dùng ví dụ khác được không anh ?
 
Chỉnh sửa lần cuối bởi điều hành viên:
Upvote 0
Đúng rùi, chính xác là khai báo K ở đầu module (có thế là module 1, sheet ..., this workbook chẳng hạn), cắt nghĩa thêm 1 chút

như Pmt0412 viết trên
pmt0412 đã viết:
iải thích thêm:
- Khai báo Private cho cả biến và sub:
biến chỉ dùng trong 1 sub nơi nó được khai báo, Sub chỉ dùng riêng trong sheet nơi nó được khai báo.
- Muốn biến dùng chung cho cả work book (và sub cũng vậy), khai báo Public
- Muốn biến dùng chung cho nhiều work book (đang mở), khai báo Global
Cấu trúc:
Private/Public/Global Sub()/<tenbien>
Riêng biến và sub dùng chung phải khai báo trong Module - General - Declarations
(Nhờ các cao thủ xem dùm đúng hông nha)


Tuy nhiên với biến thì ta không cần đặt chữ Private mặt định không viết (không viết public, global ) _. máy sẽ hiểu là Private

Như vumian khai báo trên tức là biến K là biến địa phương của module (tức là dùng trong module đó được - nhưng module khác ko dùng chung được dù có ở chung Workbook đi nữa)

Nói thêm về tại sao bài cua anhtuan1066 thì bấm mãi mà K vẫn là 1: Vì như a tuấn không khai báo gì cả với K -> khi có lệnh K=K+1 -> khi này máy mới khởi tạo biến K (và chỉ coi nó là private - biến địa phương của sub mà thôi - và mặc định ban đầu là 0) -> K=K+1 =0+1 -> K=1 -> do đó A1 =1, thoát khỏi Sub này thì biến được tự động xóa khỏi bộ nhớ
bấm nút lần tiếp theo nữa thì sub đó (CommandButton1_Click())lại chạy lại và thế là lại quá trình trên (khởi tạo K, ban đầu K có giá trị 0, K=K+1=0+1=1) -> kết quả K=1 -> nên A1 lại bằng 1
Vì thế dù có nhấn bao nhiêu lần thì điều lặp lại qtr trên Vì vậy ô A1 lun là 1

Còn nếu chúng ta khai báo ngoài sub (như vumian) thì dù thoát ra khỏi SUB (kết thúc) rồi thì K vẫn còn giữ nguyên giá trị (dĩ nhiên chỉ trong phiên làm việc hiện thời) -> vì thế cứ bấm nút gọi SUB này thì K cứ tăng lên 1 đơn vị

Nói thêm về sử dụng biến
- Khi sử dụng biến nào cần lưu ý mấy điểm sau:
+ sd biến nào thì tốt nhất chúng ta khai báo
+ Cân nhắc về phạm vi hoạt động của biến (có cần sd / lưu lại giá trị cho các sub khác, module khác, workbook khác không?)
+ Không lạm dụng biến dùng chung -> vì tốn bộ nhớ và khó quản lý
+ ....
mong các cao thủ viết thêm
 
Upvote 0
tigertiger đã viết:
Đúng rùi, chính xác là khai báo K ở đầu module (có thế là module 1, sheet ..., this workbook chẳng hạn), cắt nghĩa thêm 1 chút
Thêm chút bác nhé : Hoặc đầu Sub với khai báo :
PHP:
Static K

Thân!
 
Upvote 0
anhtuan1066 đã viết:
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
Khi chạy 1 sub, giá trị ban đầu của các biến ở trong sub đó sẽ dựa vào việc khai báo biến đó.

Có 2 TH xảy ra : (Tính trong trường hợp File vẫn mở)
1 .Giá trị của biến là kết quả cuối cùng trước đó mà nó được gán. Trong trường hợp này chúng ta đã sử dụng phương pháp lưu giữ biến (như trình bày ở trên), để lần sau sử dụng thì giá trị ban đầu của biến (đối với Sub đó)sẽ là giá trị cuối cùng mà biến vừa nhận được.

Việc này tương tự như khi ta mua bán hàng hóa. Giá gốc của hàng hóa chính là giá bán của lần mua bán trước đó.
Như vậy mỗi khi có hành động mua bán xảy ra (Sub hoạt động) thì giá gốc của hàng hóa (đối với hoạt động mua bán này) (giống như giá trị ban đầu của biến đối với SUB này) sẽ là giá mua của lần mua bán trước đó.

2. Giá trị của biến không được lưu giữ, có nghĩa là mỗi khi chạy, biến lại được làm mới một lần. Giá trị ban đầu của nó sẽ là NOTHING (Nếu là Text thì nó là ký tự rỗng, nếu là number thì nó là số 0 . . . ).

Việc này giống như số điểm của đội bóng trong một mùa bóng vậy. Cứ bắt đầu một mùa bóng, số điểm của các đội bóng là 0 điểm. Số điểm khi kết thúc mùa bóng sẽ chỉ được sử dụng trong mùa đó mà không được bảo lưu qua mùa sau.

Nói thì dài dòng, nhưng hy vọng các bạn đã hiểu rằng tại sao khi A1 luôn = 1

Thân!
 
Upvote 0
nhukhang đã viết:
Cách gọi code thông qua lệnh call nhằm mục đích bố trí sắp xếp và quản lý chương trình cho khoa học hơn, nhất là đối với những chương trình lớn và phức tạp, có nhiều lệnh phải thực hiện nhiều lần, khi chúng ta cần đến một nhiệm vụ chúng ta không cần phải viết lại cả đoạn code thực hiện nhiệm vụ đó nữa, chỉ cần dùng lệnh call...
Giải thích rất đúng. Khi 1 code sử dụng nhiều lần và sub nào cũng có thể gọi đến nó, sub ấy gọi là Procedure. Procedure (thủ tục) là thuật ngữ dùng chung trong lý thuyết lập trình của mọi ngôn ngữ, (VBA là 1 trong các ngôn ngữ).
 
Upvote 0
Cách gọi code thông qua lệnh call nhằm mục đích bố trí sắp xếp và quản lý chương trình cho khoa học hơn, nhất là đối với những chương trình lớn và phức tạp, có nhiều lệnh phải thực hiện nhiều lần, khi chúng ta cần đến một nhiệm vụ chúng ta không cần phải viết lại cả đoạn code thực hiện nhiệm vụ đó nữa, chỉ cần dùng lệnh call...

pmt0412 đã viết:
Giải thích rất đúng. Khi 1 code sử dụng nhiều lần và sub nào cũng có thể gọi đến nó, sub ấy gọi là Procedure. Procedure (thủ tục) là thuật ngữ dùng chung trong lý thuyết lập trình của mọi ngôn ngữ, (VBA là 1 trong các ngôn ngữ).

Nhưng phải bổ sung thêm là:

Khi 1 code sử dụng nhiều lần và sub nào cũng có thể gọi đến nó và có thể thay đổi với bộ số liệu đầu vào (truyền ) khi gọi đến nó
 
Upvote 0
Câu hỏi 3:
Tôi tạo 1 macro với mục đích copy vùng A1:A10 và Paste vào B1:B10... Tôi viết như sau:
PHP:
Sub Copy_Paste()
   Range("A1:A10").Copy
   Range("B1").Select
   Selection.Paste
   Application.CutCopyMode = False
End Sub
Thấy cũng rất hợp lý, vậy mà nó ko chạy...
Nếu thay đoạn Selection.Paste thành ActiveSheet.Paste hoặc Selection.PasteSpecial Paste:=xlPasteAll thì ko có vấn đề
Tại sao thế?
ANH TUẤN

Câu hỏi 4: Select
Tôi đặt name cho vùng Sheet1!A1:A10VUNG1
Trong 1 module, tôi viết 1 đoạn code đễ chọn VUNG1 như sau:
PHP:
Sub Chon()
    Range("VUNG1").Select
End Sub
Đứng tại Sheet1, Code chạy ko có vấn đê.. nhưng khi tôi chuyễn Refer to cũa VUNG1 thành Sheet2!A1:A10 rồi cũng đứng tại Sheet1 đễ chạy code thì bị báo lỗi...
Tại sao vậy?
ANH TUẤN
 
Chỉnh sửa lần cuối bởi điều hành viên:
Upvote 1
Web KT
Back
Top Bottom