Đố 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,911
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
 
Vậy thì thêm biến Rng để làm giống gì?

Thì lúc đầu em nghĩ cho nó hiểu đối tượng nó đang nạp vào là dạng Range, nên mới để như vậy, nhưng xem ra nó cũng tự hiểu đối tượng của nó đang nạp là gì!

Nhưng nếu làm như thế thì em chẳng cần phải làm mảng, vì đối tượng nó nhận cũng là dạng RANGE nên ta trực tiếp làm trên range cho chắc ăn! Nếu nói mảng mà thực hiện cho tốc độ cao trong trường hợp này thì đó là một sai lầm!
 
Lần chỉnh sửa cuối:
Upvote 0
Thì lúc đầu em nghĩ cho nó hiểu đối tượng nó đang nạp vào là dạng Range, nên mới để như vậy, nhưng xem ra nó cũng tự hiểu đối tượng của nó đang nạp là gì!

Nhưng nếu làm như thế thì em chẳng cần phải làm mảng, vì đối tượng nó nhận cũng là dạng RANGE nên ta trực tiếp làm trên range cho chắc ăn! Nếu nói mảng mà thực hiện cho tốc độ cao trong trường hợp này thì đó là một sai lầm!

Có thể Nghĩa hiểu sai vấn đề rồi (cũng đâu có ai nói gì liên quan đến tốc độ trong này đâu)
Như đã nói ở trên: Đây là ĐỐ VUI
Còn chuyện ứng dụng thì thiếu gì... chẳng hạn tôi muốn tạo ra 1 mảng mà các phần tử trong đó là Range (tôi muốn gom các Range có cùng tính chất nào đó vào chung 1 mảng rồi xử lý 1 lần)
-----------
Với code của Nghĩa, chỉ cần Dim Arr(1 To 3) As Range là được rồi
 
Upvote 0
Có thể Nghĩa hiểu sai vấn đề rồi (cũng đâu có ai nói gì liên quan đến tốc độ trong này đâu)
Như đã nói ở trên: Đây là ĐỐ VUI
Còn chuyện ứng dụng thì thiếu gì... chẳng hạn tôi muốn tạo ra 1 mảng mà các phần tử trong đó là Range (tôi muốn gom các Range có cùng tính chất nào đó vào chung 1 mảng rồi xử lý 1 lần)
-----------
Với code của Nghĩa, chỉ cần Dim Arr(1 To 3) As Range là được rồi

Trong biến đối tượng, kể cả là đối tượng Range, nếu em nhớ không lầm thì chỉ chứa max có 254 mục mà thôi. Còn nếu ta làm trực tiếp trên Range thì theo RC của cells thôi.
 
Upvote 0
Upvote 0
Thầy thử nghiệm với cái này nha:

