Tạo combobox có chức năng tìm kiếm

Liên hệ QC

biboylenka1

Thành viên hay hỏi
Tham gia
13/5/21
Bài viết
109
Được thích
97
Giới tính
Nam
Em xin chào tất cả các anh/chị trong diễn đàn!
Em muốn nhờ anh/chị trong diễn đàn tạo giúp em một combobox có chức năng tìm kiếm để hỗ trợ việc nhập liệu.
Em có mô tả mong muốn và kết quả mong muốn trong file đính kèm.Rất mong nhận được sự giúp đỡ của anh chị.
Em xin cảm ơn!
 

File đính kèm

  • Vidu combobox.xlsm
    25.7 KB · Đọc: 27
Chào anh Batman ạ.
Hôm em có tham khảo 1 bài viết khác của anh về Listbox ở một bài viết khác.
Em muốn tạo 1 Listbox ở ô B4 theo danh sách ở vùng N3:N17 nhưng mà không được.
Anh có thể hướng dẫn em được không ạ.
Em cảm ơn anh.

View attachment 264481
Góp vui trong khi ngồi nhà giãn cách chống dịch .
Bạn thử dùng tạm trong khi chờ anh Batman hoặc anh chị em khác giúp đỡ. Hy vọng đúng ý.
Vẫn là code cũ của bạn thôi. mình có sửa đổi chút ít cho đúng với đề bài.
Có gì mạo muội xin được các anh chị em lượng thứ.
 

File đính kèm

  • Danh sach chon.xlsm
    63.9 KB · Đọc: 29
Upvote 0
Dạ, luôn luôn chỉ trong ô B4 ạ.
Em xin lỗi vì giải thích thiếu thông tin ạ.

Góp vui trong khi ngồi nhà giãn cách chống dịch .
Bạn thử dùng tạm trong khi chờ anh Batman hoặc anh chị em khác giúp đỡ. Hy vọng đúng ý.
Vẫn là code cũ của bạn thôi. mình có sửa đổi chút ít cho đúng với đề bài.
Có gì mạo muội xin được các anh chị em lượng thứ.

Dạ em cảm ơn nhiều ạ.
 
Upvote 0
1. Thêm module vd. Module1 và dán code vào module.
Mã:
Option Explicit

Sub FindMultiCol_to_ListBox(ByVal findvalue, ByVal ignorecase As Boolean, ByVal matchstr As String, data, ListBox As Object, ParamArray cols())
'    - tim findvalue trong mang 2 chieu data, ket qua nhap vao ListBox. Truoc khi tim thi cac muc trong ListBox duoc xoa.
'    - findvalue: gia tri can tim
'    - data: mang 2 chieu
'    - ListBox: ListBox voi cac muc duoc tim thay
'    - cols la danh sach chi so cac cot can tim trong mang data duoc phan cach boi dau phay. Cac chi so cot phai duoc tinh
'    tu 1 cho du chi so cot trong mang duoc tinh tu dau. Vd. mang data co chi so cot duoc tinh tu 3 den 7 vd. data(1 to 100, 3 to 7)
'    thi neu ta muon tim kiem trong cot dau tien cua mang data thi ta truyen 1 chu khong phai la truyen 3.
'    Neu tim tat ca cac cot cua mang data thi ngoai cach liet ke chi so cua tat ca cac cot cung co the khong truyen cols.
'    Tuc neu bo qua cols thi hieu la tim tat ca cac cot
'    ignorecase = True la khong phan biet chu hoa chu thuong
'    matchstr = "" la tim dung
'    matchstr = "<" la tim voi findvalue la doan dau
'    matchvalue = ">" la tim voi findvalue la doan cuoi
'    matchstr khac "", "<", ">" la tim voi findvalue o vi tri bat ky
Dim r As Long, k As Long, count As Long, c, value_, chiso, result()
    ListBox.Clear
    On Error GoTo end_
    If ignorecase Then findvalue = LCase(findvalue)
    If matchstr = "<" Then
        findvalue = findvalue & "*"
    ElseIf matchstr = ">" Then
        findvalue = "*" & findvalue
    ElseIf matchstr <> "" Then
        findvalue = "*" & findvalue & "*"
    End If
    If UBound(cols) = -1 Then
        ReDim chiso(1 To UBound(data, 2) - LBound(data, 2) + 1)
        For c = 1 To UBound(chiso)
            chiso(c) = c
        Next c
    Else
        chiso = cols
    End If
    For r = LBound(data) To UBound(data)
        For Each c In chiso
            If ignorecase Then
                value_ = LCase(data(r, LBound(data, 2) + c - 1))
            Else
                value_ = data(r, LBound(data, 2) + c - 1)
            End If
            If value_ Like findvalue Then
                count = count + 1
                ReDim Preserve result(LBound(data, 2) To UBound(data, 2), 1 To count)
                For k = LBound(data, 2) To UBound(data, 2)
                    result(k, count) = data(r, k)
                Next k
                Exit For
            End If
        Next c
    Next r
    If count Then ListBox.Column = result
