Mình có viết code sau để tạo và sử dụng Data Validation trong Excel sử dụng tốt ...Tuy nhiên có 2 vấn đề phát sinh mà suy nghĩ hoài chua tìm ra cách xử lý ... Vậy úp bài nhờ các Bạn trợ giúp
1/ Vùng dữ liêu nguon() luôn luôn phát sinh nên mình sử dụng Dic để lấy duy nhất gán vào Data Validation ...nếu dữ liệu nhiều phải kéo xuống tìm mất công quá ... Vậy mình muốn hỏi có cách nào từ Sheet2.[C4] ta có thể gõ ký tự đại diện là nó tìm kiếm ra được hay không ?? .... để gán vào đó
2/ Khi mình sử dụng SendKeys ("%{Down}") để cho Data Validation nó xổ xuống cho dễ nhìn thì trên máy mình mất phím Numlock và có sử dụng Shell để bật nó lại tuy nhiên thấy nó cũng cứ nhảy link tinh à
Vậy nhờ các Bạn xem có cách nào khác xử lý tốt 2 vấn đề trên không giúp mình với
Xin cảm ơn
Mã:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim Nguon()
Nguon = Sheet1.Range(Sheet1.[B3], Sheet1.[B65536].End(3)).Value
Call Validation(Nguon, Sheet2.Range("C4"))
''Call ON_Numlock
End Sub
Public Sub Validation(ByVal dArr As Variant, ByVal Target As Range)
Dim i As Long
With CreateObject("scripting.dictionary")
For i = 1 To UBound(dArr)
If Not IsEmpty(dArr(i, 1)) Then
.Item(dArr(i, 1)) = .Count
End If
Next
Target.Validation.Delete
If .Count Then Target.Validation.Add 3, , , Join(.Keys, ",")
''SendKeys ("%{Down}")
End With
End Sub
Sub ON_Numlock()
CreateObject("WScript.Shell").SendKeys "{NUMLOCK}", True
End Sub
Mạnh mới nghĩ ra 1 giải pháp đơn giản vầy ... Nhờ các bạn Tham gia thêm
1/ Tại C4 ta gõ chữ m xong Enter ...xong ta chọn Biểu tượng Data nó xổ ra cái cần lọc ...
Tương Tự như vây ... Gõ chữ đ vv...
2/ Còn rắc rối lắm ........ là phải thực hiện tới 3 thao tác mới cho ra kết quả
3/ Chưa xử lý được SendKeys
Mong các bạn tham gia thêm
PHP:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim Nguon()
Nguon = Sheet1.Range(Sheet1.[B3], Sheet1.[B65536].End(3)).Value
If Target.Address = [C4].Address Then
Call GetListValidation(Nguon(), Sheet2.Range("C4"))
End If
End Sub
Public Sub GetListValidation(ByVal Arr As Variant, ByVal Target As Range)
Dim Dic As Object, dk As String, i As Long
Set Dic = CreateObject("scripting.dictionary")
dk = Sheet2.Range("C4").Value
For i = 1 To UBound(Arr)
If InStr(1, Arr(i, 1), dk) Then
If Not IsEmpty(Arr(i, 1)) Then
Dic.Item(Arr(i, 1)) = Dic.Count
End If
End If
Next
With Target.Validation
.Delete
If Dic.Count Then
.Add 3, , , Join(Dic.Keys, ",")
''SendKeys ("%{Down}") ', True
.ShowError = False
End If
End With
End Sub
Mình mới viết sơ bộ vậy ... còn rắc rối lắm ....Sort Nguon thì không được vì nguon còn liên quan các cột và dòng khác nữa
Mình chưa nghĩ ra làm sao gõ vào c4 xong Enter một cái nó ra luôn nếu có 1 chữ m hay nếu có nhiều chữ m thì nó ra 1 list ....nếu bạn biết chỉ dùm
vọc thử !
source của bác ok roài , chỉnh lại 4 chỗ là chạy đc !
số 444 chưa hoàn chỉnh lắm !
PHP:
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range) '111
Dim Nguon()
Nguon = Sheet1.Range(Sheet1.[B3], Sheet1.[B65536].End(3)).Value
If Target.Address = [C4].Address Then
If Selection.Address = Target.Address Then Exit Sub '---222
Target.Select '---333
Call GetListValidation(Nguon(), Sheet2.Range("C4"))
End If
End Sub
Public Sub GetListValidation(ByVal Arr As Variant, ByVal Target As Range)
Dim Dic As Object, dk As String, i As Long
Set Dic = CreateObject("scripting.dictionary")
dk = Sheet2.Range("C4").Value
For i = 1 To UBound(Arr)
If InStr(1, Arr(i, 1), dk) Then
If Not IsEmpty(Arr(i, 1)) Then
Dic.Item(Arr(i, 1)) = Dic.Count
End If
End If
Next
With Target.Validation
.Delete
If Dic.Count Then
.Add 3, , , Join(Dic.Keys, ",")
.ShowError = False
SendKeys ("%{Down}") '---444
End If
End With
End Sub
vọc thử !
source của bác ok roài , chỉnh lại 4 chỗ là chạy đc !
PHP:
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range) '111
Dim Nguon()
Nguon = Sheet1.Range(Sheet1.[B3], Sheet1.[B65536].End(3)).Value
If Target.Address = [C4].Address Then
If Selection.Address = Target.Address Then Exit Sub '---222
Target.Select '---333
Call GetListValidation(Nguon(), Sheet2.Range("C4"))
End If
End Sub
Public Sub GetListValidation(ByVal Arr As Variant, ByVal Target As Range)
Dim Dic As Object, dk As String, i As Long
Set Dic = CreateObject("scripting.dictionary")
dk = Sheet2.Range("C4").Value
For i = 1 To UBound(Arr)
If InStr(1, Arr(i, 1), dk) Then
If Not IsEmpty(Arr(i, 1)) Then
Dic.Item(Arr(i, 1)) = Dic.Count
End If
End If
Next
With Target.Validation
.Delete
If Dic.Count Then
.Add 3, , , Join(Dic.Keys, ",")
.ShowError = False
End If
SendKeys ("%{Down}") '---444
End With
End Sub
Vậy là tam ok .... Manh mới thêm Ucase vào 1 chút ...nếu xóa trắng c4 nó lấy hết
PHP:
Public Sub GetListValidation(ByVal Arr As Variant, ByVal Target As Range)
Dim Dic As Object, i As Long
Set Dic = CreateObject("scripting.dictionary")
For i = 1 To UBound(Arr)
If InStr(1, UCase(Arr(i, 1)), UCase(Target.Value)) Then
If Not IsEmpty(Arr(i, 1)) Then
Dic.Item(Arr(i, 1)) = Dic.Count
End If
End If
Next
With Target.Validation
.Delete
If Dic.Count Then
.Add 3, , , Join(Dic.Keys, ",")
.ShowError = False
End If
If Dic.Count > 1 Then SendKeys ("%{Down}")
Target.Select
End With
Set Dic = Nothing
End Sub
dòng SendKeys ("%{Down}") '---444
mình cho lại vào trong if rồi , để bên ngoài bị lỗi ,
còn chừa lại 1 trường hợp là nếu trong danh sách có 1 ký tự thì ko xổ list ra mà cho vào C4 luôn !
mục 444 bác chỉnh lại , so sánh giá trị Dic sao đó để đc như ý ^^
dòng SendKeys ("%{Down}") '---444
mình cho lại vào trong if rồi , để bên ngoài bị lỗi ,
còn chừa lại 1 trường hợp là nếu trong danh sách có 1 ký tự thì ko xổ list ra mà cho vào C4 luôn !
mục 444 bác chỉnh lại , so sánh giá trị Dic sao đó để đc như ý ^^
nói chung cũng ko rành Dic lắm
chỗ đó mình nghĩ là trong trường hợp Dic.Count=1 , và giá trị ô C4 <> giá trị duy nhất trong Dic
thì lấy giá trị trong Dic gán ra ô C4 , nhưng lấy giá trị duy nhất trong Dic ra sao ta @@
sửa phần xét send key chắc là xong rùi đó !
thôi ngủ phát !
Có một số sự kiện trong sytem mà rất có thể một ứng dụng nào đó quan tâm. Vd. tôi rất muốn system báo cho tôi biết khi có một phím nào được nhấn, chuột được click, move (trong cửa sổ nào đó của ứng dụng của tôi hoặc trong trong bất cứ cửa sổ nào trong system), khi có một cửa sổ nào đó được tạo ra hoặc bị hủy (vd. nếu ta khởi động notepad thì có một cửa sổ được tạo ra có class là "notepad", mà trong nó có cửa sổ con có class là "Edit". Cửa sổ con này là toàn bộvùng trắng mà ta nhìn thấy của trình soạn thảo văn bản)
Nếu ứng dụng có nhu cầu thì "đặt đơn" lên system xin hook cụ thể. Ứng dụng đặt đơn bằng cách gọi hàm SetWindowsHookEx với các tham số. Tham số đầu là để "báo cáo" cho sytem về loại hook cần đặt. Tham số thứ hai là địa chỉ của hàm callback. Nếu ta lập trình trong vd. VB, Delphi v...v thì code của callback có thể nằm ở trong code của ứng dụng hoặc nằm trong thư viện DLL. Về các yêu cầu thì phải đọc trong help về tham số thứ 3 và 4. Khi hàm SetWindowsHookEx trảvề giá trị <> 0 thì có nghĩa là hook đã được cài đặt thành công, và kể từ lúc này cho tới khi "nộp đơn" xin hủy hook (UnhookWindowsHookEx) khi sự kiện liên quan tới hook sảy ra thì system sẽ gọi hàm callback (do có địa chỉ của nó rồi) và truyền vào 3 tham số. Trong tham số wParam vàlParam chứa đựng mọi thông tin về sự kiện. Ứng dụng sẽ lọc ra các thông tin cần thiết để xử lý.
Rất có thể có nhiều khách hàng cùng quan tâm vd. sự kiện liên quan tới bàn phím. Lúc này cáckhách sẽ được sắp xếp theo một hàng - anh nào đặt đơn càng muộn thì càng đứng trước. Khi sảy ra sự kiện thì system sẽ gọi callback của anh đầu tiên - anh đăng ký muộn nhất, tiếp theo gọi callback của anh thứ hai v...v. Nhưng không phải lúc nào cũng thế. Tiếp theo tôi sẽ chỉ ra.
em cũng vọc vụ này hổm rày và chết ngắt trong đoạn trên.
chắc vọc sỹ mới chơi nên chả nghĩ được ý tưởng để giải quyết.
hic..... hic....
em tải thử file trên về thì việc hook nếu gõ chữ ngay trên cells của excel thì lệnh không thực hiện, nếu nhấn ra ngoài excel thì lệnh mới chạy. vậy thì khác với code của bác dhn46 rồi bác nhỉ
Tạo danh sách tìm kiếm nhiều cột và lọc hay tim trong validation mà muốn dùng chính ngay mục nhập tại ô soạn thảo excel là kỹ thuật vô cùng khó! Excel không mở đối tượng để người lập trình can thiệp và vào các thuộc tính, sự kiện vào đối tượng nhập liệu. Hiện nay A-Tools đã hack được vào đối tượng này để bắt sự kiện và tôi đã tạo ra tính năng nhập liệu nâng cao. Đây là kỹ thuật lập trình API với Hook, Subclass ở mức độ rất cao cấp, nó không phải can thiệp thông thường như các chuyên gia lập trình API trong Windows trên thế giới. Chính vì thế kỹ thuật bắt sự kiện vào mục nhập liệu của Excel - không chèn Active Controls trở thành "bí quyết" công nghệ.
Video tôi chia sẻ dưới đây không có ý quảng cáo mà chỉ ra những khó khăn và bất cập nếu lập trình VBA thông thường để tạo danh sách tìm kiếm nhiều cột như các sản phẩm khác của nhiều người, bên cạnh đó tôi cũng chỉ ra 8 đặc tính khó mà tôi đã xử lý được trong chức năng này, nếu bạn nào muốn làm thì coi như đây là ý tưởng thiết kế tham khảo.
(Tôi có thể chia sẻ kiến thức về kỹ thuật lập trình API cũng như về VBA trong các vấn đề ngoài chức năng của A-Tools. Sorry!).
Tạo danh sách tìm kiếm nhiều cột và lọc hay tim trong validation mà muốn dùng chính ngay mục nhập tại ô soạn thảo excel là kỹ thuật vô cùng khó! Excel không mở đối tượng để người lập trình can thiệp và vào các thuộc tính, sự kiện vào đối tượng nhập liệu. Hiện nay A-Tools đã hack được vào đối tượng này để bắt sự kiện và tôi đã tạo ra tính năng nhập liệu nâng cao. Đây là kỹ thuật lập trình API với Hook, Subclass ở mức độ rất cao cấp, nó không phải can thiệp thông thường như các chuyên gia lập trình API trong Windows trên thế giới. Chính vì thế kỹ thuật bắt sự kiện vào mục nhập liệu của Excel - không chèn Active Controls trở thành "bí quyết" công nghệ.
Video tôi chia sẻ dưới đây không có ý quảng cáo mà chỉ ra những khó khăn và bất cập nếu lập trình VBA thông thường để tạo danh sách tìm kiếm nhiều cột như các sản phẩm khác của nhiều người, bên cạnh đó tôi cũng chỉ ra 8 đặc tính khó mà tôi đã xử lý được trong chức năng này, nếu bạn nào muốn làm thì coi như đây là ý tưởng thiết kế tham khảo.
(Tôi có thể chia sẻ kiến thức về kỹ thuật lập trình API cũng như về VBA trong các vấn đề ngoài chức năng của A-Tools. Sorry!).
nếu tính năng này cua A tools là miễn phí vậy thầy có thể rộng lượng chia sẻ được không thầy? đang tò mò tìm hiểu để phát triển vài thứ hỗ trợ cho công việc mà bí thù lù @@
Cám ơn batman1, Anh Tuấn đã chia sẻ những kiến thức và kinh nghiệm làm.. Bạn Mutants Men! Anh Tuấn ở trên đã nói đây là kỹ thuật hook nâng cao và nó nằm trong A Tool nên ko thể chia sẻ đc. ... nên phải tự nghiên cứu thôi!
Cám ơn batman1, Anh Tuấn đã chia sẻ những kiến thức và kinh nghiệm làm.. Bạn Mutants Men! Anh Tuấn ở trên đã nói đây là kỹ thuật hook nâng cao và nó nằm trong A Tool nên ko thể chia sẻ đc. ... nên phải tự nghiên cứu thôi!
Tôi thấy vụ hook này cũng có một thành viên làm được mà một thời gian rồi không thấy onl. Tớ đây chắc cũng đi xa chủ đề của anh mạnh rồi.
Hic.... Hic....
Chả thấy ảnh đá động gì tới vụ hook này. Chắc không quan tâm
Hic.... Hic....
Tôi thấy vụ hook này cũng có một thành viên làm được mà một thời gian rồi không thấy onl. Tớ đây chắc cũng đi xa chủ đề của anh mạnh rồi.
Hic.... Hic....
Chả thấy ảnh đá động gì tới vụ hook này. Chắc không quan tâm
Hic.... Hic....
File bạn Batman1 chính là kỹ thuật Hook để bắt sự kiện bàn phím trên VBA, xét về chia sẻ mã nguồn với kỹ thuật Hook bàn phím nó tốt nhất trên GPE ! Trước đây có file gần giống file này nhưng nó bẫy chỉ cho nhập phím số. Như mình đã chia sẻ "Can thiệt vào mục nhập của Excel là kỹ thuật Hook, SubClass cao cấp trong lập trình API... Can thiệt vào đối tượng nhập liệu của Excel là vô cùng khó! ". Bạn cứ tìm trên Google từ khoá "Hook" + API + VBA,... thế giới nói nhiều về việc này để nâng cao hiểu biết về nó, không làm việc này thì làm việc khác. Kỹ thuật xử lý sự kiện nhập liệu trong Excel mình làm trong Add-in A-Tools nếu chuyển thành ngôn ngữ VBA để chạy thì sợ rằng không chạy nổi, vì VBA hỗ trợ SubClass rất kém. A-Tools là miễn phí nhiều chức năng nhưng không phải mã nguồn mở, có những bí mật về công nghệ trong sản phẩm này - Cơ sở thương thiệu có tính tính cạnh tranh nên mình không thể chia sẻ (mình chỉ có thể chia sẻ kinh nghiệp, định hướng xây dựng chức/tính năng), các kỹ thuật khác không liên quan chức năng trong A-Tools mình sẽ chia sẻ như: Công thức Excel, VBA, Delphi, API!
(Bạn tìm bài viết của mình trên GPE sẽ thấy nhiêu ví dụ về API, trong đó có file mã nguồn mở Unicode Menu In Userform khá công phu.)
Tôi khuyên các bạn, nếu kiến thức của chúng ta mới chỉ dừng lại ở VBA (kể cả cao cấp VBA thuần tuý) thì đừng sử dụng kỹ thuật Hook, SubClass vì rất dễ làm hỏng ứng dụng, có những lỗi không tìm được lý do. Chỉ dùng khi bạn có hiểu biết nhất định về nó!
Thực ra Excel và lập trình chỉ là đam mê chứ không phải công việc nên tôi không tìm hiểu các hệ điều hành khác ngoài XP Home của tôi. Tất nhiên nhiều cái tôi biết nhưng về bảo mật, thiết lập thì không có system thích hợp để kiểm nghiệm. Chả nhẽ không dùng tới trong công việc mà lại bỏ tiền ra mua Windows 7, 8, 10 và những hđh sẽ có? Vì cài Windows lậu mà bị phát hiện thì bị phạt. Nếu công việc cần tới thì cũng liều đấy nhưng công việc không liên quan gì tới lập trình.
Vài lời mở đầu vậy.
1. Tôi đã thử code trên máy bàn với XP Home + Excel 2010. Chỉ có 1 tài khoản Administrator. Kết quả luôn có trong sheet dù gõ phím khi Excel active hay khi notepad active.
3. Hàng xóm có laptop với Windows 10 Home 64-bit + Excel 2007. Cũng chỉ có 1 tài khoản Administrator. Chạy code thì cũng cho kết quả như điểm 1.
Tôi tạo thêm 1 tài khoản local (Administrator là tài khoản Microsoft). Cũng cho phép dùng Macro. Khi chạy code thì cũng có kết quả như điểm 1.
Tóm lại thì tôi chạy trên 3 máy từ system cũ XP tới system mới nhất Windows 10 đều thành công. Vì vậy tôi không hiểu bạn bị lỗi gì.
Bạn chạy không thành công với system nào vậy? Không thành công với tài khoản User hay cả với tài khoản Administrator cũng không thành công?
Nếu bạn nhấn phím mà không có kết quả trên sheet thì chỉ có thể là SetWindowsHookEx không thành công. Bạn thử sau dòng
If HookHandle <> 0 Then
MsgBox "Thanh cong"
Else
MsgBox "Khong thanh cong"
End If
rồi xem thông điệp thế nào.
Nhiều hàm API khi gọi mà không thành công thì có thể đọc thông tin về lỗi bằng hàm GetLastError. Nhưng trong trường hợp SetWindowsHook thì không biết system có để lại thông tin lỗi không vì tôi không thấy help đả động tới. Nhưng bạn vẫn có quyền thử:
1. Khai báo
Mã:
Private Declare Function GetLastError Lib "kernel32.dll" () As Long
Do không đọc kỹ nên tôi chót viết bài trước.
Nếu nói về nhấn phím trong bảng UAC thì ...
Mọi cái sảy ra hay không đều do system quyết định. Ông system là tối cao mà ổng quyết định không gọi các callback thì phải chịu thôi. Tôi không biết hướng giải quyết. Thậm chí tôi không có system với cái UAC kia để thực nghiệm.
Do không đọc kỹ nên tôi chót viết bài trước.
Nếu nói về nhấn phím trong bảng UAC thì ...
Mọi cái sảy ra hay không đều do system quyết định. Ông system là tối cao mà ổng quyết định không gọi các callback thì phải chịu thôi. Tôi không biết hướng giải quyết. Thậm chí tôi không có system với cái UAC kia để thực nghiệm.
Em đã chỉnh UAC ở mức thấp nhất, và máy tính đã có quyền Admin
nhưng khi sửa theo bài #56 thì khi nhấn phím
ở ngoài excel: dữ liệu được điền vào các ô ở trên cell
trong excel: dữ liệu điền ngay ô chọn chứ không điền như trường hợp trên
em có thử thêm Beep sau dòng: Sheet1.Cells(r, c).Value = Text
thì chỉ nghe âm thanh báo khi ở nhấn phím bên ngoài excel, vậy là trong excel thì không thể gọi LowLevelKeyboardProc chạy được
không biết vụ hook này có đả động đến chủ đề này không. nếu đi xa vấn đề quá thì mong mọi người có thể qua topic này, em hỏi mà chả ai quan tâm trả lời cả
hic..... hic....
Đây là kết quả cuối cùng úp lên tặng cho Bạn nào cần thì cứ vậy mà xài ... code xúc tích ngắn gọn ... đơn giản ....
Và dễ hiểu kèm theo tham số của hàm InStr cho những ai mới bắt đầu VBA tìm hiểu
1/ Tại C4 bạn muốn gõ cái giống gì vào đó thì gõ xong Enter
2/ nếu Xóa trắng C4 thì nó lấy hết
3/ Quá trình xử dụng nếu có lỗi gì phát sinh vui lòng báo lại tại đây
4/ Mô tả Hàm InStr cho những Bạn mới làm quen với VBA ... Mạnh Copy từ Internet
Tên hàm:
InStr
Mô tả:
InStr([start, ]string1, string2[, compare])
Tìm chuỗi string2 trong chuỗi string1, tìm từ vị trí start
Tham số:
start
Vị trí tìm
string1
Chuỗi tìm kiếm
string2
Giá trị cần tìm
compare
Chỉ rõ kiểu dữ liệu để so sánh trong quá trình tìm kiếm
Ghi chú:
Dùng cho tham số compare
vbUseCompareOption = –1
Chế độ tùy chọn, VB sẽ tự động lựa lọai dữ liệu thích hợp
vbBinaryCompare = 0
So sánh nhị phân
vbTextCompare = 1
So sánh chuỗi
vbDatabaseCompare = 2
So sánh dữ liệu
Private Sub Form_Load()
Dim SearchString, SearchChar, MyPos
SearchString = "XXpXXpXXPXXP"' String to search in.
SearchChar = "P"' Search for "P".
' So sanh theo cua text tu vi tri 4
MyPos = InStr(4, SearchString, SearchChar, 1)' Returns 6.
' So sanh theo Binary
MyPos = InStr(1, SearchString, SearchChar, 0)' Returns 9.
' So sanh theo Binary, do mac dinh la 0
MyPos = InStr(SearchString, SearchChar)' Returns 9.
MyPos = InStr(1, SearchString, "W")' Returns 0.
End Sub
PHP:
Private Sub Worksheet_Change(ByVal Target As Range)
Application.EnableEvents = False
Dim Nguon()
Nguon = Sheet1.Range(Sheet1.[B3], Sheet1.[B65536].End(3)).Value
If Target.Address = [C4].Address Then
If Target.Count = 1 Then
Call GetListValidation(Nguon(), Sheet2.Range("C4"))
End If
End If
Application.EnableEvents = True
End Sub
Public Sub GetListValidation(ByVal Arr As Variant, ByVal Target As Range)
Dim Dic As Object, i As Long
Set Dic = CreateObject("scripting.dictionary")
For i = 1 To UBound(Arr)
If InStr(1, UCase(Arr(i, 1)), UCase(Target.Value), 1) Then
If Not IsEmpty(Arr(i, 1)) Then
Dic.Item(Arr(i, 1)) = Dic.Count
End If
End If
Next
With Target.Validation
.Delete
If Dic.Count Then
.Add 3, , , Join(Dic.keys, ",")
.ShowError = False
End If
If Dic.Count > 1 Then
SendKeys ("%{Down}"), True
ElseIf Dic.Count = 1 Then
Target.Value = Dic.keys()
End If
Target.Select
End With
Set Dic = Nothing
End Sub