ComboBox: Aktuelles Item durch Eingabe ändern

Für allgemeine Fragen zur Programmierung mit PureBasic.
Andesdaf
Moderator
Beiträge: 2658
Registriert: 15.06.2008 18:22
Wohnort: Dresden

ComboBox: Aktuelles Item durch Eingabe ändern

Beitrag von Andesdaf »

Hallo,

der Standardfall unter Windows ist ja, dass man bei fokussiertem ComboBoxGadget durch Tastendruck direkt zum
ersten Item mit dem eingegebenen Anfangsbuchstaben springen kann. Ich würde diese Funktion gern ausweiten,
sodass beim weiteren Tippen die Items markiert werden, die mit der seit der Fokussierung eingegebenen Zeichenkette
beginnen.

Ich habe das bei einem anderen, nicht-PB-Programm, gesehen, habe aber per Suche keinen passenden Ansatz gefunden.
Es geht mir nicht um Editable-ComboBoxen, da ich keine freie Auswahl erlauben kann.
Win11 x64 | PB 6.00 (x64)
Andesdaf
Moderator
Beiträge: 2658
Registriert: 15.06.2008 18:22
Wohnort: Dresden

Re: ComboBox: Aktuelles Item durch Eingabe ändern

Beitrag von Andesdaf »

Der Vollständigkeit halber: ich habe eine Lösung gefunden:

Code: Alles auswählen

Import ""
  PB_Object_EnumerateStart(*object)
  PB_Object_EnumerateNext(*object,*id.Integer)
  PB_Object_EnumerateAbort(*object)
  PB_Gadget_Objects.i
EndImport

Structure COMBOSEARCH
  iID.i
  iState.i
  zText.s
EndStructure

Global.i ActiveControl

Procedure.i PBGadget(hWnd)
  Protected.i iResult,
              iGadget
              
  iResult = -1
 
  PB_Object_EnumerateStart(PB_Gadget_Objects)
  While PB_Object_EnumerateNext(PB_Gadget_Objects, @iGadget)
    If hWnd = GadgetID(iGadget)
      iResult = iGadget
      Break
    EndIf
  Wend
  PB_Object_EnumerateAbort(PB_Gadget_Objects)
  ProcedureReturn iResult
  
EndProcedure

Procedure.i ComboSearch(piGadget.i, piKey.i)
  Protected.i i,
              iFound,
              iState,
              iAnzLine
  Protected.s zText
  Static NewList sllCombo.COMBOSEARCH()
; --------------------------  
  
  ; ComboBox suchen oder Eintrag anlegen
  iFound = 0
  ForEach sllCombo()
    If sllCombo()\iID = piGadget
      iFound = 1
      Break
    EndIf
  Next
  If iFound = 0
    AddElement(sllCombo())
    sllCombo()\iID = piGadget
  EndIf
  
  ; Status vergleichen, um zwischenzeitiche manuelle Änderungen
  ; zu erkennen und den Text zurückzusetzen
  iState = GetGadgetState(piGadget)
  If sllCombo()\iState <> iState
    sllCombo()\zText = ""
  EndIf
  
  If piKey = 8
    ; Text: Key ist Backspace, dann letztes Zeichen löschen
    sllCombo()\zText = Left(sllCombo()\zText, Len(sllCombo()\zText) - 1)
  ElseIf piKey = 32
    ; Text: Key ist Leertaste, Suche komplett löschen
    sllCombo()\zText = ""
    SetGadgetState(piGadget, 0)
    ProcedureReturn 1
  Else
    ; Text: Key ist A-Z oder 0-9, dann Zeichen anhängen
    sllCombo()\zText + Chr(piKey)
  EndIf
    
  iAnzLine = CountGadgetItems(piGadget) - 1
  For i = 0 To iAnzLine
    zText = RemoveString(GetGadgetItemText(piGadget, i), " ")
    If FindString(zText, sllCombo()\zText, 0, #PB_String_NoCase)
      SetGadgetState(piGadget, i)
      sllCombo()\iState = i
      PostEvent(#PB_Event_Gadget, 0, piGadget, #PB_EventType_Change)
      ProcedureReturn 1
    EndIf
  Next i
  
  ProcedureReturn 0
  
EndProcedure

Procedure WindowCB(hWnd, msg, wParam, lParam) 
  Protected.i iResult
  
  iResult = #PB_ProcessPureBasicEvents
  
  Select msg
      
    Case #WM_COMMAND
      Select (wParam >> 16) & $FFFF
        Case #CBN_SETFOCUS
          ActiveControl = PBGadget(lParam)
        Case #CBN_KILLFOCUS
          ActiveControl = -1
      EndSelect
      
  EndSelect 

  ProcedureReturn iResult 
EndProcedure 

Procedure.l KbdHook(nCode, wParam, *p.KBDLLHOOKSTRUCT)
  Protected.i iKey,
              iGadget,
              iType
    
  If wParam = #WM_KEYDOWN
    iKey = MapVirtualKey_(*p\vkCode, 2)
    Select iKey
      Case 8, 32, 48 To 57, 65 To 90, 223, 228, 246, 252
        ; //
        ; Backspace, Space, 0-9, A-Z, ß, ä, ö, ü
        ; //
        iGadget = ActiveControl
        If IsGadget(iGadget)
          iType = GadgetType(iGadget)
          If iType = #PB_GadgetType_ComboBox
            ComboSearch(iGadget, iKey)
            ProcedureReturn 1
          EndIf
        EndIf
    EndSelect
  EndIf
  
  ProcedureReturn CallNextHookEx_(0, nCode, wParam, *p)
  
EndProcedure

; A-Z, 0-9 mgl. ohne Leerzeichen
; Backspace löscht letztes eingebenes Zeichen
; Leertaste löscht ganzen Filter

If OpenWindow(0, 0, 0, 270, 180, "ComboBoxGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  ComboBoxGadget(0, 10, 70, 250, 21)
  AddGadgetItem(0, -1, "Brauhaus")
  AddGadgetItem(0, -1, "Brauhausplatz")
  AddGadgetItem(0, -1, "Braustolz")
  AddGadgetItem(0, -1, "Xylophon")
  AddGadgetItem(0, -1, "Xylophonbauer")
  AddGadgetItem(0, -1, "Ameise")
  AddGadgetItem(0, -1, "Ameisenbär")
  AddGadgetItem(0, -1, "Amerika")
  AddGadgetItem(0, -1, "Butterbrot")
  AddGadgetItem(0, -1, "Burschenschaftler")
  AddGadgetItem(0, -1, "Ammenmärchen")
  AddGadgetItem(0, -1, "Risikobewertung")
  SetGadgetState(0, 0)
  
  SetWindowCallback(@WindowCB(), 0)
  SetWindowsHookEx_(#WH_KEYBOARD_LL, @KbdHook(), GetModuleHandle_(0), 0)
  
  Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
EndIf
Win11 x64 | PB 6.00 (x64)
Antworten