end_:
End Sub

2. Code Private Sub TextBox1_Change mới
Mã:
Private Sub TextBox1_Change()
    If khong_lam Then Exit Sub
    ListBox1.Clear
    If TextBox1.Value = "" Then
        ListBox1.List = dulieu
    Else
        FindMultiCol_to_ListBox TextBox1.Value, False, "*", dulieu, ListBox1
    End If
End Sub

3. Đọc kỹ hướng dẫn trong FindMultiCol_to_ListBox.

Trong điểm 2 là tìm đoạn trong TextBox1 ở vị trí bất kỳ, không phân biết chữ hoa hay thường, tìm trong tất cả các cột.

Nếu là vd. tìm đoạn trong TextBox1 ở vị trí ĐẦU, CÓ phân biết chữ hoa hay thường, tìm trong cột thứ 2 và thứ 3 thì

FindMultiCol_to_ListBox TextBox1.Value, TRUE, "<", dulieu, ListBox1, 2, 3
Vistaab rất vui khi bắt gặp bài viết này của anh Batman1 vì bản thân em đang tìm hiểu về vấn đề này, xin bày tỏ cảm kích và cảm ơn cá nhân anh Batman1 đã chia sẻ code.
Khi vọc code, em có thêm 1 ít chỉnh sửa để việc điều hướng bằng phím di chuyển trong TextBox1 được thuận tiện hơn cho mục đích nhập liệu của em(và có thể người khác cũng cần) nên em mạn phép chia sẻ lên đây:
Thay đổi Sub TextBox1_KeyDown thành:
Mã:
Private Sub TextBox1_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
With Worksheets("NhapLieu").Range(TextBox1.TopLeftCell.Address)
      Select Case KeyCode
        Case 9 'Tab
        ListBox1.Activate
        ListBox1.ListIndex = 0
       
        Case 13, 40 'Enter 'Down arrow
        .Offset(1).Select
       
        Case 38 'Up arrow
        .Offset(-1).Select
               
        Case Else
        'do nothing
    End Select
End With
End Sub
Mục đích: - Ấn phím Tab thì chuyển sang lựa chọn thông tin trong ListBox; Phím Enter và Mũi tên xuống thì xuống 1 hàng; Mũi tên đi lên thì lên 1 hàng.
Ngoài ra, tại sub nhaplieu, sửa .Offset(1).Select thành .Offset(,2).Select nhằm mục đích: khi lựa chọn xong sản phẩm thì tự động nhảy sang 2 cột để nhập số lượng (hoặc thông tin khác nếu cần).
Điều hướng trong ListBox có thay đổi:
Mã:
Private Sub ListBox1_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
    If KeyCode = 13 Or KeyCode = 9 Then
        If ListBox1.ListIndex > -1 Then nhaplieu
        KeyCode = 0
    ElseIf KeyCode = 37 Then
        TextBox1.Activate
    End If
