Page 5 of 5
Re: [Windows] AutoComplete for StringGadgets
Posted: Wed Jul 21, 2010 4:02 am
by netmaestro
Might have happened onto something...
MSDN wrote: You can use CLSID_ACLMulti if you want AutoComplete to use multiple lists
Code: Select all
DataSection
CLSID_ACLMulti:
Data.l $00BB2765
Data.w $6A77, $11D0
Data.b $A5, $35, $00, $C0, $4F, $D7, $D0, $62
EndDataSection
Use in place of CLSID_AutoComplete. Since you're still up for working with this, you might give this CLSID a try.
Re: [Windows] AutoComplete for StringGadgets
Posted: Wed Jul 21, 2010 4:29 pm
by rsts
Not sure that solves the updating problem. I haven't been able to get it to work yet, but then, what did you expect
The release/rebuild the list approach seems to be unreliable, at least in my testing.
According to this source code, it appears there are ways to add and remove items as part of iautocomplete. Although how to access them remains a mystery to me.
http://www.codeproject.com/kb/wtl/Custo ... e_wtl.aspx
If you decide to cook one of your own, and can understand c++, this might provide a start. Once again, way beyond me. I'll soon be looking for some other alternative. Maybe I can get xombie to update his for lists again
http://www.codeproject.com/KB/combobox/ ... plete.aspx
cheers
Re: [Windows] AutoComplete for StringGadgets
Posted: Wed Jul 21, 2010 6:10 pm
by rsts
Mr maestro
Any chance this could be contributing to my unexplained crashes? (which often occur at the procedureReturn)
http://www.purebasic.fr/english/viewtop ... +procedure
cheers
Re: [Windows] AutoComplete for StringGadgets
Posted: Wed Jul 21, 2010 6:19 pm
by netmaestro
I doubt it as that fails every time, and that's not what's happening to you. Imho, the IAutoComplete2 object isn't releasing all its resources when the \release() method is called and that's causing a crash on the next run.
Re: [Windows] AutoComplete for StringGadgets
Posted: Wed Jul 21, 2010 6:45 pm
by rsts
Thanks again.
Between perusing codeproject and msdn, I realize I'm in way over my head. I'm moving back to xombies routine, which appears it may satisfy my basic requirements, at least for now. I've spent way too much time on this and it seems I'm no closer to a real solution than I was at the start.
If you decide to roll your own, I'll be happy to lend whatever assistance I can. If you make any progress on this one, please let me know that as well.
Thanks once again for all your assistance.
cheers
Re: [Windows] AutoComplete for StringGadgets
Posted: Wed Jul 21, 2010 8:48 pm
by netmaestro
Here is a solution half-done. That is, the object is working and fully functional, it's just the display presentation isn't done. Results just go to the debug window. Size your debug window narrow and long and pretend it's a menu, then have a play with this and see if you can get it to fail:
Code: Select all
;==================================================================
;
; Library: AutoComplete v. 0.3 alpha
; Author: Lloyd Gallant (netmaestro)
; Date: July 21, 2010
; Target OS: Microsoft Windows All
; Target Compiler: PureBasic 4.50 and later
; license: Free, unrestricted, no warranty whatsoever
; credit appreciated but not required
;
;==================================================================
UseSQLiteDatabase()
#DATABASE_OK = ""
Structure AutoCompleteObject
*vTable
database.i
subclass_oldproc.i
gadget.i
dynamic.b
EndStructure
Interface iAutoCompleteObject
Attach ( gadget, *strings, size )
AddString ( gadget, *string )
Release ()
EndInterface
Procedure AddString(*this.AutoCompleteObject, gadget, *string )
text$ = PeekS(*string)
sql$ = "SELECT promptstring FROM Autocomplete where (promptstring = '"+text$+"' and gadget = '" + Str(gadget) + "')"
DatabaseQuery(*this\database, sql$)
recordcount = 0
While NextDatabaseRow(*this\database)
recordcount+1
Wend
FinishDatabaseQuery(*this\database)
If recordcount = 0
sql$ = "insert into Autocomplete (gadget, promptstring) values(" + Str(gadget) + "," + "'"+ PeekS(*string) + "')"
DatabaseUpdate(*this\database, sql$)
EndIf
ProcedureReturn 1
EndProcedure
Procedure _nmAC_StringProc(hwnd, msg, wparam, lparam)
*this.AutoCompleteObject = GetProp_(hwnd, "acdata")
oldproc = *this\subclass_oldproc
gadget = *this\gadget
Select msg
Case #WM_NCDESTROY
RemoveProp_(hwnd, "oldproc")
Case #WM_KEYUP
If GetFocus_() = hwnd
ClearDebugOutput()
text$ = GetGadgetText(*this\gadget)
If text$ <> ""
sql$ = "SELECT promptstring FROM Autocomplete where (promptstring like '"+text$+"%' and gadget = '" + Str(gadget) + "')"
DatabaseQuery(*this\database, sql$)
While NextDatabaseRow(*this\database)
Debug GetDatabaseString(*this\database,0)
Wend
FinishDatabaseQuery(*this\database)
EndIf
EndIf
Case #WM_KILLFOCUS
If *this\dynamic
text$ = GetGadgetText(gadget)
Addstring(*this, gadget, @text$)
EndIf
Case #WM_SETFOCUS
SendMessage_(hwnd, #EM_SETSEL, 0, -1)
EndSelect
ProcedureReturn CallWindowProc_(oldproc, hwnd, msg, wparam, lparam)
EndProcedure
Procedure Attach(*this.AutoCompleteObject, gadget, *strings, size )
Protected fail_status = #False
*ptr = *strings
For i=1 To size
sql$ = "insert into Autocomplete (gadget, promptstring) values(" + Str(gadget) + "," + "'"+ PeekS(PeekL(*ptr)) + "')"
If DatabaseUpdate(*this\database, sql$)
*ptr+SizeOf(integer)
Else
fail_status = #True
Break
EndIf
Next
If IsGadget(gadget) And GadgetType(gadget) = #PB_GadgetType_String And fail_status = #False
*this\gadget = gadget
*this\subclass_oldproc = SetWindowLongPtr_(GadgetID(gadget), #GWL_WNDPROC, @_nmAC_StringProc())
SetProp_(GadgetID(gadget), "acdata", *this )
Else
fail_status = #True
EndIf
If fail_status = #False
ProcedureReturn #True
Else
ProcedureReturn 0
EndIf
EndProcedure
Procedure NewObject_Autocomplete(dynamic=0)
*newobject.AutoCompleteObject = AllocateMemory(SizeOf(AutoCompleteObject))
With *newobject
\vTable = ?AutoComplete_Methods
\dynamic = dynamic
EndWith
dbOpenResult = OpenDatabase(#PB_Any, ":memory:", "", "")
If dbOpenResult
DatabaseUpdate(dbOpenResult, "CREATE TABLE AutoComplete (gadget VARCHAR, promptstring VARCHAR(255));")
If DatabaseError() = #DATABASE_OK
*newobject\database = dbOpenResult
ProcedureReturn *newobject
Else
ProcedureReturn 0
EndIf
Else
ProcedureReturn 0
EndIf
EndProcedure
Procedure Release(*this.AutoCompleteObject)
If *this\subclass_oldproc
SetWindowLongPtr_(GadgetID(*this\gadget),#GWL_WNDPROC, *this\subclass_oldproc)
EndIf
If IsDatabase(*this\database)
CloseDatabase(*this\database)
EndIf
FreeMemory(*this)
EndProcedure
DataSection
AutoComplete_Methods:
Data.l @Attach(), @AddString(), @Release()
EndDataSection
;=================================================================
; END OF INCLUDE CODESECTION
;=================================================================
; Test prog
Dim Strings.s(17)
Strings(0) = "Else"
Strings(1) = "ElseIf"
Strings(2) = "EnableDebugger"
Strings(3) = "EnableExplicit"
Strings(4) = "End"
Strings(5) = "EndDataSection"
Strings(6) = "EndEnumeration"
Strings(7) = "EndIf"
Strings(8) = "EndImport"
Strings(9) = "EndInterface"
Strings(10) = "EndMacro"
Strings(11) = "EndProcedure"
Strings(12) = "EndSelect"
Strings(13) = "EndStructure"
Strings(14) = "EndStructureUnion"
Strings(15) = "EndWith"
Strings(16) = "Enumeration"
OpenWindow(0,0,0,320,240,"",#PB_Window_ScreenCentered|#PB_Window_SystemMenu)
StringGadget(6, 10,10, 300,20,"")
StringGadget(7, 10,50, 300,20,"")
SetActiveGadget(6)
prompts1.iAutoCompleteObject = NewObject_Autocomplete(1) ; Dynamic additions on
prompts1\Attach(6, @strings(), 17 )
prompts2.iAutoCompleteObject = NewObject_Autocomplete() ; Dynamic additions off - list doesn't change
prompts2\Attach(7, @strings(), 17 )
Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
prompts1\Release()
prompts2\Release()
Re: [Windows] AutoComplete for StringGadgets
Posted: Wed Jul 21, 2010 10:11 pm
by rsts
Wow, what a novel approach. Brilliant!
At least some of us don't get lost in the forest looking for trees.
This looks very promising. Plus, I know little bit about SQLite, so can understand bits of what's going on.
My hat's of to you, Mr maestro.
Re: [Windows] AutoComplete for StringGadgets
Posted: Wed Aug 04, 2010 5:16 pm
by Xombie
Huh. I haven't messed with my autocomplete stuff for a long time. If I need to change anything, let me know.
Re: [Windows] AutoComplete for StringGadgets
Posted: Fri May 25, 2012 11:17 pm
by Marco2007
Hi,
I got a problem and I hope someone could help me, please.
Freak`s code runs fine on almost every WinOS, but on some Win7-64bit machines it chrashes when I use ExplorerGadget or Webgadget?!
This is really freaking me out
If I just put one line to the code (ExplorerGadget or WebGadget), the app is freezing, when trying to type something into the StringGadget
No error or something
Has anyone an idea, what`s the reason for this?
** Edit: WebGadget runs fine, when not using it like an Explorer (dir instead or url)...
Many, many Thanks!
Fixed AutoComplete for StringGadgets in X64 Compiler
Posted: Wed Jul 03, 2013 4:55 pm
by Peyman
i changed some lines so now its Compatible with x64 PureBasic compiler.
AutoComplete.pbi
Code: Select all
;
; Generic Implementation of an IEnumString Interface.
; New_EnumString(StringArray(), ItemCount) will create a new IEnumString instance
; with a referencecount of 1. (this means you must call IEnumString\Release()
; to release this reference once you do not need it anymore.)
;
;
;
EnableExplicit
; To allow for the ::Clone() method without dublicating the buffer,
; the string buffer is kept separate, with its own reference count.
Structure EnumStringBuffer
RefCount.l
Strings.l[0]
; following is the literal string data
EndStructure
; IEnumString data
Structure EnumString
*Vtbl
RefCount.l
StringCount.l
Enumerator.l
*Buffer.EnumStringBuffer
EndStructure
Procedure IEnumString_QueryInterface(*THIS.EnumString, *IID.IID, *Object.Integer)
If *Object = 0
ProcedureReturn #E_INVALIDARG
ElseIf CompareMemory(*IID, ?IID_IUnknown, SizeOf(IID)) Or CompareMemory(*IID, ?IID_IEnumString, SizeOf(IID))
*Object\i = *THIS
*THIS\RefCount + 1
ProcedureReturn #S_OK
Else
*Object\i = 0
ProcedureReturn #E_NOINTERFACE
EndIf
EndProcedure
Procedure IEnumString_AddRef(*THIS.EnumString)
*THIS\RefCount + 1
ProcedureReturn *THIS\RefCount
EndProcedure
Procedure IEnumString_Release(*THIS.EnumString)
*THIS\RefCount - 1
If *THIS\RefCount = 0
*THIS\Buffer\RefCount - 1
If *THIS\Buffer\RefCount = 0
FreeMemory(*THIS\Buffer)
EndIf
FreeMemory(*THIS)
ProcedureReturn 0
Else
ProcedureReturn *THIS\RefCount
EndIf
EndProcedure
Procedure IEnumString_Next(*THIS.EnumString, celt, *rgelt.Integer, *pceltFetched.Integer)
Protected count.i, i.i
If *THIS\Enumerator + celt <= *THIS\StringCount
count = celt
Else
count = *THIS\StringCount - *THIS\Enumerator
EndIf
For i = 0 To count-1
*rgelt\i = *THIS\Buffer\Strings[*THIS\Enumerator + i]
*rgelt + 4
Next i
*THIS\Enumerator + count
If *pceltFetched
*pceltFetched\i = count
EndIf
If count = celt
ProcedureReturn #S_OK
Else
ProcedureReturn #S_FALSE
EndIf
EndProcedure
Procedure IEnumString_Skip(*THIS.EnumString, celt)
*THIS\Enumerator + celt
If *THIS\Enumerator <= *THIS\StringCount
ProcedureReturn #S_OK
Else
ProcedureReturn #S_FALSE
EndIf
EndProcedure
Procedure IEnumString_Reset(*THIS.EnumString)
*THIS\Enumerator = 0
ProcedureReturn #S_OK
EndProcedure
Procedure IEnumString_Clone(*THIS.EnumString, *ppenum.Integer)
Protected *Clone.EnumString
If *ppenum = 0
ProcedureReturn #E_INVALIDARG
Else
*Clone = AllocateMemory(SizeOf(EnumString))
If *Clone
CopyMemory(*THIS, *Clone, SizeOf(EnumString))
*Clone\RefCount = 1
*Clone\Buffer\RefCount + 1
*ppenum\i = *Clone
ProcedureReturn #S_OK
Else
*ppenum\i = 0
ProcedureReturn #E_OUTOFMEMORY
EndIf
EndIf
EndProcedure
Procedure New_EnumString(Array StringArray.s(1))
Protected *THIS.EnumString = 0, *StringBuffer.EnumStringBuffer
Protected StringCount.i, Size.i, i.i
Protected *Pointer
StringCount = ArraySize(StringArray())
Size = 4 + StringCount * 4
For i = 0 To StringCount - 1
Size + Len(StringArray(i)) * 2 + 2
Next i
*StringBuffer = AllocateMemory(Size)
If *StringBuffer
*StringBuffer\RefCount = 1
*Pointer = *StringBuffer + 4 + StringCount * 4
For i = 0 To StringCount - 1
*StringBuffer\Strings[i] = *Pointer
PokeS(*Pointer, StringArray(i), -1, #PB_Unicode)
*Pointer + Len(StringArray(i)) * 2 + 2
Next i
*THIS = AllocateMemory(SizeOf(EnumString))
If *THIS
*THIS\Vtbl = ?IEnumStringVtbl
*THIS\RefCount = 1
*THIS\StringCount = StringCount
*THIS\Enumerator = 0
*THIS\Buffer = *StringBuffer
Else
FreeMemory(*StringBuffer)
EndIf
EndIf
ProcedureReturn *THIS
EndProcedure
DataSection
IEnumStringVtbl:
Data.i @IEnumString_QueryInterface()
Data.i @IEnumString_AddRef()
Data.i @IEnumString_Release()
Data.i @IEnumString_Next()
Data.i @IEnumString_Skip()
Data.i @IEnumString_Reset()
Data.i @IEnumString_Clone()
IID_IUnknown: ; {00000000-0000-0000-C000-000000000046}
Data.l $00000000
Data.w $0000, $0000
Data.b $C0, $00, $00, $00, $00, $00, $00, $46
IID_IEnumString: ; {00000101-0000-0000-C000-000000000046}
Data.l $00000101
Data.w $0000, $0000
Data.b $C0, $00, $00, $00, $00, $00, $00, $46
CLSID_AutoComplete: ; {00BB2763-6A77-11D0-A535-00C04FD7D062}
Data.l $00BB2763
Data.w $6A77, $11D0
Data.b $A5, $35, $00, $C0, $4F, $D7, $D0, $62
IID_IAutoComplete: ; {00BB2762-6A77-11D0-A535-00C04FD7D062}
Data.l $00BB2762
Data.w $6A77, $11D0
Data.b $A5, $35, $00, $C0, $4F, $D7, $D0, $62
IID_IAutoComplete2: ; {EAC04BC0-3791-11D2-BB95-0060977B464C}
Data.l $EAC04BC0
Data.w $3791, $11D2
Data.b $BB, $95, $00, $60, $97, $7B, $46, $4C
EndDataSection
#CLSCTX_INPROC_SERVER = $1
#ACO_NONE = 0 ; No autocompletion.
#ACO_AUTOSUGGEST = $1 ; Enable the autosuggest drop-down list.
#ACO_AUTOAPPEND = $2 ; Enable autoappend.
#ACO_SEARCH = $4 ; Add a search item to the dropdown list of completed strings. If this is item is selected, you should launch a search engine to assist the user.
#ACO_FILTERPREFIXES = $8 ; Don't match common prefixes, such as "www.", "http://", and so on.
#ACO_USETAB = $10 ; Use the TAB key to select an item from the drop-down list. This flag is disabled by default.
#ACO_UPDOWNKEYDROPSLIST = $20 ; Use the UP ARROW and DOWN ARROW keys to display the autosuggest drop-down list.
#ACO_RTLREADING = $40 ; If ACO_RTLREADING is set, the text is read in the opposite direction from the text in the parent window.
main.pb
Code: Select all
IncludeFile "AutoComplete.pbi"
; -----------------------------------------------
#Window_0 = 0
#String_0 = 0
Dim Strings.s(17)
Strings(0) = "Else"
Strings(1) = "ElseIf"
Strings(2) = "EnableDebugger"
Strings(3) = "EnableExplicit"
Strings(4) = "End"
Strings(5) = "EndDataSection"
Strings(6) = "EndEnumeration"
Strings(7) = "EndIf"
Strings(8) = "EndImport"
Strings(9) = "EndInterface"
Strings(10) = "EndMacro"
Strings(11) = "EndProcedure"
Strings(12) = "EndSelect"
Strings(13) = "EndStructure"
Strings(14) = "EndStructureUnion"
Strings(15) = "EndWith"
Strings(16) = "Enumeration"
; Initialize the COM environment
CoInitialize_(0)
Define *AutoComplete.IAutoComplete2, *Enum.IEnumString
If OpenWindow(#Window_0, 323, 219, 600, 300, "AutoComplete", #PB_Window_SystemMenu | #PB_Window_TitleBar | #PB_Window_ScreenCentered )
StringGadget(#String_0, 40, 40, 320, 20, "")
SetActiveGadget(#String_0)
; This creates the autocomplete object:
;
If CoCreateInstance_(?CLSID_AutoComplete, #Null, 1, ?IID_IAutoComplete2, @*AutoComplete) = #S_OK
; Lets change the options for autocomplete a bit:
; See the constant definitions above for the available options.
; There is a dropdown or in-place suggestion mode.
;
*AutoComplete\SetOptions(#ACO_AUTOSUGGEST|#ACO_USETAB)
; This creates the IEnumString interface from our string array:
;
*Enum = New_EnumString(Strings())
; This sets the autocomplet with our Enum object.
; If you want more info on the last 2 parameters, read here:
; http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/reference/ifaces/iautocomplete/Init.asp
; Note that these must be unicode strings if present!
;
; This also works for Comboboxes, you just need to get the handle to the edit
; control that is contained inside with the GetComboBoxInfo_() function.
;
*AutoComplete\Init(GadgetID(#String_0), *Enum, 0, 0)
Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow
; Release our own references to the objects to avoid a memory leak
;
*Enum\Release()
*AutoComplete\Release()
EndIf
EndIf
Re: [Windows] AutoComplete for StringGadgets
Posted: Thu Apr 11, 2019 6:10 pm
by LiK137
Autocomplete with using sql select is clear. But how to attach structured or multidimentional array like
1: MyArray(id, string)
2: MyArray\id and MyArray\string
to editable comboboxgadget to autofilter gadget contents.