Page 1 sur 1

Ouvrir une combo sans utiliser la souris

Publié : dim. 29/mars/2015 18:35
par omega
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

Re: Ouvrir une combo sans utiliser la souris

Publié : dim. 29/mars/2015 20:13
par Fig
En plaçant un hook sur le clavier par exemple ? :?:

Re: Ouvrir une combo sans utiliser la souris

Publié : lun. 30/mars/2015 9:25
par Marc56
Hello Omega,

Comme souvent en programmation, ce qui paraît simple au premier abord, l'est moins à l’exécution 8O :(
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 :roll: )

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

Re: Ouvrir une combo sans utiliser la souris

Publié : lun. 30/mars/2015 14:46
par Mesa
Si tu fais une recherche avec combobox autocomplete, ou autocompletion, tu devrais avoir plein de réponses comme celle-ci (sur le forum anglais)

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
[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.

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()

M.

Re: Ouvrir une combo sans utiliser la souris

Publié : lun. 30/mars/2015 21:33
par beruska
J'utilise toujours cette procédure AutoCompleteComboBox... j'ai fait un petit exemple

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
Bon travail...

Re: Ouvrir une combo sans utiliser la souris

Publié : mar. 31/mars/2015 8:14
par Micoute
Bonjour beruska et merci beaucoup pour ce partage !

Re: Ouvrir une combo sans utiliser la souris

Publié : mar. 31/mars/2015 9:25
par Marc56
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) ?

:P

Re: Ouvrir une combo sans utiliser la souris

Publié : mar. 31/mars/2015 11:16
par Micoute
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.

Re: Ouvrir une combo sans utiliser la souris

Publié : mar. 31/mars/2015 11:21
par falsam
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.