End Sub
Mục đích: Trong listbox, di chuyển chuột lên xuống chọn sản phẩm cần nhập, ấn Tab hoặc Enter để nhập liệu. Ấn phím mũi tên sang trái để quay lại TextBox
 
Lần chỉnh sửa cuối:
Upvote 0
Thêm module vd. Module1 và dán code vào module.
Cho mình hỏi chút nếu muốn TextBox + ListBox chỉ có ở một ô duy nhất thôi ví dụ D2 thì chỉnh code như nào với. (mục tiêu mình muốn dùng như kiểu ô tìm kiếm để nhìn những dòng có dữ liệu liên quan đến ký tự mình gõ thôi)
 

File đính kèm

  • TextBoxListBox 2.xlsm
    36.4 KB · Đọc: 11
Upvote 0
Cho mình hỏi chút nếu muốn TextBox + ListBox chỉ có ở một ô duy nhất thôi ví dụ D2 thì chỉnh code như nào với. (mục tiêu mình muốn dùng như kiểu ô tìm kiếm để nhìn những dòng có dữ liệu liên quan đến ký tự mình gõ thôi)
Trong Private Sub Worksheet_SelectionChange(ByVal Target As Range), bạn thử thay:
Mã:
If Target.count = 1 And Not Intersect(Target, [C6:C100]) Is Nothing Then
bằng
Mã:
If Target.count = 1 And Not Intersect(Target, [D2]) Is Nothing Then
 
Upvote 0
Trong Private Sub Worksheet_SelectionChange(ByVal Target As Range), bạn thử thay:
Mã:
If Target.count = 1 And Not Intersect(Target, [C6:C100]) Is Nothing Then
bằng
Mã:
If Target.count = 1 And Not Intersect(Target, [D2]) Is Nothing Then
Hoặc thành
Mã:
If Target.Address = "$D$2" Then
 
Upvote 0
Qua tham khảo thêm các bài viết của anh Batman1 trên diễn đàn, qua chủ đề này và các thông tin liên quan, mình đã hoàn thiện được file để sử dụng theo mục đích riêng của cá nhân, nay mình chia sẻ file lên đây với mọi người để cùng thảo luận thêm các vấn đề khác có liên quan:
Mô tả: Khi nhập thông tin tại cột C thì hiện listbox; ấn Tab hoặc Enter để qua listbox lựa chọn; ấn Tab hoặc Enter để nhập thông tin từ listbox vào bảng đồng thời nhảy sang cột nhập dữ liệu về số lượng tại cột F; ấn Tab, Enter hoặc các mũi tên điều hướng để tự nhảy về dòng cần nhập liệu tiếp theo ở cột C; khi nhập liệu hoàn tất, để tắt Textbox và Listbox không cho hiển thị nữa thì ấn Esc. Như vậy đã hạn chế rất nhiều số lần sử dụng chuột khi nhập liệu.
Trao đổi - Thảo luận thêm: Trong listbox, thông tin về đơn giá được định dạng phân cách phần nghìn. Tuy nhiên do kiến thức còn hạn hẹp, mình có tìm hiểu nhưng vẫn chưa hoàn thiện được 2 vần đề:
Vấn đề 1 là: Định dạng căn lề cho các cột thông tin trong listbox (như: cột chứa mã hàng và cột đơn vị tính thì căn lề giữa, cột tên hàng thì căn lề trái); Kẻ đường viên cho bảng dữ liệu trong listbox.
Vấn đề 2 là: Hiển thị tiêu đề (column head) cho listbox.
Vậy vistaab upload file và code để thuận tiện trao đổi với các thầy, anh chị và các bạn.
Code tại sheet NhapPhieu
Mã:
Option Explicit
Option Compare Text

Private dulieu, khong_lam As Boolean

