Đố 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
 
Xin đố các bạn là làm sao đếm được trên máy mình mở bao nhiêu Excel section (Có nghĩa là trong các workbook đó mình không thể nhìn thấy trong Switch Windows)?

cuối năm giải quyết hàng tồn còn đi ăn tết , ý anh là đếm coi có bao nhiêu process đang chạy có tên là excel.exe ? vậy ta dùng lệnh

Mã:
GetObject("winmgmts:").ExecQuery("Select * from Win32_Process Where Name = 'EXCEL.EXE'").Count
 
Upvote 0
cuối năm giải quyết hàng tồn còn đi ăn tết , ý anh là đếm coi có bao nhiêu process đang chạy có tên là excel.exe ? vậy ta dùng lệnh

Mã:
GetObject("winmgmts:").ExecQuery("Select * from Win32_Process Where Name = 'EXCEL.EXE'").Count
Có phải làm gì nữa không anh? Chứ em chạy dòng đó bị như hình

Excel.jpg
 
Upvote 0
Câu đố này có lẽ không vui lắm. Nhưng cứ đố đại:

Tôi có một Project, trong đó có cái moduleX, với code như sau:

Option Explicit

Sub t1()
a = 1
msgbox a
End Sub

Sub t2()
Dim a
a = 1
msgbox a
End Sub

Sub t3()
Dim a As Integer
a = 1
msgbox a
End Sub

Câu hỏi: 3 cái sub này khác nhau như thế nào?
 
Upvote 0
Câu đố này có lẽ không vui lắm. Nhưng cứ đố đại:

Tôi có một Project, trong đó có cái moduleX, với code như sau:

Option Explicit

Sub t1()
a = 1
msgbox a
End Sub

Sub t2()
Dim a
a = 1
msgbox a
End Sub

Sub t3()
Dim a As Integer
a = 1
msgbox a
End Sub

Câu hỏi: 3 cái sub này khác nhau như thế nào?

thưa anh , sub t1() khác t2() và t3() ở chỗ không có dòng Dim a
Sub t2() khác t3() ở chỗ không có chữ As Integer --=0--=0
 
Upvote 0
Vì có câu lệnh Option, nên Sub T1() sẽ báo lỗi.
 
Upvote 0
Câu đố này có lẽ không vui lắm. Nhưng cứ đố đại:

Tôi có một Project, trong đó có cái moduleX, với code như sau:
...
Câu hỏi: 3 cái sub này khác nhau như thế nào?

(Không biết có giống với bài chứng minh: 1+1=2 không anh?)
Khác: Không và có khai báo biến a, và cách khai báo biến a.

Nếu a=1 thì dùng kiểu byte,
Mã:
Option Explicit
Sub t4()
dim a as byte
a = 1
msgbox a
End Sub

và nếu chỉ có 1 giá trị =1 không đổi thì
Mã:
Option Explicit
const a as byte = 1
Sub t5()
msgbox a
End Sub
 
Upvote 0
(Không biết có giống với bài chứng minh: 1+1=2 không anh?)
Khác: Không và có khai báo biến a, và cách khai báo biến a.

Nếu a=1 thì dùng kiểu byte,

Khai báo biến: nóng (gần ý tôi rồi. Thử suy diễn thêm nữa xem)
Dùng kiểu byte: nguội ngắt (đối với tôi, byte và integer khác nhau chỉ 3 bytes là cùng, không đáng gọi là tiền lẻ, trừ phi bạn có mảng hàng trăm ngàn phần tử)

Chú: giá trj 1 chỉ là một ví dụ biến được sử dụng. Bạn có thể cho a = CInt([a1].value)
 
Upvote 0
Khi Bồ Đề Lão Tổ gõ vào đầu con khỉ họ Tôn 3 cái thì là khen hay chửi?

Lần này thì chê: nếu chỉ biết nhìn câu nói trên quan điểm khen hay chửi thì chí học tập kém quá.

