Option Explicit
Private WithEvents txtbx As MSForms.TextBox
Private WithEvents lbx As MSForms.ListBox
'//////////////////////////////////////////////////////////
'Change these Constants to meet your specific needs.
Private Const SHEET_NAME = "Sheet1"
Private Const LIST_RANGE_ADDRSS = "A7:A15000"
Private Const INPUT_CELLS = "E6,E14,G6,G14"
Private Const DROPDOWN_HEIGHT = 150 'pt
'//////////////////////////////////////////////////////////
'_________________________________________WORKBOOK EVENTS___________________________________________________
Private Sub Workbook_Activate()
Call AddNameAndBringUpList(ByVal ActiveSheet, ByVal ActiveCell)
Application.OnKey "{F1}", Me.CodeName & ".BringupList"
End Sub
Private Sub Workbook_SheetActivate(ByVal Sh As Object)
If Sh.Name = SHEET_NAME Then
Application.OnKey "{F1}", Me.CodeName & ".BringupList"
End If
End Sub
Private Sub Workbook_SheetDeactivate(ByVal Sh As Object)
If Sh.Name = SHEET_NAME Then
Application.OnKey "{F1}", ""
End If
End Sub
Private Sub Workbook_SheetSelectionChange(ByVal Sh As Object, ByVal Target As Range)
Call AddNameAndBringUpList(ByVal Sh, ByVal Target)
End Sub
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
If Sh.Name = SHEET_NAME Then
If IsError(Application.Match(Target, Range(LIST_RANGE_ADDRSS), 0)) And Not IsEmpty(Target) Then
MsgBox "Entry not in the list." & vbCrLf & vbCrLf & "Try Again ", vbCritical, "Invalid Input."
Target.Select
Target.ClearContents
End If
End If
End Sub
Private Sub Workbook_BeforeClose(Cancel As Boolean)
Application.OnKey "{F1}", ""
On Error Resume Next
Names("CurInputCell").Delete
Sheets(SHEET_NAME).OLEObjects("MyListBox").Delete
Sheets(SHEET_NAME).OLEObjects("MyTextBox").Delete
End Sub
'_________________________________________LISTBOX & TEXTBOX EVENTS___________________________________________________
Private Sub lbx_KeyUp(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
Static lastIndex As Long
With Sheets(SHEET_NAME)
If KeyCode = vbKeyEscape Then
.OLEObjects("MyTextBox").Delete
.OLEObjects("MyListBox").Delete
Exit Sub
End If
If KeyCode = vbKeyUp And lbx.ListIndex = 0 And lastIndex <> 1 Or lbx.ListCount = 0 Then
lbx.ListIndex = -1
.OLEObjects("MyTextBox").Activate
txtbx.Text = "": Exit Sub
End If
End With
txtbx.Text = lbx.Text
lastIndex = lbx.ListIndex
End Sub
Private Sub lbx_MouseUp(ByVal Button As Integer, ByVal Shift As Integer, ByVal x As Single, ByVal Y As Single)
On Error Resume Next
Range([CurInputCell]) = lbx.Value
Sheets(SHEET_NAME).OLEObjects("MyTextBox").Delete
Sheets(SHEET_NAME).OLEObjects("MyListBox").Delete
End Sub
Private Sub lbx_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
With Sheets(SHEET_NAME)
If KeyCode = VBA.vbKeyEscape Then
.OLEObjects("MyTextBox").Delete
.OLEObjects("MyListBox").Delete
Exit Sub
End If
If KeyCode = vbKeyReturn Then
Range([CurInputCell]) = lbx.Value
.OLEObjects("MyTextBox").Delete
.OLEObjects("MyListBox").Delete
Exit Sub
End If
End With
End Sub
Private Sub txtbx_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
Dim indx As Long
Dim ar() As Variant
On Error Resume Next
Select Case KeyCode
Case vbKeyDown
lbx.Selected(0) = True
Sheets(SHEET_NAME).OLEObjects("MyListBox").Activate
Exit Sub
Case vbKeyUp
Exit Sub
Case vbKeyEscape
Sheets(SHEET_NAME).OLEObjects("MyTextBox").Delete
Sheets(SHEET_NAME).OLEObjects("MyListBox").Delete
Exit Sub
Case vbKeyReturn
With txtbx
indx = WorksheetFunction.Match(.Text, Application.Transpose(Range(LIST_RANGE_ADDRSS)), 0)
If indx = 0 Then
MsgBox "Entry not in the list." & vbCrLf & vbCrLf & "Try Again ", vbCritical, "Invalid Input."
.SelStart = 0
.SelLength = Len(.Text)
Else
Range([CurInputCell]) = .Text
Sheets(SHEET_NAME).OLEObjects("MyTextBox").Delete
Sheets(SHEET_NAME).OLEObjects("MyListBox").Delete
Exit Sub
End If
End With
Case VBA.vbKeyBack
End Select
Application.OnTime Now, Me.CodeName & ".FilterList"
End Sub
'__________________________________________HELPER ROUTINES________________________________________________
Private Sub AddNameAndBringUpList(ByVal Sh As Object, ByVal Target As Range)
On Error Resume Next
If Sh.Name = SHEET_NAME Then
If Not IsError(Application.Match(Target.Address(False, False), Split(INPUT_CELLS, ","), 0)) Then
If Target.Cells.Count = 1 Then
Sh.OLEObjects("MyTextBox").Delete
Sh.OLEObjects("MyListBox").Delete
Names.Add "CurInputCell", Target.Address(False, False), False
Application.OnKey "{F1}", Me.CodeName & ".BringupList"
End If
Else
Application.OnKey "{F1}", ""
Sh.OLEObjects("MyTextBox").Delete
Sh.OLEObjects("MyListBox").Delete
End If
End If
End Sub
Private Sub HookAndBuildControls()
Dim oCell As Range
Dim ar() As Variant
On Error Resume Next
Set txtbx = Sheets(SHEET_NAME).OLEObjects("MyTextBox").Object
With txtbx
.SpecialEffect = fmSpecialEffectFlat
.BackColor = &HC0FFFF ' &H80FFFF
.BorderStyle = fmBorderStyleSingle
.ForeColor = vbRed
.Font.Bold = True
End With
Set lbx = Sheets(SHEET_NAME).OLEObjects("MyListBox").Object
With Range([CurInputCell])
lbx.Left = .Left
lbx.Top = .Offset(1).Top + 1
lbx.Height = DROPDOWN_HEIGHT
lbx.Width = .Width + 12
End With
With lbx
.SpecialEffect = fmSpecialEffectFlat
.BackColor = &HC0FFFF '&H80FFFF
.BorderStyle = fmBorderStyleSingle
.IntegralHeight = False
.Height = .Height
.IntegralHeight = True
End With
ar = Application.Transpose(Range(LIST_RANGE_ADDRSS))
lbx.List = ar
Sheets(SHEET_NAME).OLEObjects("MyListBox").Visible = False
Sheets(SHEET_NAME).OLEObjects("MyListBox").Visible = True
txtbx.Activate
End Sub
Private Sub FilterList()
On Error Resume Next
Dim i As Long
Dim ar() As Variant
Dim resultString As String
Dim delim As String: delim = Chr(1)
ar = Application.Transpose(Range(LIST_RANGE_ADDRSS))
With lbx
ar(1) = Chr(2) & delim & ar(1)
resultString = Join(Filter(Split("|" & Join(ar, Chr(2) & delim), Chr(2)), delim & txtbx.Text, compare:=vbTextCompare), "")
If Len(resultString) <> 0 Then
.List = Split(Right(resultString, Len(resultString) - 1), delim)
Else
.Clear
End If
.IntegralHeight = False
.Height = .Height
.IntegralHeight = True
End With
End Sub
Private Sub BringupList()
Dim oTxtBx As OLEObject
Dim oLbx As OLEObject
If Not IsError(Application.Match(ActiveCell.Address(False, False), Split(INPUT_CELLS, ","), 0)) Then
If ActiveCell.Address = Range([CurInputCell]).Address Then
With Range([CurInputCell])
Set oTxtBx = Sheets(SHEET_NAME).OLEObjects.Add(ClassType:="Forms.TextBox.1", Link:=False, _
DisplayAsIcon:=False, Left:=.Left, Top:=.Top, Width:=.Width, Height:=.Height)
End With
oTxtBx.Name = "MyTextBox"
Set oLbx = Sheets(SHEET_NAME).OLEObjects.Add(ClassType:="Forms.ListBox.1")
oLbx.Name = "MyListBox"
Application.OnTime Now, Me.CodeName & ".HookAndBuildControls"
End If
End If
End Sub