Private Sub nhaplieu()
Dim c As Long
    With Worksheets("NhapPhieu").Range(TextBox1.TopLeftCell.Address)
        For c = 1 To 4
            .Offset(0, c - 2).Value = ListBox1.List(ListBox1.ListIndex, c - 1)
        Next c
        .Offset(, 3).Select
        ListBox1.Visible = False
        TextBox1.Visible = False
    End With
End Sub

Private Sub ListBox1_DblClick(ByVal Cancel As MSForms.ReturnBoolean)
    nhaplieu
End Sub

Private Sub ListBox1_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
    If KeyCode = 13 Or KeyCode = 9 Then
        If ListBox1.ListIndex > -1 Then nhaplieu
        KeyCode = 0
    ElseIf KeyCode = 37 Then
        TextBox1.Activate
    End If
End Sub

Private Sub TextBox1_Change()
    If khong_lam Then Exit Sub
    ListBox1.Clear
    If TextBox1.Value = "" Then
        ListBox1.List = Sheet1.Range("B3:E100").Value
    Else
        FindMultiCol_to_ListBox TextBox1.Value, True, "*", dulieu, ListBox1
    End If
End Sub
Private Sub TextBox1_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
With Worksheets("NhapPhieu").Range(TextBox1.TopLeftCell.Address)
      Select Case KeyCode
        Case 9, 13 'Tab 'Enter
        ListBox1.Activate
        ListBox1.ListIndex = 0

        Case 40 'Enter 'Down arrow
        .Offset(1).Select

        Case 38 'Up arrow
        .Offset(-1).Select
       
        Case 27 'Esc
        ListBox1.Clear
        ListBox1.Visible = False
        TextBox1.Visible = False
       
        End Select
End With
End Sub

Private Sub Worksheet_Change(ByVal Target As Range)
Dim i As Long
    For i = 6 To 100
        If Target.Address = "$F$" & i Then
            Target.Offset(1, -3).Select
        End If
    Next i
End Sub

Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim lastRow As Long, iwk As Long
'    ListBox1.Visible = False
'    TextBox1.Visible = False
    khong_lam = True
    TextBox1.Value = Empty
    khong_lam = False
    If Target.count = 1 And Not Intersect(Target, [C6:C100]) Is Nothing Then
        dulieu = Empty
        With Worksheets("GIABAN")
            lastRow = .Range("B" & Rows.count).End(xlUp).Row
            If lastRow > 1 Then
                dulieu = .Range("B3:E" & lastRow).Value
                For iwk = 1 To UBound(dulieu, 1)
                    dulieu(iwk, 4) = Format(dulieu(iwk, 4), "#,##0")
                Next iwk
                ListBox1.List = dulieu
                With TextBox1
                    .Left = Target.Left
                    .Top = Target.Top
                    .Width = Target.Width
                    .Height = Target.Height + 3
                    .Visible = True
                    .Activate
                End With
                With ListBox1
                     .Left = Target.Offset(0, 1).Left
                    '.Left = TextBox1.Left
                    .Top = TextBox1.Top + TextBox1.Height
                    .ColumnHeads = False
                    .ColumnCount = 4
                    .Visible = True
                   
                End With
            End If
        End With
    End If
End Sub
Code tại Module InputFL
Mã:
Option Explicit

