Đố 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
 
Xác định 1 chuổi có tồn tại trong 1 file hay không?

Bài toán này với Excel 2003 là quá dể dàng: Dùng FileSearch, nhưng còn Excel 2007 thì sao?
Ví dụ: Ta muốn biết từ khóa "GPE" có tồn tại trong file D:\Test.xls thì làm thế nào?
Các bạn thử nghĩ đến tình huống này xem, biết đâu có lúc cần đến
Ghi chú:
- Chuổi tìm không cần phân biệt chữ HOA hay thường
- Code phải chạy được trên Excel 2007
-------------------------------------------------------------------------------------------------------
Nói thêm:
Bài toán này tôi tin chắc rằng cho dù các bạn có search khắp google cũng e rằng không tìm thấy câu trả lời dù đã từng có rất nhiều người quan tâm... Tuy nhiên, đã là ĐỐ VUI thì các bạn cứ yên tâm rằng code không hề phức tạp tí nào
 
Upvote 0
Đóng 1 file .EXE đang chạy

Trước tiên mời các bạn xem bài này:
Đóng file .exe đã mở bằng Shell như thế nào?
Ở đây người ta cần 1 code có khả năng đóng 1 file EXE đang chạy! Giải pháp cũng đã có rồi và nếu như search trên google các bạn sẽ thấy người ta đều dùng giải pháp này (hộ trợ bằng hàm API)
Xin hỏi: Liệu có code nào ngắn gọn hơn không? (ngắn cở 1 vài dòng càng tốt)
 
Upvote 0
Anh ơi, code sau không biết có đúng ý anh không?
Mã:
Sub Close_Process()
Dim sCloseProcess As String

sCloseProcess = "TASKKILL /F /IM Excel.exe"
Shell sCloseProcess , vbHide

End Sub

Lê Văn Duyệt
 
Upvote 0
Anh ơi, code sau không biết có đúng ý anh không?
Mã:
Sub Close_Process()
Dim sCloseProcess As String
 
sCloseProcess = "TASKKILL /F /IM Excel.exe"
Shell sCloseProcess , vbHide
 
End Sub

Lê Văn Duyệt
Chính xác! Và tôi nghĩ đây là cách ngắn gọn nhất!
Còn câu trên Duyệt làm luôn đi.. cũng có liên quan đến lệnh DOS như câu này đấy!
Thử nghiên cứu lệnh FIND trong DOS xem! Nó có khả năng phát hiện 1 chuổi nào đó có tồn tại trong 1 file hay không!
Hãy xem hình:

untitled.JPG

Vấn đề còn lại là làm sao áp dụng được lệnh này vào VBA (quá dể)
 

File đính kèm

  • untitled.JPG
    untitled.JPG
    58.7 KB · Đọc: 81
Lần chỉnh sửa cuối:
Upvote 0
Vòng lập FOR có thể nhanh hơn không?

Tôi thường đánh số thứ tự cho 1 cột bằng cách dùng Evaluate("ROW(R:R)")
Ví dụ đoạn code này:
PHP:
Sub Test1()
  Dim TG As Double
  TG = Timer
  Range("A:A").Value = Evaluate("ROW(R:R)")
  MsgBox Format(Timer - TG, "0.000000000")
End Sub
Các bạn hãy cho biết nếu tôi dùng vòng lập For.. Next để làm công việc đánh STT này thì liệu tốc độ làm việc có thể bằng với code trên hay không?
(Tôi nghĩ thậm chí còn hơn nữa đấy)
-------------------------------
Hãy dùng Excel 2007 với 1,048,576 dòng mà thử nghiệm cho ngon ăn nhé
 
Upvote 0
Tôi thường đánh số thứ tự cho 1 cột bằng cách dùng Evaluate("ROW(R:R)")
Ví dụ đoạn code này:
PHP:
Sub Test1()
  Dim TG As Double
  TG = Timer
  Range("A:A").Value = Evaluate("ROW(R:R)")
  MsgBox Format(Timer - TG, "0.000000000")