gõ đầu 3 cái không phải để khen hay chửi , mà để kiểm tra độ cứng của cái đầu --=0--=0
em đang mệt bỗng được nghe anh Vetmini chê thì tự nhiên thấy tươi tỉnh trở lại ngay , cám ơn anh .
Giờ ta nói lại về câu hỏi nhé
Với sự khác nhau về câu chữ giữa 3 sub đã nêu ở trên (như kiểu con cá khác con mực vì nó có xương ) , sự khác nhau này gây ra hậu quả gì ?

sub t1() không khai báo biến đồng thời có lệnh Option Explicit
Thủ tục này sẽ chạy khi vô tình có 1 biến toàn cục nào đó có tên là a , ngược lại sẽ báo lỗi

Sub t3() có khai báo biến a là kiểu Integer , khi biên dịch , hệ thống sẽ cấp cho a 1 vùng nhớ thích hợp , và cố định dành cho kiểu Integer

Sub t2() khai báo a , nhưng không xác định kiểu , trình biên dịch tự hiểu biến a mang kiểu mặc định là Variant . Vì không biết a là "cái giống gì" , nên hệ thống không thể cấp trước cho a 1 vùng nhớ cố định , hệ quả là trong khi code đang chạy , mỗi lần gặp lệnh gán

Mã:
a = Some value

trình biên dịch mới thực hiện động tác xem coi biến a là "cái giống gì" , từ đó mới cấp cho a 1 vùng nhớ thích hợp .

đấy là những suy nghĩ nông cạn của em , mong anh góp ý .
Mấy bữa trước nghe nói anh bị bệnh nan y , thật em cũng buồn , sợ thiếu mất người chửi mình , nay thấy anh vẫn khỏe mạnh , em rất vui
--=0--=0
Chúc anh nhiều sức khỏe , luôn đồng hành cùng diễn đàn .
 
Upvote 0
Đúng gần hết rồi. Suy diễn thêm chút nữa đi.

Gợi ý 1: nhiệm vụ của cái câu Option Explicit

Gợi ý 2: kết nối sớm và kết nối trễ

trình biên dịch mới thực hiện động tác xem coi biến a là "cái giống gì" , từ đó mới cấp cho a 1 vùng nhớ thích hợp


Không hoàn toàn sai. Nhưng động tác này xảy ra lúc chạy chứ không phải lúc biên dịch -> kết nối trễ
 
Upvote 0
Đúng gần hết rồi. Suy diễn thêm chút nữa đi.

Gợi ý 1: nhiệm vụ của cái câu Option Explicit

Gợi ý 2: kết nối sớm và kết nối trễ



Không hoàn toàn sai. Nhưng động tác này xảy ra lúc chạy chứ không phải lúc biên dịch -> kết nối trễ
[/COLOR]

thử lại lần nữa vậy , lệnh Option Explicit làm cho trình biên dịch phải thực hiện kết nối sớm bao nhiêu có thể , nếu không có Option Explicit thì sub t1() và t2() là như nhau , đều là kết nối trễ . --=0--=0
 
Upvote 0
Biến toàn cục nằm trong vùng nhớ heap (vùng nhớ chính), biến cục bộ nằm trong vùng nhớ stack (vùng nhớ thuộc về hàm/sub)
Khi khởi chạy Project là các biến toàn cục đã được thành lập rồi. Việc thành lập khong liên quan đến kết nối sớm/trễ. Việc định dạng mới liên quan đến kết nối.

Minh hoạ kêt nói trễ và sớm như sau: (minh hoạ để dễ hiểu chứ không phải để giải thích kỹ thuật, bởi vì kỹ thuật thực hiện còn tuỳ theo ngôn ngữ và hệ điều hành)
Các biến kết nối sớm, ví dụ như Integer được trình dịch cho vùng nhớ ngay lúc Dim. Khi gặp lệnh gán (dấu =) thì chương trình chỉ việc chép kết quả của biểu thức bên phải dấu gán vào vùng nhớ đó. String tuy không có vùng nhớ xác định, nhưng trình dịch cũng đã cho nó vùng chỉ định dạng của nó rồi, cho nên cũng có thể coi như kết nối sớm
Các biến variant được trình dịch cho vào bảng kết nối trễ. Lúc đó nó chỉ có tên chứ chưa có dạng. Đến lúc được gán trị nó mới được trỏ vào cái kết quả của biểu thức bên phải dấu gán (thường là một cóp py của cái kết quả này). Và vì vậy nó mang kiểu của cái nó trỏ vào, cho đến khi có lệnh gán trỏ nó vào kiểu khác.