Sub FindMultiCol_to_ListBox(ByVal findvalue, ByVal ignorecase As Boolean, ByVal matchstr As String, data, ListBox As Object, ParamArray cols())
'    - tim findvalue trong mang 2 chieu data, ket qua nhap vao ListBox. Truoc khi tim thi cac muc trong ListBox duoc xoa.
'    - findvalue: gia tri can tim
'    - data: mang 2 chieu
'    - ListBox: ListBox voi cac muc duoc tim thay
'    - cols la danh sach chi so cac cot can tim trong mang data duoc phan cach boi dau phay. Cac chi so cot phai duoc tinh
'    tu 1 cho du chi so cot trong mang duoc tinh tu dau. Vd. mang data co chi so cot duoc tinh tu 3 den 7 vd. data(1 to 100, 3 to 7)
'    thi neu ta muon tim kiem trong cot dau tien cua mang data thi ta truyen 1 chu khong phai la truyen 3.
'    Neu tim tat ca cac cot cua mang data thi ngoai cach liet ke chi so cua tat ca cac cot cung co the khong truyen cols.
'    Tuc neu bo qua cols thi hieu la tim tat ca cac cot
'    ignorecase = True la khong phan biet chu hoa chu thuong
'    matchstr = "" la tim dung
'    matchstr = "<" la tim voi findvalue la doan dau
'    matchvalue = ">" la tim voi findvalue la doan cuoi
'    matchstr khac "", "<", ">" la tim voi findvalue o vi tri bat ky
' Nguon code: Batman1(GPE)
Dim r As Long, k As Long, count As Long, c, value_, chiso, result()
    ListBox.Clear
    On Error GoTo end_
   
    If ignorecase Then findvalue = LCase(findvalue)
    If matchstr = "<" Then
        findvalue = findvalue & "*"
    ElseIf matchstr = ">" Then
        findvalue = "*" & findvalue
    ElseIf matchstr <> "" Then
        findvalue = "*" & findvalue & "*"
    End If
   
    If UBound(cols) = -1 Then
        ReDim chiso(1 To UBound(data, 2) - LBound(data, 2) + 1)
        For c = 1 To UBound(chiso)
            chiso(c) = c
        Next c
    Else
        chiso = cols
    End If
   
    For r = LBound(data) To UBound(data)
        For Each c In chiso
            If ignorecase Then
                value_ = LCase(data(r, LBound(data, 2) + c - 1))
            Else
                value_ = data(r, LBound(data, 2) + c - 1)
            End If
           
            If value_ Like findvalue Then
                count = count + 1
                ReDim Preserve result(LBound(data, 2) To UBound(data, 2), 1 To count)
                For k = LBound(data, 2) To UBound(data, 2)
                    result(k, count) = data(r, k)
                Next k
                Exit For
            End If
        Next c
    Next r
   
    If count Then ListBox.Column = result
end_:
End Sub
Vistaab xin phép sửa lại nội dung: "Trong listbox, thông tin về đơn giá được định dạng phân cách phần nghìn." Cái này là chưa làm được, chỉ hiển thị trong listbox thì được, nhưng khi nhập vào máy thì bị lỗi, Cụ thể:
Với code:
Mã:
For iwk = 1 To UBound(dulieu, 1)

     dulieu(iwk, 4) = Format(dulieu(iwk, 4), "#,##0")

 Next iwk
Giá trị nhập vào bảng bị chia cho 1000 lần(ví dụ: giá trị hiển thị 3.500 thì khi nhập vào được ghi nhận là 3,5)
Nếu thay "#,##0" bằng "#.##0" thì giá trị hiển thị lại nhân lên với 1000 lần.
 

File đính kèm

  • Input - DA.xlsm
    45.2 KB · Đọc: 33
Lần chỉnh sửa cuối:
Upvote 0
1. Có thể căn trái, phải, giữa (TextAlign) nhưng cho toàn bộ ListBox chứ không cho từng cột riêng rẽ.

2. Có các khả năng:
- dùng thuộc tính RowSource của ListBox + ColumnHeads = True, nhưng lúc này không dùng được thuộc tính List hay Column (ListBox.List = mảng, ListBox.Column = mảng)
- Dùng vd. ListBox.List = mảng nhưng khi soạn mảng thì thêm tiêu đề vào dòng đầu của mảng. Phải phục vụ trường hợp khi người dùng chọn dòng đầu.
- Dùng 1 hàng Label ngay trên ListBox với Caption là những tiêu đề.
 
