ComboBox with delete icon

Post your working scripts, libraries and tools for AHK v1.1 and older
drozdman
Posts: 78
Joined: 05 Dec 2015, 01:07

ComboBox with delete icon

29 Sep 2018, 17:09

When I saw this nice TAB library by jballi with delete icons for tabs, I got an idea to make something like that for ComboBox. It can't be done with the same method (owner draw), though.
I used SetWinEventHook with the event EVENT_OBJECT_SELECTION.
To paint the delete icon I used either TextOut or DrawIconEx (icon in Win7/8).

Code: Select all

#SingleInstance force
Menu, Tray, Icon, shell32.dll,  3 
Menu, Tray, Add, Exit , Close 
Menu, Tray, Default, Exit 

SetWinDelay, -1
SetControlDelay, -1



global del_ico:=0 ; 0= text "X", 1= icon
global objListIDs:= Object() 
global single_ico:=0


global List_id, List_id_2, GuiHwnd  
Gui,1: +HWNDGuiHwnd 
Gui,1:Font,  S10 CDefault , Segoe UI  


Gui,1:Font,  S10  , Segoe UI
queries:="1note|2note|3note|4note|5note|6note|7note|8note|11note|12note|13note|14note"
Gui,1:Add, ComboBox, x50 y40  +HWNDList_id vqueryList  , %queries% ;gCombo
	fn := Func("List_Func").Bind(List_id)
	GuiControl, +g, % List_id, % fn	

 Gui,1:Add, ComboBox, x50 y100  +HWNDList_id_2 vqueryList_2  , %queries%|2note|3note|4note|5note ;gCombo

	fn := Func("List_Func").Bind(List_id_2)
	GuiControl, +g, % List_id_2, % fn	


Gui 1:Show, w300 h200 , Test_Drozd 


Gosub, Combo_WinEvent
return



;====================================================


List_Func(hwnd, win){
	global Win_ID, Gui1_Id, List__
	
		del:=ComboDel(hwnd)		
			if(del==1)
				return

}



	ComboDel(hwnd){
		VarSetCapacity(POINT,8,0)
		DllCall("GetCursorPos","Ptr",&POINT)
		DllCall("ScreenToClient","Ptr",hwnd,"Ptr",&POINT)
		x:=NumGet(POINT,0,"Int")
		y:=NumGet(POINT,4,"Int") 

		GuiControlGet, Pos, Pos, %hwnd%
		GuiControlGet, item_,,	%hwnd%
		
		if(PosW-x<20){
			MsgBox, 0x00040003, , Do you want to delete this item? `n%item_% ;+100 "No" as default
				IfMsgBox, No
					return 1
				IfMsgBox Cancel
					return 1
				 
		GuiControl, +AltSubmit, %hwnd%
		GuiControlGet, line_,, %hwnd%
		Control, Delete, %line_%,, ahk_id %hwnd%
		GuiControl, -AltSubmit, %hwnd%     
		;ToolTip_("Deleted item:" "`n" item_ , 1)
		;del_in_ini(item_)
				return 1	
		}		
		return 0 
	}
	
;====================================================


WinProcCallback(hWinEventHook, event, hwnd, idObject, idChild, dwEventThread, dwmsEventTime){
  Critical  
  if !hwnd
    return
  event:=Format("0x{1:x}",event) ; decimal to hexadecimal
	hwnd:=Format("0x{1:x}",hwnd) 
	;EVENT_OBJECT_REORDER:= 0x8004, EVENT_OBJECT_FOCUS:= 0x8005, EVENT_OBJECT_SELECTION:= 0x8006
	if(event=0x8006){ ;EVENT_OBJECT_SELECTION		
		del_icons(hwnd,del_ico)
		return 0
	}
}


UnhookWinEvent(hWinEventHook){
  DllCall("UnhookWinEvent", "Ptr",hWinEventHook)
  DllCall("CoUninitialize")
}


;====================================================

