Đố 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
 
Trong VBA thì chắc là Caller

Đó chính là vấn đề (cái Caller)
Còn việc viết gì trong Sub thì tùy ý mọi người, miễn sao có sự tồn tại của Caller để CHỈ DUY NHẤT BUTTON mới gọi được Sub
Thế thôi!
Như em, viết thế này cũng được
Mã:
Sub GiGiDo()
  MsgBox Application.Caller
End Sub
(Đúng ra sau 3 ngày nữa, nếu không ai trả lời thì anh siwtom mới có quyền trả lời, thế mới công bằng chứ nhỉ?)
Ẹc... Ẹc...
---------------
Trước đây mình đã thấy một thấy một số cao thủ nói rằng Sheet CodeName là thuộc tính Read-only rất khó Edit bằng code sao gọi là chuyện bình thường được?
Edit thì khó nhưng chỉ LẤY TÊN CÙA NÓ thì đúng là chuyện bình thường mà anh! Và em cũng chỉ đang nói về vụ lấy tên thôi
(trong khi chỉ cái chuyện lấy tên bình thường ấy anh lại đi đường vòng cho mất công.... Ẹc... Ẹc...)
 
Lần chỉnh sửa cuối:
Upvote 0
...
Có lẽ bạn chưa biết Sheet CodeName, bạn xem hàm trong file bên dưới.