Mã:
    Dim Arr(1 To 1000) As Range, i As [COLOR=#ff0000][B]Byte[/B][/COLOR]
    For i = 1 To [COLOR=#ff0000][B]254[/B][/COLOR]
        Set Arr(i) = Cells(i, 1)
        Arr(i).Value = Cells(i, 2).Value
        Arr(i).Name = Cells(i, 3).Value
    Next

Thầy thay cái số 254 thành số lớn hơn xem nó có chạy được không ạ?

Đó là tại Nghĩa thôi!
Ai biểu Dim i as Byte làm chi
Tôi chả bao giờ chơi cái Byte này cả (trừ những trường hợp đặc biệt) ---> Cứ Long cho chắc
 
Upvote 0
chưa hẳn thế



Ngồi một lúc là nghĩ ra cả đống thôi.

Toàn bộ code của class module clsTest
Mã:
Public Value
Public Name

module1
Mã:
Public Type MYSTRUCT
    Value As String
    Name As String
End Type

Sub hichic()
Dim Arr(1 To 10) As New clsTest, tmp(1 To 10) As MYSTRUCT
    For i = 1 To 10
        Arr(i).Value = Cells(i, 1)
        Arr(i).Name = Cells(i, 2)
        
        tmp(i).Value = Cells(i, 1)
        tmp(i).Name = Cells(i, 2)
    Next i
    
    MsgBox UBound(Arr)
    MsgBox Arr(8).Name
    
    MsgBox UBound(tmp)
    MsgBox tmp(8).Value
End Sub

Hôm sau có đố thì ghi chú trừ anh siwtom ra, hi hi.

Nhưng em làm khác tí:

Code trong Class1:

Mã:
Public Name As String
Public Value As Long

Code trong Module:

Mã:
Sub Test()
    Dim Arr(1 To 10) As Class1
    Dim i As Long
    For i = 1 To 10
        Set Arr(i) = New Class1
        Arr(i).Value = Cells(i, 1)
        Arr(i).Name = Cells(i, 2)
    Next i
    MsgBox UBound(Arr)
    MsgBox Arr(8).Name
End Sub

Đây là một trong những bài học vỡ lòng về Class
Cám ơn anh, cám ơn mọi người đã quan tâm.
 

File đính kèm

  • Book1.xls
    27.5 KB · Đọc: 11
Lần chỉnh sửa cuối:
Upvote 0
Upvote 0
Xây dựng hàm TRIM trong VBA mà không cần vòng lập

Như ta đã biết, hàm TRIM trên bảng tính khác với TRIM trong VBA
TRIM trong VBA chỉ remove khoảng trắng ở đầu và cuối chuổi (ở giữa chuổi nó không làm)
Thông thường khi muốn dùng TRIM giống như TRIM trên bảng tính thì:
- Hoặc là dùng WorksheetFunction.Trim
- Hoặc là tự viết 1 UDF (thường dùng trong các ứng dụng khác)
Với UDF, khi xây dựng nó sẽ không tránh khỏi phải thông qua 1 vòng lập
----------------
Vậy xin hỏi: Có thể dùng code VBA để xây dựng hàm TRIM giống như TRIM trên bảng tính (tức là nó có khả năng xóa mọi khoảng trắng thừa trong chuổi kể cả đầu, cuối và giữa chuổi) mà không cần đến vòng lập không?
(Đương nhiên cũng không dùng WorksheetFunction)
---------------------------------------------
Lưu ý: nghỉ chơi với anh siwtom
Ẹc.... Ẹc...
 
Lần chỉnh sửa cuối:
Upvote 0
Như ta đã biết, hàm TRIM trên bảng tính khác với TRIM trong VBA
TRIM trong VBA chỉ remove khoảng trắng ở đầu và cuối chuổi (ở giữa chuổi nó không làm)
Thông thường khi muốn dùng TRIM giống như TRIM trên bảng tính thì:
- Hoặc là dùng WorksheetFunction.Trim
- Hoặc là tự viết 1 UDF (thường dùng trong các ứng dụng khác)
Với UDF, khi xây dựng nó sẽ không tránh khỏi phải thông qua 1 vòng lập
----------------
Vậy xin hỏi: Có thể dùng code VBA để xây dựng hàm TRIM giống như TRIM trên bảng tính (tức là nó có khả năng xóa mọi khoảng trắng thừa trong chuổi kể cả đầu, cuối và giữa chuổi) mà không cần đến vòng lập không?
(Đương nhiên cũng không dùng WorksheetFunction)
---------------------------------------------
Lưu ý: nghỉ chơi với anh siwtom
Ẹc.... Ẹc...

Có liên quan gì đến cái này không Thầy?

CreateObject("vbscript.regexp")
 
Upvote 0
Nhưng ndu đã suýt đúng khi nói "các phần tử của Arr phải là BIẾN ĐỐI TƯỢNG". Ec, ec...
Msgbox TypeName(Arr) => Object()

Trông xa tưởng là mèo, lại gần hóa ra chim.

Em thì đang nghĩ anh nói đến Arr là Range
Vì thật ra nếu làm giống như Nghĩa đã làm cũng hoàn toàn đáp ứng được yêu cầu anh đưa ra rồi
-------------------
Có liên quan gì đến cái này không Thầy?

CreateObject("vbscript.regexp")
Cứ tùy ý sử dụng nếu thấy nó có.. "liên quan"
Ẹc... ẹc...
 
Upvote 0
Như ta đã biết, hàm TRIM trên bảng tính khác với TRIM trong VBA
TRIM trong VBA chỉ remove khoảng trắng ở đầu và cuối chuổi (ở giữa chuổi nó không làm)
Thông thường khi muốn dùng TRIM giống như TRIM trên bảng tính thì:
- Hoặc là dùng WorksheetFunction.Trim
- Hoặc là tự viết 1 UDF (thường dùng trong các ứng dụng khác)
Với UDF, khi xây dựng nó sẽ không tránh khỏi phải thông qua 1 vòng lập
----------------
Vậy xin hỏi: Có thể dùng code VBA để xây dựng hàm TRIM giống như TRIM trên bảng tính (tức là nó có khả năng xóa mọi khoảng trắng thừa trong chuổi kể cả đầu, cuối và giữa chuổi) mà không cần đến vòng lập không?
(Đương nhiên cũng không dùng WorksheetFunction)
---------------------------------------------
Lưu ý: nghỉ chơi với anh siwtom
Ẹc.... Ẹc...

Như thế này có được không ạ
Mã:
Function UdfTrim(Str As String)
With CreateObject("Vbscript.RegExp")
    .Global = True
    .Pattern = "\s{2,}"
    Str = .Replace(Str, " ")
End With
    UdfTrim = Trim(Str)
End Function
 
Upvote 0
Như thế này có được không ạ
Mã:
Function UdfTrim(Str As String)
With CreateObject("Vbscript.RegExp")
    .Global = True
    .Pattern = [COLOR=#ff0000]"\s{2,}"[/COLOR]
    Str = .Replace(Str, " ")
End With
    UdfTrim = Trim(Str)
End Function

Chính xác là cái đỏ đỏ ấy rồi còn gi
(dhn46 cũng là chuyên gia về RegExp, lý ra cũng phải cho nghỉ chơi sớm)
 
Upvote 0
Vầy cũng được mà
Mã:
.Pattern = " +"
 
Upvote 0
Quả thật, cái "ngôn ngữ" của thằng ".Pattern" này nó có nhiều cái mà mình chẳng biết quy luật cụ thể là như thế nào cả!
Reg thì khó nhưng với những dạng chuỗi như thế này thì anh Nghĩa có thể hiểu "dễ" như sau

Với
Mã:
.Pattern = " +"
+/ Dấu cộng là lặp lại phần đằng trước từ 1 lần trở lên, => phần đằng trước là dấu cách tương ứng mẫu (\s). (cái này tương ứng "\s+") => Trong đoạn Str cứ chỗ nào có 1 dấu cách trở lên thì đánh dấu nó lại
+/ Dùng .replace để thay thế phần đánh dấu đó.

Với
Mã:
.Pattern = "\s{2,}"
thì anh hiểu như sau
+/ mẫu \s là dấu cách
+/ {x,} => Trong đoạn Str cứ chỗ nào lặp lại phía trước (là dấu cách) ít nhất 2 lần (từ 2 dấu cách trở lên) thì đánh dấu (1 dấu cách thì không đánh dấu)
+/ Dùng Replace để thay thế

Những bài viết về Reg của bác SiwTom rất hay anh có thể tham khảo
(Bài viết có cả chân dài, chân ngắn... sinh động và vô cũng lôi cuốn, anh tìm hiểu xem sao nhé . Hihi)
 
Upvote 0
Em dám cá với anh rằng anh thanhlanh hổng phải nói đến cái này
-------------------------

Tôi cũng nghĩ là thanhlanh không "lường" tới những cái này.
Nhưng người ta đố thì mình cứ "dự thi" thôi.

Nói cho cùng thì đó là "cái gì đó" mà có ít nhất là 2 trường giá trị là Value và Name.
Tôi nói 2 trường chứ không nói 2 thuộc tính. Nhưng thường thì khi thiết kế đối tượng (class) thì những trường của nó nên là Private. Lúc đó mọi truy cập tới data đều phải thông qua các thuộc tính hoặc phương thức. Người dùng code không thể trực tiếp thay đổi giá trị của các trường được.

Vậy chỉ có thể là 2 cấu trúc: record hoặc object (class)
 
Upvote 0
Hôm sau có đố thì ghi chú trừ anh siwtom ra, hi hi.

Nhưng em làm khác tí:

Code trong Class1:

Mã:
Public Name As String
Public Value As Long

Code trong Module:

Mã:
Sub Test()
    Dim Arr(1 To 10) As Class1
    Dim i As Long
    For i = 1 To 10
        Set Arr(i) = New Class1
        Arr(i).Value = Cells(i, 1)
        Arr(i).Name = Cells(i, 2)
    Next i
    MsgBox UBound(Arr)
    MsgBox Arr(8).Name
End Sub

Đây là một trong những bài học vỡ lòng về Class
Cám ơn anh, cám ơn mọi người đã quan tâm.

Thôi chết rồi. Gửi bài xong mới thấy là thanhlanh cũng có mưu đồ dùng class
 
Upvote 0
Web KT

Bài viết mới nhất

Back
Top Bottom