Combo_WinEvent:
EVENT_OBJECT_REORDER:= 0x8004, EVENT_OBJECT_FOCUS:= 0x8005, EVENT_OBJECT_SELECTION:= 0x8006

global CB_EditID , CB_ListID
	CtrlHwnd:=List_id
	VarSetCapacity(CB_info, 40 + (3 * A_PtrSize), 0)
	NumPut(40 + (3 * A_PtrSize), CB_info, 0, "UInt")
	DllCall("User32.dll\GetComboBoxInfo", "Ptr", CtrlHwnd, "Ptr", &CB_info)
	CB_EditID := NumGet(CB_info, 40 + A_PtrSize, "Ptr") ;48/44
	CB_ListID := NumGet(CB_info, 40 + (2 * A_PtrSize), "Ptr") ; 56/48
	
	CB_EditID:=Format("0x{1:x}",CB_EditID) , CB_ListID:=Format("0x{1:x}",CB_ListID) 
	
	GuiHwnd_:=CB_ListID
	ThreadId := DllCall("GetWindowThreadProcessId", "Int", GuiHwnd_, "UInt*", PID)	

	
EventHook:=DllCall("SetWinEventHook","UInt",0x8006,"UInt",0x8006,"Ptr",0,"Ptr"
					,RegisterCallback("WinProcCallback")	,"UInt", PID,"UInt", ThreadId,"UInt", 0)  

	OnExit(Func("UnhookWinEvent").Bind(EventHook))	
	
	objListIDs[CB_ListID]:=List_id	
;---

	CtrlHwnd:=List_id_2
	DllCall("User32.dll\GetComboBoxInfo", "Ptr", CtrlHwnd, "Ptr", &CB_info)
	CB_ListID_2 := NumGet(CB_info, 40 + (2 * A_PtrSize), "Ptr") ; 56/48
	CB_ListID_2:=Format("0x{1:x}",CB_ListID_2) 
	
	GuiHwnd_:=CB_ListID_2
	ThreadId_2 := DllCall("GetWindowThreadProcessId", "Int", GuiHwnd_, "UInt*", PID2)	 ; LPDWORD
 
	
EventHook_2:=DllCall("SetWinEventHook","UInt",0x8006,"UInt",0x8006,"Ptr",0,"Ptr"
				,RegisterCallback("WinProcCallback"),"UInt", PID2,"UInt", ThreadId_2,"UInt", 0)  ; from this	

	OnExit(Func("UnhookWinEvent").Bind(EventHook_2))	
	objListIDs[CB_ListID_2]:=List_id_2	
	
return


;====================================================



del_icons(CB_ListID,del_ico:=0){
	List_id:=objListIDs[CB_ListID]
	SendMessage,0x0146,0,0, ,% "ahk_id " List_id ;CB_GETCOUNT:= 0x0146
	len:=ErrorLevel
	WinGetPos, ,,, CB_height, ahk_id %CB_ListID% 
	row_height2:=CB_height/len
	SendMessage,0x0154,1,0, ,% "ahk_id " List_id ;CB_GETITEMHEIGHT:= 0x0154
	row_height:= ErrorLevel
	
	if(List_id=List_id_2){
		iconOnWin(CB_ListID,len,row_height)
	}else{
		if(del_ico)
			iconOnWin(CB_ListID,len,row_height)
		else
			textOnWin(CB_ListID,len,row_height,"X")
	}
}


