Page 1 of 2
Autocomplete for Comboboxgadget - Simple version
Posted: Sun Nov 08, 2009 3:24 am
by mesozorn
I have seen other autocomplete routines posted which are very good indeed. This is mine which is very short and very simple:
Code: Select all
Structure comboboxinfo
cbSize.l
rcItem.RECT
rcButton.RECT
stateButton.l
hwndCombo.l
hwndEdit.l
hwndList.l
EndStructure
cbinfo.comboboxinfo
OpenWindow(0, 0, 0, 270, 140, "ComboBoxGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
ComboBoxGadget(0, 10, 10, 250, 21, #PB_ComboBox_Editable)
AddGadgetItem(0, -1, "Adams")
AddGadgetItem(0, -1, "Franklin")
AddGadgetItem(0, -1, "Jefferson")
AddGadgetItem(0, -1, "Walters")
AddGadgetItem(0, -1, "Washington")
SetActiveGadget(0)
Repeat
W=WaitWindowEvent()
If W=#WM_KEYDOWN And GetActiveGadget()=0
acg=GetActiveGadget()
cbinfo\cbsize=SizeOf(comboboxinfo)
GetComboBoxInfo_(GadgetID(acg),@cbinfo)
tb=cbinfo.comboboxinfo\hwndedit
SendMessage_(tb, #EM_GETSEL, @spos.l, @epos.l)
matchesfound=0
For x=0 To CountGadgetItems(acg)-1
If LCase(Left(GetGadgetText(acg),spos)+LCase(Chr(EventwParam())))=LCase(Left(GetGadgetItemText(acg,x),spos+1)) And epos=Len(GetGadgetText(acg))
matchesfound+1:match=x
If matchesfound>1:Break:EndIf
EndIf
Next x
If matchesfound=1
ks=GetKeyState_(#VK_SHIFT)
If ks<2:addchar$=LCase(Chr(EventwParam())):Else:addchar$=UCase(Chr(EventwParam())):EndIf
SetGadgetText(acg,Left(GetGadgetText(acg),spos)+addchar$+Mid(GetGadgetItemText(acg,match),spos+2))
SendMessage_(tb, #EM_SETSEL, spos+1, epos+999)
PeekMessage_(@msg.MSG, GadgetID(acg), #WM_KEYFIRST, #WM_KEYLAST, #PM_REMOVE)
EndIf
EndIf
Until W = #PB_Event_CloseWindow
It is of course very easy to enhance this so as to be able to add autocomplete functionality to any comboboxgadget created on the fly, without having to go back and edit this source to include each new gadget. I have not added these extra lines to the example above only because it is a fairly obvious enhancement.
Re: Autocomplete for Comboboxgadget - Simple version
Posted: Tue Nov 10, 2009 8:38 pm
by akj
@mesozorn:
There is a bug in your routine in that hWnd is never assigned a value, but is used in the line
Code: Select all
PeekMessage_(@msg, hWnd, #WM_KEYFIRST, #WM_KEYLAST, #PM_REMOVE)
Re: Autocomplete for Comboboxgadget - Simple version
Posted: Tue Nov 10, 2009 8:56 pm
by mesozorn
akj wrote:@mesozorn:
There is a bug in your routine in that hWnd is never assigned a value, but is used in the line
Code: Select all
PeekMessage_(@msg, hWnd, #WM_KEYFIRST, #WM_KEYLAST, #PM_REMOVE)
Thanks for noticing. It still seems to work correctly even if hwnd is left as 0 regardless of anything else, but just to be safe I have now edited it to be:
Code: Select all
PeekMessage_(@msg.MSG, GadgetID(acg), #WM_KEYFIRST, #WM_KEYLAST, #PM_REMOVE)
Re: Autocomplete for Comboboxgadget - Simple version
Posted: Fri Nov 13, 2009 7:23 pm
by Amnesty
Its amazing simple, thank you for this.
How can I use this with numbers, I am thinking about customer IDs. (for example 11208736)
When I am using only numbers in Comboboxgadget, autocomplete is not working.
Sorry, it works with numbers but not with NumPad.
Re: Autocomplete for Comboboxgadget - Simple version
Posted: Fri Nov 13, 2009 8:13 pm
by mesozorn
This modified version works for NumPad, but there are still a bunch of other non-standard characters which will trip it up as well. I will post a further modified version later which will handle all types of keys. The original version is mainly for regular letters and numbers.
Code: Select all
Structure comboboxinfo
cbSize.l
rcItem.RECT
rcButton.RECT
stateButton.l
hwndCombo.l
hwndEdit.l
hwndList.l
EndStructure
cbinfo.comboboxinfo
OpenWindow(0, 0, 0, 270, 140, "ComboBoxGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
ComboBoxGadget(0, 10, 10, 250, 21, #PB_ComboBox_Editable)
AddGadgetItem(0, -1, "12345")
AddGadgetItem(0, -1, "23468")
AddGadgetItem(0, -1, "48347")
AddGadgetItem(0, -1, "58237")
AddGadgetItem(0, -1, "58772")
SetActiveGadget(0)
Repeat
W=WaitWindowEvent()
If W=#WM_KEYDOWN And GetActiveGadget()=0
acg=GetActiveGadget()
cbinfo\cbsize=SizeOf(comboboxinfo)
GetComboBoxInfo_(GadgetID(acg),@cbinfo)
tb=cbinfo.comboboxinfo\hwndedit
SendMessage_(tb, #EM_GETSEL, @spos.l, @epos.l)
matchesfound=0
For x=0 To CountGadgetItems(acg)-1
If (LCase(Left(GetGadgetText(acg),spos)+LCase(Chr(EventwParam())))=LCase(Left(GetGadgetItemText(acg,x),spos+1)) And epos=Len(GetGadgetText(acg))) Or (EventwParam()>=96 And EventwParam()<=105 And LCase(Left(GetGadgetText(acg),spos)+LCase(Chr(EventwParam()-48)))=LCase(Left(GetGadgetItemText(acg,x),spos+1)) And epos=Len(GetGadgetText(acg)))
matchesfound+1:match=x
If matchesfound>1:Break:EndIf
EndIf
Next x
If matchesfound=1
If EventwParam()>=96 And EventwParam()<=105:ep=EventwParam()-48:Else:ep=EventwParam():EndIf
ks=GetKeyState_(#VK_SHIFT)
If ks<2:addchar$=LCase(Chr(ep)):Else:addchar$=UCase(Chr(ep)):EndIf
SetGadgetText(acg,Left(GetGadgetText(acg),spos)+addchar$+Mid(GetGadgetItemText(acg,match),spos+2))
SendMessage_(tb, #EM_SETSEL, spos+1, epos+999)
PeekMessage_(@msg.MSG, GadgetID(acg), #WM_KEYFIRST, #WM_KEYLAST, #PM_REMOVE)
EndIf
EndIf
Re: Autocomplete for Comboboxgadget - Simple version
Posted: Fri Nov 13, 2009 9:32 pm
by mesozorn
Okay, the new version below works for all keys and characters I believe. I switched to using the subclassing approach which makes it even more APISH than before, but I was already using plenty of API calls in the original version, so not that much difference I suppose. Just note two things:
1) It is the textbox portion of the ComboBoxGadget which gets subclassed, and not the entire ComboBoxGadget itself. You can use a simple procedure or macro to do this in one clean step, but I've left the long version in for illustration.
2) This is my first attempt ever at subclassing, so it may be buggy.
Code: Select all
Structure comboboxinfo
cbSize.l
rcItem.RECT
rcButton.RECT
stateButton.l
hwndCombo.l
hwndEdit.l
hwndList.l
EndStructure
Global cbinfo.comboboxinfo
Global oldcomboProc
Procedure.i ComboAutoComplete(hWnd, uMsg, wParam, lParam)
Protected result
Select uMsg
Case #WM_CHAR
acg=GetActiveGadget() ;GetDlgCtrlID_(hwnd)
SendMessage_(hwnd, #EM_GETSEL, @spos.l, @epos.l)
matchesfound=0
For x=0 To CountGadgetItems(acg)-1
If LCase(Left(GetGadgetText(acg),spos)+LCase(Chr(wParam)))=LCase(Left(GetGadgetItemText(acg,x),spos+1)) And epos=Len(GetGadgetText(acg))
matchesfound+1:match=x
If matchesfound>1:Break:EndIf
EndIf
Next x
If matchesfound=1
ks=GetKeyState_(#VK_SHIFT)
If ks<2:addchar$=LCase(Chr(wparam)):Else:addchar$=UCase(Chr(wparam)):EndIf
SetGadgetText(acg,Left(GetGadgetText(acg),spos)+addchar$+Mid(GetGadgetItemText(acg,match),spos+2))
SendMessage_(hwnd, #EM_SETSEL, spos+1, epos+999)
result=0
Else
result = CallWindowProc_(oldcomboproc, hWnd, uMsg, wParam, lParam)
EndIf
Default
result = CallWindowProc_(oldcomboproc, hWnd, uMsg, wParam, lParam)
EndSelect
ProcedureReturn result
EndProcedure
OpenWindow(0, 0, 0, 270, 140, "ComboBoxGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
ComboBoxGadget(0, 10, 10, 250, 21, #PB_ComboBox_Editable)
cbinfo\cbsize=SizeOf(comboboxinfo)
GetComboBoxInfo_(GadgetID(0),@cbinfo)
tb=cbinfo.comboboxinfo\hwndedit
oldcomboproc = SetWindowLong_(tb, #GWL_WNDPROC, @ComboAutoComplete())
AddGadgetItem(0, -1, "12345")
AddGadgetItem(0, -1, "23/468")
AddGadgetItem(0, -1, "483~47")
AddGadgetItem(0, -1, "58237")
AddGadgetItem(0, -1, "58.772")
SetActiveGadget(0)
Repeat
W=WaitWindowEvent()
Until W = #PB_Event_CloseWindow
Re: Autocomplete for Comboboxgadget - Simple version
Posted: Mon Apr 12, 2010 5:18 pm
by ThoPie
Unfortunately, this great ComboBox-Autocompletion works not with PureBasic 4.5x. Please can anybody adapt this for the usage with version 4.5.
Thanks a lot.
Re: Autocomplete for Comboboxgadget - Simple version
Posted: Mon Apr 12, 2010 5:25 pm
by srod
GetComboBoxInfo_() is not reliable for the new combos. I have replaced this and the example seems to work ok.
Code: Select all
Global oldcomboProc
Procedure.i ComboAutoComplete(hWnd, uMsg, wParam, lParam)
Protected result
Select uMsg
Case #WM_CHAR
acg=GetActiveGadget() ;GetDlgCtrlID_(hwnd)
SendMessage_(hwnd, #EM_GETSEL, @spos.l, @epos.l)
matchesfound=0
For x=0 To CountGadgetItems(acg)-1
If LCase(Left(GetGadgetText(acg),spos)+LCase(Chr(wParam)))=LCase(Left(GetGadgetItemText(acg,x),spos+1)) And epos=Len(GetGadgetText(acg))
matchesfound+1:match=x
If matchesfound>1:Break:EndIf
EndIf
Next x
If matchesfound=1
ks=GetKeyState_(#VK_SHIFT)
If ks<2:addchar$=LCase(Chr(wparam)):Else:addchar$=UCase(Chr(wparam)):EndIf
SetGadgetText(acg,Left(GetGadgetText(acg),spos)+addchar$+Mid(GetGadgetItemText(acg,match),spos+2))
SendMessage_(hwnd, #EM_SETSEL, spos+1, epos+999)
result=0
Else
result = CallWindowProc_(oldcomboproc, hWnd, uMsg, wParam, lParam)
EndIf
Default
result = CallWindowProc_(oldcomboproc, hWnd, uMsg, wParam, lParam)
EndSelect
ProcedureReturn result
EndProcedure
OpenWindow(0, 0, 0, 270, 140, "ComboBoxGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
hWnd = ComboBoxGadget(0, 10, 10, 250, 21, #PB_ComboBox_Editable)
hWnd = GetWindow_(hWnd, #GW_CHILD)
hWndEdit = FindWindowEx_(hWnd, 0, "EDIT", 0)
oldcomboproc = SetWindowLong_(hWndEdit, #GWL_WNDPROC, @ComboAutoComplete())
AddGadgetItem(0, -1, "12345")
AddGadgetItem(0, -1, "23/468")
AddGadgetItem(0, -1, "483~47")
AddGadgetItem(0, -1, "58237")
AddGadgetItem(0, -1, "58.772")
SetActiveGadget(0)
Repeat
W=WaitWindowEvent()
Until W = #PB_Event_CloseWindow
Re: Autocomplete for Comboboxgadget - Simple version
Posted: Mon Apr 12, 2010 5:30 pm
by ThoPie
Wow! Thanks.

Re: Autocomplete for Comboboxgadget - Simple version
Posted: Mon Apr 12, 2010 5:44 pm
by USCode
How about a cross-platform version??? Possible?
Re: Autocomplete for Comboboxgadget - Simple version
Posted: Mon Apr 12, 2010 9:27 pm
by mesozorn
srod wrote:GetComboBoxInfo_() is not reliable for the new combos. I have replaced this and the example seems to work ok.
Out of curiosity, why is it that this API command will no longer work on a ComboBoxGadget under PB 4.5? GetComboBoxInfo_() is a standard Windows command, so shouldn't it always work on a standard Windows combo control?
Re: Autocomplete for Comboboxgadget - Simple version
Posted: Mon Apr 12, 2010 9:48 pm
by ts-soft
ComboBox is changed to ComboBoxEx to support images!
Re: Autocomplete for Comboboxgadget - Simple version
Posted: Mon Apr 12, 2010 10:04 pm
by mesozorn
ts-soft wrote:ComboBox is changed to ComboBoxEx to support images!
Ah I see, in which case is there going to be any support for either of:
SendMessage_(hWnd,#CBEM_GETCOMBOCONTROL,0,0)
SendMessage_(hWnd,#CBEM_GETEDITCONTROL,0,0)
? Right now neither of those API constants appear to be recognized..? They would be helpful in either extracting the standard ComboBox portion of the ComboBoxEx, or getting the edit control handle directly. Is there any way of finding out what those numerical constants would be and declaring them oneself, even if they are not yet included in PB by default? Thanks...
Re: Autocomplete for Comboboxgadget - Simple version
Posted: Sun Jun 05, 2011 11:54 am
by Fangbeast
Code: Select all
Global oldcomboProc
Procedure.i ComboAutoComplete(hWnd, uMsg, wParam, lParam)
Protected result
Select uMsg
Case #WM_CHAR
acg=GetActiveGadget() ;GetDlgCtrlID_(hwnd)
SendMessage_(hwnd, #EM_GETSEL, @spos.l, @epos.l)
matchesfound=0
For x=0 To CountGadgetItems(acg)-1
If LCase(Left(GetGadgetText(acg),spos)+LCase(Chr(wParam)))=LCase(Left(GetGadgetItemText(acg,x),spos+1)) And epos=Len(GetGadgetText(acg))
matchesfound+1:match=x
If matchesfound>1:Break:EndIf
EndIf
Next x
If matchesfound=1
ks=GetKeyState_(#VK_SHIFT)
If ks<2:addchar$=LCase(Chr(wparam)):Else:addchar$=UCase(Chr(wparam)):EndIf SetGadgetText(acg,Left(GetGadgetText(acg),spos)+addchar$+Mid(GetGadgetItemText(acg,match),spos+2))
SendMessage_(hwnd, #EM_SETSEL, spos+1, epos+999)
result=0
Else
result = CallWindowProc_(oldcomboproc, hWnd, uMsg, wParam, lParam)
EndIf
Default
result = CallWindowProc_(oldcomboproc, hWnd, uMsg, wParam, lParam)
EndSelect
ProcedureReturn result
EndProcedure
OpenWindow(0, 0, 0, 270, 140, "ComboBoxGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
hWnd = ComboBoxGadget(0, 10, 10, 250, 21, #PB_ComboBox_Editable)
hWnd = GetWindow_(hWnd, #GW_CHILD)
hWndEdit = FindWindowEx_(hWnd, 0, "EDIT", 0)
oldcomboproc = SetWindowLong_(hWndEdit, #GWL_WNDPROC, @ComboAutoComplete())
AddGadgetItem(0, -1, "12345")
AddGadgetItem(0, -1, "23/468")
AddGadgetItem(0, -1, "483~47")
AddGadgetItem(0, -1, "58237")
AddGadgetItem(0, -1, "58.772")
SetActiveGadget(0)
Repeat
W=WaitWindowEvent()
Until W = #PB_Event_CloseWindow
I'm afraid to touch working code that I don't understand so I am wondering how this can be extended to cover multiple comboboxes as oldcomboproc is only for a single combo box as I understand it??
Re: Autocomplete for Comboboxgadget - Simple version
Posted: Sun Jun 05, 2011 12:52 pm
by netmaestro
oldcomboproc is only for a single combo box as I understand it??
'oldcomboproc' is going to be the same for all comboboxes you subclass as it's the default combobox procedure. You can safely use this with multiple combo boxes.