Ouvrir une combo sans utiliser la souris
Ouvrir une combo sans utiliser la souris
Bonjour,
Je souhaiterai afficher la liste des refernces commencant par la lettre tapee par lutilisateur, au fur et a mesure que lutilisateur tape une lettre dans la zone du combo editable, la liste change en fonction des lettres saisies.
Merci
Excusez-moi pour les fautes, cest le clavier qui dconne... humm
Je souhaiterai afficher la liste des refernces commencant par la lettre tapee par lutilisateur, au fur et a mesure que lutilisateur tape une lettre dans la zone du combo editable, la liste change en fonction des lettres saisies.
Merci
Excusez-moi pour les fautes, cest le clavier qui dconne... humm
Win7 (x64) 64 bits Pb 5.72
Re: Ouvrir une combo sans utiliser la souris
En plaçant un hook sur le clavier par exemple ? 

Il y a deux méthodes pour écrire des programmes sans erreurs. Mais il n’y a que la troisième qui marche.
Version de PB : 6.00LTS - 64 bits
Version de PB : 6.00LTS - 64 bits
Re: Ouvrir une combo sans utiliser la souris
Hello Omega,
Comme souvent en programmation, ce qui paraît simple au premier abord, l'est moins à l’exécution
Avec une liste déroulante éditable, c'est complexe (je vois pas comment, à part interception des touches clavier comme indiqué)
Par contre, la liste déroulante classique (StringGadget ), auto-sélectionne un élément dès qu'on tape une lettre.
La liste ne se déroule pas, mais le choix se fait quand même.
Si plusieurs termes commencent de la même façon, ça boucle automatiquement.
Un moyen relativement simple pourrait donc être d'utiliser 2 gadgets: StringGadget + ComboBoxGadget et faire en sorte de mettre à jour le StringGadget à chaque changement du ComboBoxGadget.
(Je sais pas si je m'explique bien
)
Voilà l'idée, reste plus qu'à (essayer de) concrétiser.

Comme souvent en programmation, ce qui paraît simple au premier abord, l'est moins à l’exécution