End Sub
Các bạn hãy cho biết nếu tôi dùng vòng lập For.. Next để làm công việc đánh STT này thì liệu tốc độ làm việc có thể bằng với code trên hay không?

Theo em thì nếu dùng For... Next tốc độ sẽ không bằng việc dùng Evaluate. Em có nói ở đây, chắc anh chưa đọc.

Lê Văn Duyệt
 
Upvote 0
Theo em thì nếu dùng For... Next tốc độ sẽ không bằng việc dùng Evaluate. Em có nói ở đây, chắc anh chưa đọc.

Lê Văn Duyệt
Chưa chắc đâu, ít nhất là với bài này!
Mời nghiên cứu tiếp
(Tôi thí nghiệm mấy chục lần trên cả Excel 2003 và 2007 rồi mới dám.. đố ấy chứ... Ẹc... Ec...)
 
Upvote 0
Chưa chắc đâu, ít nhất là với bài này!
Mời nghiên cứu tiếp
(Tôi thí nghiệm mấy chục lần trên cả Excel 2003 và 2007 rồi mới dám.. đố ấy chứ... Ẹc... Ec...)

Ẹc...Ẹc...Chán anh quá anh nói luôn đi... Ẹc ... Ẹc... Anh nói ghét cái Excel 2007 mà... Ẹc...Ẹc...

Lê Văn Duyệt
 
Upvote 0
Ẹc...Ẹc...Chán anh quá anh nói luôn đi...
Nếu dùng For... Next bình thường, quét đến đâu điền dữ liệu đến nấy thì lết bánh là cái chắc... Nhưng nếu ta gán giá trị STT vào các phần tử của 1 Array, xong vòng lập ta quăng Array này vào vùng dữ liệu luôn thì khác à nha
PHP:
Sub Test2()
  Dim i As Long, Arr() As Long, TG As Double
  TG = Timer
  ReDim Arr(1 To Cells.Rows.Count, 1 To 1)
  For i = 1 To Cells.Rows.Count
    Arr(i, 1) = i
  Next
  Range("C:C").Value = Arr
  MsgBox Format(Timer - TG, "0.000000000")
End Sub
Thử nghiệm sẽ biết câu trả lời ---> Tôi thử nhiều lần và thấy tốc độ gần như tương đương nhau (có đôi lúc cách dùng vòng lập này còn cho tốc độ cao hơn)
Từ thí nghiệm này ta rút ra kết luận:
- Với công việc có liên quan đến vòng lập, ta không nên làm theo kiẻu quét đến đâu ra kết quả đến nấy
- Chúng ta nên làm công tác "chuẩn bị" theo kiểu "thu gom"... để khi hoàn tất vòng lập là "cạp" 1 cái xong mọi thứ
- Phương pháp này sẽ đẩy tốc độ lên cao đến không ngờ
--------------------------------------------------------------------------------------------------
Anh nói ghét cái Excel 2007 mà... Ẹc...Ẹc...
Ghét, bởi vậy tôi đâu có cài, chỉ xài Portable để mở file của người khác thôi!... Ẹc... Ẹc...
--------------------------------------------------------------------------------------------------
Tôi biết chắc Duyệt vẫn dùng cách này thường xuyên, có điều bất chợt nên chưa nghĩ đến đấy thôi (thế nên mới dám đố, gọi là đánh bất ngờ, địch không kịp trở tay... Ẹc... Ẹc...)
Có điều:
Cái này thì chẳng thú vị gì cả ---> Mình ta độc diển.. vui gì.. ai ơi!
 

File đính kèm

  • STT.rar
    21.6 KB · Đọc: 31
Upvote 0
Gởi Anh Tuấn,

Nếu xét hai thủ tục trên, em thấy rằng việc so sánh như anh không công bằng.

Mã:
Sub Test1()
  Dim TG As Double
  TG = Timer
  [A:A] = [ROW(R:R)]
  [E1] = Format(Timer - TG, "0.000000000")
End Sub
Với thủ tục này thì phải Evaluate từng hàng một.