textOnWin(hwnd, len,row_h,text_:="X"){  ;% Chr(215) × "X"

	hDC := DllCall("User32.dll\GetDC", "Ptr", hwnd)
	WinGetPos, x, y, W, H, ahk_id %hwnd% 
	x:=W-12,y:=0
	heightF:=12 , weight:=400,fontName:="Arial"  ;"Segoe Print"
	widthF:=6
	hFont:=DllCall("CreateFont", "Int", heightF,"Int",widthF, "Int",  0, "Int", 0,"Int",  weight, "Uint", 0,"Uint", 0,"uint", 0, "Uint", 0, "Uint", 0, "Uint", 0, "Uint", 0, "Uint", 0, "str", fontName)
	DllCall("SelectObject", "UPtr", hDC, "UPtr", hFont, "UPtr")
	colorR:=0x0000BB
	colorG:=0xAFAFAF

 

	VarSetCapacity(POINT,8,0)
	DllCall("GetCursorPos","Ptr",&POINT)
	DllCall("ScreenToClient","Ptr",hwnd,"Ptr",&POINT)
	PosX:=NumGet(POINT,0,"Int"),		PosY:=NumGet(POINT,4,"Int") 
		
	colorR:=0x0000EE
	m:=2
	y:=m
	Loop, % len {

		if(PosY>=y-m && PosY<y+row_h-m){
			DllCall("SetTextColor", "UPtr", hDC, "UInt",colorR )
			DllCall("SetBkMode","Ptr",hDC,"Int",1) ;TRANSPARENT := 1
			DllCall("TextOut", "uint",hDC, "int",x, "int",y, "str",text_, "int",StrLen(text_)) 		
		}else{	
			if(!single_ico && !del_ico){
				DllCall("SetTextColor", "UPtr", hDC, "UInt",colorG )
				DllCall("SetBkMode","Ptr",hDC,"Int",1) ;TRANSPARENT := 1
				DllCall("TextOut", "uint",hDC, "int",x, "int",y, "str",text_, "int",StrLen(text_)) 
			}
		}
		y+=row_h
	}
DllCall("DeleteObject", "UPtr", hFont)
DllCall("ReleaseDC", "Uint", hwnd, "Uint", hDC)
}


;==============================================
iconOnWin(hwnd,len,row_h){
	;hIcon:=LoadPicture("C:\AutoHotkey Scripts\icons\test\Close_16x16.ico","",ImageType)
	;hIcon:=LoadPicture("shell32.dll","Icon132 w16 h-1" ,ImageType) ; 
	hIcon:=LoadPicture("imageres.dll","Icon162 w16 h-1" ,ImageType) ; Win7,8
	
	hDC := DllCall("User32.dll\GetDC", "Ptr", hwnd)
	
	WinGetPos, x, y, W, H, ahk_id %hwnd% 
	x:=W-18,y:=0
	VarSetCapacity(POINT,8,0)
	DllCall("GetCursorPos","Ptr",&POINT)
	DllCall("ScreenToClient","Ptr",hwnd,"Ptr",&POINT)
	PosX:=NumGet(POINT,0,"Int"),		PosY:=NumGet(POINT,4,"Int")

	cxWidth:=cyWidth:=0
	m:=0
	y:=m
	Loop, % len {
		if(PosY>=y-m && PosY<y+row_h-m){
			RC:=DllCall("DrawIconEx","Ptr",hDC,"Int",x ,"Int",y ,"Ptr",hIcon ,"Int",cxWidth ,"Int",cyWidth ,"UInt",0 ,"Ptr",0,"UInt",0x3)
		}
		y+=row_h
	}
	DllCall("ReleaseDC", "Uint", CtrlHwnd, "Uint", hDC)	
}

;====================================================



GuiClose:
Close:
Esc:: 
ExitApp
	


[attachment=0]Combo delete icon.png[/attachment]
Attachments
Combo delete icon.png
(3.39 KiB) Downloaded 142 times
User avatar
jballi
Posts: 727
Joined: 29 Sep 2013, 17:34

Re: ComboBox with delete icon

02 Oct 2018, 19:56

Cool! 8-) Thanks for sharing.
DRocks
Posts: 565
Joined: 08 May 2018, 10:20

Re: ComboBox with delete icon

03 Oct 2018, 10:05

wow. this is great man. Thanks for showing how to do that!

Return to “Scripts and Functions (v1)”

Who is online

Users browsing this forum: No registered users and 180 guests