Điều trên giải thích điểm khác nhau giữa sub t2() và t3(). Nói thẳng ra, biến a trong t3() bắt buộc phải là Integer, biến a trong t2() có thể là cái gì cũng được.

Như vậy, khi tôi đọc code, cần debug code hay phát triển thêm code, tôi có thể dựa trên đặc tính trên để khẳng định rằng ngừoi viết code muốn xác định trước nhiệm vụ của a trong t3() luôn luôn là Integer, và a trong t2() thì chưa xác định, có lúc là kiểu này nhưng cũng có lúc kiểu khác.

Ba cái subs trên khác nhau không phải do viết theo kiểu lười biếng, mà chúng có lý do của chúng. Nếu có sự lười biếng thì chỉ là lười biếng đặt tên (tên 'a' chả minh bạch chút nào)

Nhiệm vụ của 'Option Explicit':
Vì có lệnh này, khi đọc qua t1(), tôi nhận ra ngay a là biến toàn cục được khai báo Public ở 1 moduleY hay Z nào đó. Bởi vì nếu không phải biến toàn cục, trình dịch còn lâu mới chấp nhận.
Nếu khong có lệnh này thì tôi không thể biết ngay rằng đây là biến toàn cục hay không. Néu quên dùng lệnh Find để tìm khắp các module thì có mà chết.
Khi nhận ra nó là biến toàn cục thì tôi cũng đồng thời biết rằng t1() không phải là hàm độc lập. Khi chạy nó có nhiều khả năng ảnh hưởng đến các hàm khác dùng chung biến này. Và mỗi lần chạy chưa chắc nó ra kết quả giống nhau.
Ví dụ bạn thay lệnh a = 1 với
a = a + 1
Mỗi lượt chạy t1() sẽ cho bạn kết quả khác.

Tóm lại, cái khác nhau giữa 3 cái hàm trên không hẳn nằm ở chỗ người viết lười hay siêng "khai báo biến tường minh". Ngừoi viết code này có dụng ý riêng cho mỗi loại khai báo.
 
Lần chỉnh sửa cuối:
Upvote 0
Các bạn xem clip bên dưới nhé:

[video=youtube;O8F5NNdRVfg]https://www.youtube.com/watch?v=O8F5NNdRVfg&feature=youtu.be[/video]
 
Upvote 0
Các bạn xem clip bên dưới nhé:

[video=youtube;O8F5NNdRVfg]https://www.youtube.com/watch?v=O8F5NNdRVfg&feature=youtu.be[/video]

ở trên người ta có nói rồi mà

cuối năm giải quyết hàng tồn còn đi ăn tết , ý anh là đếm coi có bao nhiêu process đang chạy có tên là excel.exe ? vậy ta dùng lệnh



Mã:
GetObject("winmgmts:").ExecQuery("Select * from Win32_Process Where Name = 'EXCEL.EXE'").Count

vậy xin anh Hai Lúa Miền Tây cho biết sự khác nhau "winmgmts:" và "winmgmts:root\CIMV2"
 
Upvote 0
1. ở trên người ta có nói rồi mà



2. vậy xin anh Hai Lúa Miền Tây cho biết sự khác nhau "winmgmts:" và "winmgmts:root\CIMV2"

1. Xin lỗi tôi đã thấy câu trả lời này ở trên, nên tôi đưa đáp án của tôi ra mà thôi.
2. Tôi chỉ biết vận dung, còn để phân tích thì với trình độ của tôi không thể trả lời cho bạn được.
 
Upvote 0
Web KT
Back
Top Bottom