...
Còn đây là code của mình:
Mã:
[COLOR=#ff0000][B]Sub EditWorksheetCodenames()[/B][/COLOR]
    Dim Ws As Worksheet, i As Integer
    If TypeName(ActiveWorkbook) = "Nothing" Then Exit Sub
    For Each Ws In ActiveWorkbook.Worksheets
        i = i + 1
        On Error Resume Next
        'Cells(i, 1) = Ws.Name
        Ws.Parent.VBProject.vbcomponents(Ws.CodeName).Properties("_CodeName") = "GPE" & i
        'On Error GoTo 0
    Next Ws
End Sub


Function shCodeName(ByVal shName As String) As String
    On Error Resume Next    ' Neu khong tim thay Sheet shName
    shCodeName = ActiveWorkbook.VBProject.vbcomponents(Sheets(shName).CodeName).Properties("_CodeName")
End Function

Việc biết hay không biết Sheet CodeName chả liên quan gì đến hàm cả.

EditWorksheetCodenames() trả về cái gì mới quan trọng. Theo code trên thì nó là Sub.

Thắc mắc của tôi thực ra là câu đố ngầm. Nên cho nó trả về cái gì?

Theo như code trước đây thì có vài bạn muốn trả về True/False. Nhưng nếu tôi viết hàm này thì tôi cho nó trả về số sheets mà nó đổi tên - dĩ nhiên là nếu nó chả đổi sheet nào thì nó trả về 0.
 
Upvote 0
Đó chính là vấn đề (cái Caller)
Còn việc viết gì trong Sub thì tùy ý mọi người, miễn sao có sự tồn tại của Caller để CHỈ DUY NHẤT BUTTON mới gọi được Sub
Thế thôi!
Như em, viết thế này cũng được
Mã:
Sub GiGiDo()
  MsgBox Application.Caller
End Sub
^^ bh em biết thêm được caller <--- cảm ơn diễn đàn GPE nói chung và anh Ndu, Switom nói riêng :D
Nếu em viết như vầy :
Mã:
Sub GPE()
    Dim button1 As Button
        Set button1 = Worksheets(1).Buttons(Application.Caller)
        MsgBox button1.Name
End Sub
Application.Caller --> như là một Name động của các button vậy , ta chỉ cần click bất kỳ button nào thì code đều chạy hết --> em hiểu vậy có đúng không các anh nhj ??
 
Lần chỉnh sửa cuối:
Upvote 0
^^ bh em biết thêm được caller <--- cảm ơn diễn đàn GPE nói chung và anh Ndu, Switom nói riêng :D
Nếu em viết như vầy :
Mã:
Sub GPE()
    Dim button1 As Button
        Set button1 = Worksheets(1).Buttons(Application.Caller)
        MsgBox button1.Name
End Sub
Application.Caller --> như là một Name động của các button vậy , ta chỉ cần click bất kỳ button nào thì code đều chạy hết --> em hiểu vậy có đúng không các anh nhj ??

Bất cứ button nào Assign Maco với Sub GPE chứ
Giải thích thế này sẽ dễ hiểu:
- TUI chính là Sub GPE
- Còn thằng nào "gọi điện thoại" đến TUI thì thằng đó là CALLER
 
Upvote 0
Đố về Freeze Panes.

Trong sheet chứa Freeze Panes, đố các bạn xác định được ô nào đầu tiên giao nhau mà không bị đóng băng.

(Trong File đính kèm, ô cần tìm là ô DP107).
 

File đính kèm

  • FreezePanes.xls
    22.5 KB · Đọc: 10
Lần chỉnh sửa cuối:
Upvote 0

File đính kèm

  • FreezePanes.jpg
    FreezePanes.jpg
    39 KB · Đọc: 51
Upvote 0
Dùng send keys ctrl+home là sẽ lấy được địa chỉ của nó.
Cũng là một giải pháp rất hay, nhưng nếu không dùng SendKeys thì còn cách nào nữa không?

Giả sử cột cần tìm là cột hoặc hàng, hoặc cả hai bị HIDE thì cách send keys ctrl+home không phát huy được tác dụng nha!
 
Lần chỉnh sửa cuối:
Upvote 0
Upvote 0
Upvote 0
Nhưng thủ tục đầy đủ hơn phải là như thế này:

Mã:
Sub FindFrozenCell()
    With ActiveWindow
        If .Split Then
            .ScrollRow = 1
            .ScrollColumn = 1
            MsgBox ActiveWindow.VisibleRange(1, 1).Address(0, 0)
        Else
            MsgBox "Khong co cot, hang nao bi dong bang."
        End If
    End With
End Sub

Nếu không có ScrollRow và ScrollColumn thì sẽ không chính xác được địa chỉ giao nhau đâu nhé!
 
Upvote 0
Nhưng thủ tục đầy đủ hơn phải là như thế này:

Mã:
Sub FindFrozenCell()
    With ActiveWindow
        If .Split Then
            .ScrollRow = 1
            .ScrollColumn = 1
            MsgBox [B][COLOR=#ff0000]ActiveWindow.VisibleRange(1, 1)[/COLOR][/B].Address(0, 0)
        Else
            MsgBox "Khong co cot, hang nao bi dong bang."
        End If
    End With
End Sub

Nếu không có ScrollRow và ScrollColumn thì sẽ không chính xác được địa chỉ giao nhau đâu nhé!

Sẳn đây đố luôn, nếu thay "cái vụ" màu đỏ thành một thủ tục khác, vậy theo các bạn sẽ thay vào đó cái gì để có kết quả như chưa thay? Nói chung là không dùng VisibleRange.
 
Upvote 0
Nhưng thủ tục đầy đủ hơn phải là như thế này:

Mã:
Sub FindFrozenCell()
    With ActiveWindow
        If .Split Then
            .ScrollRow = 1
            .ScrollColumn = 1
            MsgBox ActiveWindow.VisibleRange(1, 1).Address(0, 0)
        Else
            MsgBox "Khong co cot, hang nao bi dong bang."
        End If
    End With
End Sub

Nếu không có ScrollRow và ScrollColumn thì sẽ không chính xác được địa chỉ giao nhau đâu nhé!

Có thể dùng cách khác mà không cần phải dùng đến Scroll.
 
Upvote 0
Upvote 0
Thủ thuật này nó sẽ lấy địa chỉ ở cell chéo với DP107, đó là cell DO106 + thêm 1 dòng và 1 cột sẽ ra kết quả:
Chắc HLMT đang nói đến Panes(x) với x từ 1 đến 4 phải không? Nhưng trước khi làm phải Panes.Count trước đấy nhé, không thôi sẽ gặp lỗi đấy! (chỉ đóng băng dòng hoặc đóng băng cột).

Nhưng để tránh rắc rối, hay bẩy lỗi nhiều, mình không dùng VisibleRange luôn.
 
Lần chỉnh sửa cuối:
Upvote 0
Chắc HLMT đang nói đến Panes(x) với x từ 1 đến 4 phải không? Nhưng trước khi làm phải Panes.Count trước đấy nhé, không thôi sẽ gặp lỗi đấy! (chỉ đóng băng dòng hoặc đóng băng cột).

Nhưng để tránh rắc rối, hay bẩy lỗi nhiều, mình không dùng VisibleRange luôn.

Vầy chắc được:
Mã:
Sub GoHome()
  With ActiveWindow
    .ScrollRow = 1
    .ScrollColumn = 1
    Application.Goto Cells(.ScrollRow, .ScrollColumn), True
  End With
  MsgBox ActiveCell.Address
End Sub
 
Upvote 0
Vầy chắc được:
Mã:
Sub GoHome()
  With ActiveWindow
    .ScrollRow = 1
    .ScrollColumn = 1
    Application.Goto Cells(.ScrollRow, .ScrollColumn), True
  End With
  MsgBox ActiveCell.Address
End Sub
Đúng là em đã dùng cách này! Nhưng gọn hơn tí!

Mã:
Sub FindFrozenCell()
    With ActiveWindow
        If .Split Then
            .ScrollRow = 1
            .ScrollColumn = 1
            MsgBox [COLOR=#ff0000]Cells(.ScrollRow, .ScrollColumn)[/COLOR].Address(0, 0)
        Else
            MsgBox "Khong co cot, hang nao bi dong bang."
        End If
    End With
End Sub

Tuy rằng ta đặt .ScrollRow = 1, .ScrollColumn = 1, nhưng nếu gặp FreezePanes nó sẽ dừng lại nơi mà ta thiết lập, vì thế, lợi dụng điểm này ta có thể lấy được hàng và cột của chúng.
 
Lần chỉnh sửa cuối:
Upvote 0
Đúng là em đã dùng cách này! Nhưng gọn hơn tí!

Mã:
Sub FindFrozenCell()
    With ActiveWindow
        If .Split Then
          [COLOR=#ff0000]  .ScrollRow = 1
            .ScrollColumn = 1[/COLOR]
            MsgBox Cells([COLOR=#ff0000].ScrollRow, .ScrollColumn[/COLOR]).Address(0, 0)
        Else
            MsgBox "Khong co cot, hang nao bi dong bang."
        End If
    End With
End Sub

Tuy rằng ta đặt .ScrollRow = 1, .ScrollColumn = 1, nhưng nếu gặp FreezePanes nó sẽ dừng lại nơi mà ta thiết lập, vì thế, lợi dụng điểm này ta có thể lấy được hàng và cột của chúng.
Ở trên em có nói cái chổ màu đỏ không cần dùng Sroll.
 
Upvote 0
Web KT

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

Back
Top Bottom