Upvote 0
Chào cả nhà
không liên quan câu hỏi bạn bên trên nhân tiện mượn thông tin file bạn làm ảnh câu hỏi nhờ cả nhà giúp đỡ
đó là làm cách nào để khống chế cho sử dụng ô tùy thích mình chọn trong ecxel
ví dụ chỉ có thể thao tác được đến dòng 140 ( như hình bên dưới) từ 141 là trắng
1631286204756.png
Cảm ơn mọi người
 
Upvote 0
1. Có thể căn trái, phải, giữa (TextAlign) nhưng cho toàn bộ ListBox chứ không cho từng cột riêng rẽ.

2. Có các khả năng:
- dùng thuộc tính RowSource của ListBox + ColumnHeads = True, nhưng lúc này không dùng được thuộc tính List hay Column (ListBox.List = mảng, ListBox.Column = mảng)
- Dùng vd. ListBox.List = mảng nhưng khi soạn mảng thì thêm tiêu đề vào dòng đầu của mảng. Phải phục vụ trường hợp khi người dùng chọn dòng đầu.
- Dùng 1 hàng Label ngay trên ListBox với Caption là những tiêu đề.
Cảm ơn hướng dẫn thêm của anh. Em còn có 1 thắc mắc xin hướng dẫn của anh:
Em muốn bẫy lỗi trong trường hợp chuỗi ký tự nhập vào textbox không tồn tại trong listbox mà vẫn ấn phím Tab để nhảy sang listbox lựa chọn thì báo lỗi (như hình ảnh bên dưới sau khi đã ấn debug).
Em có suy nghĩ đặt điều kiện TextBox1.Value <> "" và giá trị hàm FindMultiCol_to_ListBox TextBox1.Value, True, "*", dulieu, ListBox1 trả về là 1 khoảng rỗng thì thực hiện 1 lệnh khác (ví dụ: msgbox thông báo không tìm thấy kết quả phù hợp). Mong anh hướng dẫn thêm, cảm ơn anh.


2021-09-10_214421.png
 
Upvote 0
Chào cả nhà
không liên quan câu hỏi bạn bên trên nhân tiện mượn thông tin file bạn làm ảnh câu hỏi nhờ cả nhà giúp đỡ
đó là làm cách nào để khống chế cho sử dụng ô tùy thích mình chọn trong ecxel
ví dụ chỉ có thể thao tác được đến dòng 140 ( như hình bên dưới) từ 141 là trắng
View attachment 265834
Cảm ơn mọi người
Chọn dòng từ 141 đến cuối, chuột phải, Hide.
 
Upvote 0
Em muốn bẫy lỗi trong trường hợp chuỗi ký tự nhập vào textbox không tồn tại trong listbox mà vẫn ấn phím Tab để nhảy sang listbox lựa chọn thì báo lỗi (như hình ảnh bên dưới sau khi đã ấn debug).
Tôi viết đã lâu mà không có hứng dò lại từng bước, vì có thể nhiều chỗ liên quan tới nhau nên sửa 1 chỗ sẽ ảnh hưởng tới những chỗ khác. Tôi nghĩ là trong vấn đề này không như thế, nhưng ý thức cho bạn để bạn kiểm tra kỹ.

Khi giá trị trong TextBox không được tìm thấy ở ListBox thì ListBox RỖNG, ai cũng nhìn thấy, nên ít ai cố ý nhấn TAB. Nhưng nếu bạn đề phòng người dùng sơ xuất hoặc cố ý thì thêm điều kiện IF thôi.

Sửa thành
Mã:
Case 9, 13 'Tab 'Enter mục thì mới thực hiện.
        If ListBox1.ListCount Then    ' hoặc ListBox1.ListCount > 0, tức nếu ListBox có ít nhất 1 mục thì mới thực hiện
            ListBox1.Activate
            ListBox1.ListIndex = 0
        End If
 
Upvote 0
Web KT

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

Back
Top Bottom