Trong khi thủ tục này:
Mã:
Sub Test2()
  Dim i As Long, Arr() As Long, TG As Double
  TG = Timer
  ReDim Arr(1 To Cells.Rows.Count, 1 To 1)
  For i = 1 To Cells.Rows.Count
    [COLOR="Red"][B]Arr(i, 1) = i[/B][/COLOR]
  Next
  Range("B:B").Value = Arr
  [G1] = Format(Timer - TG, "0.000000000")
End Sub
Chỉ gán giá trị.

Để cho công bằng thì ta thử cái này xem sao:
Mã:
Sub Test3()
    Dim i As Long, Arr() As Long, TG As Double
    TG = Timer
    ReDim Arr(1 To Cells.Rows.Count, 1 To 1)
    For i = 1 To Cells.Rows.Count
       [COLOR="Red"] Arr(i, 1) = Cells(i, 1).Row[/COLOR]
    Next
    Range("C:C").Value = Arr
    [I1] = Format(Timer - TG, "0.000000000")
End Sub

Thực sự ra khi làm việc với một vùng dữ liệu, thì chuyển vùng dữ liệu này qua mảng, rồi làm việc với mảng này, xong đưa lại vùng.
Đây là cách mà các VBA Expert thường khuyên nên thực hiện
. (Em sẽ đưa cái này vào đây)


Lê Văn Duyệt
PS: Em phải tham khảo một số nguồn.
 
Lần chỉnh sửa cuối:
Upvote 0
Gởi Anh Tuấn,

Nếu xét hai thủ tục trên, em thấy rằng việc so sánh như anh không công bằng.

Mã:
Sub Test1()
  Dim TG As Double
  TG = Timer
  [A:A] = [ROW(R:R)]
  [E1] = Format(Timer - TG, "0.000000000")
End Sub
Với thủ tục này thì phải Evaluate từng hàng một.

Trong khi thủ tục này:
Mã:
Sub Test2()
  Dim i As Long, Arr() As Long, TG As Double
  TG = Timer
  ReDim Arr(1 To Cells.Rows.Count, 1 To 1)
  For i = 1 To Cells.Rows.Count
    [COLOR=Red][B]Arr(i, 1) = i[/B][/COLOR]
  Next
  Range("B:B").Value = Arr
  [G1] = Format(Timer - TG, "0.000000000")
End Sub
Chỉ gán giá trị.

Để cho công bằng thì ta thử cái này xem sao:
Mã:
Sub Test3()
    Dim i As Long, Arr() As Long, TG As Double
    TG = Timer
    ReDim Arr(1 To Cells.Rows.Count, 1 To 1)
    For i = 1 To Cells.Rows.Count
       [COLOR=Red] Arr(i, 1) = Cells(i, 1).Row[/COLOR]
    Next
    Range("C:C").Value = Arr
    [I1] = Format(Timer - TG, "0.000000000")
End Sub
Lê Văn Duyệt
PS: Em phải tham khảo một số nguồn.
Vậy là Duyệt hiểu sai ý của tôi rồi
Tôi đâu cố ý so sánh Evaluate với For... Next ---> Chỉ muốn nói rằng trong 1 số trường hợp khi dùng For... Next, ta vẫn có cách để tăng tốc cho nó bằng những xảo thuật riêng!
Bài trên chỉ đưa file giả lập để chúng ta tìm cách gì đó khi dùng For.. next sao cho đạt được tốc độ như khi dùng Evaluate
Mục đích cuối cùng là: TĂNG TỐC CHO VÒNG LẬP... Chỉ vậy thôi!
 
Lần chỉnh sửa cuối:
Upvote 0
Vậy là Duyệt hiểu sai ý của tôi rồi
Tôi đâu cố ý so sánh Evaluate với For... Next ---> Chỉ muốn nói rằng trong 1 số trường hợp khi dùng For... Next, ta vẫn có cách để tăng tốc cho nó bằng những xảo thuật riêng!
Bài trên chỉ đưa file giả lập để chúng ta tìm cách gì đó khi dùng For.. next sao cho đạt được tốc độ như khi dùng Evaluate
Mục đích cuối cùng là: TĂNG TỐC CHO VÒNG LẬP... Chỉ vậy thôi!

