Autocomplete

Anfängerfragen zum Programmieren mit PureBasic.
friedelinde
Beiträge: 12
Registriert: 15.02.2010 16:46

Autocomplete

Beitrag von friedelinde »

Im PureBasicForum fand ich diesen sehr schnellen Code von Peyman um ein Stringgadget mit einer autocompleteFunktion zu erweitern. Als Anfänger erschließt sich mir der Code zwar noch nicht: aber egal, er funktioniert prima.

Code: Alles auswählen

;  http://www.purebasic.fr/english/viewtopic.php?f=12&t=24721&hilit=AutoComplete&start=60
;  Peyman, 03.07.2013

;  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



#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)
     
      
      ; Release our own references to the objects to avoid a memory leak
      ;
      *Enum\Release()       
      *AutoComplete\Release()     
    EndIf
    
EndIf
  
  
Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow
Bei dem Versuch die autocompleteFunktion in eine Procedure zu packen etwa so:

Code: Alles auswählen

Procedure autocomplete(STR_Gadget, Array Auswahl(1))
    If CoCreateInstance_(?CLSID_AutoComplete, #Null, 1, ?IID_IAutoComplete2, @*AutoComplete) = #S_OK
      *AutoComplete\SetOptions(#ACO_AUTOSUGGEST|#ACO_USETAB)

      *Enum = New_EnumString(Auswahl())
    
      *AutoComplete\Init(GadgetID(Str_Gadget), *Enum, 0, 0)
     
      *Enum\Release()       
      *AutoComplete\Release()     
    EndIf
	
EndProcedure 
kommt die Fehlermeldung : Die folgende Variable hat kein Struktur: AutoComplete
Kann mir einer erklären warum?
Und was bedeutet bitte schön ?CLSID_AutoComplete und @*AutoComplete ??
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8808
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Re: Autocomplete

Beitrag von NicTheQuick »

Wenn du *AutoComplete und *Enum innerhalb der Procedure nutzen möchtest, dann musst du die beiden Variablen natürlich deklarieren, sonst wird das nichts.

Statt dem

Code: Alles auswählen

Define *AutoComplete.IAutoComplete2, *Enum.IEnumString
im Hauptprogramm schreibst du in der Procedure also

Code: Alles auswählen

Protected *AutoComplete.IAutoComplete2, *Enum.IEnumString
Und was bedeutet bitte schön ?CLSID_AutoComplete und @*AutoComplete ??
?CLSID_AutoComplete ist der Pointer zu dem Label mit dem entsprechenden Namen in der DataSection.
@*AutoComplete ist ein Pointer auf einen Pointer.
Benutzeravatar
7x7
Beiträge: 591
Registriert: 14.08.2007 15:41
Computerausstattung: ganz toll
Wohnort: Lelbach

Re: Autocomplete

Beitrag von 7x7 »

Und was bedeutet bitte schön ?CLSID_AutoComplete und @*AutoComplete ??
NicTheQuick hat geschrieben: ?CLSID_AutoComplete ist der Pointer zu dem Label mit dem entsprechenden Namen in der DataSection.
@*AutoComplete ist ein Pointer auf einen Pointer.
Zum besseren Verständnis: Ein "Pointer" ist eine Adresse im Speicher
- alles was ich hier im Forum sage/schreibe ist lediglich meine Meinung und keine Tatsachenbehauptung
- unkommentierter Quellcode = unqualifizierter Müll
friedelinde
Beiträge: 12
Registriert: 15.02.2010 16:46

Re: Autocomplete

Beitrag von friedelinde »

Herzlichen Dank. Auch wenn ich die Zusammenhänge noch nicht verstehe,durch die Deklaration in der Procedure läuft der Code jetzt fehlerfrei.

Code: Alles auswählen

Procedure  autocomplete(Str_Eingabe,Array LIV_Auswahl$(1))

 Protected *AutoComplete.IAutoComplete2, *Enum.IEnumString

 If CoCreateInstance_(?CLSID_AutoComplete, #Null, 1, ?IID_IAutoComplete2, @*AutoComplete) = #S_OK
;
      *AutoComplete\SetOptions(#ACO_AUTOSUGGEST|#ACO_USETAB |#ACO_AUTOAPPEND| #ACO_UPDOWNKEYDROPSLIST)
      *Enum = New_EnumString(LIV_Auswahl$())
      *AutoComplete\Init(GadgetID(Str_Eingabe), *Enum, 0, 0)
      *Enum\Release()       
      *AutoComplete\Release() 
      
 EndIf
      
EndProcedure
Allerdings gibt es jetzt das Problem, die Funktion autocomplete in eine WaitWindows - Eventschleife einzubinden, etwa so:

Code: Alles auswählen

Enumeration FormWindow
  #Window_1
EndEnumeration

Enumeration FormGadget
  #String_1
EndEnumeration


Procedure OpenWindow_1(x = 0, y = 0, width = 600, height = 400)
  OpenWindow(#Window_1, x, y, width, height,"" , #PB_Window_SystemMenu)
  StringGadget(#String_1, 121, 97, 242, 25, "")
EndProcedure

Procedure Window_1_Events(event)
  Select event
    Case #PB_Event_CloseWindow
      ProcedureReturn #False

    Case #PB_Event_Menu
      Select EventMenu()
      EndSelect

    Case #PB_Event_Gadget
      Select EventGadget()
          Case #String_1
          autocomplete(#String_1, strings$())
      EndSelect
  EndSelect
  ProcedureReturn #True
EndProcedure

OpenWindow_1()

Repeat
  event = WaitWindowEvent()
Until Window_1_Events(event) = #False

End
Durch das andauernde Abfragen der Windows Events, kann die Funktion nicht abgearbeitet werden. Gibt es eine Möglichkeit, die permanente Abfrage der Events in der Procedure anzuhalten?
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8808
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Re: Autocomplete

Beitrag von NicTheQuick »

Ab jetzt muss dir jemand helfen, der Windows hat. Das kann ich nicht testen.
Benutzeravatar
Kukulkan
Beiträge: 1066
Registriert: 09.09.2004 07:07
Wohnort: Süddeutschland
Kontaktdaten:

Re: Autocomplete

Beitrag von Kukulkan »

Hallo,

wenn es jemanden interessiert, ich habe mal ein Cross-Platform Auto-Complete für E-Mail-Adressen gemacht. Das kann sicher recht einfach auch umgebaut werden auf was anderes als E-Mail-Adressen. Das besondere an diesem Modul ist, dass die Eingabe von mehreren E-Mail-Adressen per Komma, Strichpunkt oder Leerzeichen erfolgen kann und das Auto-Complete dann immer noch funktioniert.

Code: Alles auswählen

EnableExplicit

Structure AddressList
  Mailaddress.s
  FirstName.s
  LastName.s
EndStructure

CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
  CompilerIf #PB_Compiler_Version < 470 Or (#PB_Compiler_Version >= 500 And Subsystem("Carbon"))
    ImportC ""
      GetControlData(ControlRef.L, ControlPartCode.L, TagName.L, BufferSize.L, *Buffer, *ActualSize)
      SetControlData(ControlRef.L, ControlPartCode.L, TagName.L, BufferSize.L, *Buffer)
    EndImport
    
    #kControlEditTextPart = 5
    #kControlEditTextSelectionTag = $73656C65
    
    Structure ControlEditTextSelectionRec
      SelStart.W
      SelEnd.W
    EndStructure
  CompilerElse
    Global NSRangeZero.NSRange
    Procedure.i acTextEditor(Gadget.i)
      Protected TextField.i = GadgetID(Gadget)
      Protected Window.i = CocoaMessage(0, TextField, "window")
      ProcedureReturn CocoaMessage(0, Window, "fieldEditor:", #YES, "forObject:", TextField)
    EndProcedure
  CompilerEndIf
CompilerEndIf

; Sets the selection in a StringGadget() independent of Operating System
; If Start.i < 1, every selection is removed.
; If Length.i = 0, only the cursor is set.
Procedure SetStringGadgetSelection(GadgetID.i, Start.i, Length.i)
  If Start.i > 0 And Length.i > -1
    ; Set selection
    CompilerSelect #PB_Compiler_OS
      CompilerCase #PB_OS_Windows
        SendMessage_(GadgetID(GadgetID), #EM_SETSEL, Start.i - 1, Start.i + Length.i - 1)
      CompilerCase #PB_OS_Linux
        gtk_editable_select_region_(GadgetID(GadgetID), Start - 1, Start -1 + Length)
      CompilerCase #PB_OS_MacOS
        CompilerIf #PB_Compiler_Version < 470 Or (#PB_Compiler_Version >= 500 And Subsystem("Carbon"))
          Protected TextSelection.ControlEditTextSelectionRec
          TextSelection\selStart = Start - 1
          TextSelection\selEnd = Start -1 + Length
          SetControlData(GadgetID(GadgetID), #kControlEditTextPart, #kControlEditTextSelectionTag, SizeOf(ControlEditTextSelectionRec), @TextSelection)
        CompilerElse
          Protected Range.NSRange\location = Start - 1 : Range\length = Length
          CocoaMessage(0, acTextEditor(GadgetID), "setSelectedRange:@", @Range)
        CompilerEndIf
    CompilerEndSelect
  Else
    ; Deselect all
    CompilerSelect #PB_Compiler_OS
      CompilerCase #PB_OS_Windows
        SendMessage_(GadgetID(GadgetID.i), #EM_SETSEL, -1, 0)
      CompilerCase #PB_OS_Linux
        gtk_editable_delete_selection_(GadgetID(GadgetID))
      CompilerCase #PB_OS_MacOS
        CompilerIf #PB_Compiler_Version < 470 Or (#PB_Compiler_Version >= 500 And Subsystem("Carbon"))
          TextSelection\selStart = -1
          TextSelection\selEnd = -1
          SetControlData(GadgetID(GadgetID), #kControlEditTextPart, #kControlEditTextSelectionTag, SizeOf(ControlEditTextSelectionRec), @TextSelection)
        CompilerElse
          CocoaMessage(0, acTextEditor(GadgetID), "setSelectedRange:@", @NSRangeZero)
        CompilerEndIf
    CompilerEndSelect
  EndIf
EndProcedure

Procedure.i GetStringGadgetSelectionStart(GadgetID.i)
  ; Get selection
  Protected Start.i = 0
  Protected Stop.i = 0
  CompilerSelect #PB_Compiler_OS
    CompilerCase #PB_OS_Windows
      SendMessage_(GadgetID(GadgetID.i), #EM_GETSEL, @Start.i, @Stop.i)
      ProcedureReturn Start.i + 1
    CompilerCase #PB_OS_Linux
      gtk_editable_get_selection_bounds_(GadgetID(GadgetID), @Start, @Stop)
      ProcedureReturn Start + 1
    CompilerCase #PB_OS_MacOS
      CompilerIf #PB_Compiler_Version < 470 Or (#PB_Compiler_Version >= 500 And Subsystem("Carbon"))
        Protected TextSelection.ControlEditTextSelectionRec
        GetControlData(GadgetID(GadgetID), #kControlEditTextPart, #kControlEditTextSelectionTag, SizeOf(ControlEditTextSelectionRec), @TextSelection.ControlEditTextSelectionRec, 0)
        ProcedureReturn TextSelection\SelStart + 1
      CompilerElse
        Protected Range.NSRange
        CocoaMessage(@Range, acTextEditor(GadgetID), "selectedRange")
        ProcedureReturn Range\location + 1
      CompilerEndIf
  CompilerEndSelect
EndProcedure

Procedure.i GetStringGadgetSelectionLength(GadgetID.i)
  ; Get selection
  Protected Start.i = 0
  Protected Stop.i = 0
  CompilerSelect #PB_Compiler_OS
    CompilerCase #PB_OS_Windows
      SendMessage_(GadgetID(GadgetID), #EM_GETSEL, @Start.i, @Stop.i)
      ProcedureReturn Stop.i - Start.i
    CompilerCase #PB_OS_Linux
      gtk_editable_get_selection_bounds_(GadgetID(GadgetID), @Start, @Stop)
      ProcedureReturn Stop - Start
    CompilerCase #PB_OS_MacOS
      CompilerIf #PB_Compiler_Version < 470 Or (#PB_Compiler_Version >= 500 And Subsystem("Carbon"))
        Protected TextSelection.ControlEditTextSelectionRec
        GetControlData(GadgetID(GadgetID), #kControlEditTextPart, #kControlEditTextSelectionTag, SizeOf(ControlEditTextSelectionRec), @TextSelection.ControlEditTextSelectionRec, 0)
        ProcedureReturn TextSelection\SelEnd - TextSelection\SelStart
      CompilerElse
        Protected Range.NSRange
        CocoaMessage(@Range, acTextEditor(GadgetID), "selectedRange")
        ProcedureReturn Range\length
      CompilerEndIf
  CompilerEndSelect
EndProcedure

Procedure.i AutoCompleteFindStringRev(String$, StringToFind$, StringToFind2$ = "", StringToFind3$ = "")
  Protected x.i = 0
  String$ = UCase(String$)
  StringToFind$ = UCase(StringToFind$)
  StringToFind2$ = UCase(StringToFind2$)
  StringToFind3$ = UCase(StringToFind3$)
  For x.i = Len(String$) To 1 Step -1
    If Mid(String$, x.i, Len(StringToFind$)) = StringToFind$
      ProcedureReturn x.i
    EndIf
    If Mid(String$, x.i, Len(StringToFind2$)) = StringToFind2$
      ProcedureReturn x.i
    EndIf
    If Mid(String$, x.i, Len(StringToFind3$)) = StringToFind3$
      ProcedureReturn x.i
    EndIf
  Next
  ProcedureReturn 0
EndProcedure

Procedure AutoCompleteStringGadget(strGadgID.i, List Options.AddressList())
  Static NewMap LastLength.i()
  Static NewMap LastAddress.s()
  Protected StandardDivider.s = ";"
  Protected TempText.s        = ""
  Protected RightChar.s       = ""
  Protected Offset.i          = 1
  Protected Left.i            = 0
  Protected Part.s            = ""
  Protected Content.s         = GetGadgetText(strGadgID.i)
  Protected Address.s         = ""
  
  Left.i = AutoCompleteFindStringRev(Content.s, ",", ";", " ")
  If Left.i > 0: Offset.i = Left.i + 1: EndIf
  Part.s = UCase(Trim(Mid(Content.s, Offset.i)))
  
  If Len(Content.s) > LastLength(Str(strGadgID.i))
    RightChar.s = Right(Content.s, 1)
    If LastAddress(Str(strGadgID.i)) <> "" And (RightChar.s = "," Or RightChar.s = ";" Or RightChar.s = " ")
      Left.i = AutoCompleteFindStringRev(Left(Content.s, Left.i - 1), ",", ";", " ")
      Offset.i  = 1
      If Left.i > 0: Offset.i = Left.i + 1: EndIf
      TempText.s = Left(Content.s, Offset.i - 1) + LastAddress(Str(strGadgID.i)) + StandardDivider.s
      SetGadgetText(strGadgID.i, TempText.s)
      SetStringGadgetSelection(strGadgID.i, Len(TempText.s) + 1, 0)
      LastAddress(Str(strGadgID.i)) = ""
    EndIf
    If Len(Part.s) > 0
      LastAddress(Str(strGadgID.i)) = ""
      CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
        ; On mac we do not use the builtin address book. Instead, we are using the 
        ; Mac address book by default. The others are only used if we do not find
        ; something that matches in the Mac address book.
        Address.s = mac_FindEmailAddress(Part.s)
        If Address.s <> ""
          TempText.s = Left(Content.s, Offset.i - 1) + Address.s
          SetGadgetText(strGadgID.i, TempText.s)
          SetStringGadgetSelection(strGadgID.i, Offset.i + Len(Part.s), 500)
          LastAddress(Str(strGadgID.i)) = Address.s
          LastLength(Str(strGadgID.i)) = Len(Content.s)
          ProcedureReturn
        EndIf
      CompilerEndIf
      ForEach Options()
        If Left(UCase(Options()\Mailaddress), Len(Part.s)) = Part.s
          TempText.s = Left(Content.s, Offset.i - 1) + Options()\Mailaddress
          SetGadgetText(strGadgID.i, TempText.s)
          SetStringGadgetSelection(strGadgID.i, Offset.i + Len(Part.s), 500)
          LastAddress(Str(strGadgID.i)) = Options()\Mailaddress
          Break
        EndIf
      Next
    EndIf
  EndIf
  LastLength(Str(strGadgID.i)) = Len(Content.s)  
EndProcedure

; EXAMPLE USAGE:
; ================================================================================

NewList MailAddresses.AddressList()
AddElement(MailAddresses())
MailAddresses()\Mailaddress = "apple@company.com"
AddElement(MailAddresses())
MailAddresses()\Mailaddress = "apple2@company.com"
AddElement(MailAddresses())
MailAddresses()\Mailaddress = "berry@company.com"
AddElement(MailAddresses())
MailAddresses()\Mailaddress = "peach@company.com"
AddElement(MailAddresses())
MailAddresses()\Mailaddress = "banana@company.com"

If OpenWindow(0, 200, 300, 395, 160, "PureBasic Window", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
 
  Define strGadgID.i = StringGadget(#PB_Any, 10, 10, 380, 26, "")
  Define btnGadgID.i = ButtonGadget(#PB_Any, 10, 40, 380, 26, "Button")
 
  SetActiveGadget(strGadgID.i)
  
  Repeat
    Define Event.i = WaitWindowEvent()
    
    If Event.i = #PB_Event_CloseWindow
      Define Quit.i = 1
    EndIf
    If Event.i = #PB_Event_Gadget
      Define et.i = EventType()
      Define gd.i = EventGadget()
      
      If gd.i = strGadgID.i And et.i = #PB_EventType_Change
        AutoCompleteStringGadget(gd.i, MailAddresses())
      EndIf
    EndIf
  Until Quit.i = 1
EndIf
End
Grüße,

Kukulkan
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8808
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Re: Autocomplete

Beitrag von NicTheQuick »

Das ist ziemlich geil! :allright:
Pack es doch bitte in "Codes, Tipps & Tricks", damit es jeder finden kann. Meinst du, du schaffst es noch eine Funktion einzubauen, die wie bspw. die Adressleiste im Firefox andere Mailadressen vorschlägt, die ebenfalls mit den bisher eingegebenen Buchstaben beginnen?
Antworten