Đố 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
 
Chỉ có 1 cách duy nhất
1 câu lệnh duy nhất
Vừa sort
Vừa subtotal
vừa copy qua sheet khác

Đó là

Đọc sách lão chết tiệt
 
Upvote 0
Chỉ có 1 cách duy nhất
1 câu lệnh duy nhất
Vừa sort
Vừa subtotal
vừa copy qua sheet khác

Đó là

Đọc sách lão chết tiệt
Ngay từ đầu em cũng nghĩ sẽ dùng PivotTable, vì với PivotTable thì tự nó đã copy và cho subtotal rồi.... Có điều không biết có đúng ý của Duyệt hay không nữa
 
Upvote 0
Hic, vừa làm thử. Ít nhất 3 câu lệnh!
 
Upvote 0
Thầy viết bao nhiêu câu lệnh cũng được, miễn là 1 dòng (one line code) mà! thêm dấu : để cách dòng thôi hihihii
Bản thân 1 câu lệnh đã phải xuống 3 dòng, 3 câu lệnh mà không xuống dòng nó dài cả thước!
Chắc chắn làm vậy không phải là đáp án.
 
Upvote 0
Ngay từ đầu em cũng nghĩ sẽ dùng PivotTable, vì với PivotTable thì tự nó đã copy và cho subtotal rồi.... Có điều không biết có đúng ý của Duyệt hay không nữa

Mình có một vùng (~ mảng), vậy làm sao để tương tự như sau:
Mã:
Application.Thisworkbook.Worksheets("Sheet2").Range("A2").Paste[B][COLOR="red"] (2 công việc kia ở đây)[/COLOR][/B]

Lê Văn Duyệt
 
Upvote 0
Em có một câu đố khác.