Trời, vậy mà em cứ tưởng. Mà theo cách lập luận của anh, em nghĩ không chỉ em tưởng vậy mà người khác cũng tưởng vậy. Ẹc...Ẹc...

Anh ơi, theo em nghĩ "Không phải tăng tốc cho vòng lập" mà là tăng tốc cho các đoạn mã xử lý mới đúng... Ẹc... Ẹc...

Lê Văn Duyệt
 
Upvote 0
Trời, vậy mà em cứ tưởng. Mà theo cách lập luận của anh, em nghĩ không chỉ em tưởng vậy mà người khác cũng tưởng vậy. Ẹc...Ẹc...

Anh ơi, theo em nghĩ "Không phải tăng tốc cho vòng lập" mà là tăng tốc cho các đoạn mã xử lý mới đúng... Ẹc... Ẹc...

Lê Văn Duyệt
Tôi thấy Duyệt có bài viết:
Tăng tốc cho code VBA của bạn
Chắc là phải thêm rất nhiều bài viết nữa... Vì cái vụ TĂNG TỐC này có thể nói là: NÓI HOÀI KHÔNG HẾT (đôi lúc làm thực tế mới phát hiện ra)
---------------------------------------
Giờ có 1 câu đố khác đây:
Đố các bạn biết làm thế nào để khi MsgBox hiện ra mà ta vẫn có thể Select cell thoải mái
Nói thêm: Cái MsgBox mà tôi đề cập ở đây nói đúng hơn là 1 control có dạng như MsgBox (tức cũng có nút OK, Yes, No, Cancel.. vân vân)
(Cái trò này hơi... khoai đây)
 
Lần chỉnh sửa cuối:
Upvote 0
Một câu hỏi khá thú vị:
Một câu hỏi khá thú vị đã viết:
Định dạng tập tin *.xls có thể lưu được bao nhiêu hàng (row)?

Các bạn hãy thử tìm hiểu xem?

Lê Văn Duyệt
 
Upvote 0

File đính kèm

  • Take_Time_Temp.zip
    79.8 KB · Đọc: 42
Lần chỉnh sửa cuối:
Upvote 0
Để thử nghiệm, các bạn hãy tải về tập tin đính kèm và đặt cùng thư mục với tập tin ở thread trên.

Sau đó mở tập tin testmacro2.xls và thực hiện thủ tục FindTheLastRow bạn sẽ biết được số dòng hiện tại của tập tin trên.

Lê Văn Duyệt
 

File đính kèm

  • testmacro2.zip
    8.2 KB · Đọc: 21
Upvote 0
Vậy vấn đề là làm sao chúng ta có thể lưu dữ liệu lớn hơn số dòng mà định dạng *.xls đạt được 65,536 dòng?

Lê Văn Duyệt
 
Upvote 0
Vậy vấn đề là làm sao chúng ta có thể lưu dữ liệu lớn hơn số dòng mà định dạng *.xls đạt được 65,536 dòng?

Lê Văn Duyệt
Khi mở file lên, tôi thấy có cảnh báo này:

untitled.JPG


Đọc thông báo và suy ra rằng: Tôi có thể làm được điều này khi Save As *.xls từ 1 file *.txt nào đó
Đúng không?
Tại file đính kèm này về, Save As *.xls là biết liền
 

File đính kèm

  • Test.rar
    16.6 KB · Đọc: 22
Upvote 0
Vâng, Đúng như anh nói.

Đây là một giải pháp đường vòng.

Chúng ta thao tác với một tập tin text nhưng đuôi của file text không phải là txt mà là xls.

Khi kết nối với tập tin này (xls), chúng ta sẽ kết nối bình thường giống như tôi đã làm ở trên.
Như vậy chúng ta có thể lưu dữ liệu trên tập tin xls với số lượng dòng lớn hơn. Nhưng chú ý rằng nếu bạn mở tập tin trong Excel 2003 trở về trước thì coi như các dòng vượt trên 65,536 sẽ mất đi.

Lê Văn Duyệt
 
Upvote 0
Web KT
Back
Top Bottom