Hey Xombie - have you done any further updates to your code?
Since I switched to the WinAPI implementation Vista users have complained about it locking up the software. I've verified that and am looking for other solutions now.
Autocompleting Combobox and Strings
-Mitchell
Check out kBilling for all your billing software needs!
http://www.k-billing.com
Code Signing / Authenticode Certificates (Get rid of those Unknown Publisher warnings!)
http://codesigning.ksoftware.net
Check out kBilling for all your billing software needs!
http://www.k-billing.com
Code Signing / Authenticode Certificates (Get rid of those Unknown Publisher warnings!)
http://codesigning.ksoftware.net
Karbon,
I've been using this revision for my current personal project but I've only updated the combobox part and not the string/editor part. Let me know if there's anything wrong with it and I can update it fairly quickly for you.
I've been using this revision for my current personal project but I've only updated the combobox part and not the string/editor part. Let me know if there's anything wrong with it and I can update it fairly quickly for you.
Code: Select all
;- Coded by Xombie 12/19/2005, updated 8/18/2006, updated 12/11/2007
;- Structures
Structure s_ACStringStructure
FakeString.s[0]
EndStructure
Structure s_AutoComplete
;
Gadget.l
Handle.l
Parent.l
CallBack.l
; The old callback handle.
ArrayAddress.l
; Only valid for edit controls, this will be the address of the first element in an array of strings.
PopList.b
; Non-zero if displaying a small popup list of matching text. The value is the number of characters to match on. This
; completely changes the behavior of the autocompletion routines. Individual words are matched to a list of words.
ShowDrop.b
;
EndStructure
Structure _s_AutoComplete_Info
;
Gadget.l
;
IdentifierWindow.l
HandleWindow.l
;
IdentifierList.l
HandleList.l
;
CallBack.l
;
EndStructure
;-
EnableExplicit
;- Global Variables
Global NewList _ac_Main.s_AutoComplete()
Global __ac_Info._s_AutoComplete_Info
;-
Procedure _ac_QuickSortArray(Address.l, g.l, d.l)
; Modified from the PureBasic advanced examples.
Define.s v, tmp, t
;
Define.l i, j, ok
;
Define.s_ACStringStructure *Position
; This will be a pointer to the strings in the array.
*Position = Address
;
If g < d
v = *Position\FakeString[d]
i = g-1
j = d
;
Repeat
Repeat : i=i+1 : Until LCase(*Position\FakeString[i]) >= LCase(v)
ok = 0
Repeat
If j>0 : j=j-1 : Else : ok=1 : EndIf
If LCase(*Position\FakeString[j]) <= LCase(v) : ok=1 : EndIf
Until ok<>0
tmp = *Position\FakeString[i]
*Position\FakeString[i] = *Position\FakeString[j]
*Position\FakeString[j] = tmp
Until j <= i
;
t = *Position\FakeString[j]
*Position\FakeString[j] = *Position\FakeString[i]
*Position\FakeString[i] = *Position\FakeString[d]
*Position\FakeString[d] = t
;
_ac_QuickSortArray(Address, g, i-1)
_ac_QuickSortArray(Address, i+1, d)
;
EndIf
;
EndProcedure
Procedure _ac_KillList()
;
If __ac_Info\IdentifierWindow
;
FreeGadget(__ac_Info\IdentifierList)
;
CloseWindow(__ac_Info\IdentifierWindow)
;
__ac_Info\IdentifierWindow = 0
;
__ac_Info\HandleWindow = 0
;
__ac_Info\IdentifierList = 0
;
__ac_Info\HandleList = 0
;
EndIf
;
EndProcedure
Procedure.l _ac_HandleListEvents(HandleWindow.l, Message.l, wParam.l, lParam.l)
;
Define.l lResult
;
Define.l HoldLength
;
Define.s HoldString
;
Define.l *Position
;
Define.l Type
;
Define.CHARRANGE HoldRange
;
Type = GadgetType(_ac_Main()\Gadget)
;
If Message = #WM_LBUTTONDBLCLK
;
HoldString = GetGadgetText(_ac_Main()\Gadget)
; Store the current text.
HoldLength = Len(HoldString)
;
*Position = @HoldString + HoldLength - 1
;
While *Position > @HoldString
;
If PeekB(*Position) < 33 : Break : EndIf
;
*Position - 1
;
Wend
;
If Type = #PB_GadgetType_Editor : SendMessage_(_ac_Main()\Handle, #EM_HIDESELECTION, #True, #Null) : EndIf
;
If PeekB(*Position) < 33
;
If Type = #PB_GadgetType_String
SendMessage_(_ac_Main()\Handle, #EM_SETSEL, *Position - @HoldString + 1, HoldLength)
Else
HoldRange\cpMin = *Position - @HoldString + 1 : HoldRange\cpMax = HoldLength
SendMessage_(_ac_Main()\Handle, #EM_EXSETSEL, *Position - @HoldString + 1, HoldLength)
EndIf
;
Else
;
If Type = #PB_GadgetType_String
SendMessage_(_ac_Main()\Handle, #EM_SETSEL, *Position - @HoldString, HoldLength)
Else
HoldRange\cpMin = *Position - @HoldString : HoldRange\cpMax = HoldLength
SendMessage_(_ac_Main()\Handle, #EM_EXSETSEL, *Position - @HoldString, HoldLength)
EndIf
;
EndIf
;
HoldString = GetGadgetText(__ac_Info\IdentifierList) + " "
;
SendMessage_(_ac_Main()\Handle, #EM_REPLACESEL, #True, @HoldString)
;
If Type = #PB_GadgetType_Editor : SendMessage_(_ac_Main()\Handle, #EM_HIDESELECTION, #False, #Null) : EndIf
;
_ac_KillList()
;
SetActiveGadget(__ac_Info\Gadget)
;
ProcedureReturn 1
;
EndIf
;
lResult = CallWindowProc_(__ac_Info\CallBack, HandleWindow, Message, wParam, lParam)
;
ProcedureReturn lResult
;
EndProcedure
;- Popup Autocomplete
Procedure.l _ac_PopList(HoldComplete.s_AutoComplete(), ItemCount.l, Text.s)
;
Define.l iLoop, jLoop
;
Define.l lResult
;
Define.l Parent
;
Define.l lHold
;
Define.s HoldString, HoldText
;
Define.l HoldLength
;
Define.l HoldHeight
;
Define.l CharacterPosition
;
Define.l *Position
;
Define.l iCount
;
Define.b CaughtMatch
;
Define.POINT HoldPoint
;
Define.s_ACStringStructure *HoldArray
; This will be a pointer to the strings in the array.
HoldLength = Len(Text)
;
*Position = @Text + HoldLength - 1
;
If PeekB(*Position) = 32 : _ac_KillList() : EndIf
; Only autocompleting single words.
While *Position > @Text
;
If PeekB(*Position) < 33 : Break : EndIf
;
*Position - 1
;
Wend
;
If PeekB(*Position) < 33
;
If PeekS(*Position + 1) = ""
;
_ac_KillList()
;
ProcedureReturn
;
EndIf
;
CharacterPosition = *Position - @Text + 2
;
HoldText = LCase(PeekS(*Position + 1))
;
Else
;
If PeekS(*Position) = ""
;
_ac_KillList()
;
ProcedureReturn
;
EndIf
;
CharacterPosition = *Position - @Text
; Subtract one to make zero based.
HoldText = LCase(PeekS(*Position))
;
EndIf
;
HoldLength = Len(HoldText)
;
If HoldLength < HoldComplete()\PopList
;
_ac_KillList()
;
ProcedureReturn
;
EndIf
;
*HoldArray = HoldComplete()\ArrayAddress
;
While iLoop <= ItemCount
; Loop through the list of items.
HoldString = LCase(*HoldArray\FakeString[iLoop])
; Store the text at index iLoop. This little trick of getting the items in a array by addresses is thanks (again) to freak ( http://forums.purebasic.com/english/viewtopic.php?t=15366 )
If HoldText = Left(HoldString, HoldLength)
;
If HoldText = HoldString : CaughtMatch = #True : EndIf
;
HoldHeight + 1
;
If HoldHeight = 5 : Break : EndIf
;
EndIf
;
iLoop + 1
;
Wend
;
If HoldHeight = 0 Or (HoldHeight = 1 And CaughtMatch)
;
_ac_KillList()
;
ProcedureReturn
;
EndIf
;
__ac_Info\Gadget = HoldComplete()\Gadget
;
If __ac_Info\IdentifierWindow
; The popup window already exists.
ClearGadgetItemList(__ac_Info\IdentifierList)
; Remove all current items from the list.
iLoop = 0
;
While iLoop <= ItemCount
; Loop through the list of items.
If HoldText = LCase(Left(*HoldArray\FakeString[iLoop], HoldLength))
; This little trick of getting the items in a array by addresses is thanks (again) to freak ( http://forums.purebasic.com/english/viewtopic.php?t=15366 )
CaughtMatch = #False
;
iCount = CountGadgetItems(__ac_Info\IdentifierList)
For jLoop = 1 To iCount
;
If LCase(*HoldArray\FakeString[iLoop]) = LCase(GetGadgetItemText(__ac_Info\IdentifierList, jLoop - 1, 0)) : CaughtMatch = #True : Break : EndIf
;
Next jLoop
;
If CaughtMatch = #False : AddGadgetItem(__ac_Info\IdentifierList, -1, *HoldArray\FakeString[iLoop]) : EndIf
;
EndIf
;
iLoop + 1
;
Wend
;
ResizeWindow(__ac_Info\IdentifierWindow, #PB_Ignore, #PB_Ignore, #PB_Ignore, (HoldHeight * 14) + 4)
;
ResizeGadget(__ac_Info\IdentifierList, #PB_Ignore, #PB_Ignore, #PB_Ignore, (HoldHeight * 14) + 1)
;
Else
; The popup window does not exist.
lResult = SendMessage_(HoldComplete()\Handle, #EM_POSFROMCHAR, @HoldPoint, CharacterPosition)
;
lHold = GetParent_(HoldComplete()\Handle) : While lHold : Parent = lHold : lHold = GetParent_(lHold) : Wend
; Get the handle to the parent window of the edit control.
lResult = MapWindowPoints_(HoldComplete()\Handle, lHold, @HoldPoint, 1)
; Convert the coordinates to the main window.
__ac_Info\IdentifierWindow = OpenWindow(#PB_Any, 0, 0, 244, (HoldHeight * 14) + 4, "", #PB_Window_WindowCentered | #PB_Window_BorderLess, Parent)
;
If __ac_Info\IdentifierWindow
;
__ac_Info\HandleWindow = WindowID(__ac_Info\IdentifierWindow)
;
If CreateGadgetList(__ac_Info\HandleWindow)
;
__ac_Info\IdentifierList = ListViewGadget(#PB_Any, 2, 2, 240, (HoldHeight * 14) + 1)
;
__ac_Info\HandleList = GadgetID(__ac_Info\IdentifierList)
;
__ac_Info\CallBack = SetWindowLong_(__ac_Info\HandleList, #GWL_WNDPROC, @_ac_HandleListEvents())
;
iLoop = 0
;
While iLoop <= ItemCount
; Loop through the list of items.
If HoldText = LCase(Left(*HoldArray\FakeString[iLoop], HoldLength))
; This little trick of getting the items in a array by addresses is thanks (again) to freak ( http://forums.purebasic.com/english/viewtopic.php?t=15366 )
CaughtMatch = #False
;
iCount = CountGadgetItems(__ac_Info\IdentifierList)
For jLoop = 1 To iCount
;
If LCase(*HoldArray\FakeString[iLoop]) = LCase(GetGadgetItemText(__ac_Info\IdentifierList, jLoop - 1, 0)) : CaughtMatch = #True : Break : EndIf
;
Next jLoop
;
If CaughtMatch = #False : AddGadgetItem(__ac_Info\IdentifierList, -1, *HoldArray\FakeString[iLoop]) : EndIf
;
EndIf
;
iLoop + 1
;
Wend
;
Else
;
ProcedureReturn
;
EndIf
;
Else
;
ProcedureReturn
;
EndIf
;
ResizeWindow(__ac_Info\IdentifierWindow, HoldPoint\X, HoldPoint\Y + 14, #PB_Ignore, #PB_Ignore)
;
EndIf
;
SetGadgetState(__ac_Info\IdentifierList, 0)
;
SetActiveGadget(HoldComplete()\Gadget)
;
EndProcedure
;- Callback Functions
Procedure.l _ac_HandleEditEvents(HandleWindow.l, Message.l, wParam.l, lParam.l)
; Custom callback for edit controls.
Define.l lResult
;
Define.l iLoop
;
Define.l HoldTotal
;
Define.l HoldLength
;
Define.l HoldCombinedLength
;
Define.l HoldStart
;
Define.l HoldEnd
;
Define.CHARRANGE HoldRange
;
Define.s HoldString
;
Define.s CombinedText
;
Define.l *Position
;
Define.s_ACStringStructure *HoldArray
; This will be a pointer to the strings in the array.
Define.l Type
;
ResetList(_ac_Main())
While NextElement(_ac_Main())
;
If _ac_Main()\Handle = HandleWindow : Break : EndIf
;
Wend
;
If _ac_Main()\CallBack = -1 : ProcedureReturn : EndIf
; This should never happen as this callback is only set for autocomplete items.
Type = GadgetType(_ac_Main()\Gadget)
;
HoldTotal = PeekL(_ac_Main()\ArrayAddress - 8)
; Return the number of items in the array.
If HoldTotal = 0
; No need to complete if 0 items.
lResult = CallWindowProc_(_ac_Main()\CallBack, HandleWindow, Message, wParam, lParam)
;
Else
;
*HoldArray = _ac_Main()\ArrayAddress
; Point to the first element in the array.
If Message = #WM_DESTROY
;
SetWindowLong_(GadgetID(_ac_Main()\Gadget), #GWL_WNDPROC, _ac_Main()\CallBack)
;
DeleteElement(_ac_Main())
;
ElseIf Message = #WM_CHAR
;
HoldString = GetGadgetText(_ac_Main()\Gadget)
; Store the current text.
HoldLength = Len(HoldString)
;
If Type = #PB_GadgetType_String
SendMessage_(HandleWindow, #EM_GETSEL, @HoldStart, @HoldEnd)
Else
SendMessage_(HandleWindow, #EM_EXGETSEL, 0, @HoldRange)
HoldStart = HoldRange\cpMin : HoldEnd = HoldRange\cpMax
EndIf
;
If __ac_Info\HandleWindow
;
If wParam = #VK_TAB Or wParam = #VK_RETURN
;
HoldString = ReplaceString(HoldString, Chr(13)+Chr(10), Chr(13))
;
HoldLength = Len(HoldString)
;
*Position = @HoldString + HoldLength - 1
;
While *Position > @HoldString
;
If PeekB(*Position) < 33 : Break : Else : *Position - 1 : EndIf
;
Wend
;
If Type = #PB_GadgetType_Editor : SendMessage_(_ac_Main()\Handle, #EM_HIDESELECTION, #True, #Null) : EndIf
; Temporarily hide the selection of the text. This will prevent a flicker as the text is replaced.
If PeekB(*Position) < 33 : *Position + 1 : EndIf
;
If Type = #PB_GadgetType_String
SendMessage_(_ac_Main()\Handle, #EM_SETSEL, *Position - @HoldString, HoldLength)
Else
HoldRange\cpMin = *Position - @HoldString : HoldRange\cpMax = HoldLength
SendMessage_(_ac_Main()\Handle, #EM_EXSETSEL, 0, @HoldRange)
EndIf
;
HoldString = GetGadgetText(__ac_Info\IdentifierList) + " "
; Add a trailing space to the text.
SendMessage_(_ac_Main()\Handle, #EM_REPLACESEL, #True, @HoldString)
; Replace the text with the completed text.
If Type = #PB_GadgetType_Editor : SendMessage_(_ac_Main()\Handle, #EM_HIDESELECTION, #False, #Null) : EndIf
; Show the selection again.
_ac_KillList()
;
wParam = 0
;
ProcedureReturn 1
;
EndIf
;
EndIf
;
If wParam = #VK_BACK
;
If Type = #PB_GadgetType_Editor
CombinedText = LCase(Mid(HoldString, 1, HoldStart) + Mid(HoldString, HoldEnd + 1, HoldLength - HoldEnd + 1))
Else
CombinedText = LCase(Mid(HoldString, 1, HoldStart - 1) + Mid(HoldString, HoldEnd + 1, HoldLength - HoldEnd + 1))
EndIf
;
Else
;
CombinedText = LCase(Mid(HoldString, 1, HoldStart) + Mid(HoldString, HoldEnd + 1, HoldLength - HoldEnd + 1) + Chr(wParam))
;
EndIf
;
HoldCombinedLength = Len(CombinedText)
;
If HoldCombinedLength = 0
;
SetGadgetText(_ac_Main()\Gadget, "")
;
Else
;
If _ac_Main()\PopList
;
If HoldCombinedLength >= _ac_Main()\PopList
;
_ac_PopList(_ac_Main(), HoldTotal - 1, CombinedText)
;
Else
;
_ac_KillList()
;
EndIf
;
Else
;
For iLoop = 0 To HoldTotal - 1
; Loop through all items in the array.
If LCase(Left(*HoldArray\FakeString[iLoop], HoldCombinedLength)) = CombinedText
; Found a matching item in the combobox. This little trick of getting the items in a array by addresses is thanks (again) to freak ( http://forums.purebasic.com/english/viewtopic.php?t=15366 )
SetGadgetText(_ac_Main()\Gadget, *HoldArray\FakeString[iLoop])
;
If Type = #PB_GadgetType_String
SendMessage_(HandleWindow, #EM_SETSEL, HoldCombinedLength, -1)
Else
HoldRange\cpMin = HoldCombinedLength : HoldRange\cpMax = -1
SendMessage_(HandleWindow, #EM_SETSEL, 0, @HoldRange)
EndIf
;
wParam = 0
;
Break
; Exit the loop.
EndIf
;
Next iLoop
;
EndIf
;
EndIf
;
If wParam : lResult = CallWindowProc_(_ac_Main()\CallBack, HandleWindow, Message, wParam, lParam) : EndIf
;
ElseIf Message = #WM_KEYDOWN
;
If _ac_Main()\PopList And __ac_Info\HandleWindow
;
HoldString = GetGadgetText(_ac_Main()\Gadget)
; Store the current text.
If wParam = #VK_ESCAPE
;
_ac_KillList()
;
wParam = 0
;
ElseIf wParam = #VK_UP
;
HoldTotal = GetGadgetState(__ac_Info\IdentifierList)
;
If HoldTotal - 1 > 0 : HoldTotal - 1 : Else : HoldTotal = 0 : EndIf
;
SetGadgetState(__ac_Info\IdentifierList, HoldTotal)
;
wParam = 0
;
ElseIf wParam = #VK_RETURN
; The code for completion will be handled under the WM_CHAR message.
If __ac_Info\HandleWindow : wParam = 0 : EndIf
;
ElseIf wParam = #VK_RIGHT
;
wParam = 0
;
ElseIf wParam = #VK_DOWN
;
HoldTotal = GetGadgetState(__ac_Info\IdentifierList)
;
If HoldTotal + 1 > CountGadgetItems(__ac_Info\IdentifierList) : HoldTotal = CountGadgetItems(__ac_Info\IdentifierList) : Else : HoldTotal + 1 : EndIf
;
SetGadgetState(__ac_Info\IdentifierList, HoldTotal)
;
wParam = 0
;
ElseIf wParam = #VK_LEFT
;
wParam = 0
;
ElseIf wParam = #VK_HOME
;
SetGadgetState(__ac_Info\IdentifierList, 0)
;
wParam = 0
;
ElseIf wParam = #VK_PRIOR
;
HoldTotal = GetGadgetState(__ac_Info\IdentifierList)
;
If HoldTotal - 5 > 0 : HoldTotal - 5 : Else : HoldTotal = 0 : EndIf
;
SetGadgetState(__ac_Info\IdentifierList, HoldTotal)
;
wParam = 0
;
ElseIf wParam = #VK_NEXT
;
HoldTotal = GetGadgetState(__ac_Info\IdentifierList)
;
If HoldTotal + 5 > CountGadgetItems(__ac_Info\IdentifierList) - 1 : HoldTotal = CountGadgetItems(__ac_Info\IdentifierList) - 1 : Else : HoldTotal + 5 : EndIf
;
SetGadgetState(__ac_Info\IdentifierList, HoldTotal)
;
wParam = 0
;
ElseIf wParam = #VK_END
;
SetGadgetState(__ac_Info\IdentifierList, CountGadgetItems(__ac_Info\IdentifierList) - 1)
;
wParam = 0
;
EndIf
;
SetActiveGadget(_ac_Main()\Gadget)
;
EndIf
;
If wParam : lResult = CallWindowProc_(_ac_Main()\CallBack, HandleWindow, message, wParam, lParam) : EndIf
;
ElseIf message = #WM_KILLFOCUS
;
If wParam <> __ac_Info\HandleWindow
;
_ac_KillList()
;
SendMessage_(_ac_Main()\Handle, #EM_SETSEL, -1, 0)
;
EndIf
;
lResult = CallWindowProc_(_ac_Main()\CallBack, HandleWindow, message, wParam, lParam)
;
Else
;
lResult = CallWindowProc_(_ac_Main()\CallBack, HandleWindow, message, wParam, lParam)
;
EndIf
;
EndIf
;
ProcedureReturn lResult
;
EndProcedure
Procedure.l _ac_HandleComboEvents(HandleWindow.l, Message.l, wParam.l, lParam.l)
; Custom callback for combobox controls.
Define.l lResult
;
Define.l CallBack
;
Define.l Gadget
;
Define.l Parent
;
Define.l iLoop
;
Define.l HoldTotal
;
Define.l HoldLength
;
Define.l HoldCombinedLength
;
Define.l HoldStart
;
Define.l HoldEnd
;
Define.l HoldSelection
;
Define.s HoldString
;
Define.s PreText
;
Define.s PostText
;
Define.s CombinedText
;
Define.s MatchText
;
ResetList(_ac_Main())
While NextElement(_ac_Main())
;
If _ac_Main()\Handle = HandleWindow
;
Parent = _ac_Main()\Parent
;
Gadget = _ac_Main()\Gadget
;
CallBack = _ac_Main()\CallBack
;
Break
;
EndIf
;
Wend
; Retrieve the handle to the combobox and the gadget id.
If CallBack = -1 : ProcedureReturn : EndIf
; This should never happen as this callback is only set for autocomplete items.
If Message = #WM_DESTROY
;
lResult = CallWindowProc_(CallBack, HandleWindow, Message, wParam, lParam)
; Call the next callback handler.
SetWindowLong_(GadgetID(_ac_Main()\Gadget), #GWL_WNDPROC, _ac_Main()\CallBack)
;
DeleteElement(_ac_Main())
;
ElseIf Message = #WM_CHAR
;
HoldTotal = SendMessage_(Parent, #CB_GETCOUNT, 0, 0)
; Return the number of items in the combobox.
If HoldTotal
; Only need to check for autocompletion if items exist in the combobox.
If _ac_Main()\ShowDrop And SendMessage_(GadgetID(Gadget), #CB_GETDROPPEDSTATE, #Null, #Null) = #False : SendMessage_(GadgetID(Gadget), #CB_SHOWDROPDOWN, #True, #Null) : EndIf
;
HoldString = GetGadgetText(Gadget)
; Store the current combobox text.
HoldLength = Len(HoldString)
;
SendMessage_(Parent, #CB_GETEDITSEL, @HoldStart, @HoldEnd)
; Store the start and end selection values.
If wParam = #VK_BACK
;
CombinedText = LCase(Mid(HoldString, 1, HoldStart - 1))
;
Else
;
PreText = Mid(HoldString, 1, HoldStart)
; The text before the selection.
PostText = Mid(HoldString, HoldEnd + 1, HoldLength - HoldEnd)
; The text after the selection.
CombinedText = LCase(PreText + PostText + Chr(wParam))
;
EndIf
;
HoldCombinedLength = Len(CombinedText)
;
If HoldCombinedLength = 0
;
SetGadgetText(Gadget, "")
;
Else
;
For iLoop = 0 To HoldTotal - 1
; Loop through all items in the combo box.
MatchText = GetGadgetItemText(Gadget, iLoop, 0)
; Store the text at index iLoop.
If LCase(Left(MatchText, HoldCombinedLength)) = CombinedText
; Found a matching item in the combobox.
SetGadgetText(Gadget, MatchText)
;
HoldSelection = HoldCombinedLength | -1 << 16
; Convert the start and end selection into an lParam. The start position is the combined length of the pre
; and post text. The end is set to -1 to select the rest of the text.
SendMessage_(GadgetID(Gadget), #CB_SETCURSEL, iLoop, #Null)
;
SendMessage_(Parent, #CB_SETEDITSEL, 0, HoldSelection)
;
wParam = 0
;
; SetGadgetState(Gadget, iLoop)
Break
; Exit the loop.
EndIf
;
Next iLoop
;
EndIf
;
If wParam : lResult = CallWindowProc_(CallBack, HandleWindow, Message, wParam, lParam) : EndIf
;
Else
;
lResult = CallWindowProc_(CallBack, HandleWindow, Message, wParam, lParam)
;
EndIf
;
Else
;
lResult = CallWindowProc_(CallBack, HandleWindow, Message, wParam, lParam)
;
EndIf
;
If lResult : ProcedureReturn lResult : EndIf
;
EndProcedure
;- Main Functions
Procedure ac_SetAutocomplete(Gadget.l, ShowDrop.b = #False, EditGadgetArrayAddress.l = 0, PopList.b = #False)
; EditGadgetArrayAddress is exactly that. The address to the first element of a plain string array. This will be used
; for the autocompletion list. Feel free to modify this to handle linked lists or whatever. It will be ignored for
; combobox. See s_AutoComplete for information on PopList.
Define.l Handle
;
Define.s HoldString
;
Define.l Type
;
ResetList(_ac_Main())
While NextElement(_ac_Main())
If _ac_Main()\Gadget = Gadget : ProcedureReturn : EndIf
Wend
; Check if the gadget already exists in the autocomplete list.
Handle = GadgetID(Gadget)
;
If GadgetType(Gadget) = #PB_GadgetType_Editor Or GadgetType(Gadget) = #PB_GadgetType_String
; String type.
If EditGadgetArrayAddress
; An edit control must be associated with an array address.
AddElement(_ac_Main())
;
_ac_Main()\Gadget = Gadget
_ac_Main()\Handle = Handle
; The handle to the edit control.
_ac_Main()\Parent = 0
; An edit control is not like a combobox. Does not have a parent container.
_ac_Main()\CallBack = SetWindowLong_(Handle, #GWL_WNDPROC, @_ac_HandleEditEvents())
; The callback will be set for the edit control, not the combobox.
_ac_QuickSortArray(EditGadgetArrayAddress, 0, PeekL(EditGadgetArrayAddress - 8))
;
_ac_Main()\ArrayAddress = EditGadgetArrayAddress
;
_ac_Main()\PopList = PopList
;
_ac_Main()\ShowDrop = ShowDrop
;
EndIf
;
ElseIf GadgetType(Gadget) = #PB_GadgetType_ComboBox
; Combobox type
AddElement(_ac_Main())
;
_ac_Main()\Gadget = Gadget
_ac_Main()\Handle = GetWindow_(Handle, #GW_CHILD)
; This is the handle to the edit control within the combobox. I think I got this little tidbit from fr34k but don't quote me on that.
_ac_Main()\Parent = Handle
; This will be the handle to the combobox control.
_ac_Main()\CallBack = SetWindowLong_(_ac_Main()\Handle, #GWL_WNDPROC, @_ac_HandleComboEvents())
; The callback will be set for the edit control, not the combobox.
_ac_Main()\ShowDrop = ShowDrop
;
EndIf
;
EndProcedure
Procedure ac_UpdateArray(Gadget.l, ArrayAddress.l, PopList.b)
;
ResetList(_ac_Main())
While NextElement(_ac_Main())
;
If _ac_Main()\Gadget = Gadget
;
_ac_QuickSortArray(ArrayAddress, 0, PeekL(ArrayAddress - 8))
;
_ac_Main()\ArrayAddress = ArrayAddress
;
_ac_Main()\PopList = PopList
;
Break
;
EndIf
;
Wend
;
EndProcedure
Re: Autocompleting Combobox and Strings
Since I can't get the posted version to compile, I'm wondering if there is a newer version now (I'm interested in the string completion feature)?
Or has anyone solved the problems with freaks api code and Vista/Win7?
Or another autocomplete option?
cheers
Or has anyone solved the problems with freaks api code and Vista/Win7?
Or another autocomplete option?
cheers
- netmaestro
- PureBasic Bullfrog
- Posts: 8451
- Joined: Wed Jul 06, 2005 5:42 am
- Location: Fort Nelson, BC, Canada
Re: Autocompleting Combobox and Strings
I tested freak's code using 4.41 on Win7 and it works fine. There are just a couple tweaks:Or has anyone solved the problems with freaks api code and Vista/Win7?
1. Put the Array keyword in to overcome the "error in procedure arguments" error in the include. Other than this the include needs no more changes.
2. Remove the CreateGadgetList() from the demo program.
3. To correct the IMA on closing the window, close the window (or free the used gadget) in the demo program before executing the Release() methods:
Code: Select all
Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow
CloseWindow(#window_0) ; <-------------------------- Insert this line to overcome the IMA in the Release() method
; Release our own references to the objects to avoid a memory leak
;
Enum\Release()
AutoComplete\Release()
BERESHEIT
Re: Autocompleting Combobox and Strings
Many thanks Mr. netmaestro.
I'll give it a try
cheers
I'll give it a try

cheers
Re: Autocompleting Combobox and Strings
Hi, any update for this Autocomplete by Xombie? old code give me problem, autocomplete not work if i close and reopen the window, or crash if i redim array many time, the last code not compile with pb 4.61, other example of autocomplete in the forum use popup list and for my project is not good, please anyone have a working version of this autocomplete by Xombie?