Em có một dữ liệu gồm một vùng dữ liệu từ A1:D50. Hàng đầu tiên là tên trường dữ liệu (Mã vật tư| Tên vật tư| S.L| Đvt
Yêu cầu:
_ Sắp xếp vùng dữ liệu (sort) theo cột A.
_ Tính Subtotal ở cột C theo dữ liệu ở cột A.
_ Sau đó copy qua một sheet khác.
_ Chỉ dùng một dòng mã (one line code).

Lê Văn Duyệt
Lâu rồi mà chẳng thấy ai có ý kiến, thôi Duyệt giải luôn đi
 
Upvote 0
Câu đố về xử lý mảng

Tôi có 1 hàm thế này:
PHP:
Function JoinArray(ByVal sArray, ByVal Sep As String) As String
  Dim Item, TmpArr, Arr(), i As Long
  TmpArr = sArray
  For Each Item In TmpArr
    If Trim(CStr(Item)) <> "" Then
      ReDim Preserve Arr(i)
      Arr(i) = CStr(Item)
      i = i + 1
    End If
  Next
  If i Then JoinArray = Join(Arr, Sep)
End Function
Hàm này dùng để nối các phần tử của 1 mảng bất kỳ (ngoại trừ phần tử rổng) thành 1 chuổi với dấu phân cách cho trước
Ví dụ: Nối các phần tử trong vùng A1:B4 bằng công thức =JoinArray(A1:B4,", ")
Xem sơ qua thì dường như hàm không có vấn đề gì. Thế nhưng khi ta sửa tham chiếu thành 1 cell =JoinArray(A1,", ") thì hàm bị lỗi #VALUE!
Xin lỗi nguyên nhân và cách khắc phục?
 
Upvote 0
Tôi có 1 hàm thế này:
PHP:
Function JoinArray(ByVal sArray, ByVal Sep As String) As String
  Dim Item, TmpArr, Arr(), i As Long
  TmpArr = sArray
  For Each Item In TmpArr
    If Trim(CStr(Item)) <> "" Then
      ReDim Preserve Arr(i)
      Arr(i) = CStr(Item)
      i = i + 1
    End If
  Next
  If i Then JoinArray = Join(Arr, Sep)
End Function
Hàm này dùng để nối các phần tử của 1 mảng bất kỳ (ngoại trừ phần tử rổng) thành 1 chuổi với dấu phân cách cho trước
Ví dụ: Nối các phần tử trong vùng A1:B4 bằng công thức =JoinArray(A1:B4,", ")
Xem sơ qua thì dường như hàm không có vấn đề gì. Thế nhưng khi ta sửa tham chiếu thành 1 cell =JoinArray(A1,", ") thì hàm bị lỗi #VALUE!
Xin lỗi nguyên nhân và cách khắc phục?
Theo em thì khi tham chiếu là 1 cell thì tham chiếu đó không phải là mảng nên sẽ bị lỗi khi anh duyệt qua các phần tử của mảng. Cụ thể là lỗi ở dòng lệnh này:
PHP:
For Each Item In TmpArr
Vậy để khắc phục thì trước hết kiểm tra xem nó có phải là mảng không. Nếu không phải là mảng thì gán giá trị của tham chiếu vào kết quả và thoát Function luôn. Nếu không thì tiếp tục.
Em đề xuất sửa lại như thế này:
PHP:
Function JoinArray(ByVal sArray, ByVal Sep As String) As String
  Dim Item, TmpArr, Arr(), i As Long
  If Not IsArray(sArray) Then
    JoinArray = Trim(CStr(sArray))
    Exit Function
  End If
  TmpArr = sArray
  For Each Item In TmpArr
    If Trim(CStr(Item)) <> "" Then
      ReDim Preserve Arr(i)
      Arr(i) = CStr(Item)
      i = i + 1
    End If
  Next
  If i Then JoinArray = Join(Arr, Sep)
End Function
 
Upvote 0
Theo em thì khi tham chiếu là 1 cell thì tham chiếu đó không phải là mảng nên sẽ bị lỗi khi anh duyệt qua các phần tử của mảng. Cụ thể là lỗi ở dòng lệnh này:
PHP:
For Each Item In TmpArr
Vậy để khắc phục thì trước hết kiểm tra xem nó có phải là mảng không. Nếu không phải là mảng thì gán giá trị của tham chiếu vào kết quả và thoát Function luôn. Nếu không thì tiếp tục.
Em đề xuất sửa lại như thế này:
PHP:
Function JoinArray(ByVal sArray, ByVal Sep As String) As String
  Dim Item, TmpArr, Arr(), i As Long
  If Not IsArray(sArray) Then
    JoinArray = Trim(CStr(sArray))
    Exit Function
  End If
  TmpArr = sArray
  '...............
  '............
  If i Then JoinArray = Join(Arr, Sep)
End Function
Ngoài IsArray ra không biết còn cách khác không nhỉ?
Các bạn nghiên cứu xem!
 
Upvote 0
Lâu rồi mà chẳng thấy ai có ý kiến, thôi Duyệt giải luôn đi

Câu đố đã viết:
Em có một dữ liệu gồm một vùng dữ liệu từ A1:D50. Hàng đầu tiên là tên trường dữ liệu (Mã vật tư| Tên vật tư| S.L| Đvt
Yêu cầu:
_ Sắp xếp vùng dữ liệu (sort) theo cột A.
_ Tính Subtotal ở cột C theo dữ liệu ở cột A.
_ Sau đó copy qua một sheet khác.
_ Chỉ dùng một dòng mã (one line code).

Nếu phân tích câu hỏi ở trên thì chúng ta có 3 vấn đề cần giải quyết:
  1. Sắp xếp: bước này thường là bước đầu tiên trước khi tổng hợp.
  2. Subtotal: đây mới là bước tổng hợp và phải thực hiện sau bước thứ nhất.
  3. Xuất dữ liệu: đưa số liệu sau khi xử lý qua một vùng khác.
Đây là 3 bài toán chúng ta thường gặp trên diễn đàn và cũng là vấn đề em quan tâm "làm sao có một thủ tục (i.e một hàng code) để thực hiện các bước ở trên"

Nếu giải theo mẹo:
Learning_Excel đã viết:
Thầy viết bao nhiêu câu lệnh cũng được, miễn là 1 dòng (one line code) mà! thêm dấu : để cách dòng thôi hihihii
Rõ ràng cũng thỏa mãn yêu cầu.

Nếu giải một cách chính thống:
Rõ ràng như Bác ptm0412
ptm0412 đã viết:
Hic, vừa làm thử. Ít nhất 3 câu lệnh!
Rõ ràng, nó tương ứng với 3 vấn đề trên.
Vậy câu trả lời là: nếu không dùng một thủ tục tự viết thì không thể nào đạt được yêu cầu của bài toán ở trên (tính đến thời điểm hiện nay, vì biết đâu trong phiên bản sau M$ sẽ có một hàm/thủ tục để thực hiện điều đó).

Lê Văn Duyệt
 
Lần chỉnh sửa cuối:
Upvote 0
Ngoài IsArray ra không biết còn cách khác không nhỉ?
Các bạn nghiên cứu xem!
Anh thử kiểm tra phần tử mãng với hàm IsEmpty xem sao?

Mã:
Function JoinArray(ByVal sArray, ByVal Sep As String) As String
    Dim Item, TmpArr, Arr(), i As Long
    TmpArr = sArray
    For Each Item In TmpArr
        'If Trim(CStr(Item)) <> "" Then
        If Not IsEmpty(Item) Then
            ReDim Preserve Arr(i)
            Arr(i) = CStr(Item)
            i = i + 1
        End If
    Next
    If i Then JoinArray = Join(Arr, Sep)
End Function

Lê Văn Duyệt
 
Upvote 0
Anh thử kiểm tra phần tử mãng với hàm IsEmpty xem sao?

Mã:
Function JoinArray(ByVal sArray, ByVal Sep As String) As String
    Dim Item, TmpArr, Arr(), i As Long
    TmpArr = sArray
    For Each Item In TmpArr
        'If Trim(CStr(Item)) <> "" Then
        If Not IsEmpty(Item) Then
            ReDim Preserve Arr(i)
            Arr(i) = CStr(Item)
            i = i + 1
        End If
    Next
    If i Then JoinArray = Join(Arr, Sep)
End Function

Lê Văn Duyệt
Thí nghiệm hàm trên:
=JoinArray(A1,", ")
thì thấy vẫn còn lỗi mà Duyệt
 
Upvote 0
Ngoài IsArray ra không biết còn cách khác không nhỉ?
Các bạn nghiên cứu xem!
Nếu không dùng IsArray thì dùng bẫy lỗi. Em làm như thế này:
PHP:
Function JoinArray(ByVal sArray, ByVal Sep As String) As String
  Dim Item, TmpArr, Arr(), i As Long
  TmpArr = sArray
  On Error GoTo Err
  For Each Item In TmpArr
    If Trim(CStr(Item)) <> "" Then
      ReDim Preserve Arr(i)
      Arr(i) = CStr(Item)
      i = i + 1
    End If
  Next
  If i Then JoinArray = Join(Arr, Sep)
  Exit Function
Err:
  JoinArray = sArray
End Function
 
Upvote 0
Thí nghiệm hàm trên:
=JoinArray(A1,", ")
thì thấy vẫn còn lỗi mà Duyệt
Vậy ta có thể dùng hàm TypeName để kiểm tra kiểu của biến:
Mã:
Function UDF(Variable As Variant) As String
    UDF = TypeName(Variable)
End Function

Hàm TypeName sẽ trả về chuổi thông tin về biến. Không áp dụng cho kiểu người dùng.
Xin tham khảo tại đây.

Nhưng theo em nghĩ, đối với trường hợp này thì dùng hàm kiểm tra xem có phải mảng không là hợp lý nhất.

Lê Văn Duyệt
 
Lần chỉnh sửa cuối:
Upvote 0
Vâng! Chính xác là dùng On Error...TypeName = "Variant()"
Cái nào cũng được và đương nhiên khi dùng On Error... là khi ta đã thừa biết lỗi ấy là gì rồi (chứ không phải là bất chấp thủ đoạn)
----------------------
Không biết còn cái gì để đố nữa không đây? Hay là bạn Thắng và Duyệt nêu chủ đề gì đó xem
 
Upvote 0
Vâng! Chính xác là dùng On Error...TypeName = "Variant()"
Cái nào cũng được và đương nhiên khi dùng On Error... là khi ta đã thừa biết lỗi ấy là gì rồi (chứ không phải là bất chấp thủ đoạn)
----------------------
Không biết còn cái gì để đố nữa không đây? Hay là bạn Thắng và Duyệt nêu chủ đề gì đó xem
Những gì em biết đều học được từ GPE nên em đâu có cái gì mới, lạ để đố đâu.
 
Upvote 0
hi, mình vô tình làm như thế này mà nó cũng ra kết quả

Private Sub Button1_Click()
K = K + 1
Range("A1").Value = Range("a1").Value + K
End Sub
Nhờ các ace giải thích dùm!
hihi
 
Upvote 0
hi, mình vô tình làm như thế này mà nó cũng ra kết quả

Private Sub Button1_Click()
K = K + 1
Range("A1").Value = Range("a1").Value + K
End Sub
Nhờ các ace giải thích dùm!
hihi
Nếu không khai báo public biến K, khi bắt đầu chạy code, K = Nothing, chạy dòng lệnh K = K +1, K sẽ bằng 1.
Vậy sau mỗi lần chạy code, A1 sẽ = A1 + 1, và cứ thế tăng dần

Nghĩa là code trên tương tự:

PHP:
Private Sub Button1_Click()
    Range("A1").Value = Range("a1").Value + 1
End Sub

Khỏi cần biến K!
 
Upvote 0
Web KT

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

Back
Top Bottom