Avec une liste déroulante éditable, c'est complexe (je vois pas comment, à part interception des touches clavier comme indiqué)
Par contre, la liste déroulante classique (StringGadget ), auto-sélectionne un élément dès qu'on tape une lettre.
La liste ne se déroule pas, mais le choix se fait quand même.
Si plusieurs termes commencent de la même façon, ça boucle automatiquement.
Un moyen relativement simple pourrait donc être d'utiliser 2 gadgets: StringGadget + ComboBoxGadget et faire en sorte de mettre à jour le StringGadget à chaque changement du ComboBoxGadget.
(Je sais pas si je m'explique bien

Voilà l'idée, reste plus qu'à (essayer de) concrétiser.

Re: Ouvrir une combo sans utiliser la souris
Si tu fais une recherche avec combobox autocomplete, ou autocompletion, tu devrais avoir plein de réponses comme celle-ci (sur le forum anglais)
[Edition]
J'ai sous la main un code qui ouvre une liste. Ce n'est pas un combo mais ça fait le même effet.
M.
Code : Tout sélectionner
;
;- Coded by Xombie 12/19/2005, updated 7/13/2006
;
;- Enumeration
Enumeration ; Control Type Enumeration
#ac_String
#ac_Combo
EndEnumeration
;- 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.
EndStructure
;- Global Variables
Global NewList _ac_Main.s_AutoComplete()
;- Helper Functions
Procedure.b ac_GetGadgetType(Handle.l)
; Return the gadget type based on the classname used in CreateWindowExW_()
HoldString.s
; This will store the length of the wide character string, in characters.
lCount.l
; Used to store the number of character copied.
HoldString = Space(255)
; Allocate size for our string.
GetClassName_(Handle, @HoldString, 255)
; Call our function to retrieve the classname.
If HoldString = "Edit"
ProcedureReturn #ac_String
ElseIf HoldString = "ComboBox"
ProcedureReturn #ac_Combo
EndIf
;
EndProcedure
Procedure.b ac_GadgetExists(Gadget.l)
;
ResetList(_ac_Main())
While NextElement(_ac_Main())
If _ac_Main()\Gadget = Gadget : ProcedureReturn #True : EndIf
Wend
;
ProcedureReturn #False
;
EndProcedure
Procedure.l ac_GetOldCallback(Handle.l)
;
ResetList(_ac_Main())
While NextElement(_ac_Main())
If _ac_Main()\Handle = Handle : ProcedureReturn _ac_Main()\CallBack : EndIf
Wend
;
ProcedureReturn -1
;
EndProcedure
;- Callback Functions
Procedure.l ac_HandleEditEvents(HandleWindow.l, message.l, wParam.l, lParam.l)
; Custom callback for edit controls.
lResult.l
;
CallBack.l
;
Gadget.l
;
ArrayAddress.l
;
iLoop.l
;
HoldTotal.l
;
HoldLength.l
;
HoldCombinedLength.l
;
HoldStart.l
;
HoldEnd.l
;
HoldSelection.l
;
HoldString.s
;
PreText.s
;
PostText.s
;
CombinedText.s
;
MatchText.s
;
*Position.s_ACStringStructure
; This will be a pointer to the strings in the array.
CallBack = ac_GetOldCallback(HandleWindow)
; Return the old callback procedure address.
If CallBack = -1 : ProcedureReturn : EndIf
; This should never happen as this callback is only set for autocomplete items.
ResetList(_ac_Main())
While NextElement(_ac_Main())
If _ac_Main()\Handle = HandleWindow : ArrayAddress = _ac_Main()\ArrayAddress : Gadget = _ac_Main()\Gadget : Break : EndIf
Wend
;
HoldTotal = PeekL(ArrayAddress - 8)
; Return the number of items in the array.
If HoldTotal = 0 : ProcedureReturn : EndIf
; No need to complete if 0 items.
*Position = ArrayAddress
; Point to the first element in the array.
If message = #WM_CHAR
;
HoldString = GetGadgetText(Gadget)
; Store the current text.
HoldLength = Len(HoldString)
;
SendMessage_(HandleWindow, #EM_GETSEL, @HoldStart, @HoldEnd)
; Store the start and end selection values.
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))
;
HoldCombinedLength = Len(CombinedText)
;
For iLoop = 0 To HoldTotal - 1
; Loop through all items in the array.
MatchText = PeekS(@*Position\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 LCase(Left(MatchText, HoldCombinedLength)) = CombinedText
; Found a matching item in the combobox.
SetGadgetText(Gadget, MatchText)
;
SendMessage_(HandleWindow, #EM_SETSEL, HoldCombinedLength, -1)
;
wParam = 0
;
Break
; Exit the loop.
EndIf
;
Next iLoop
;
If wParam <> 0 : lResult = CallWindowProc_(CallBack, HandleWindow, message, wParam, lParam) : EndIf
;
Else
;
lResult = CallWindowProc_(CallBack, HandleWindow, message, wParam, lParam)
;
EndIf
;
ProcedureReturn lResult
;
EndProcedure
Procedure.l ac_HandleComboEvents(HandleWindow.l, message.l, wParam.l, lParam.l)
; Custom callback for combobox controls.
lResult.l
;
CallBack.l
;
Gadget.l
;
Parent.l
;
iLoop.l
;
HoldTotal.l
;
HoldLength.l
;
HoldCombinedLength.l
;
HoldStart.l
;
HoldEnd.l
;
HoldSelection.l
;
HoldString.s
;
PreText.s
;
PostText.s
;
CombinedText.s
;
MatchText.s
;
CallBack = ac_GetOldCallback(HandleWindow)
; Return the old callback procedure address.
If CallBack = -1 : ProcedureReturn : EndIf
; This should never happen as this callback is only set for autocomplete items.
ResetList(_ac_Main())
While NextElement(_ac_Main())
If _ac_Main()\Handle = HandleWindow : Parent = _ac_Main()\Parent : Gadget = _ac_Main()\Gadget : Break : EndIf
Wend
; Retrieve the handle to the combobox and the gadget id.
If 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.
HoldString = GetGadgetText(Gadget)
; Store the current combobox text.
HoldLength = Len(HoldString)
;
SendMessage_(Parent, #CB_GETEDITSEL, @HoldStart, @HoldEnd)
; Store the start and end selection values.
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))
;
HoldCombinedLength = Len(CombinedText)
;
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_(Parent, #CB_SETEDITSEL, 0, HoldSelection)
;
wParam = 0
;
Break
; Exit the loop.
EndIf
;
Next iLoop
;
If wParam <> 0 : 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
;
ProcedureReturn lResult
;
EndProcedure
;- Main Functions
Procedure ac_SetAutocomplete(Gadget.l, EditGadgetArrayAddress.l)
; 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.
Type.b
;
Handle.l
;
If ac_GadgetExists(Gadget) : ProcedureReturn : EndIf
; Check if the gadget already exists in the autocomplete list.
Handle = GadgetID(Gadget)
;
Type = ac_GetGadgetType(Handle)
;
If Type = #ac_String
; String type.
If EditGadgetArrayAddress = 0 : ProcedureReturn : EndIf
; 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_Main()\ArrayAddress = EditGadgetArrayAddress
;
ElseIf Type = #ac_Combo
; 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()\ArrayAddress = 0
;
Else
; Not a combo or string type. Currently, no other controls are supported.
ProcedureReturn
;
EndIf
;
EndProcedure
Procedure ac_RemoveAutocomplete(Gadget.l)
;
Handle.l
;
If ac_GadgetExists(Gadget) : ProcedureReturn : EndIf
; Check if the gadget already exists in the autocomplete list.
Handle = GadgetID(Gadget)
;
ResetList(_ac_Main())
While NextElement(_ac_Main())
If _ac_Main()\Gadget = Gadget : SetWindowLong_(Handle, #GWL_WNDPROC, _ac_Main()\CallBack) : Break : EndIf
Wend
;
EndProcedure
Procedure ac_DestroyAutocomplete()
; Remove all autocomplete items.
If CountList(_ac_Main()) = 0 : ProcedureReturn : EndIf
; No need to destroy if no items in the list.
ResetList(_ac_Main())
While NextElement(_ac_Main())
SetWindowLong_(Handle, #GWL_WNDPROC, _ac_Main()\CallBack)
Wend
;
EndProcedure
; By Xombie - 12/12/2005
;
Enumeration ; Window List
#WindowMain
EndEnumeration
Enumeration ; Menu List
#MenuMain
EndEnumeration
Enumeration ; Control List
#ButtonTest
#StringTest
#StringTest2
#ComboTest
EndEnumeration
;- Global Variables
Dim Array01.s(10)
Dim array02.s(20)
;- Includes
;XIncludeFile "Autocomplete.pb"
;- Main Program
DoQuit.b
;
If OpenWindow(#WindowMain, 100, 300, 300, 200, "Test", #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget)
;
;If CreateGadgetList(WindowID(#WindowMain))
StringGadget(#StringTest, 0, 0, 100, 20, "")
StringGadget(#StringTest2, 0, 21, 100, 20, "")
ComboBoxGadget(#ComboTest, GadgetX(#StringTest2), GadgetY(#StringTest2) + GadgetHeight(#StringTest2) + 1, 100, 30, #PB_ComboBox_Editable)
ButtonGadget(#ButtonTest, GadgetX(#ComboTest), GadgetY(#ComboTest) + GadgetHeight(#ComboTest) + 1, 100, 20, "Test")
;EndIf
;
;{ Create autocomplete lists
;
;/ Create items for the combobox.
AddGadgetItem(#ComboTest, -1, "One")
AddGadgetItem(#ComboTest, -1, "Two")
AddGadgetItem(#ComboTest, -1, "Three")
AddGadgetItem(#ComboTest, -1, "Four")
AddGadgetItem(#ComboTest, -1, "Five")
AddGadgetItem(#ComboTest, -1, "Six")
AddGadgetItem(#ComboTest, -1, "Seven")
AddGadgetItem(#ComboTest, -1, "Eight")
AddGadgetItem(#ComboTest, -1, "Nine")
AddGadgetItem(#ComboTest, -1, "Ten")
AddGadgetItem(#ComboTest, -1, "The")
AddGadgetItem(#ComboTest, -1, "quick")
AddGadgetItem(#ComboTest, -1, "brown")
AddGadgetItem(#ComboTest, -1, "fox")
AddGadgetItem(#ComboTest, -1, "jack")
AddGadgetItem(#ComboTest, -1, "jumped")
AddGadgetItem(#ComboTest, -1, "over")
AddGadgetItem(#ComboTest, -1, "the")
AddGadgetItem(#ComboTest, -1, "two")
AddGadgetItem(#ComboTest, -1, "lazy")
AddGadgetItem(#ComboTest, -1, "dogs")
;/ Create items for the first string
Array01(0) = "Jack"
Array01(1) = "and"
Array01(2) = "Jill"
Array01(3) = "went"
Array01(4) = "up"
Array01(5) = "the"
Array01(6) = "hill"
Array01(7) = "to"
Array01(8) = "fetch"
Array01(9) = "a"
Array01(10) = "pail"
;/ Create items for the second string
array02(0) = "Jack"
array02(1) = "Sprat"
array02(2) = "could"
array02(3) = "eat"
array02(4) = "no"
array02(5) = "fat"
array02(6) = "and"
array02(7) = "his"
array02(8) = "wife"
array02(9) = "could"
array02(10) = "eat"
array02(11) = "no"
array02(12) = "lean"
array02(13) = "but"
array02(14) = "between"
array02(15) = "the"
array02(16) = "both"
array02(17) = "of"
array02(18) = "them"
array02(19) = "they"
array02(20) = "licked"
;}
;
ac_SetAutocomplete(#StringTest, @Array01())
;
ac_SetAutocomplete(#StringTest2, @array02())
;
ac_SetAutocomplete(#ComboTest, 0)
;
Repeat
;
EventID.l = WaitWindowEvent()
;
If EventID = #PB_Event_CloseWindow ; If the user has pressed on the close button
;
DoQuit = #True
;
ElseIf EventID = #PB_Event_Gadget
;
If EventGadget() = #ButtonTest
;
If EventType() = #PB_EventType_LeftClick
;
;
EndIf
;
EndIf
;
EndIf
;
Until DoQuit = #True
EndIf
ac_DestroyAutocomplete()
; Remove all autocompleting items.
End
J'ai sous la main un code qui ouvre une liste. Ce n'est pas un combo mais ça fait le même effet.
Code : Tout sélectionner
;==================================================================
;
; Library: AutoComplete v. 0.9 alpha (WIP)
; 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
;
; Contributors: rsts ( DeleteString )
; dige ( keyboard navigation )
;
;==================================================================
Import ""
PB_Gadget_GetRootWindow(hwnd) ; Find root window of gadgetid
EndImport
Structure MSLLHOOKSTRUCT
pt.point
mouseData.l
flags.l
time.l
dwExtraInfo.l
EndStructure
Structure stringdb
gadget.i
prompt.s
EndStructure
Structure AutoCompleteObject
*vTable
List pstr.stringdb() ; db for strings
subclass_oldproc.i ; oldproc for string gadget (to set back on release)
gadget.i ; string gadget#
popwin.i ; popup window# for list
listbox.i ; gadget# for popup listview
listbox_oldproc.i ; oldproc for listbox
parent.i ; root window of application
dynamic.b ; bool for auto-add content to list on stringgadget lostfocus, 1=add, 0=no add
minlength.b ; minimum number of chars for text to be added to popup list
EndStructure
Interface iAutoCompleteObject
Attach ( gadget, *strings, size )
AddString ( gadget, *string )
DeleteString ( gadget, *string )
Release ()
EndInterface
Global _nmAC_Hook, _nmAC_ListFont = LoadFont(#PB_Any, "MS San Serif", 8)
Global NewList _nmAC_Pops()
Procedure AddString(*this.AutoCompleteObject, gadget, *string )
text$ = PeekS(*string)
ForEach *this\pstr()
If UCase(*this\pstr()\prompt) = UCase(text$)
ProcedureReturn 0
EndIf
Next
AddElement(*this\pstr())
*this\pstr()\gadget = gadget
*this\pstr()\prompt = PeekS(*string)
SortStructuredList(*this\pstr(), #PB_Sort_Ascending, OffsetOf(stringdb\prompt), #PB_String)
ProcedureReturn 1
EndProcedure
Procedure ShowPopupList(hwnd, *this.AutoCompleteObject)
Protected NewList strings.s()
text$ = GetGadgetText(*this\gadget)
If text$ <> ""
ForEach *this\pstr()
If Left(UCase(*this\pstr()\prompt), Len(text$)) = UCase(text$)
AddElement(strings())
strings()= *this\pstr()\prompt
EndIf
Next
If ListSize(strings())
GetWindowRect_(hwnd, @wr.RECT)
parent = PB_Gadget_GetRootWindow(hwnd)
With wp.point
\x = GadgetX(*this\gadget)
\y = GadgetY(*this\gadget)+GadgetHeight(*this\gadget)
EndWith
ClientToScreen_(parent, @wp)
hdc = CreateCompatibleDC_(0)
lastwidth = 0 + 80
ForEach strings()
GetTextExtentPoint32_(hdc, strings(), Len(strings()), @sz.size)
If sz\cx > lastwidth
lastwidth = sz\cx +80
EndIf
Next
DeleteDC_(hdc)
popwinheight = 15*ListSize(strings())+3
If popwinheight > 500
popwinheight = 500
EndIf
ResizeWindow(*this\popwin, wp\x,wp\y,lastwidth, popwinheight)
ResizeGadget(*this\listbox, 0,0, WindowWidth(*this\popwin),WindowHeight(*this\popwin))
ClearGadgetItems(*this\listbox)
ForEach strings()
AddGadgetItem(*this\listbox, -1, strings())
Next
HideWindow(*this\popwin,0)
SetFocus_(hwnd)
Else
ClearList(strings())
ClearGadgetItems(*this\listbox)
If IsWindowVisible_(WindowID(*this\popwin))
HideWindow(*this\popwin, 1)
EndIf
EndIf
Else
ClearList(strings())
ClearGadgetItems(*this\listbox)
If IsWindowVisible_(WindowID(*this\popwin))
HideWindow(*this\popwin, 1)
EndIf
EndIf
EndProcedure
Procedure _nmAC_StringProc(hwnd, msg, wparam, lparam)
*this.AutoCompleteObject = GetProp_(hwnd, "acdata")
Protected oldproc = *this\subclass_oldproc
Select msg
Case #WM_NCDESTROY
RemoveProp_(hwnd, "oldproc")
Case #WM_LBUTTONUP, #WM_KEYUP
ForEach _nmAC_Pops()
HideWindow(_nmAC_Pops(), 1)
Next
ShowPopupList(hwnd, *this)
If msg=#WM_KEYUP
Select wParam
Case #VK_DOWN
If IsWindowVisible_(WindowID(*this\popwin))
SetActiveGadget(*this\listbox)
SetGadgetState(*this\listbox,0)
EndIf
Case #VK_ESCAPE
ForEach _nmAC_Pops()
HideWindow(_nmAC_Pops(), 1)
Next
EndSelect
EndIf
Case #WM_KILLFOCUS
If *this\dynamic
If wParam <> WindowID(*this\popwin) And wParam <> hwnd
text$ = GetGadgetText(*this\gadget)
If Len(text$)>=*this\minlength
AddString(*this, *this\gadget, @text$)
EndIf
EndIf
EndIf
EndSelect
ProcedureReturn CallWindowProc_(oldproc, hwnd, msg, wparam, lparam)
EndProcedure
Procedure DeleteString(*this.AutoCompleteObject, gadget, *string )
text$ = PeekS(*string)
If text$
ForEach *this\pstr()
If UCase(*this\pstr()\prompt) = UCase(text$)
DeleteElement(*this\pstr())
ProcedureReturn 1
EndIf
Next
ProcedureReturn 0
Else
ProcedureReturn 0
EndIf
EndProcedure
Procedure _nmAC_ListProc(hwnd, msg, wparam, lparam)
Static hold=1 ; Logical device to prevent premature jump to String Gadget
*this.AutoCompleteObject = GetProp_(hwnd, "acdata")
oldproc = *this\listbox_oldproc
Select msg
Case #WM_NCDESTROY
RemoveProp_(hwnd, "oldproc")
Case #WM_KEYUP
If wParam = #VK_TAB Or wParam = #VK_SPACE Or wparam = #VK_RETURN
text$ = GetGadgetText(*this\listbox)
SetGadgetText(*this\gadget, text$)
HideWindow(*this\popwin, 1)
ElseIf wparam = #VK_ESCAPE
HideWindow(*this\popwin, 1)
ElseIf wparam = #VK_UP
If GetGadgetState(*this\listbox) = 0
If Not hold
SetGadgetState(*this\listbox, -1)
SetActiveGadget(*this\gadget)
EndIf
EndIf
EndIf
Case #WM_KEYDOWN
If GetGadgetState(*this\listbox) = 0
hold=0
Else
hold=1
EndIf
Case #WM_LBUTTONDBLCLK
text$ = GetGadgetText(*this\listbox)
SetGadgetText(*this\gadget, text$)
HideWindow(*this\popwin, 1)
Case #WM_RBUTTONUP
text$ = GetGadgetText(*this\listbox)
If text$
If MessageRequester("Autocomplete:","Remove "+Chr(34)+text$+Chr(34)+" from this List?", #MB_YESNO) = #PB_MessageRequester_Yes
Deletestring(*this, *this\gadget, @text$)
EndIf
EndIf
SetFocus_(*this\gadget)
ShowPopupList(GadgetID(*this\gadget), *this)
EndSelect
ProcedureReturn CallWindowProc_(oldproc, hwnd, msg, wparam, lparam)
EndProcedure
Procedure MouseHook(nCode, wParam, lParam)
If wParam = #WM_LBUTTONDOWN
*ms.MSLLHOOKSTRUCT = lparam
clickwindow = WindowFromPoint_(*ms\pt\x|(*ms\pt\y<<32))
If Not GetProp_(clickwindow, "acdata")
wn$ = Space(100)
GetWindowText_(clickwindow, @wn$, 99)
If wn$ <> "Autocomplete:" And wn$ <> "&Yes" And wn$<> "&No"
ForEach _nmAC_Pops()
HideWindow(_nmAC_Pops(), 1)
Next
EndIf
EndIf
EndIf
ProcedureReturn CallNextHookEx_(_nmAC_Hook, nCode, wParam, lParam)
EndProcedure
Procedure Attach(*this.AutoCompleteObject, gadget, *strings, size )
Protected fail_status = #False
*ptr = *strings
For i=1 To size
AddElement(*this\pstr())
*this\pstr()\gadget = gadget
*this\pstr()\prompt = PeekS(PeekL(*ptr))
*ptr+SizeOf(integer)
Next
SortStructuredList(*this\pstr(), #PB_Sort_Ascending, OffsetOf(stringdb\prompt), #PB_String)
If IsGadget(gadget) And GadgetType(gadget) = #PB_GadgetType_String
*this\gadget = gadget
SetProp_(GadgetID(gadget), "acdata", *this )
*this\subclass_oldproc = SetWindowLongPtr_(GadgetID(gadget), #GWL_WNDPROC, @_nmAC_StringProc())
*this\parent = PB_Gadget_GetRootWindow(hwnd)
*this\popwin = OpenWindow(#PB_Any, 0,0,200,100,"ACPopup",#PB_Window_BorderLess|#PB_Window_Invisible, *this\parent)
AddElement(_nmAC_Pops())
_nmAC_Pops() = *this\popwin
SetWindowLongPtr_(WindowID(*this\popwin), #GWL_EXSTYLE, GetWindowLongPtr_(WindowID(*this\popwin), #GWL_EXSTYLE)|#WS_EX_TOOLWINDOW|#WS_EX_STATICEDGE)
SetWindowPos_(WindowID(*this\popwin), 0,0,0,0,0,#SWP_NOMOVE|#SWP_NOSIZE|#SWP_NOZORDER|#SWP_FRAMECHANGED)
StickyWindow(*this\popwin, 1)
old = UseGadgetList(0)
*this\listbox = ListViewGadget(#PB_Any,0,0,200,100)
UseGadgetList(old)
SetGadgetFont(*this\listbox, FontID(_nmAC_ListFont))
SetProp_(GadgetID(*this\listbox), "acdata", *this )
*this\listbox_oldproc = SetWindowLongPtr_(GadgetID(*this\listbox), #GWL_WNDPROC, @_nmAC_ListProc())
If Not _nmAC_Hook
_nmAC_Hook = SetWindowsHookEx_(#WH_MOUSE_LL, @MouseHook(), 0, 0)
EndIf
Else
fail_status = #True
EndIf
ProcedureReturn 1-fail_status ; 1=success, 0=failed
EndProcedure
Procedure NewObject_Autocomplete(dynamic=0, minlength=3) ; ( [dynamic], [minlength] )
*newobject.AutoCompleteObject = AllocateMemory(SizeOf(AutoCompleteObject))
If *newobject
InitializeStructure(*newobject, AutoCompleteObject)
With *newobject
\vTable = ?AutoComplete_Methods
\dynamic = dynamic
\minlength = minlength
EndWith
ProcedureReturn *newobject
Else
ProcedureReturn 0
EndIf
EndProcedure
Procedure Release(*this.AutoCompleteObject)
If *this\subclass_oldproc
SetWindowLongPtr_(GadgetID(*this\gadget),#GWL_WNDPROC, *this\subclass_oldproc)
EndIf
If IsWindow(*this\popwin)
CloseWindow(*this\popwin)
EndIf
ClearStructure(*this, AutoCompleteObject)
FreeMemory(*this)
EndProcedure
DataSection
AutoComplete_Methods:
Data.l @Attach(), @AddString(), @DeleteString(), @Release()
EndDataSection
;=================================================================
; END OF INCLUDE CODESECTION
;=================================================================
;XIncludeFile "Autocomplete_Object.pbi"
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"
w=OpenWindow(#PB_Any,0,0,640,480,"",#PB_Window_ScreenCentered|#PB_Window_SystemMenu)
StringGadget(6, 10,10, 300,20,"")
StringGadget(7, 10,50, 300,20,"")
prompts.iAutoCompleteObject = NewObject_Autocomplete(1)
prompts\Attach(6, @strings(), 17 )
prompts\AddString(6, @"Excellent")
prompts2.iAutoCompleteObject = NewObject_Autocomplete()
prompts2\Attach(7, @strings(), 17 )
SetActiveGadget(6)
Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
prompts\Release()
prompts2\Release()
Re: Ouvrir une combo sans utiliser la souris
J'utilise toujours cette procédure AutoCompleteComboBox... j'ai fait un petit exemple
Bon travail...
Code : Tout sélectionner
Procedure AutocompleteComboBox_SearchEdit(hwnd.l, lParam.l)
Tampon.s = Space(50)
GetClassName_(hwnd, @Tampon, 50)
If Tampon = "Edit" ; Nom de l'objet recherché
PokeL(lParam, hwnd)
EndIf
ProcedureReturn #True
EndProcedure
Procedure AutocompleteComboBox(ComboBox.l)
ComboxEdit = 0
EnumChildWindows_(GadgetID(ComboBox), @AutocompleteComboBox_SearchEdit(), @ComboxEdit)
TextTyped.s = UCase (GetGadgetText(ComboBox))
SendMessage_(ComboxEdit, #EM_GETSEL, @Selection_Start, @Selection_End)
LenTextTyped = Selection_Start
LenTextSave = GetGadgetData(ComboBox)
If LenTextTyped <= LenTextSave
SetGadgetData(ComboBox, LenTextTyped)
ElseIf LenTextTyped
MaxItem.l = CountGadgetItems(ComboBox) - 1
For Item.l = 0 To MaxItem
ItemText.s = GetGadgetItemText(ComboBox, Item, 0)
If TextTyped = UCase (Left(ItemText, LenTextTyped))
SetGadgetState(ComboBox, Item)
Selection_Start = LenTextTyped
Selection_End = Len(ItemText)
SendMessage_(ComboxEdit, #EM_SETSEL, Selection_Start, Selection_End)
SetGadgetData(ComboBox, LenTextTyped)
Item = MaxItem
Break
EndIf
Next
EndIf
EndProcedure
; un petit exemple avec une mini-liste de prénoms mis en ordre alphabétique...
LoadFont(3,"arial", 12,#PB_Font_Bold)
SetGadgetFont(#PB_Default,FontID(3))
OpenWindow(0,0,0,400,200,"",#PB_Window_SystemMenu | #PB_Window_ScreenCentered)
ComboBoxGadget(1, 10, 40, 300, 25, #PB_ComboBox_UpperCase | #PB_ComboBox_Editable)
AddGadgetItem(1,-1,"Albert"): AddGadgetItem(1,-1,"Antoine"): AddGadgetItem(1,-1,"Aymerick")
AddGadgetItem(1,-1,"Benoit"): AddGadgetItem(1,-1,"Bernard"): AddGadgetItem(1,-1,"Brunehilde")
AddGadgetItem(1,-1,"Bruno"): AddGadgetItem(1,-1,"Charles"): AddGadgetItem(1,-1,"Claude")
AddGadgetItem(1,-1,"Claudine"): AddGadgetItem(1,-1,"Fabien"): AddGadgetItem(1,-1,"Fabrice")
AddGadgetItem(1,-1,"Fernand"): AddGadgetItem(1,-1,"Georges"): AddGadgetItem(1,-1,"Guy")
AddGadgetItem(1,-1,"Henri"): AddGadgetItem(1,-1,"Henriette"): AddGadgetItem(1,-1,"Martine")
SetActiveGadget(1)
Repeat
glEvent = WaitWindowEvent()
glGadget= EventGadget()
If glEvent = #PB_Event_Gadget
Select glGadget
Case 1
AutocompleteComboBox(1)
EndSelect
EndIf
Until glEvent = #PB_Event_CloseWindow
Re: Ouvrir une combo sans utiliser la souris
Bonjour beruska et merci beaucoup pour ce partage !
Microsoft Windows 10 Famille 64 bits : Carte mère : ASRock 970 Extreme3 R2.0 : Carte Graphique NVIDIA GeForce RTX 3080 : Processeur AMD FX 6300 6 cœurs 12 threads 3,50 GHz PB 6.20 LTS (x64)
Un homme doit être poli, mais il doit aussi être libre !
Un homme doit être poli, mais il doit aussi être libre !
Re: Ouvrir une combo sans utiliser la souris
J'aime bien la clarté et la légèreté de la proposition de Beruska (excellent, ça pourrait être intégré aux fonctionnalités du gadget) et les fonctionnalités de celles rapportées par Mesa.
Un truc intéressant serait un mix des deux: c'est-à-dire celle de Beruska avec en plus une petite fenêtre flottante indiquant les autres termes possibles (si plus de 1 possible). (même sans être sélectionnable)
Peut-être en utilisant simplement la fonctionnalité ToolTip ? Mais la partie compliquée serait de forcer le ToolTip à réapparaitre à chaque frappe de clavier (peut-être avec #PB_EventType_Change) ?

Un truc intéressant serait un mix des deux: c'est-à-dire celle de Beruska avec en plus une petite fenêtre flottante indiquant les autres termes possibles (si plus de 1 possible). (même sans être sélectionnable)
Peut-être en utilisant simplement la fonctionnalité ToolTip ? Mais la partie compliquée serait de forcer le ToolTip à réapparaitre à chaque frappe de clavier (peut-être avec #PB_EventType_Change) ?

Re: Ouvrir une combo sans utiliser la souris
Celle de netmaestro, je l'ai utilisée pour mon conjugueur et elle est géniale, je pense que celle de beruska, bien que plus légère, est surement équivalente.
Microsoft Windows 10 Famille 64 bits : Carte mère : ASRock 970 Extreme3 R2.0 : Carte Graphique NVIDIA GeForce RTX 3080 : Processeur AMD FX 6300 6 cœurs 12 threads 3,50 GHz PB 6.20 LTS (x64)
Un homme doit être poli, mais il doit aussi être libre !
Un homme doit être poli, mais il doit aussi être libre !
- falsam
- Messages : 7317
- Inscription : dim. 22/août/2010 15:24
- Localisation : IDF (Yvelines)
- Contact :
Re: Ouvrir une combo sans utiliser la souris
le code de Beruska est plus léger et répond au plus prés à la demande d'Omega. Manque plus que l'affichage de la combo box durant la saisie.
Configuration : Windows 11 Famille 64-bit - PB 6.20 x64 - AMD Ryzen 7 - 16 GO RAM
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%